相关支付

This commit is contained in:
hy001 2026-06-24 12:57:33 +08:00
parent 720c7cec50
commit 21bab83eea
10 changed files with 336 additions and 158 deletions

View File

@ -175,6 +175,7 @@ gateway:
- /product/apple/config - /product/apple/config
- /game/sud/** - /game/sud/**
- /web/pay/** - /web/pay/**
- /order/web/pay/**
- /external/oss/upload - /external/oss/upload
- /telegram/webhook - /telegram/webhook
- /account/create/getRegion - /account/create/getRegion

View File

@ -3,13 +3,14 @@ package com.red.circle.order.inner.model.cmd;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.red.circle.framework.core.dto.CommonCommand; import com.red.circle.framework.core.dto.CommonCommand;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.io.Serial; import java.io.Serial;
import java.math.BigDecimal; import java.math.BigDecimal;
import lombok.Data; import java.util.List;
import lombok.EqualsAndHashCode; import lombok.Data;
import lombok.experimental.Accessors; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/** /**
* <p> * <p>
@ -43,11 +44,17 @@ public class SysPayApplicationCommodityCmd extends CommonCommand {
/** /**
* 开通支付国家. * 开通支付国家.
*/ */
@JsonSerialize(using = ToStringSerializer.class) @JsonSerialize(using = ToStringSerializer.class)
private Long payCountryId; private Long payCountryId;
/** /**
* 区域ID. * 批量创建时的国家列表表结构仍是一条商品对应一个国家所以只在新增时拆成多条记录.
*/
@JsonSerialize(contentUsing = ToStringSerializer.class)
private List<Long> payCountryIds;
/**
* 区域ID.
*/ */
private String regionId; private String regionId;

View File

@ -1,12 +1,13 @@
package com.red.circle.order.app.command.pay.web; package com.red.circle.order.app.command.pay.web;
import com.google.api.client.util.Lists; import com.google.api.client.util.Lists;
import com.google.api.client.util.Maps; import com.google.api.client.util.Maps;
import com.google.api.client.util.Sets; import com.google.api.client.util.Sets;
import com.red.circle.common.business.core.amount.PayAmountArithmeticUtils; import com.red.circle.common.business.core.amount.PayAmountArithmeticUtils;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum; import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.framework.core.asserts.ResponseAssert; import com.red.circle.common.business.core.util.CountryCodeAliasUtils;
import com.red.circle.framework.core.response.CommonErrorCode; import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.order.app.convertor.PayAppConvertor; import com.red.circle.order.app.convertor.PayAppConvertor;
import com.red.circle.order.app.dto.clientobject.pay.ApplicationCommodityCardV2CO; import com.red.circle.order.app.dto.clientobject.pay.ApplicationCommodityCardV2CO;
import com.red.circle.order.app.dto.clientobject.pay.PayApplicationCO; import com.red.circle.order.app.dto.clientobject.pay.PayApplicationCO;
@ -23,6 +24,8 @@ import com.red.circle.order.infra.database.rds.service.pay.PayApplicationCommodi
import com.red.circle.order.infra.database.rds.service.pay.PayApplicationService; import com.red.circle.order.infra.database.rds.service.pay.PayApplicationService;
import com.red.circle.order.infra.database.rds.service.pay.PayChannelService; import com.red.circle.order.infra.database.rds.service.pay.PayChannelService;
import com.red.circle.order.infra.database.rds.service.pay.PayCountryChannelDetailsService; import com.red.circle.order.infra.database.rds.service.pay.PayCountryChannelDetailsService;
import com.red.circle.other.inner.endpoint.sys.SysCountryCodeClient;
import com.red.circle.other.inner.model.dto.sys.SysCountryCodeDTO;
import com.red.circle.tool.core.collection.CollectionUtils; import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.num.ArithmeticUtils; import com.red.circle.tool.core.num.ArithmeticUtils;
import com.red.circle.tool.core.text.StringUtils; import com.red.circle.tool.core.text.StringUtils;
@ -54,6 +57,7 @@ public class PayWebApplicationCommodityV2QueryExe {
private final PayCountryAliasResolver payCountryAliasResolver; private final PayCountryAliasResolver payCountryAliasResolver;
private final PayApplicationCommodityService payApplicationCommodityService; private final PayApplicationCommodityService payApplicationCommodityService;
private final PayCountryChannelDetailsService payCountryChannelDetailsService; private final PayCountryChannelDetailsService payCountryChannelDetailsService;
private final SysCountryCodeClient sysCountryCodeClient;
public ApplicationCommodityCardV2CO execute(PayWebApplicationCommodityCmd cmd) { public ApplicationCommodityCardV2CO execute(PayWebApplicationCommodityCmd cmd) {
@ -165,7 +169,17 @@ public class PayWebApplicationCommodityV2QueryExe {
} }
private PayCountry getPayCountry(PayWebApplicationCommodityCmd cmd) { private PayCountry getPayCountry(PayWebApplicationCommodityCmd cmd) {
return payCountryAliasResolver.resolveUsablePayCountry(cmd.getPayCountryId()); if (Objects.nonNull(cmd.getPayCountryId()) || StringUtils.isBlank(cmd.getCountryCode())) {
return payCountryAliasResolver.resolveUsablePayCountry(cmd.getPayCountryId());
}
String normalizedCountryCode = CountryCodeAliasUtils.normalizePaymentCountryCode(
cmd.getCountryCode());
SysCountryCodeDTO countryCode = ResponseAssert.requiredSuccess(
sysCountryCodeClient.getByCode(normalizedCountryCode));
ResponseAssert.notNull(CommonErrorCode.NOT_SUPPORTED_REGION, countryCode);
// H5 只传用户国家码这里仅把真实国家转成商品表使用的支付国家ID是否开放支付国家由 H5 JSON 控制.
return payCountryAliasResolver.resolveUsablePayCountryByCountryId(countryCode.getId());
} }
private List<PayChannelDetailsCO> getPayChannels(List<PayChannel> payChannels, private List<PayChannelDetailsCO> getPayChannels(List<PayChannel> payChannels,

View File

@ -26,8 +26,10 @@ public class PayWebOrderStatusQueryExe {
public PayOrderStatusCO execute(PayOrderStatusCmd cmd) { public PayOrderStatusCO execute(PayOrderStatusCmd cmd) {
OrderUserPurchasePay mysqlOrder = getMysqlOrder(cmd.getOrderId()); OrderUserPurchasePay mysqlOrder = getMysqlOrder(cmd.getOrderId());
ResponseAssert.notNull(OrderErrorCode.NO_PURCHASE_RECORD_FOUND, mysqlOrder); ResponseAssert.notNull(OrderErrorCode.NO_PURCHASE_RECORD_FOUND, mysqlOrder);
Long expectedUserId = Objects.nonNull(cmd.getReqUserId()) ? cmd.getReqUserId() : cmd.getUserId();
// 登录态请求继续使用网关注入的 reqUserId公开 H5 轮询没有登录态只允许用下单用户ID校验同一笔订单.
ResponseAssert.isTrue(OrderErrorCode.NO_PURCHASE_RECORD_FOUND, ResponseAssert.isTrue(OrderErrorCode.NO_PURCHASE_RECORD_FOUND,
Objects.equals(mysqlOrder.getUserId(), cmd.getReqUserId())); Objects.nonNull(expectedUserId) && Objects.equals(mysqlOrder.getUserId(), expectedUserId));
InAppPurchaseStatus status = MiFaPayMysqlOrderSupport InAppPurchaseStatus status = MiFaPayMysqlOrderSupport
.toInAppPurchaseStatus(mysqlOrder.getPayStatus()); .toInAppPurchaseStatus(mysqlOrder.getPayStatus());
return new PayOrderStatusCO() return new PayOrderStatusCO()

View File

@ -14,17 +14,15 @@ import com.red.circle.other.inner.endpoint.sys.SysCountryCodeClient;
import com.red.circle.other.inner.model.dto.sys.SysCountryCodeDTO; import com.red.circle.other.inner.model.dto.sys.SysCountryCodeDTO;
import com.red.circle.tool.core.collection.CollectionUtils; import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.parse.DataTypeUtils; import com.red.circle.tool.core.parse.DataTypeUtils;
import com.red.circle.tool.core.regex.RegexConstant; import com.red.circle.tool.core.regex.RegexConstant;
import com.red.circle.tool.core.text.StringUtils; import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.other.inner.asserts.user.UserErrorCode; import com.red.circle.other.inner.asserts.user.UserErrorCode;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO; import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.other.inner.model.dto.user.reigon.RegionRelationDTO; import com.red.circle.other.inner.endpoint.user.region.UserRegionClient;
import com.red.circle.other.inner.enums.user.RegionRelationGroupEnum; import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
import com.red.circle.other.inner.endpoint.user.region.RegionRelationClient;
import com.red.circle.other.inner.endpoint.user.region.UserRegionClient;
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
import com.red.circle.wallet.inner.endpoint.freight.FreightGoldClient; import com.red.circle.wallet.inner.endpoint.freight.FreightGoldClient;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -47,9 +45,8 @@ public class UserProfileAndCountryQueryExe {
private final PayCountryAliasResolver payCountryAliasResolver; private final PayCountryAliasResolver payCountryAliasResolver;
private final UserProfileClient userProfileClient; private final UserProfileClient userProfileClient;
private final SysCountryCodeClient sysCountryCodeClient; private final SysCountryCodeClient sysCountryCodeClient;
private final RegionRelationClient regionRelationClient;
public UserProfileAndCountryCO execute(PayWebUserCmd cmd) {
public UserProfileAndCountryCO execute(PayWebUserCmd cmd) {
UserProfileDTO userProfile = getUserProfile(cmd); UserProfileDTO userProfile = getUserProfile(cmd);
@ -64,27 +61,17 @@ public class UserProfileAndCountryQueryExe {
.toWebSiteUseProfileCO(userProfile); .toWebSiteUseProfileCO(userProfile);
webSiteUseProfile.setAccount(userProfile.actualAccount()); webSiteUseProfile.setAccount(userProfile.actualAccount());
List<PayCountry> payCountryList; String regionId = ResponseAssert.requiredSuccess(
userRegionClient.getRegionId(userProfile.getId())
String regionId = ResponseAssert.requiredSuccess( );
userRegionClient.getRegionId(userProfile.getId())
); if (Objects.equals(cmd.getSysOrigin(), SysOriginPlatformEnum.LIKEI.name())) {
return toLikeiUserCountryResult(userProfile, webSiteUseProfile, regionId);
if (Objects.equals(cmd.getSysOrigin(), SysOriginPlatformEnum.LIKEI.name())) { }
ResponseAssert.isTrue(CommonErrorCode.NOT_SUPPORTED_REGION, StringUtils.isNotBlank(regionId));
List<PayCountry> payCountryList = payCountryService.listAllShelf();
List<RegionRelationDTO> regionRelationList = getRegionRelationList(userProfile, regionId); Map<Long, SysCountryCodeDTO> mapCountryCode = getMapCountryCode(payCountryList);
ResponseAssert.notEmpty(CommonErrorCode.NOT_SUPPORTED_REGION, regionRelationList); ResponseAssert.notEmpty(CommonErrorCode.NOT_SUPPORTED_REGION, mapCountryCode);
payCountryList = getPayCountryList(regionRelationList);
ResponseAssert.notEmpty(CommonErrorCode.NOT_SUPPORTED_REGION, payCountryList);
} else {
payCountryList = payCountryService.listAllShelf();
}
Map<Long, SysCountryCodeDTO> mapCountryCode = getMapCountryCode(payCountryList);
ResponseAssert.notEmpty(CommonErrorCode.NOT_SUPPORTED_REGION, mapCountryCode);
Map<Long, PayCountry> compatiblePayCountryMap = getCompatiblePayCountryMap(payCountryList); Map<Long, PayCountry> compatiblePayCountryMap = getCompatiblePayCountryMap(payCountryList);
return new UserProfileAndCountryCO() return new UserProfileAndCountryCO()
@ -105,9 +92,48 @@ public class UserProfileAndCountryQueryExe {
}).filter(Objects::nonNull).collect(Collectors.toList())) }).filter(Objects::nonNull).collect(Collectors.toList()))
.setUserProfile(webSiteUseProfile) .setUserProfile(webSiteUseProfile)
.setRegionId(regionId); .setRegionId(regionId);
} }
private UserProfileAndCountryCO toLikeiUserCountryResult(UserProfileDTO userProfile,
WebSiteUseProfileCO webSiteUseProfile, String regionId) {
SysCountryCodeDTO countryCode = getUserCountryCode(userProfile);
ResponseAssert.notNull(CommonErrorCode.NOT_SUPPORTED_REGION, countryCode);
PayCountry compatiblePayCountry = payCountryAliasResolver
.resolveUsablePayCountryByCountryId(countryCode.getId());
// LIKEI/Yumi 的支付国家开放由 H5 JSON 控制这里仅返回用户真实国家商品接口再按国家码查该国商品.
PayCountryCO payCountryCO = new PayCountryCO()
.setId(Objects.nonNull(compatiblePayCountry) ? compatiblePayCountry.getId() : null)
.setPayCountryId(Objects.nonNull(compatiblePayCountry) ? compatiblePayCountry.getId() : null)
.setCountryId(countryCode.getId())
.setCurrency(Objects.nonNull(compatiblePayCountry) ? compatiblePayCountry.getCurrency() : null)
.setCountry(countryCode);
return new UserProfileAndCountryCO()
.setCountryList(Collections.singletonList(payCountryCO))
.setUserProfile(webSiteUseProfile)
.setRegionId(regionId);
}
private SysCountryCodeDTO getUserCountryCode(UserProfileDTO userProfile) {
if (Objects.nonNull(userProfile.getCountryId())) {
return ResponseAssert.requiredSuccess(
sysCountryCodeClient.getById(userProfile.getCountryId())
);
}
if (StringUtils.isNotBlank(userProfile.getCountryCode())) {
return ResponseAssert.requiredSuccess(
sysCountryCodeClient.getByCode(userProfile.getCountryCode())
);
}
return null;
}
private UserProfileDTO getUserProfile(PayWebUserCmd cmd) { private UserProfileDTO getUserProfile(PayWebUserCmd cmd) {
if (StringUtils.isNotBlank(cmd.getAccount()) && StringUtils.isNotBlank(cmd.getSysOrigin())) { if (StringUtils.isNotBlank(cmd.getAccount()) && StringUtils.isNotBlank(cmd.getSysOrigin())) {
@ -146,18 +172,4 @@ public class UserProfileAndCountryQueryExe {
(left, right) -> left)); (left, right) -> left));
} }
private List<RegionRelationDTO> getRegionRelationList(UserProfileDTO userProfile, }
String regionId) {
return ResponseAssert.requiredSuccess(
regionRelationClient
.listByRegionId(regionId, userProfile.getOriginSys(),
RegionRelationGroupEnum.OPEN_PAY_COUNTRY)
);
}
private List<PayCountry> getPayCountryList(List<RegionRelationDTO> regionRelationList) {
return payCountryService
.listByIds(regionRelationList.stream().map(RegionRelationDTO::getRelationId).collect(
Collectors.toSet()));
}
}

View File

@ -23,4 +23,9 @@ public class PayOrderStatusCmd extends AppExtCommand {
*/ */
@NotBlank(message = "orderId required.") @NotBlank(message = "orderId required.")
private String orderId; private String orderId;
/**
* H5公开支付页没有登录态轮询状态时必须用下单用户ID继续做订单归属校验.
*/
private Long userId;
} }

View File

@ -27,13 +27,18 @@ public class PayWebApplicationCommodityCmd extends AppExtCommand {
@NotNull(message = "applicationId required.") @NotNull(message = "applicationId required.")
private Long applicationId; private Long applicationId;
/** /**
* 国家. * 国家.
*/ */
private Long payCountryId; private Long payCountryId;
/** /**
* 金币类型. * 国家编码H5 先拿用户国家再用国家码查询商品避免前端硬编码支付国家ID.
*/
private String countryCode;
/**
* 金币类型.
*/ */
private PayApplicationCommodityType type; private PayApplicationCommodityType type;

View File

@ -1,8 +1,9 @@
package com.red.circle.order.inner.service.impl; package com.red.circle.order.inner.service.impl;
import com.alibaba.nacos.shaded.com.google.common.collect.Lists; import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
import com.red.circle.framework.core.asserts.ResponseAssert; import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.dto.PageResult; import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.order.infra.database.rds.entity.pay.PayApplication; import com.red.circle.order.infra.database.rds.entity.pay.PayApplication;
import com.red.circle.order.infra.database.rds.entity.pay.PayApplicationCommodity; import com.red.circle.order.infra.database.rds.entity.pay.PayApplicationCommodity;
import com.red.circle.order.infra.database.rds.service.pay.PayApplicationCommodityService; import com.red.circle.order.infra.database.rds.service.pay.PayApplicationCommodityService;
@ -13,16 +14,17 @@ import com.red.circle.order.inner.model.cmd.SysPayApplicationCommodityQryCmd;
import com.red.circle.order.inner.model.dto.SysPayApplicationCommodityDTO; import com.red.circle.order.inner.model.dto.SysPayApplicationCommodityDTO;
import com.red.circle.order.inner.model.dto.SysPayApplicationDTO; import com.red.circle.order.inner.model.dto.SysPayApplicationDTO;
import com.red.circle.order.inner.service.PayApplicationClientService; import com.red.circle.order.inner.service.PayApplicationClientService;
import com.red.circle.tool.core.collection.CollectionUtils; import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.text.StringUtils; import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.other.inner.endpoint.user.region.RegionConfigClient; import com.red.circle.other.inner.endpoint.user.region.RegionConfigClient;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/** /**
* 开通支付应用. * 开通支付应用.
@ -106,11 +108,31 @@ public class PayApplicationClientServiceImpl implements PayApplicationClientServ
Collectors.toSet()))); Collectors.toSet())));
} }
@Override @Override
public void addOrUpdateCommodity(SysPayApplicationCommodityCmd param) { @Transactional(rollbackFor = Exception.class)
payApplicationCommodityService.saveOrUpdate( public void addOrUpdateCommodity(SysPayApplicationCommodityCmd param) {
webPayInnerConvertor.toPayApplicationCommodity(param)); if (Objects.nonNull(param.getId()) || CollectionUtils.isEmpty(param.getPayCountryIds())) {
} // 编辑沿用原来的单条更新批量国家只服务新增避免一次编辑误伤多个已存在商品.
payApplicationCommodityService.saveOrUpdate(
webPayInnerConvertor.toPayApplicationCommodity(param));
return;
}
List<PayApplicationCommodity> commodities = param.getPayCountryIds().stream()
.filter(Objects::nonNull)
.distinct()
.map(payCountryId -> {
PayApplicationCommodity commodity = webPayInnerConvertor.toPayApplicationCommodity(param);
// 商品表当前以国家维度存储新增多选国家时需要拆成多条独立商品记录.
commodity.setId(null);
commodity.setPayCountryId(payCountryId);
return commodity;
})
.collect(Collectors.toList());
ResponseAssert.notEmpty(CommonErrorCode.NOT_FOUND_RECORD_INFO, commodities);
payApplicationCommodityService.saveBatch(commodities);
}
@Override @Override
public void switchShelf(Long id, Boolean shelf) { public void switchShelf(Long id, Boolean shelf) {

View File

@ -1,5 +1,5 @@
package com.red.circle.other.app.command.team.query; package com.red.circle.other.app.command.team.query;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.red.circle.common.business.dto.cmd.app.AppIdLongCmd; import com.red.circle.common.business.dto.cmd.app.AppIdLongCmd;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor; import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
@ -24,10 +24,10 @@ import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
* 团队成员列表. * 团队成员列表.
* *
@ -36,58 +36,43 @@ import org.springframework.stereotype.Component;
@Component @Component
@RequiredArgsConstructor @RequiredArgsConstructor
public class TeamMemberListQryExe { public class TeamMemberListQryExe {
private final TeamMemberService teamMemberService; private final TeamMemberService teamMemberService;
private final UserProfileGateway userProfileGateway; private final UserProfileGateway userProfileGateway;
private final UserProfileAppConvertor userProfileAppConvertor; private final UserProfileAppConvertor userProfileAppConvertor;
private final TeamMemberTargetService teamMemberTargetService; private final TeamMemberTargetService teamMemberTargetService;
private final TeamPolicyManagerService teamPolicyManagerService; private final TeamPolicyManagerService teamPolicyManagerService;
private final TeamProfileService teamProfileService; private final TeamProfileService teamProfileService;
public List<TeamMemberCO> execute(AppIdLongCmd cmd) { public List<TeamMemberCO> execute(AppIdLongCmd cmd) {
List<TeamMember> teamMembers = teamMemberService.listTeamMember(cmd.getId(), List<TeamMember> teamMembers = teamMemberService.listTeamMember(cmd.getId(),
3000); 3000);
if (CollectionUtils.isEmpty(teamMembers)) { if (CollectionUtils.isEmpty(teamMembers)) {
return Lists.newArrayList(); return Lists.newArrayList();
} }
Set<Long> memberUserIds = teamMembers.stream().map(TeamMember::getMemberId) Set<Long> memberUserIds = teamMembers.stream().map(TeamMember::getMemberId)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Map<Long, UserProfileDTO> userProfileMap = userProfileAppConvertor.toMapUserProfileDTO( Map<Long, UserProfileDTO> userProfileMap = userProfileAppConvertor.toMapUserProfileDTO(
userProfileGateway.mapByUserIds(memberUserIds)); userProfileGateway.mapByUserIds(memberUserIds));
Map<Long, TeamMemberTarget> teamMemberTargetMap = teamMemberTargetService.mapMemberBillTarget( Map<Long, TeamMemberTarget> teamMemberTargetMap = teamMemberTargetService.mapMemberBillTarget(
cmd.getId(), memberUserIds, ZonedDateTimeAsiaRiyadhUtils.nowYearMonthToInt()); cmd.getId(), memberUserIds, ZonedDateTimeAsiaRiyadhUtils.nowYearMonthToInt());
List<TeamMemberCO> teamMemberCOs = teamMembers.stream().map(teamMember -> new TeamMemberCO() List<TeamMemberCO> teamMemberCOs = teamMembers.stream()
.setId(teamMember.getMemberId()) .map(teamMember -> assembleTeamMemberCO(
.setUserProfile(userProfileMap.get(teamMember.getMemberId())) teamMember,
.setTargetFormat(Optional.ofNullable(teamMemberTargetMap.get(teamMember.getMemberId())) userProfileMap.get(teamMember.getMemberId()),
.map(target -> NumUtils.formatLong(target.sumAcceptGiftValue())) teamMemberTargetMap.get(teamMember.getMemberId())))
.orElse("0")) .collect(Collectors.toList());
.setTimeHours(Optional.ofNullable(teamMemberTargetMap.get(teamMember.getMemberId()))
.map(target -> BigDecimal.valueOf(target.sumAllTargetTime())
.divide(BigDecimal.valueOf(60), 2, RoundingMode.DOWN)
.stripTrailingZeros().toPlainString())
.orElse("0"))
.setEffectiveDay(Optional.ofNullable(teamMemberTargetMap.get(teamMember.getMemberId()))
.map(TeamMemberTarget::sumEffectiveDay)
.orElse(0))
.setUseDiamonds("0")
.setSurplusDiamonds("0")
.setRole(Objects.toString(teamMember.getRole()))
.setWalletWithdrawal(Objects.isNull(teamMember.getWalletWithdrawal()) || Objects.equals(
teamMember.getWalletWithdrawal(), Boolean.TRUE))
.setCreateTime(teamMember.getCreateTime())
).collect(Collectors.toList());
return teamMemberCOs; return teamMemberCOs;
} }
public TeamMemberCountResultCO executeCount(AppIdLongCmd cmd) { public TeamMemberCountResultCO executeCount(AppIdLongCmd cmd) {
List<TeamMember> teamMembers = teamMemberService.listTeamMember(cmd.getId(), List<TeamMember> teamMembers = teamMemberService.listTeamMember(cmd.getId(),
3000); 3000);
if (CollectionUtils.isEmpty(teamMembers)) { if (CollectionUtils.isEmpty(teamMembers)) {
return new TeamMemberCountResultCO() return new TeamMemberCountResultCO()
.setMemberQuantity(0) .setMemberQuantity(0)
@ -95,7 +80,7 @@ public class TeamMemberListQryExe {
.setTargetFormatSum("0") .setTargetFormatSum("0")
.setTargetSum(0L); .setTargetSum(0L);
} }
// 获取团队信息和政策管理器 // 获取团队信息和政策管理器
TeamProfile teamProfile = teamProfileService.getById(cmd.getId()); TeamProfile teamProfile = teamProfileService.getById(cmd.getId());
if (teamProfile == null) { if (teamProfile == null) {
@ -105,10 +90,10 @@ public class TeamMemberListQryExe {
.setTargetFormatSum("0") .setTargetFormatSum("0")
.setTargetSum(0L); .setTargetSum(0L);
} }
TeamPolicyManager teamPolicyManager = teamPolicyManagerService.getReleaseByRegionAndType( TeamPolicyManager teamPolicyManager = teamPolicyManagerService.getReleaseByRegionAndType(
teamProfile.getSysOrigin(), teamProfile.getRegion()); teamProfile.getSysOrigin(), teamProfile.getRegion());
if (teamPolicyManager == null || CollectionUtils.isEmpty(teamPolicyManager.getPolicy())) { if (teamPolicyManager == null || CollectionUtils.isEmpty(teamPolicyManager.getPolicy())) {
return new TeamMemberCountResultCO() return new TeamMemberCountResultCO()
.setMemberQuantity(teamMembers.size()) .setMemberQuantity(teamMembers.size())
@ -116,30 +101,30 @@ public class TeamMemberListQryExe {
.setTargetFormatSum("0") .setTargetFormatSum("0")
.setTargetSum(0L); .setTargetSum(0L);
} }
// 获取团队成员的目标总和 // 获取团队成员的目标总和
Set<Long> memberUserIds = teamMembers.stream().map(TeamMember::getMemberId) Set<Long> memberUserIds = teamMembers.stream().map(TeamMember::getMemberId)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Map<Long, TeamMemberTarget> teamMemberTargetMap = teamMemberTargetService.mapMemberBillTarget( Map<Long, TeamMemberTarget> teamMemberTargetMap = teamMemberTargetService.mapMemberBillTarget(
cmd.getId(), memberUserIds, ZonedDateTimeAsiaRiyadhUtils.nowYearMonthToInt()); cmd.getId(), memberUserIds, ZonedDateTimeAsiaRiyadhUtils.nowYearMonthToInt());
// 计算目标总和 // 计算目标总和
Long targetSum = teamMemberTargetMap.values().stream() Long targetSum = teamMemberTargetMap.values().stream()
.filter(Objects::nonNull) .filter(Objects::nonNull)
.mapToLong(target -> Optional.ofNullable(target.sumAcceptGiftValue()).orElse(0L)) .mapToLong(target -> Optional.ofNullable(target.sumAcceptGiftValue()).orElse(0L))
.sum(); .sum();
// 根据团队目标总和匹配对应的TeamPolicy返回对应的挡位 // 根据团队目标总和匹配对应的TeamPolicy返回对应的挡位
Integer matchedLevel = findMatchedLevel(teamPolicyManager.getPolicy(), targetSum); Integer matchedLevel = findMatchedLevel(teamPolicyManager.getPolicy(), targetSum);
return new TeamMemberCountResultCO() return new TeamMemberCountResultCO()
.setMemberQuantity(teamMembers.size()) .setMemberQuantity(teamMembers.size())
.setLevel(matchedLevel) .setLevel(matchedLevel)
.setTargetFormatSum(NumUtils.formatLong(targetSum)) .setTargetFormatSum(NumUtils.formatLong(targetSum))
.setTargetSum(targetSum); .setTargetSum(targetSum);
} }
/** /**
* 根据目标总和查找匹配的等级. * 根据目标总和查找匹配的等级.
* 逻辑从高等级到低等级遍历找到第一个满足条件的等级 * 逻辑从高等级到低等级遍历找到第一个满足条件的等级
@ -152,7 +137,7 @@ public class TeamMemberListQryExe {
if (CollectionUtils.isEmpty(policies) || targetSum == null) { if (CollectionUtils.isEmpty(policies) || targetSum == null) {
return null; return null;
} }
// 按等级降序排列从高等级到低等级匹配 // 按等级降序排列从高等级到低等级匹配
return policies.stream() return policies.stream()
.sorted((p1, p2) -> Integer.compare(p2.getLevel(), p1.getLevel())) .sorted((p1, p2) -> Integer.compare(p2.getLevel(), p1.getLevel()))
@ -161,24 +146,61 @@ public class TeamMemberListQryExe {
.map(TeamPolicy::getLevel) .map(TeamPolicy::getLevel)
.orElse(0); .orElse(0);
} }
public List<TeamMemberCO> searchTeamMember(Long reqUserId, String account) { private TeamMemberCO assembleTeamMemberCO(
TeamMember reqTeamMember = teamMemberService.getByMemberId(reqUserId); TeamMember teamMember,
if (reqTeamMember == null) { UserProfileDTO userProfile,
return Collections.emptyList(); TeamMemberTarget teamMemberTarget) {
} return new TeamMemberCO()
.setId(teamMember.getMemberId())
List<UserProfile> userProfiles = userProfileGateway.getByAccount(account); .setUserProfile(userProfile)
if (CollectionUtils.isEmpty(userProfiles)) { .setTargetFormat(Optional.ofNullable(teamMemberTarget)
return Collections.emptyList(); .map(target -> NumUtils.formatLong(target.sumAcceptGiftValue()))
} .orElse("0"))
UserProfile userProfile = userProfiles.get(0); .setTimeHours(Optional.ofNullable(teamMemberTarget)
TeamMember teamMember = teamMemberService.getByMemberId(userProfile.getId()); .map(target -> BigDecimal.valueOf(target.sumAllTargetTime())
if (teamMember == null || !teamMember.getTeamId().equals(reqTeamMember.getTeamId())) { .divide(BigDecimal.valueOf(60), 2, RoundingMode.DOWN)
return Collections.emptyList(); .stripTrailingZeros().toPlainString())
} .orElse("0"))
return Collections.singletonList(new TeamMemberCO().setUserProfile(userProfileAppConvertor.toUserProfileDTO(userProfile))); .setEffectiveDay(Optional.ofNullable(teamMemberTarget)
.map(TeamMemberTarget::sumEffectiveDay)
.orElse(0))
.setUseDiamonds("0")
.setSurplusDiamonds("0")
.setRole(Objects.toString(teamMember.getRole()))
.setWalletWithdrawal(Objects.isNull(teamMember.getWalletWithdrawal()) || Objects.equals(
teamMember.getWalletWithdrawal(), Boolean.TRUE))
.setCreateTime(teamMember.getCreateTime());
}
public List<TeamMemberCO> searchTeamMember(Long reqUserId, String account) {
TeamMember reqTeamMember = teamMemberService.getByMemberId(reqUserId);
if (reqTeamMember == null) {
return Collections.emptyList();
} }
List<UserProfile> userProfiles = userProfileGateway.getByAccount(account);
if (CollectionUtils.isEmpty(userProfiles)) {
return Collections.emptyList();
}
UserProfile userProfile = userProfiles.get(0);
TeamMember teamMember = teamMemberService.getByMemberId(userProfile.getId());
if (teamMember == null || !teamMember.getTeamId().equals(reqTeamMember.getTeamId())) {
return Collections.emptyList();
}
TeamMemberTarget teamMemberTarget = teamMemberTargetService
.mapMemberBillTarget(
reqTeamMember.getTeamId(),
Collections.singleton(teamMember.getMemberId()),
ZonedDateTimeAsiaRiyadhUtils.nowYearMonthToInt())
.get(teamMember.getMemberId());
return Collections.singletonList(assembleTeamMemberCO(
teamMember,
userProfileAppConvertor.toUserProfileDTO(userProfile),
teamMemberTarget));
}
} }

View File

@ -0,0 +1,88 @@
package com.red.circle.other.app.command.team.query;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.clientobject.team.TeamMemberCO;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMember;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamMemberTarget;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberTargetService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamPolicyManagerService;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamProfileService;
import com.red.circle.other.inner.enums.team.TeamMemberTargetIndex;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
class TeamMemberListQryExeTest {
@Test
void searchTeamMemberShouldReturnCurrentWorkSummary() {
TeamMemberService teamMemberService = mock(TeamMemberService.class);
UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
UserProfileAppConvertor userProfileAppConvertor = mock(UserProfileAppConvertor.class);
TeamMemberTargetService teamMemberTargetService = mock(TeamMemberTargetService.class);
TeamPolicyManagerService teamPolicyManagerService = mock(TeamPolicyManagerService.class);
TeamProfileService teamProfileService = mock(TeamProfileService.class);
TeamMemberListQryExe exe = new TeamMemberListQryExe(
teamMemberService,
userProfileGateway,
userProfileAppConvertor,
teamMemberTargetService,
teamPolicyManagerService,
teamProfileService
);
Long requesterUserId = 2064760394110529538L;
Long targetUserId = 2065155499803865089L;
Long teamId = 2064760394110529538L;
UserProfile targetProfile = new UserProfile();
targetProfile.setId(targetUserId);
targetProfile.setAccount("1018375");
targetProfile.setUserNickname("misra");
UserProfileDTO targetProfileDTO = new UserProfileDTO();
TeamMember requesterMember = new TeamMember()
.setMemberId(requesterUserId)
.setTeamId(teamId);
TeamMember targetMember = new TeamMember()
.setMemberId(targetUserId)
.setTeamId(teamId);
TeamMemberTarget target = new TeamMemberTarget()
.setUserId(targetUserId)
.setTeamId(teamId)
.setDailyTargets(List.of(
new TeamMemberTargetIndex()
.setAcceptGiftValue(425_289L)
.setOwnOnlineTime(2L)
.setEffectiveDay(1)
));
when(teamMemberService.getByMemberId(requesterUserId)).thenReturn(requesterMember);
when(userProfileGateway.getByAccount("1018375")).thenReturn(List.of(targetProfile));
when(teamMemberService.getByMemberId(targetUserId)).thenReturn(targetMember);
when(userProfileAppConvertor.toUserProfileDTO(targetProfile)).thenReturn(targetProfileDTO);
when(teamMemberTargetService.mapMemberBillTarget(
eq(teamId),
eq(Collections.singleton(targetUserId)),
anyInt())).thenReturn(Map.of(targetUserId, target));
List<TeamMemberCO> result = exe.searchTeamMember(requesterUserId, "1018375");
assertEquals(1, result.size());
assertEquals(targetUserId, result.get(0).getId());
assertSame(targetProfileDTO, result.get(0).getUserProfile());
assertEquals("425.28K", result.get(0).getTargetFormat());
assertEquals("0.03", result.get(0).getTimeHours());
assertEquals(1, result.get(0).getEffectiveDay());
}
}