自动结算
This commit is contained in:
parent
6573219751
commit
85f3ffbc10
@ -28,6 +28,11 @@ public class TeamManualSalaryPaymentCmd extends Command {
|
||||
*/
|
||||
private String countryCode;
|
||||
|
||||
/**
|
||||
* 工资账期,为空时使用当前整月账期.
|
||||
*/
|
||||
private Integer billBelong;
|
||||
|
||||
/**
|
||||
* 指定发放用户,为空时按国家全量发放.
|
||||
*/
|
||||
|
||||
@ -27,6 +27,11 @@ public class TeamManualSalaryPaymentQryCmd extends PageCommand {
|
||||
*/
|
||||
private String countryCode;
|
||||
|
||||
/**
|
||||
* 工资账期,为空时使用当前整月账期.
|
||||
*/
|
||||
private Integer billBelong;
|
||||
|
||||
/**
|
||||
* 用户 id.
|
||||
*/
|
||||
|
||||
@ -146,6 +146,11 @@ public class TeamManualSalaryPaymentDTO implements Serializable {
|
||||
*/
|
||||
private BigDecimal currentSalaryBalance;
|
||||
|
||||
/**
|
||||
* 当前用户是否为团队代理本人.
|
||||
*/
|
||||
private Boolean agentMember;
|
||||
|
||||
/**
|
||||
* 当前档位是否已发放.
|
||||
*/
|
||||
|
||||
@ -228,6 +228,7 @@ public class TeamSalaryBackServiceImpl implements TeamSalaryBackService {
|
||||
.setMemberOverIssuedSalary(dto.getMemberOverIssuedSalary())
|
||||
.setAgentOverIssuedSalary(dto.getAgentOverIssuedSalary())
|
||||
.setCurrentSalaryBalance(dto.getCurrentSalaryBalance())
|
||||
.setAgentMember(dto.getAgentMember())
|
||||
.setPaid(dto.getPaid());
|
||||
}
|
||||
|
||||
|
||||
@ -30,6 +30,7 @@ import com.red.circle.tool.core.sequence.IdWorkerUtils;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Duration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -96,7 +97,10 @@ public class GmVipGiftServiceImpl implements GmVipGiftService {
|
||||
expireAt, now);
|
||||
vipOrderRecordService.save(order);
|
||||
|
||||
Set<Long> previousResourceIds = vipResourceIds(currentState);
|
||||
upsertUserVipState(currentState, userProfile, config, startAt, expireAt, now);
|
||||
expireSupersededVipResources(userProfile.getOriginSys(), userProfile.getId(), config,
|
||||
previousResourceIds, now);
|
||||
giftVipResources(userProfile.getId(), config, now, cmd.getReqUserId());
|
||||
|
||||
GmVipGiftRecord record = buildGiftRecord(cmd, applicant, userProfile, fromLevel, config,
|
||||
@ -272,6 +276,63 @@ public class GmVipGiftServiceImpl implements GmVipGiftService {
|
||||
now, opUser);
|
||||
}
|
||||
|
||||
private void expireSupersededVipResources(String sysOrigin, Long userId,
|
||||
VipLevelConfig targetConfig, Set<Long> previousResourceIds, Timestamp now) {
|
||||
Set<Long> targetResourceIds = vipResourceIds(targetConfig);
|
||||
Set<Long> allVipResourceIds = new HashSet<>();
|
||||
vipLevelConfigService.query()
|
||||
.eq(VipLevelConfig::getSysOrigin, sysOrigin)
|
||||
.list()
|
||||
.forEach(config -> allVipResourceIds.addAll(vipResourceIds(config)));
|
||||
allVipResourceIds.addAll(previousResourceIds);
|
||||
allVipResourceIds.removeAll(targetResourceIds);
|
||||
if (CollectionUtils.isEmpty(allVipResourceIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
userPropsBackpackService.update()
|
||||
.set(UserPropsBackpack::getExpireTime, now)
|
||||
.set(UserPropsBackpack::getUseProps, Boolean.FALSE)
|
||||
.set(UserPropsBackpack::getAllowGive, Boolean.FALSE)
|
||||
.set(UserPropsBackpack::getUpdateTime, now)
|
||||
.eq(UserPropsBackpack::getUserId, userId)
|
||||
.in(UserPropsBackpack::getPropsId, allVipResourceIds)
|
||||
.gt(UserPropsBackpack::getExpireTime, now)
|
||||
.execute();
|
||||
}
|
||||
|
||||
private Set<Long> vipResourceIds(VipLevelConfig config) {
|
||||
Set<Long> ids = new HashSet<>();
|
||||
if (Objects.isNull(config)) {
|
||||
return ids;
|
||||
}
|
||||
addPositive(ids, config.getBadgeResourceId());
|
||||
addPositive(ids, config.getAvatarFrameResourceId());
|
||||
addPositive(ids, config.getEntryEffectResourceId());
|
||||
addPositive(ids, config.getChatBubbleResourceId());
|
||||
addPositive(ids, config.getFloatPictureResourceId());
|
||||
return ids;
|
||||
}
|
||||
|
||||
private Set<Long> vipResourceIds(UserVipState state) {
|
||||
Set<Long> ids = new HashSet<>();
|
||||
if (Objects.isNull(state)) {
|
||||
return ids;
|
||||
}
|
||||
addPositive(ids, state.getBadgeResourceId());
|
||||
addPositive(ids, state.getAvatarFrameResourceId());
|
||||
addPositive(ids, state.getEntryEffectResourceId());
|
||||
addPositive(ids, state.getChatBubbleResourceId());
|
||||
addPositive(ids, state.getFloatPictureResourceId());
|
||||
return ids;
|
||||
}
|
||||
|
||||
private void addPositive(Set<Long> ids, Long id) {
|
||||
if (Objects.nonNull(id) && id > 0) {
|
||||
ids.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
private void giveProp(Long userId, Long propsId, String type, Integer days, Timestamp now,
|
||||
Long opUser) {
|
||||
if (Objects.isNull(propsId) || propsId <= 0 || Objects.isNull(days) || days <= 0) {
|
||||
|
||||
@ -52,5 +52,6 @@ public class TeamManualSalaryCO implements Serializable {
|
||||
private BigDecimal memberOverIssuedSalary;
|
||||
private BigDecimal agentOverIssuedSalary;
|
||||
private BigDecimal currentSalaryBalance;
|
||||
private Boolean agentMember;
|
||||
private Boolean paid;
|
||||
}
|
||||
|
||||
@ -132,10 +132,10 @@ public class TestRestController extends BaseController {
|
||||
teamSalaryPaymentTask.teamSalaryPaymentTaskTest();
|
||||
}
|
||||
|
||||
@PostMapping("/processTeamMonthBill")
|
||||
public void processTeamMonthBill() {
|
||||
teamBillTask.processTeamBillRetry();
|
||||
}
|
||||
@PostMapping("/processTeamMonthBill")
|
||||
public void processTeamMonthBill() {
|
||||
teamBillTask.processTeamMonthBillTest();
|
||||
}
|
||||
|
||||
@PostMapping("/activity/send/game")
|
||||
public void activitySendGame(@RequestBody RewardPoolCmd cmd) {
|
||||
|
||||
@ -2,7 +2,6 @@ package com.red.circle.other.app.command.bd.query;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||
import com.red.circle.component.redis.RedisKeys;
|
||||
import com.red.circle.component.redis.service.RedisService;
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.order.inner.endpoint.InAppPurchaseDetailsClient;
|
||||
@ -17,7 +16,6 @@ import com.red.circle.other.app.service.BdSalarySettlementServiceImpl;
|
||||
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
||||
import com.red.circle.other.infra.database.mongo.dto.team.TeamBillMemberTarget;
|
||||
import com.red.circle.other.infra.database.mongo.entity.bd.BdSalaryPolicy;
|
||||
import com.red.circle.other.infra.database.mongo.entity.bd.BdSalarySettlementRecord;
|
||||
import com.red.circle.other.infra.database.mongo.entity.team.team.*;
|
||||
import com.red.circle.other.infra.database.mongo.service.bd.BdSalaryPolicyService;
|
||||
import com.red.circle.other.infra.database.mongo.service.team.team.*;
|
||||
@ -29,7 +27,6 @@ import com.red.circle.other.infra.database.rds.entity.team.BusinessDevelopmentBa
|
||||
import com.red.circle.other.infra.database.rds.entity.team.BusinessDevelopmentTeam;
|
||||
import com.red.circle.other.infra.database.rds.service.team.BusinessDevelopmentBaseInfoService;
|
||||
import com.red.circle.other.infra.database.rds.service.team.BusinessDevelopmentTeamService;
|
||||
import com.red.circle.other.inner.endpoint.team.bd.BdTeamLeaderClient;
|
||||
import com.red.circle.other.inner.enums.team.TeamBillCycleStatus;
|
||||
import com.red.circle.other.inner.model.dto.agency.agency.TeamCounter;
|
||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||
@ -43,8 +40,6 @@ import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.YearMonth;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
@ -80,8 +75,10 @@ public class TeamBdMemberBillListQryExe {
|
||||
* @return 账单列表
|
||||
*/
|
||||
public TeamBdMemberCO execute(TeamBdMemberBillCmd cmd) {
|
||||
Integer billBelong = resolveBillBelong(cmd.getBillBelong());
|
||||
|
||||
// 1. 缓存查询
|
||||
String key = "bdcenter:" + cmd.getType() + ":" + cmd.getReqUserId();
|
||||
String key = "bdcenter:" + cmd.getType() + ":" + cmd.getReqUserId() + ":" + billBelong;
|
||||
TeamBdMemberCO cached = redisService.getStringToObject(key, TeamBdMemberCO.class);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
@ -90,45 +87,68 @@ public class TeamBdMemberBillListQryExe {
|
||||
// 2. 根据类型执行不同的查询逻辑
|
||||
TeamBdMemberCO result;
|
||||
if ("BD".equals(cmd.getType())) {
|
||||
result = queryBdTeamData(cmd.getReqUserId());
|
||||
result = queryBdTeamData(cmd.getReqUserId(), billBelong);
|
||||
} else {
|
||||
result = queryBdLeaderTeamData(cmd.getReqUserId());
|
||||
result = queryBdLeaderTeamData(cmd.getReqUserId(), billBelong);
|
||||
}
|
||||
|
||||
// 3. 缓存结果
|
||||
redisService.setString(key, JSON.toJSONString(result), 2, TimeUnit.MINUTES);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Integer resolveBillBelong(Integer billBelong) {
|
||||
if (billBelong == null) {
|
||||
return TeamBillCycleUtils.getCalcBillBelong();
|
||||
}
|
||||
|
||||
String value = String.valueOf(billBelong);
|
||||
if (value.length() == 6) {
|
||||
int month = Integer.parseInt(value.substring(4, 6));
|
||||
if (month >= 1 && month <= 12) {
|
||||
return billBelong;
|
||||
}
|
||||
}
|
||||
|
||||
if (value.length() == 8) {
|
||||
try {
|
||||
LocalDate.of(
|
||||
Integer.parseInt(value.substring(0, 4)),
|
||||
Integer.parseInt(value.substring(4, 6)),
|
||||
Integer.parseInt(value.substring(6, 8)));
|
||||
return billBelong;
|
||||
} catch (RuntimeException ignored) {
|
||||
return TeamBillCycleUtils.getCalcBillBelong();
|
||||
}
|
||||
}
|
||||
|
||||
return TeamBillCycleUtils.getCalcBillBelong();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询 BD 的团队数据(返回 Agent 团队列表).
|
||||
*/
|
||||
private TeamBdMemberCO queryBdTeamData(Long bdUserId) {
|
||||
private TeamBdMemberCO queryBdTeamData(Long bdUserId, Integer currentBillBelong) {
|
||||
// 1. 查询该 BD 的所有团队
|
||||
List<BusinessDevelopmentTeam> bdTeamList = businessDevelopmentTeamService.listByUserId(bdUserId);
|
||||
|
||||
|
||||
if (CollectionUtils.isEmpty(bdTeamList)) {
|
||||
return createEmptyResult();
|
||||
return createEmptyResult(currentBillBelong);
|
||||
}
|
||||
|
||||
// 2. 获取当前账单周期
|
||||
Integer currentBillBelong = TeamBillCycleUtils.getCalcBillBelong();
|
||||
|
||||
// 3. 获取团队ID集合
|
||||
Set<Long> teamIdSet = bdTeamList.stream()
|
||||
.map(BusinessDevelopmentTeam::getTeamId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// 获取所有区域的政策配置
|
||||
Map<Long, TeamBillCycle> billCycleMap = teamBillCycleService.mapByTeamIds2(
|
||||
teamIdSet, currentBillBelong, TeamBillCycleStatus.UNPAID);
|
||||
Map<Long, TeamBillCycle> billCycleMap = getBillCycleMap(teamIdSet, currentBillBelong);
|
||||
Map<String, TeamPolicyManager> regionPolicyMap = teamPolicyManagerService.mapRegionReleaseWithCountry(
|
||||
billCycleMap.values().stream().map(TeamBillCycle::getRegion).collect(Collectors.toSet()));
|
||||
|
||||
// 4. 查询当前周期的账单
|
||||
Map<Long, List<TeamMemberTarget>> memberBillTarget =
|
||||
teamMemberTargetService.mapMemberBillTarget(teamIdSet, currentBillBelong);
|
||||
Map<Long, List<TeamMemberTarget>> memberBillTarget = getMemberBillTargetMap(teamIdSet, currentBillBelong);
|
||||
|
||||
// 5. 获取团队Profile信息
|
||||
Map<Long, TeamProfile> teamProfileMap = teamProfileService.mapProfileByIds(teamIdSet);
|
||||
@ -168,9 +188,9 @@ public class TeamBdMemberBillListQryExe {
|
||||
result.setTotalSalary(totalSalary);
|
||||
result.setTotalRecharge(totalRecharge);
|
||||
result.setBillTitle(TeamBillCycleUtils.parseBillBelongToDateRangeStr(currentBillBelong));
|
||||
|
||||
|
||||
// 11. 计算当前账单的 BD 工资信息
|
||||
BdHistoryCO bdHistoryCO = calculateCurrentBdBill(currentBillBelong,
|
||||
BdHistoryCO bdHistoryCO = calculateCurrentBdBill(currentBillBelong,
|
||||
bdTeamList.size(), totalSalary, totalRecharge);
|
||||
result.setBdHistoryCO(bdHistoryCO);
|
||||
|
||||
@ -180,27 +200,24 @@ public class TeamBdMemberBillListQryExe {
|
||||
/**
|
||||
* 查询 BD Leader 的团队数据(返回 BD 列表,每个 BD 汇总其所有团队).
|
||||
*/
|
||||
private TeamBdMemberCO queryBdLeaderTeamData(Long bdLeaderUserId) {
|
||||
private TeamBdMemberCO queryBdLeaderTeamData(Long bdLeaderUserId, Integer currentBillBelong) {
|
||||
// 1. 查询该 Leader 下的所有 BD
|
||||
List<BusinessDevelopmentBaseInfo> bdList =
|
||||
List<BusinessDevelopmentBaseInfo> bdList =
|
||||
businessDevelopmentBaseInfoService.listBdByLeadUserId(bdLeaderUserId);
|
||||
|
||||
|
||||
if (CollectionUtils.isEmpty(bdList)) {
|
||||
return createEmptyResult();
|
||||
return createEmptyResult(currentBillBelong);
|
||||
}
|
||||
|
||||
// 2. 获取当前账单周期
|
||||
Integer currentBillBelong = TeamBillCycleUtils.getCalcBillBelong();
|
||||
|
||||
// 3. 收集所有 BD 的用户ID
|
||||
Set<Long> bdUserIdSet = bdList.stream()
|
||||
.map(BusinessDevelopmentBaseInfo::getUserId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
|
||||
// 4. 批量查询所有 BD 的用户信息
|
||||
Map<Long, UserProfileDTO> bdUserProfileMap = userProfileAppConvertor.toMapUserProfileDTO(
|
||||
userProfileGateway.mapByUserIds(bdUserIdSet));
|
||||
|
||||
|
||||
// 5. 为每个 BD 构建汇总数据
|
||||
List<TeamBdMemberBillCO> memberBillList = bdList.stream()
|
||||
.map(bdInfo -> buildBdSummaryBillCO(bdInfo, bdUserProfileMap, currentBillBelong))
|
||||
@ -213,7 +230,7 @@ public class TeamBdMemberBillListQryExe {
|
||||
BigDecimal totalRecharge = memberBillList.stream()
|
||||
.map(TeamBdMemberBillCO::getTeamRechargeAmount)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
|
||||
// 7. 计算总的 Agent 数量(所有 BD 的 Agent 总和)
|
||||
Integer totalAgentCount = memberBillList.stream()
|
||||
.map(TeamBdMemberBillCO::getTeamMemberCount)
|
||||
@ -228,9 +245,9 @@ public class TeamBdMemberBillListQryExe {
|
||||
result.setTotalSalary(totalSalary);
|
||||
result.setTotalRecharge(totalRecharge);
|
||||
result.setBillTitle(TeamBillCycleUtils.parseBillBelongToDateRangeStr(currentBillBelong));
|
||||
|
||||
|
||||
// 9. 计算当前账单的 BD Leader 工资信息(使用总的 Agent 数量)
|
||||
BdHistoryCO bdHistoryCO = calculateCurrentBdBill(currentBillBelong,
|
||||
BdHistoryCO bdHistoryCO = calculateCurrentBdBill(currentBillBelong,
|
||||
totalAgentCount, totalSalary, totalRecharge);
|
||||
bdHistoryCO.setBdNumber(bdList.size());
|
||||
result.setBdHistoryCO(bdHistoryCO);
|
||||
@ -245,9 +262,9 @@ public class TeamBdMemberBillListQryExe {
|
||||
BusinessDevelopmentBaseInfo bdInfo,
|
||||
Map<Long, UserProfileDTO> bdUserProfileMap,
|
||||
Integer currentBillBelong) {
|
||||
|
||||
|
||||
TeamBdMemberBillCO co = new TeamBdMemberBillCO();
|
||||
|
||||
|
||||
// 1. 设置 BD 用户信息(这里的 Agent 字段实际上是 BD 信息)
|
||||
UserProfileDTO bdUserProfile = bdUserProfileMap.get(bdInfo.getUserId());
|
||||
if (bdUserProfile != null) {
|
||||
@ -256,11 +273,11 @@ public class TeamBdMemberBillListQryExe {
|
||||
co.setAgentName(bdUserProfile.getUserNickname());
|
||||
co.setAgentAvatar(bdUserProfile.getUserAvatar());
|
||||
}
|
||||
|
||||
|
||||
// 2. 查询该 BD 的所有团队
|
||||
List<BusinessDevelopmentTeam> bdTeamList =
|
||||
List<BusinessDevelopmentTeam> bdTeamList =
|
||||
businessDevelopmentTeamService.listByUserId(bdInfo.getUserId());
|
||||
|
||||
|
||||
if (CollectionUtils.isEmpty(bdTeamList)) {
|
||||
co.setTeamMemberCount(0);
|
||||
co.setTeamSalaryAmount(BigDecimal.ZERO);
|
||||
@ -269,30 +286,28 @@ public class TeamBdMemberBillListQryExe {
|
||||
co.setEndDate("");
|
||||
return co;
|
||||
}
|
||||
|
||||
|
||||
// 3. 设置团队数量(该 BD 管理的 Agent 数量)
|
||||
co.setTeamMemberCount(bdTeamList.size());
|
||||
|
||||
|
||||
// 4. 账单周期日期
|
||||
String[] dates = TeamBillCycleUtils.parseBillBelongToDateRange(currentBillBelong);
|
||||
co.setStartDate(dates[0]);
|
||||
co.setEndDate(dates[1]);
|
||||
|
||||
|
||||
// 5. 获取团队ID集合
|
||||
Set<Long> teamIdSet = bdTeamList.stream()
|
||||
.map(BusinessDevelopmentTeam::getTeamId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
|
||||
// 6. 查询账单数据
|
||||
Map<Long, TeamBillCycle> billCycleMap = teamBillCycleService.mapByTeamIds2(
|
||||
teamIdSet, currentBillBelong, TeamBillCycleStatus.UNPAID);
|
||||
Map<Long, TeamBillCycle> billCycleMap = getBillCycleMap(teamIdSet, currentBillBelong);
|
||||
|
||||
Map<String, TeamPolicyManager> regionPolicyMap = teamPolicyManagerService.mapRegionReleaseWithCountry(
|
||||
billCycleMap.values().stream().map(TeamBillCycle::getRegion).collect(Collectors.toSet()));
|
||||
|
||||
// 4. 查询当前周期的账单
|
||||
Map<Long, List<TeamMemberTarget>> memberBillTarget =
|
||||
teamMemberTargetService.mapMemberBillTarget(teamIdSet, currentBillBelong);
|
||||
Map<Long, List<TeamMemberTarget>> memberBillTarget = getMemberBillTargetMap(teamIdSet, currentBillBelong);
|
||||
|
||||
BigDecimal totalSalary = BigDecimal.ZERO;
|
||||
for (BusinessDevelopmentTeam bdTeam : bdTeamList) {
|
||||
@ -300,27 +315,25 @@ public class TeamBdMemberBillListQryExe {
|
||||
totalSalary = totalSalary.add(getTeamTotalSalary(billCycleMap, memberBillTarget, regionPolicyMap, teamId));
|
||||
}
|
||||
co.setTeamSalaryAmount(totalSalary);
|
||||
|
||||
|
||||
// 8. 获取所有 Agent ID
|
||||
Set<Long> teamIds = bdTeamList.stream()
|
||||
.map(BusinessDevelopmentTeam::getTeamId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
|
||||
// 9. 查询充值数据并汇总
|
||||
Map<Long, BigDecimal> rechargeMap = getRechargeMap(currentBillBelong, teamIds);
|
||||
BigDecimal totalRecharge = rechargeMap.values().stream()
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
co.setTeamRechargeAmount(totalRecharge);
|
||||
|
||||
|
||||
return co;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建空结果.
|
||||
*/
|
||||
private TeamBdMemberCO createEmptyResult() {
|
||||
Integer currentBillBelong = TeamBillCycleUtils.getCalcBillBelong();
|
||||
|
||||
private TeamBdMemberCO createEmptyResult(Integer currentBillBelong) {
|
||||
TeamBdMemberCO result = new TeamBdMemberCO();
|
||||
result.setMemberBillList(Collections.emptyList());
|
||||
result.setMemberCount(0);
|
||||
@ -329,15 +342,34 @@ public class TeamBdMemberBillListQryExe {
|
||||
result.setTotalSalary(BigDecimal.ZERO);
|
||||
result.setTotalRecharge(BigDecimal.ZERO);
|
||||
result.setBillTitle(TeamBillCycleUtils.parseBillBelongToDateRangeStr(currentBillBelong));
|
||||
|
||||
|
||||
// 空结果也要计算 BD 工资信息(全部为0)
|
||||
BdHistoryCO bdHistoryCO = calculateCurrentBdBill(currentBillBelong,
|
||||
BdHistoryCO bdHistoryCO = calculateCurrentBdBill(currentBillBelong,
|
||||
0, BigDecimal.ZERO, BigDecimal.ZERO);
|
||||
result.setBdHistoryCO(bdHistoryCO);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<Long, TeamBillCycle> getBillCycleMap(Set<Long> teamIdSet, Integer billBelong) {
|
||||
Map<Long, TeamBillCycle> billCycleMap = new HashMap<>(
|
||||
teamBillCycleService.mapByTeamIds2(teamIdSet, billBelong, TeamBillCycleStatus.SETTLED));
|
||||
billCycleMap.putAll(teamBillCycleService.mapByTeamIds2(teamIdSet, billBelong, TeamBillCycleStatus.UNPAID));
|
||||
return billCycleMap;
|
||||
}
|
||||
|
||||
private Map<Long, List<TeamMemberTarget>> getMemberBillTargetMap(Set<Long> teamIdSet, Integer billBelong) {
|
||||
if (CollectionUtils.isEmpty(teamIdSet)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
if (String.valueOf(billBelong).length() == 6) {
|
||||
Map<Long, List<TeamMemberTarget>> result = new HashMap<>();
|
||||
teamIdSet.forEach(teamId -> result.put(teamId, teamMemberTargetService.listByMonthlyBillBelong(teamId, billBelong)));
|
||||
return result;
|
||||
}
|
||||
return teamMemberTargetService.mapMemberBillTarget(teamIdSet, billBelong);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<Long, BigDecimal> getRechargeMap(Integer currentBillBelong, Set<Long> teamIds) {
|
||||
if (CollectionUtils.isEmpty(teamIds)) {
|
||||
@ -404,7 +436,7 @@ public class TeamBdMemberBillListQryExe {
|
||||
Integer billBelong) {
|
||||
|
||||
TeamBdMemberBillCO co = new TeamBdMemberBillCO();
|
||||
|
||||
|
||||
// 代理用户信息
|
||||
UserProfileDTO userProfile = userProfileMap.get(bdTeam.getAgentId());
|
||||
if (userProfile != null) {
|
||||
@ -416,7 +448,7 @@ public class TeamBdMemberBillListQryExe {
|
||||
|
||||
// 团队信息
|
||||
co.setTeamId(bdTeam.getTeamId());
|
||||
|
||||
|
||||
TeamProfile teamProfile = teamProfileMap.get(bdTeam.getTeamId());
|
||||
if (teamProfile != null) {
|
||||
Long memberCount = Optional.ofNullable(teamProfile.getCounter())
|
||||
@ -449,8 +481,15 @@ public class TeamBdMemberBillListQryExe {
|
||||
}
|
||||
|
||||
List<TeamMemberTarget> targetList = teamMemberTargetMap.get(teamId);
|
||||
List<TeamBillMemberTarget> memberTargets = TeamBillCycleUtils.calculatorPolicyTargetWithMap(targetList, policyManagerMap);
|
||||
return ownTotalSalary(memberTargets);
|
||||
if (CollectionUtils.isNotEmpty(targetList)) {
|
||||
List<TeamBillMemberTarget> memberTargets = TeamBillCycleUtils.calculatorPolicyTargetWithMap(targetList, policyManagerMap);
|
||||
return ownTotalSalary(memberTargets);
|
||||
}
|
||||
|
||||
return Optional.ofNullable(billCycle.getSettleResult())
|
||||
.map(TeamBillSettleResult::getTotalSalary)
|
||||
.orElse(BigDecimal.ZERO)
|
||||
.setScale(2, RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
private BigDecimal ownTotalSalary(List<TeamBillMemberTarget> teamBillMemberTargets) {
|
||||
@ -470,7 +509,7 @@ public class TeamBdMemberBillListQryExe {
|
||||
*/
|
||||
private BdHistoryCO calculateCurrentBdBill(Integer billBelong,
|
||||
Integer agencyNumber,
|
||||
BigDecimal teamSalaryAmount,
|
||||
BigDecimal teamSalaryAmount,
|
||||
BigDecimal teamRechargeAmount) {
|
||||
String billTitle = TeamBillCycleUtils.parseBillBelongToDateRangeStr(billBelong);
|
||||
|
||||
@ -482,22 +521,19 @@ public class TeamBdMemberBillListQryExe {
|
||||
currentBill.setTeamRechargeAmount(teamRechargeAmount);
|
||||
currentBill.setStatus(BdSettlementStatus.PENDING.name());
|
||||
currentBill.setStatusText("In Progress");
|
||||
|
||||
// 创建临时结算记录用于政策匹配
|
||||
BdSalarySettlementRecord tempRecord = new BdSalarySettlementRecord();
|
||||
|
||||
|
||||
// 获取所有启用的政策
|
||||
List<BdSalaryPolicy> salaryPolicies = bdSalaryPolicyService.listEnabledByType(BdPolicyType.TEAM_SALARY);
|
||||
List<BdSalaryPolicy> rechargePolicies = bdSalaryPolicyService.listEnabledByType(BdPolicyType.TEAM_RECHARGE);
|
||||
|
||||
|
||||
// 匹配政策1:Team Salary Policy
|
||||
SalaryCalcResult salaryResult = BdSalarySettlementServiceImpl.matchAndCalculate(
|
||||
salaryPolicies, agencyNumber, teamSalaryAmount);
|
||||
|
||||
currentBill.setBdIncomeSalary(salaryResult.getSalary());
|
||||
currentBill.setBdRatioSalary(salaryResult.getCommissionRate());
|
||||
|
||||
// 匹配政策2:Team Recharge Policy
|
||||
|
||||
// 匹配政策2:Team Recharge Policy
|
||||
SalaryCalcResult rechargeResult = BdSalarySettlementServiceImpl.matchAndCalculate(
|
||||
rechargePolicies, agencyNumber, teamRechargeAmount);
|
||||
|
||||
|
||||
@ -21,10 +21,14 @@ import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
||||
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
|
||||
import com.red.circle.other.domain.model.user.UserProfile;
|
||||
import com.red.circle.other.domain.model.user.ability.RegionConfig;
|
||||
import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService;
|
||||
import com.red.circle.other.infra.database.mongo.entity.live.RoomSetting;
|
||||
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
|
||||
import com.red.circle.other.infra.database.rds.service.props.PropsVipActualEquityService;
|
||||
import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService;
|
||||
import com.red.circle.other.infra.database.rds.entity.props.PropsBackpack;
|
||||
import com.red.circle.other.infra.database.rds.entity.props.PropsNobleVipAbility;
|
||||
import com.red.circle.other.infra.database.rds.service.props.PropsBackpackService;
|
||||
import com.red.circle.other.infra.database.rds.service.props.PropsNobleVipAbilityService;
|
||||
import com.red.circle.other.infra.database.mongo.entity.live.RoomSetting;
|
||||
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
|
||||
import com.red.circle.other.infra.database.rds.service.props.PropsVipActualEquityService;
|
||||
import com.red.circle.other.infra.utils.I18nUtils;
|
||||
import com.red.circle.other.inner.asserts.PropsErrorCode;
|
||||
import com.red.circle.other.inner.endpoint.material.props.PropsNobleVipClient;
|
||||
@ -46,11 +50,14 @@ import com.red.circle.wallet.inner.model.cmd.DiamondReceiptCmd;
|
||||
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
|
||||
import com.red.circle.wallet.inner.model.dto.WalletReceiptDTO;
|
||||
import com.red.circle.wallet.inner.model.dto.WalletReceiptResDTO;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -73,10 +80,12 @@ public class PropsPurchasingCmdExe {
|
||||
private final EnumConfigCacheService enumConfigCacheService;
|
||||
private final RoomProfileManagerService roomProfileManagerService;
|
||||
private final PropsVipActualEquityService propsVipActualEquityService;
|
||||
private final TaskMqMessage taskMqMessage;
|
||||
private final PropsNobleVipClient propsNobleVipClient;
|
||||
private final UserProfileAppConvertor userProfileAppConvertor;
|
||||
private final UserRegionGateway userRegionGateway;
|
||||
private final TaskMqMessage taskMqMessage;
|
||||
private final PropsNobleVipClient propsNobleVipClient;
|
||||
private final UserProfileAppConvertor userProfileAppConvertor;
|
||||
private final UserRegionGateway userRegionGateway;
|
||||
private final PropsBackpackService propsBackpackService;
|
||||
private final PropsNobleVipAbilityService propsNobleVipAbilityService;
|
||||
|
||||
public BigDecimal execute(PropsPurchasingCmd cmd) {
|
||||
if (cmd.getDays() <= 0) {
|
||||
@ -123,10 +132,12 @@ public class PropsPurchasingCmdExe {
|
||||
|
||||
if (commodity.getPropsAbility() instanceof NobleVipAbility nobleVipAbility) {
|
||||
log.warn("查询赠送参数信息:{}"+JSON.toJSON(commodity));
|
||||
|
||||
nobleVipAbility = commodity.getNobleVipAbility();
|
||||
if (nobleVipAbility.cardId() != null) {
|
||||
propsStoreGateway.shippingProductProps(new ProductProps()
|
||||
|
||||
nobleVipAbility = commodity.getNobleVipAbility();
|
||||
expireSupersededNobleVipMaterials(cmd.acceptUser(), commodity, nobleVipAbility,
|
||||
TimestampUtils.now());
|
||||
if (nobleVipAbility.cardId() != null) {
|
||||
propsStoreGateway.shippingProductProps(new ProductProps()
|
||||
.setInitiateUserId(cmd.requiredReqUserId())
|
||||
.setAcceptUserId(cmd.acceptUser())
|
||||
.setDays(cmd.getDays())
|
||||
@ -186,11 +197,70 @@ public class PropsPurchasingCmdExe {
|
||||
propsVipActualEquityService.save(cmd.getAcceptUserId(),
|
||||
commodity.getPropsResources().getId(), Long.valueOf(cmd.getDays()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void sendGiveAwayNotice(PropsPurchasingCmd cmd, PropsStoreCommodity commodity) {
|
||||
}
|
||||
}
|
||||
|
||||
private void expireSupersededNobleVipMaterials(Long userId, PropsStoreCommodity commodity,
|
||||
NobleVipAbility targetAbility, Timestamp now) {
|
||||
Set<Long> targetIds = nobleVipMaterialIds(targetAbility);
|
||||
if (Objects.nonNull(commodity.getPropsResources())
|
||||
&& Objects.nonNull(commodity.getPropsResources().getId())) {
|
||||
targetIds.add(commodity.getPropsResources().getId());
|
||||
}
|
||||
|
||||
Set<Long> allVipIds = new HashSet<>();
|
||||
propsNobleVipAbilityService.query().list()
|
||||
.forEach(ability -> allVipIds.addAll(nobleVipMaterialIds(ability)));
|
||||
allVipIds.removeAll(targetIds);
|
||||
if (allVipIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
propsBackpackService.update()
|
||||
.set(PropsBackpack::getExpireTime, now)
|
||||
.set(PropsBackpack::getUseProps, Boolean.FALSE)
|
||||
.set(PropsBackpack::getAllowGive, Boolean.FALSE)
|
||||
.set(PropsBackpack::getUpdateTime, now)
|
||||
.eq(PropsBackpack::getUserId, userId)
|
||||
.in(PropsBackpack::getPropsId, allVipIds)
|
||||
.gt(PropsBackpack::getExpireTime, now)
|
||||
.execute();
|
||||
}
|
||||
|
||||
private Set<Long> nobleVipMaterialIds(NobleVipAbility ability) {
|
||||
Set<Long> ids = new HashSet<>();
|
||||
if (Objects.isNull(ability) || Objects.isNull(ability.getNobleVipAbility())) {
|
||||
return ids;
|
||||
}
|
||||
addPositive(ids, ability.id());
|
||||
addPositive(ids, ability.avatarFrameId());
|
||||
addPositive(ids, ability.cardId());
|
||||
addPositive(ids, ability.chatBubbleId());
|
||||
addPositive(ids, ability.dataCardId());
|
||||
return ids;
|
||||
}
|
||||
|
||||
private Set<Long> nobleVipMaterialIds(PropsNobleVipAbility ability) {
|
||||
Set<Long> ids = new HashSet<>();
|
||||
if (Objects.isNull(ability)) {
|
||||
return ids;
|
||||
}
|
||||
addPositive(ids, ability.getId());
|
||||
addPositive(ids, ability.getAvatarFrameId());
|
||||
addPositive(ids, ability.getCarId());
|
||||
addPositive(ids, ability.getChatBubbleId());
|
||||
addPositive(ids, ability.getDataCardId());
|
||||
return ids;
|
||||
}
|
||||
|
||||
private void addPositive(Set<Long> ids, Long id) {
|
||||
if (Objects.nonNull(id) && id > 0) {
|
||||
ids.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void sendGiveAwayNotice(PropsPurchasingCmd cmd, PropsStoreCommodity commodity) {
|
||||
UserProfileDTO userProfileDTO = userProfileAppConvertor.toUserProfileDTO(userProfileGateway.getByUserId(cmd.requiredReqUserId()));
|
||||
RegionConfig region = userRegionGateway.getRegionConfigByUserId(userProfileDTO.getId());
|
||||
|
||||
|
||||
@ -32,6 +32,7 @@ import org.springframework.stereotype.Component;
|
||||
public class TeamBillTask {
|
||||
|
||||
private static final boolean SALARY_SETTLEMENT_PAUSED = true;
|
||||
private static final boolean BILL_CYCLE_SWITCH_PAUSED = false;
|
||||
|
||||
private final TeamSalaryMqMessage otherMqMessage;
|
||||
private final TeamProfileService teamProfileService;
|
||||
@ -58,23 +59,21 @@ public class TeamBillTask {
|
||||
|
||||
|
||||
private void processTeamBill() {
|
||||
if (SALARY_SETTLEMENT_PAUSED) {
|
||||
log.warn("process_team_bill skipped: salary settlement is temporarily paused");
|
||||
if (BILL_CYCLE_SWITCH_PAUSED) {
|
||||
log.warn("process_team_bill skipped: bill cycle switch is temporarily paused");
|
||||
return;
|
||||
}
|
||||
|
||||
log.warn("开始执行账单处理:{},{}", ZonedDateTimeUtils.nowAsiaRiyadhToInt(), LocalDateTime.now());
|
||||
// 出单
|
||||
teamBillCycleService.billStatusPayOut();
|
||||
|
||||
// 创建本月账单,发出结算信号
|
||||
consumeProcessPayOutBill();
|
||||
log.warn("结束账单处理");
|
||||
}
|
||||
log.warn("开始执行账期切换:{},{}", ZonedDateTimeUtils.nowAsiaRiyadhToInt(), LocalDateTime.now());
|
||||
|
||||
// 只创建新月账期,上月账单保留原状态,后续由后台人工结算。
|
||||
consumeProcessPayOutBill();
|
||||
log.warn("结束账期切换");
|
||||
}
|
||||
|
||||
public void processTeamBillRetry() {
|
||||
if (SALARY_SETTLEMENT_PAUSED) {
|
||||
log.warn("process_team_bill_retry skipped: salary settlement is temporarily paused");
|
||||
if (BILL_CYCLE_SWITCH_PAUSED) {
|
||||
log.warn("process_team_bill_retry skipped: bill cycle switch is temporarily paused");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -138,12 +137,16 @@ public class TeamBillTask {
|
||||
.setOperationTime(TimestampUtils.now())
|
||||
.setOperationBackUser(teamProfile.getCreateUser());
|
||||
|
||||
teamBillCycleService.createIfAbsent(cmd);
|
||||
|
||||
otherMqMessage.teamBillSettle(new TeamBillSettleEvent()
|
||||
.setTeamId(teamProfile.getId()));
|
||||
|
||||
success.incrementAndGet();
|
||||
teamBillCycleService.createIfAbsent(cmd);
|
||||
|
||||
if (SALARY_SETTLEMENT_PAUSED) {
|
||||
log.warn("团队账单结算消息暂停发送: teamId={}", teamProfile.getId());
|
||||
} else {
|
||||
otherMqMessage.teamBillSettle(new TeamBillSettleEvent()
|
||||
.setTeamId(teamProfile.getId()));
|
||||
}
|
||||
|
||||
success.incrementAndGet();
|
||||
|
||||
} catch (Exception e) {
|
||||
fail.incrementAndGet();
|
||||
|
||||
@ -1,14 +1,10 @@
|
||||
package com.red.circle.other.app.dto.cmd;
|
||||
|
||||
import com.red.circle.common.business.dto.PageQueryCmd;
|
||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* BD 成员账单查询命令.
|
||||
*
|
||||
@ -22,4 +18,9 @@ public class TeamBdMemberBillCmd extends AppExtCommand {
|
||||
@NotBlank
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 账单月份,格式 yyyyMM。为空时默认当前月。
|
||||
*/
|
||||
private Integer billBelong;
|
||||
|
||||
}
|
||||
|
||||
@ -115,9 +115,9 @@ public class TeamBillCycleServiceImpl implements TeamBillCycleService {
|
||||
return Maps.newHashMap();
|
||||
}
|
||||
|
||||
Criteria criteria = new Criteria().orOperator(
|
||||
Criteria.where("billBelong").is(billBelong)
|
||||
);
|
||||
Criteria criteria = String.valueOf(billBelong).length() == 6
|
||||
? getBillBelongCriteria(billBelong)
|
||||
: new Criteria().orOperator(Criteria.where("billBelong").is(billBelong));
|
||||
|
||||
List<TeamBillCycle> teamBillCycles = mongoTemplate.find(
|
||||
Query.query(criteria.and("teamId").in(teamIds).and("status").is(status)),
|
||||
|
||||
@ -21,6 +21,7 @@ import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberTar
|
||||
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.infra.database.mongo.service.team.team.TeamSalaryPaymentService;
|
||||
import com.red.circle.other.inner.enums.team.TeamMemberRole;
|
||||
import com.red.circle.other.inner.enums.team.TeamPolicyTypeEnum;
|
||||
import com.red.circle.other.inner.model.cmd.team.TeamManualSalaryPaymentCmd;
|
||||
import com.red.circle.other.inner.model.cmd.team.TeamManualSalaryPaymentQryCmd;
|
||||
@ -85,8 +86,9 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
public PageResult<TeamManualSalaryPaymentDTO> page(TeamManualSalaryPaymentQryCmd cmd) {
|
||||
validatePage(cmd);
|
||||
|
||||
Integer billBelong = resolveBillBelong(cmd.getBillBelong());
|
||||
List<ManualSalaryRow> rows = buildRows(cmd.getSysOrigin(), cmd.getCountryCode(),
|
||||
singletonUserId(cmd.getUserId()), TeamBillCycleUtils.getCalcBillBelong());
|
||||
singletonUserId(cmd.getUserId()), billBelong);
|
||||
rows = sortRows(rows, cmd.getSortField(), cmd.getSortOrder());
|
||||
|
||||
int cursor = 1;
|
||||
@ -114,7 +116,7 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
public List<TeamManualSalaryPaymentResultDTO> pay(TeamManualSalaryPaymentCmd cmd) {
|
||||
validatePay(cmd);
|
||||
|
||||
Integer billBelong = TeamBillCycleUtils.getCalcBillBelong();
|
||||
Integer billBelong = resolveBillBelong(cmd.getBillBelong());
|
||||
String lockKey = MANUAL_SALARY_LOCK_PREFIX + cmd.getSysOrigin() + ":" + cmd.getCountryCode()
|
||||
+ ":" + billBelong;
|
||||
ResponseAssert.isTrue(CommonErrorCode.OPERATION_CONFLICT,
|
||||
@ -130,10 +132,13 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
continue;
|
||||
}
|
||||
|
||||
TeamSalaryPayment payment = teamSalaryPaymentService.createIfAbsent(row.getUserId(),
|
||||
billBelong, row.getSysOrigin());
|
||||
|
||||
for (PolicyPayment policyPayment : row.getPayments()) {
|
||||
Long receiverUserId = getPaymentReceiverUserId(row, policyPayment);
|
||||
if (Objects.isNull(receiverUserId)) {
|
||||
continue;
|
||||
}
|
||||
TeamSalaryPayment payment = teamSalaryPaymentService.createIfAbsent(receiverUserId,
|
||||
billBelong, row.getSysOrigin());
|
||||
if (policyPayment.getSalary().compareTo(BigDecimal.ZERO) <= 0
|
||||
&& Boolean.TRUE.equals(teamSalaryPaymentService.checkRepeatPayment(payment.getId(),
|
||||
row.getUserId(), row.getRegion(), policyPayment.getLevel(),
|
||||
@ -141,10 +146,6 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
continue;
|
||||
}
|
||||
|
||||
Long receiverUserId = policyPayment.isAnchor() ? row.getUserId() : row.getTeamOwnId();
|
||||
if (Objects.isNull(receiverUserId)) {
|
||||
continue;
|
||||
}
|
||||
BigDecimal issueSalary = policyPayment.getSalary().compareTo(BigDecimal.ZERO) > 0
|
||||
? policyPayment.getSalary()
|
||||
: BigDecimal.ZERO.setScale(2, RoundingMode.DOWN);
|
||||
@ -240,8 +241,14 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
Map<Long, TeamMember> memberMap = teamMemberService.mapByMemberIds(memberIds);
|
||||
Map<Long, TeamProfile> teamProfileMap = teamProfileService.mapProfileByIds(teamIds);
|
||||
Set<Integer> salaryPaymentBillBelongs = getMergedSalaryPaymentBillBelongs(billBelong);
|
||||
Set<Long> paymentRelatedUserIds = new HashSet<>(memberIds);
|
||||
teamProfileMap.values().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(TeamProfile::getOwnUserId)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(paymentRelatedUserIds::add);
|
||||
List<TeamSalaryPayment> salaryPayments = teamSalaryPaymentService
|
||||
.listByPaymentOrRecipientUserIdsAndDateNumbers(sysOrigin, memberIds,
|
||||
.listByPaymentOrRecipientUserIdsAndDateNumbers(sysOrigin, paymentRelatedUserIds,
|
||||
salaryPaymentBillBelongs);
|
||||
Map<String, TeamSalaryPayment> salaryPaymentMap = toSalaryPaymentMap(salaryPayments);
|
||||
|
||||
@ -337,9 +344,13 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
if (Objects.isNull(userId) || CollectionUtils.isEmpty(salaryPaymentMap)) {
|
||||
return List.of();
|
||||
}
|
||||
return getMergedSalaryPaymentBillBelongs(billBelong).stream()
|
||||
.map(item -> salaryPaymentMap.get(paymentId(userId, item)))
|
||||
Set<Integer> mergedBillBelongs = getMergedSalaryPaymentBillBelongs(billBelong);
|
||||
return salaryPaymentMap.values().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(payment -> mergedBillBelongs.contains(payment.getDateNumber()))
|
||||
.filter(payment -> Objects.equals(payment.getUserId(), userId)
|
||||
|| listValidSalaryDetails(List.of(payment)).stream()
|
||||
.anyMatch(details -> Objects.equals(details.getTeamMemberId(), userId)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@ -368,24 +379,27 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
|
||||
List<TeamSalaryPayment> cyclePayments = listCyclePayments(salaryPaymentMap,
|
||||
target.getUserId(), billBelong);
|
||||
PaymentSummary receivedPaymentSummary = summarizeReceivedPayments(
|
||||
new ArrayList<>(salaryPaymentMap.values()), target.getUserId());
|
||||
BigDecimal expectedMemberSalary = salaryValue(billTarget.getMemberSalary());
|
||||
BigDecimal expectedAgentSalary = salaryValue(billTarget.getOwnSalary());
|
||||
BigDecimal expectedSalary = expectedTotalSalary(billTarget);
|
||||
BigDecimal payableSalary = expectedSalary.subtract(receivedPaymentSummary.getTotalIssuedSalary())
|
||||
BigDecimal expectedAgentSalary = Objects.nonNull(teamProfile.getOwnUserId())
|
||||
? salaryValue(billTarget.getOwnSalary())
|
||||
: BigDecimal.ZERO.setScale(2, RoundingMode.DOWN);
|
||||
BigDecimal expectedSalary = expectedMemberSalary.add(expectedAgentSalary)
|
||||
.setScale(2, RoundingMode.DOWN);
|
||||
PaymentSummary receivedPaymentSummary = summarizeTargetEntitlementPayments(cyclePayments,
|
||||
target.getUserId(), expectedMemberSalary, expectedAgentSalary);
|
||||
BigDecimal payableMemberSalary = expectedMemberSalary
|
||||
.subtract(receivedPaymentSummary.getMemberIssuedSalary())
|
||||
.setScale(2, RoundingMode.DOWN);
|
||||
BigDecimal payableAgentSalary = expectedAgentSalary
|
||||
.subtract(receivedPaymentSummary.getAgentIssuedSalary())
|
||||
.setScale(2, RoundingMode.DOWN);
|
||||
BigDecimal payableSalary = payableAmount(payableMemberSalary).add(
|
||||
payableAmount(payableAgentSalary))
|
||||
.setScale(2, RoundingMode.DOWN);
|
||||
boolean currentLevelSettled = areCurrentRolesSettled(cyclePayments, target.getUserId(), region,
|
||||
billTarget, payableSalary);
|
||||
billTarget, receivedPaymentSummary, expectedMemberSalary, expectedAgentSalary);
|
||||
List<PolicyPayment> policyPayments = buildSettlementPayments(policyManager, billTarget,
|
||||
cyclePayments, target.getUserId(), region, receivedPaymentSummary, payableSalary,
|
||||
currentLevelSettled);
|
||||
cyclePayments, target.getUserId(), region, receivedPaymentSummary, currentLevelSettled);
|
||||
|
||||
TeamManualSalaryPaymentDTO dto = new TeamManualSalaryPaymentDTO()
|
||||
.setId(target.getId())
|
||||
@ -396,7 +410,7 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
.setTeamOwnId(teamProfile.getOwnUserId())
|
||||
.setUserId(target.getUserId())
|
||||
.setBillBelong(billBelong)
|
||||
.setLastSettlementTarget(getLastSettlementTarget(cyclePayments))
|
||||
.setLastSettlementTarget(getLastSettlementTarget(cyclePayments, target.getUserId()))
|
||||
.setCurrentTarget(target.sumAcceptGiftValue())
|
||||
.setPolicyLevel(billTarget.getLevel())
|
||||
.setSatisfyLevel(billTarget.getSatisfyLevel())
|
||||
@ -413,6 +427,7 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
.setMemberOverIssuedSalary(receivedPaymentSummary.getMemberOverIssuedSalary())
|
||||
.setAgentOverIssuedSalary(receivedPaymentSummary.getAgentOverIssuedSalary())
|
||||
.setCurrentSalaryBalance(getAccurateBalance(target.getUserId()))
|
||||
.setAgentMember(isAgentMember(member, teamProfile, target))
|
||||
.setPaid(currentLevelSettled);
|
||||
|
||||
return new ManualSalaryRow(dto, target, teamProfile, policyManager, billTarget, policyPayments);
|
||||
@ -468,34 +483,27 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
.setSatisfyLevel(Boolean.FALSE);
|
||||
}
|
||||
|
||||
private BigDecimal expectedTotalSalary(TeamBillMemberTarget billTarget) {
|
||||
if (Objects.isNull(billTarget)) {
|
||||
return BigDecimal.ZERO.setScale(2, RoundingMode.DOWN);
|
||||
}
|
||||
return salaryValue(billTarget.getMemberSalary())
|
||||
.add(salaryValue(billTarget.getOwnSalary()))
|
||||
.setScale(2, RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
private BigDecimal salaryValue(BigDecimal value) {
|
||||
return Optional.ofNullable(value)
|
||||
.orElse(BigDecimal.ZERO)
|
||||
.setScale(2, RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
private BigDecimal payableAmount(BigDecimal value) {
|
||||
BigDecimal amount = salaryValue(value);
|
||||
return amount.compareTo(BigDecimal.ZERO) > 0 ? amount : BigDecimal.ZERO.setScale(2,
|
||||
RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
private List<PolicyPayment> buildSettlementPayments(TeamPolicyManager policyManager,
|
||||
TeamBillMemberTarget billTarget, List<TeamSalaryPayment> cyclePayments, Long userId,
|
||||
String region, PaymentSummary paymentSummary, BigDecimal payableSalary,
|
||||
boolean currentLevelSettled) {
|
||||
String region, PaymentSummary paymentSummary, boolean currentLevelSettled) {
|
||||
if (currentLevelSettled || Objects.isNull(billTarget)
|
||||
|| Objects.isNull(billTarget.getLevel())) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
TeamPolicy policy = findPolicy(policyManager, billTarget.getLevel());
|
||||
BigDecimal remainingPayable = payableSalary.compareTo(BigDecimal.ZERO) > 0
|
||||
? payableSalary.setScale(2, RoundingMode.DOWN)
|
||||
: BigDecimal.ZERO.setScale(2, RoundingMode.DOWN);
|
||||
BigDecimal memberExpected = salaryValue(billTarget.getMemberSalary());
|
||||
BigDecimal agentExpected = salaryValue(billTarget.getOwnSalary());
|
||||
BigDecimal memberMissing = memberExpected.subtract(paymentSummary.getMemberIssuedSalary())
|
||||
@ -508,31 +516,17 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
billTarget.getLevel(), Boolean.FALSE);
|
||||
|
||||
List<PolicyPayment> payments = new ArrayList<>();
|
||||
if (remainingPayable.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
if (!memberHasSettlementRecord && memberExpected.compareTo(BigDecimal.ZERO) > 0) {
|
||||
payments.add(new PolicyPayment(policy, billTarget.getLevel(),
|
||||
BigDecimal.ZERO.setScale(2, RoundingMode.DOWN), Boolean.TRUE));
|
||||
}
|
||||
if (!agentHasSettlementRecord && agentExpected.compareTo(BigDecimal.ZERO) > 0) {
|
||||
payments.add(new PolicyPayment(policy, billTarget.getLevel(),
|
||||
BigDecimal.ZERO.setScale(2, RoundingMode.DOWN), Boolean.FALSE));
|
||||
}
|
||||
return payments;
|
||||
}
|
||||
|
||||
if (memberMissing.compareTo(BigDecimal.ZERO) > 0) {
|
||||
BigDecimal issueSalary = memberMissing.min(remainingPayable).setScale(2, RoundingMode.DOWN);
|
||||
if (issueSalary.compareTo(BigDecimal.ZERO) > 0) {
|
||||
payments.add(new PolicyPayment(policy, billTarget.getLevel(), issueSalary, Boolean.TRUE));
|
||||
remainingPayable = remainingPayable.subtract(issueSalary).setScale(2, RoundingMode.DOWN);
|
||||
}
|
||||
payments.add(new PolicyPayment(policy, billTarget.getLevel(), memberMissing, Boolean.TRUE));
|
||||
} else if (!memberHasSettlementRecord && memberExpected.compareTo(BigDecimal.ZERO) > 0) {
|
||||
payments.add(new PolicyPayment(policy, billTarget.getLevel(),
|
||||
BigDecimal.ZERO.setScale(2, RoundingMode.DOWN), Boolean.TRUE));
|
||||
}
|
||||
if (agentMissing.compareTo(BigDecimal.ZERO) > 0
|
||||
&& remainingPayable.compareTo(BigDecimal.ZERO) > 0) {
|
||||
BigDecimal issueSalary = agentMissing.min(remainingPayable).setScale(2, RoundingMode.DOWN);
|
||||
if (issueSalary.compareTo(BigDecimal.ZERO) > 0) {
|
||||
payments.add(new PolicyPayment(policy, billTarget.getLevel(), issueSalary, Boolean.FALSE));
|
||||
}
|
||||
if (agentMissing.compareTo(BigDecimal.ZERO) > 0) {
|
||||
payments.add(new PolicyPayment(policy, billTarget.getLevel(), agentMissing, Boolean.FALSE));
|
||||
} else if (!agentHasSettlementRecord && agentExpected.compareTo(BigDecimal.ZERO) > 0) {
|
||||
payments.add(new PolicyPayment(policy, billTarget.getLevel(),
|
||||
BigDecimal.ZERO.setScale(2, RoundingMode.DOWN), Boolean.FALSE));
|
||||
}
|
||||
return payments;
|
||||
}
|
||||
@ -549,21 +543,25 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
}
|
||||
|
||||
private boolean areCurrentRolesSettled(List<TeamSalaryPayment> cyclePayments, Long userId,
|
||||
String region, TeamBillMemberTarget billTarget, BigDecimal payableSalary) {
|
||||
String region, TeamBillMemberTarget billTarget, PaymentSummary paymentSummary,
|
||||
BigDecimal expectedMemberSalary, BigDecimal expectedAgentSalary) {
|
||||
if (Objects.isNull(billTarget) || Objects.isNull(billTarget.getLevel())
|
||||
|| payableSalary.compareTo(BigDecimal.ZERO) > 0) {
|
||||
|| Objects.isNull(paymentSummary)) {
|
||||
return false;
|
||||
}
|
||||
return isRoleSettled(cyclePayments, userId, region, billTarget.getLevel(), Boolean.TRUE,
|
||||
salaryValue(billTarget.getMemberSalary()))
|
||||
expectedMemberSalary, paymentSummary.getMemberIssuedSalary())
|
||||
&& isRoleSettled(cyclePayments, userId, region, billTarget.getLevel(), Boolean.FALSE,
|
||||
salaryValue(billTarget.getOwnSalary()));
|
||||
expectedAgentSalary, paymentSummary.getAgentIssuedSalary());
|
||||
}
|
||||
|
||||
private boolean isRoleSettled(List<TeamSalaryPayment> cyclePayments, Long userId, String region,
|
||||
Integer policyLevel, Boolean anchor, BigDecimal expectedSalary) {
|
||||
return expectedSalary.compareTo(BigDecimal.ZERO) <= 0
|
||||
|| hasPaidPolicy(cyclePayments, userId, region, policyLevel, anchor);
|
||||
Integer policyLevel, Boolean anchor, BigDecimal expectedSalary, BigDecimal issuedSalary) {
|
||||
if (expectedSalary.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return true;
|
||||
}
|
||||
return Optional.ofNullable(issuedSalary).orElse(BigDecimal.ZERO).compareTo(expectedSalary) >= 0
|
||||
&& hasPaidPolicy(cyclePayments, userId, region, policyLevel, anchor);
|
||||
}
|
||||
|
||||
private boolean hasPaidPolicy(List<TeamSalaryPayment> cyclePayments, Long userId, String region,
|
||||
@ -575,36 +573,39 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
&& Objects.equals(details.getAnchor(), anchor));
|
||||
}
|
||||
|
||||
private Long getLastSettlementTarget(List<TeamSalaryPayment> cyclePayments) {
|
||||
private Long getLastSettlementTarget(List<TeamSalaryPayment> cyclePayments, Long targetUserId) {
|
||||
return listValidSalaryDetails(cyclePayments).stream()
|
||||
.filter(details -> Objects.equals(details.getTeamMemberId(), targetUserId))
|
||||
.max(Comparator.comparing(details -> Optional.ofNullable(details.getCreateTime())
|
||||
.orElse(new Timestamp(0))))
|
||||
.map(TeamSalaryPaymentDetails::getTarget)
|
||||
.orElse(0L);
|
||||
}
|
||||
|
||||
private PaymentSummary summarizePayments(List<TeamSalaryPayment> cyclePayments) {
|
||||
return summarizeDetails(listValidSalaryDetails(cyclePayments));
|
||||
}
|
||||
|
||||
private PaymentSummary summarizeReceivedPayments(List<TeamSalaryPayment> cyclePayments,
|
||||
Long receiverUserId) {
|
||||
if (Objects.isNull(receiverUserId)) {
|
||||
private PaymentSummary summarizeTargetEntitlementPayments(List<TeamSalaryPayment> cyclePayments,
|
||||
Long targetUserId, BigDecimal expectedMemberSalary, BigDecimal expectedAgentSalary) {
|
||||
if (Objects.isNull(targetUserId)) {
|
||||
return emptyPaymentSummary();
|
||||
}
|
||||
List<TeamSalaryPaymentDetails> details = listValidSalaryDetails(cyclePayments).stream()
|
||||
.filter(detail -> Objects.equals(receiverUserId, getSalaryReceiverUserId(detail)))
|
||||
.filter(detail -> Objects.equals(targetUserId, detail.getTeamMemberId()))
|
||||
.collect(Collectors.toList());
|
||||
return summarizeDetails(details);
|
||||
return summarizeDetails(details, expectedMemberSalary, expectedAgentSalary);
|
||||
}
|
||||
|
||||
private PaymentSummary summarizeDetails(List<TeamSalaryPaymentDetails> details) {
|
||||
private PaymentSummary summarizeDetails(List<TeamSalaryPaymentDetails> details,
|
||||
BigDecimal expectedMemberSalary, BigDecimal expectedAgentSalary) {
|
||||
BigDecimal memberIssuedSalary = sumDetailsSalary(details, Boolean.TRUE);
|
||||
BigDecimal agentIssuedSalary = sumDetailsSalary(details, Boolean.FALSE);
|
||||
BigDecimal totalIssuedSalary = memberIssuedSalary.add(agentIssuedSalary)
|
||||
.setScale(2, RoundingMode.DOWN);
|
||||
BigDecimal memberOverIssuedSalary = getOverIssuedSalary(details, Boolean.TRUE);
|
||||
BigDecimal agentOverIssuedSalary = getOverIssuedSalary(details, Boolean.FALSE);
|
||||
BigDecimal memberOverIssuedSalary = memberIssuedSalary.subtract(
|
||||
salaryValue(expectedMemberSalary))
|
||||
.max(BigDecimal.ZERO)
|
||||
.setScale(2, RoundingMode.DOWN);
|
||||
BigDecimal agentOverIssuedSalary = agentIssuedSalary.subtract(salaryValue(expectedAgentSalary))
|
||||
.max(BigDecimal.ZERO)
|
||||
.setScale(2, RoundingMode.DOWN);
|
||||
BigDecimal overIssuedSalary = memberOverIssuedSalary.add(agentOverIssuedSalary)
|
||||
.setScale(2, RoundingMode.DOWN);
|
||||
return new PaymentSummary(totalIssuedSalary, memberIssuedSalary, agentIssuedSalary,
|
||||
@ -616,17 +617,6 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
return new PaymentSummary(zero, zero, zero, zero, zero, zero);
|
||||
}
|
||||
|
||||
private Long getSalaryReceiverUserId(TeamSalaryPaymentDetails details) {
|
||||
if (Objects.isNull(details)) {
|
||||
return null;
|
||||
}
|
||||
if (Boolean.TRUE.equals(details.getAnchor())
|
||||
&& !Boolean.TRUE.equals(details.getHostSalaryToAgent())) {
|
||||
return details.getTeamMemberId();
|
||||
}
|
||||
return details.getTeamOwnId();
|
||||
}
|
||||
|
||||
private BigDecimal sumDetailsSalary(List<TeamSalaryPaymentDetails> details, Boolean anchor) {
|
||||
return details.stream()
|
||||
.filter(detail -> Objects.equals(detail.getAnchor(), anchor))
|
||||
@ -635,38 +625,6 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
.setScale(2, RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
private BigDecimal getOverIssuedSalary(List<TeamSalaryPaymentDetails> details) {
|
||||
return getOverIssuedSalary(details, null);
|
||||
}
|
||||
|
||||
private BigDecimal getOverIssuedSalary(List<TeamSalaryPaymentDetails> details, Boolean anchor) {
|
||||
if (CollectionUtils.isEmpty(details)) {
|
||||
return BigDecimal.ZERO.setScale(2, RoundingMode.DOWN);
|
||||
}
|
||||
Set<String> issuedKeys = new HashSet<>();
|
||||
return details.stream()
|
||||
.filter(detail -> Objects.isNull(anchor) || Objects.equals(detail.getAnchor(), anchor))
|
||||
.sorted(Comparator.comparing(detail -> Optional.ofNullable(detail.getCreateTime())
|
||||
.orElse(new Timestamp(0))))
|
||||
.filter(detail -> !issuedKeys.add(paymentDetailsPolicyKey(detail)))
|
||||
.map(detail -> Optional.ofNullable(detail.getSalary()).orElse(BigDecimal.ZERO))
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add)
|
||||
.setScale(2, RoundingMode.DOWN);
|
||||
}
|
||||
|
||||
private String paymentDetailsPolicyKey(TeamSalaryPaymentDetails details) {
|
||||
if (Objects.isNull(details)
|
||||
|| Objects.isNull(details.getTeamMemberId())
|
||||
|| StringUtils.isBlank(details.getTeamRegionId())
|
||||
|| Objects.isNull(details.getPolicyLevel())
|
||||
|| Objects.isNull(details.getAnchor())) {
|
||||
return Optional.ofNullable(details).map(TeamSalaryPaymentDetails::getId)
|
||||
.orElse(String.valueOf(System.identityHashCode(details)));
|
||||
}
|
||||
return details.getTeamMemberId() + ":" + details.getTeamRegionId() + ":"
|
||||
+ details.getPolicyLevel() + ":" + details.getAnchor();
|
||||
}
|
||||
|
||||
private List<TeamSalaryPaymentDetails> listValidSalaryDetails(
|
||||
List<TeamSalaryPayment> cyclePayments) {
|
||||
if (CollectionUtils.isEmpty(cyclePayments)) {
|
||||
@ -729,6 +687,25 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
teamSalaryPaymentService.updatePolicyMap(paymentId, policyMap);
|
||||
}
|
||||
|
||||
private Integer resolveBillBelong(Integer billBelong) {
|
||||
return Objects.nonNull(billBelong) ? billBelong : TeamBillCycleUtils.getCalcBillBelong();
|
||||
}
|
||||
|
||||
private Long getPaymentReceiverUserId(ManualSalaryRow row, PolicyPayment payment) {
|
||||
if (Objects.isNull(row) || Objects.isNull(payment)) {
|
||||
return null;
|
||||
}
|
||||
return payment.isAnchor() ? row.getUserId() : row.getTeamOwnId();
|
||||
}
|
||||
|
||||
private boolean isAgentMember(TeamMember member, TeamProfile teamProfile,
|
||||
TeamMemberTarget target) {
|
||||
return Objects.nonNull(target)
|
||||
&& ((Objects.nonNull(teamProfile)
|
||||
&& Objects.equals(teamProfile.getOwnUserId(), target.getUserId()))
|
||||
|| (Objects.nonNull(member) && TeamMemberRole.OWN.eq(member.getRole())));
|
||||
}
|
||||
|
||||
private void validatePage(TeamManualSalaryPaymentQryCmd cmd) {
|
||||
ResponseAssert.notNull(ResponseErrorCode.REQUEST_PARAMETER_ERROR, cmd);
|
||||
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR, cmd.getSysOrigin());
|
||||
@ -741,10 +718,6 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
|
||||
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR, cmd.getCountryCode());
|
||||
}
|
||||
|
||||
private String paymentId(Long userId, Integer billBelong) {
|
||||
return userId + "_" + billBelong;
|
||||
}
|
||||
|
||||
private static class PaymentSummary {
|
||||
|
||||
private final BigDecimal totalIssuedSalary;
|
||||
|
||||
@ -27,6 +27,7 @@ import com.red.circle.other.infra.database.mongo.service.team.team.TeamPolicyMan
|
||||
import com.red.circle.other.infra.database.mongo.service.team.team.TeamProfileService;
|
||||
import com.red.circle.other.infra.database.mongo.service.team.team.TeamSalaryPaymentService;
|
||||
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamSalaryPayment;
|
||||
import com.red.circle.other.inner.enums.team.TeamMemberRole;
|
||||
import com.red.circle.other.inner.enums.team.TeamMemberTargetIndex;
|
||||
import com.red.circle.other.inner.model.cmd.team.TeamManualSalaryPaymentCmd;
|
||||
import com.red.circle.other.inner.model.dto.agency.agency.TeamManualSalaryPaymentResultDTO;
|
||||
@ -38,6 +39,7 @@ import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
@ -73,13 +75,16 @@ class TeamManualSalaryPaymentClientServiceImplTest {
|
||||
|
||||
List<?> payments = ReflectionTestUtils.invokeMethod(service, "buildSettlementPayments",
|
||||
null, billTarget, List.of(currentPayment), userId, region, paymentSummary,
|
||||
new BigDecimal("12.25"), false);
|
||||
false);
|
||||
|
||||
assertEquals(1, payments.size());
|
||||
assertEquals(2, payments.size());
|
||||
Object payment = payments.get(0);
|
||||
assertEquals(6, ReflectionTestUtils.getField(payment, "level"));
|
||||
assertEquals(Boolean.TRUE, ReflectionTestUtils.getField(payment, "anchor"));
|
||||
assertEquals(new BigDecimal("12.25"), ReflectionTestUtils.getField(payment, "salary"));
|
||||
assertEquals(new BigDecimal("13.00"), ReflectionTestUtils.getField(payment, "salary"));
|
||||
assertEquals(Boolean.FALSE, ReflectionTestUtils.getField(payments.get(1), "anchor"));
|
||||
assertEquals(BigDecimal.ZERO.setScale(2), ReflectionTestUtils.getField(payments.get(1),
|
||||
"salary"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -101,7 +106,7 @@ class TeamManualSalaryPaymentClientServiceImplTest {
|
||||
|
||||
List<?> payments = ReflectionTestUtils.invokeMethod(service, "buildSettlementPayments",
|
||||
null, billTarget, List.of(), userId, region, paymentSummary,
|
||||
new BigDecimal("-1.25"), false);
|
||||
false);
|
||||
|
||||
assertEquals(2, payments.size());
|
||||
assertEquals(BigDecimal.ZERO.setScale(2), ReflectionTestUtils.getField(payments.get(0),
|
||||
@ -193,7 +198,8 @@ class TeamManualSalaryPaymentClientServiceImplTest {
|
||||
.thenReturn(new TeamSalaryPayment().setId(paymentId));
|
||||
when(userBankBalanceClient.getBalance(userId))
|
||||
.thenReturn(ResultResponse.success(BankBalanceDTO.of(0L)))
|
||||
.thenReturn(ResultResponse.success(BankBalanceDTO.of(1225L)));
|
||||
.thenReturn(ResultResponse.success(BankBalanceDTO.of(0L)))
|
||||
.thenReturn(ResultResponse.success(BankBalanceDTO.of(1300L)));
|
||||
when(userBankBalanceClient.incr(any())).thenReturn(ResultResponse.success(Boolean.TRUE));
|
||||
when(userBankRunningWaterClient.add(any())).thenReturn(ResultResponse.success());
|
||||
when(teamSalaryPaymentService.mapPolicy(paymentId)).thenReturn(new HashMap<>());
|
||||
@ -205,16 +211,212 @@ class TeamManualSalaryPaymentClientServiceImplTest {
|
||||
|
||||
assertEquals(1, results.size());
|
||||
assertEquals(userId, results.get(0).getUserId());
|
||||
assertEquals(new BigDecimal("12.25"), results.get(0).getIssuedSalary());
|
||||
assertEquals(new BigDecimal("13.00"), results.get(0).getIssuedSalary());
|
||||
ArgumentCaptor<TeamSalaryPaymentDetails> detailsCaptor =
|
||||
ArgumentCaptor.forClass(TeamSalaryPaymentDetails.class);
|
||||
verify(teamSalaryPaymentService).paymentSalary(eq(paymentId), detailsCaptor.capture());
|
||||
assertEquals(new BigDecimal("12.25"), detailsCaptor.getValue().getSalary());
|
||||
assertEquals(new BigDecimal("13.00"), detailsCaptor.getValue().getSalary());
|
||||
assertEquals(Boolean.TRUE, detailsCaptor.getValue().getAnchor());
|
||||
verify(teamSalaryPaymentService, never()).checkRepeatPayment(anyString(), anyLong(),
|
||||
anyString(), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void payShouldIssueMemberSalaryToAnchorAndAgentSalaryToTeamOwner() {
|
||||
RedisService redisService = mock(RedisService.class);
|
||||
TeamMemberService teamMemberService = mock(TeamMemberService.class);
|
||||
TeamProfileService teamProfileService = mock(TeamProfileService.class);
|
||||
UserBankBalanceClient userBankBalanceClient = mock(UserBankBalanceClient.class);
|
||||
TeamMemberTargetService teamMemberTargetService = mock(TeamMemberTargetService.class);
|
||||
TeamSalaryPaymentService teamSalaryPaymentService = mock(TeamSalaryPaymentService.class);
|
||||
TeamPolicyManagerService teamPolicyManagerService = mock(TeamPolicyManagerService.class);
|
||||
UserBankRunningWaterClient userBankRunningWaterClient = mock(UserBankRunningWaterClient.class);
|
||||
TeamManualSalaryPaymentClientServiceImpl service = new TeamManualSalaryPaymentClientServiceImpl(
|
||||
redisService, teamMemberService, teamProfileService, userBankBalanceClient,
|
||||
teamMemberTargetService, teamSalaryPaymentService, teamPolicyManagerService,
|
||||
userBankRunningWaterClient);
|
||||
|
||||
String sysOrigin = "LIKEI";
|
||||
String countryCode = "PH";
|
||||
String region = "2046067717605224449";
|
||||
Long anchorUserId = 2054591808909930498L;
|
||||
Long ownerUserId = 2057118411766427649L;
|
||||
Long teamId = 2054614353419759617L;
|
||||
Integer billBelong = TeamBillCycleUtils.getCalcBillBelong();
|
||||
String anchorPaymentId = anchorUserId + "_" + billBelong;
|
||||
String ownerPaymentId = ownerUserId + "_" + billBelong;
|
||||
TeamMemberTarget target = new TeamMemberTarget()
|
||||
.setId("target-id")
|
||||
.setTimeId(2056024761217118210L)
|
||||
.setSysOrigin(sysOrigin)
|
||||
.setRegion(region)
|
||||
.setCountryCode(countryCode)
|
||||
.setTeamId(teamId)
|
||||
.setUserId(anchorUserId)
|
||||
.setBillBelong(billBelong)
|
||||
.setDailyTargets(List.of(new TeamMemberTargetIndex()
|
||||
.setOwnOnlineTime(717L)
|
||||
.setAcceptGiftValue(15151819L)));
|
||||
TeamPolicyManager policyManager = new TeamPolicyManager()
|
||||
.setSysOrigin(sysOrigin)
|
||||
.setRegion(region)
|
||||
.setCountryCode(countryCode)
|
||||
.setPolicy(List.of(new TeamPolicy()
|
||||
.setLevel(6)
|
||||
.setTarget(8810000L)
|
||||
.setOnlineTime(10L)
|
||||
.setEffectiveDay(0)
|
||||
.setMemberSalary(new BigDecimal("15.00"))
|
||||
.setOwnSalary(new BigDecimal("3.75"))
|
||||
.setTotalSalary(new BigDecimal("18.75"))));
|
||||
|
||||
when(redisService.lock(anyString(), anyLong())).thenReturn(true);
|
||||
when(teamMemberTargetService.listManualSalaryTargets(eq(sysOrigin), eq(countryCode), anySet(),
|
||||
eq(billBelong))).thenReturn(List.of(target));
|
||||
when(teamMemberService.mapByMemberIds(anySet())).thenReturn(Map.of(anchorUserId,
|
||||
new TeamMember().setMemberId(anchorUserId).setTeamId(teamId)
|
||||
.setRole(TeamMemberRole.MEMBER)));
|
||||
when(teamProfileService.mapProfileByIds(anySet())).thenReturn(Map.of(teamId,
|
||||
new TeamProfile().setId(teamId).setOwnUserId(ownerUserId).setRegion(region)));
|
||||
when(teamSalaryPaymentService.listByPaymentOrRecipientUserIdsAndDateNumbers(eq(sysOrigin),
|
||||
anySet(), anySet())).thenReturn(List.of());
|
||||
when(teamPolicyManagerService.getReleaseByRegionAndType(sysOrigin, region, null, countryCode))
|
||||
.thenReturn(policyManager);
|
||||
when(teamSalaryPaymentService.createIfAbsent(anchorUserId, billBelong, sysOrigin))
|
||||
.thenReturn(new TeamSalaryPayment().setId(anchorPaymentId));
|
||||
when(teamSalaryPaymentService.createIfAbsent(ownerUserId, billBelong, sysOrigin))
|
||||
.thenReturn(new TeamSalaryPayment().setId(ownerPaymentId));
|
||||
when(userBankBalanceClient.getBalance(anchorUserId))
|
||||
.thenReturn(ResultResponse.success(BankBalanceDTO.of(0L)))
|
||||
.thenReturn(ResultResponse.success(BankBalanceDTO.of(0L)))
|
||||
.thenReturn(ResultResponse.success(BankBalanceDTO.of(1500L)));
|
||||
when(userBankBalanceClient.getBalance(ownerUserId))
|
||||
.thenReturn(ResultResponse.success(BankBalanceDTO.of(0L)))
|
||||
.thenReturn(ResultResponse.success(BankBalanceDTO.of(375L)));
|
||||
when(userBankBalanceClient.incr(any())).thenReturn(ResultResponse.success(Boolean.TRUE));
|
||||
when(userBankRunningWaterClient.add(any())).thenReturn(ResultResponse.success());
|
||||
when(teamSalaryPaymentService.mapPolicy(anchorPaymentId)).thenReturn(new HashMap<>());
|
||||
when(teamSalaryPaymentService.mapPolicy(ownerPaymentId)).thenReturn(new HashMap<>());
|
||||
|
||||
List<TeamManualSalaryPaymentResultDTO> results = service.pay(new TeamManualSalaryPaymentCmd()
|
||||
.setSysOrigin(sysOrigin)
|
||||
.setCountryCode(countryCode)
|
||||
.setUserIds(List.of(anchorUserId)));
|
||||
|
||||
assertEquals(2, results.size());
|
||||
assertEquals(new BigDecimal("15.00"), results.stream()
|
||||
.filter(result -> Objects.equals(result.getUserId(), anchorUserId))
|
||||
.findFirst()
|
||||
.orElseThrow()
|
||||
.getIssuedSalary());
|
||||
assertEquals(new BigDecimal("3.75"), results.stream()
|
||||
.filter(result -> Objects.equals(result.getUserId(), ownerUserId))
|
||||
.findFirst()
|
||||
.orElseThrow()
|
||||
.getIssuedSalary());
|
||||
|
||||
ArgumentCaptor<TeamSalaryPaymentDetails> anchorDetailsCaptor =
|
||||
ArgumentCaptor.forClass(TeamSalaryPaymentDetails.class);
|
||||
verify(teamSalaryPaymentService).paymentSalary(eq(anchorPaymentId),
|
||||
anchorDetailsCaptor.capture());
|
||||
assertEquals(anchorUserId, anchorDetailsCaptor.getValue().getTeamMemberId());
|
||||
assertEquals(Boolean.TRUE, anchorDetailsCaptor.getValue().getAnchor());
|
||||
|
||||
ArgumentCaptor<TeamSalaryPaymentDetails> ownerDetailsCaptor =
|
||||
ArgumentCaptor.forClass(TeamSalaryPaymentDetails.class);
|
||||
verify(teamSalaryPaymentService).paymentSalary(eq(ownerPaymentId),
|
||||
ownerDetailsCaptor.capture());
|
||||
assertEquals(anchorUserId, ownerDetailsCaptor.getValue().getTeamMemberId());
|
||||
assertEquals(ownerUserId, ownerDetailsCaptor.getValue().getTeamOwnId());
|
||||
assertEquals(Boolean.FALSE, ownerDetailsCaptor.getValue().getAnchor());
|
||||
assertEquals(new BigDecimal("3.75"), ownerDetailsCaptor.getValue().getSalary());
|
||||
}
|
||||
|
||||
@Test
|
||||
void payShouldNotRepeatAgentSalaryWhenTargetEntitlementAlreadyPaid() {
|
||||
RedisService redisService = mock(RedisService.class);
|
||||
TeamMemberService teamMemberService = mock(TeamMemberService.class);
|
||||
TeamProfileService teamProfileService = mock(TeamProfileService.class);
|
||||
UserBankBalanceClient userBankBalanceClient = mock(UserBankBalanceClient.class);
|
||||
TeamMemberTargetService teamMemberTargetService = mock(TeamMemberTargetService.class);
|
||||
TeamSalaryPaymentService teamSalaryPaymentService = mock(TeamSalaryPaymentService.class);
|
||||
TeamPolicyManagerService teamPolicyManagerService = mock(TeamPolicyManagerService.class);
|
||||
UserBankRunningWaterClient userBankRunningWaterClient = mock(UserBankRunningWaterClient.class);
|
||||
TeamManualSalaryPaymentClientServiceImpl service = new TeamManualSalaryPaymentClientServiceImpl(
|
||||
redisService, teamMemberService, teamProfileService, userBankBalanceClient,
|
||||
teamMemberTargetService, teamSalaryPaymentService, teamPolicyManagerService,
|
||||
userBankRunningWaterClient);
|
||||
|
||||
String sysOrigin = "LIKEI";
|
||||
String countryCode = "PH";
|
||||
String region = "2046067717605224449";
|
||||
Long anchorUserId = 2054591808909930498L;
|
||||
Long ownerUserId = 2057118411766427649L;
|
||||
Long teamId = 2054614353419759617L;
|
||||
Integer billBelong = TeamBillCycleUtils.getCalcBillBelong();
|
||||
String ownerPaymentId = ownerUserId + "_" + billBelong;
|
||||
TeamMemberTarget target = new TeamMemberTarget()
|
||||
.setId("target-id")
|
||||
.setTimeId(2056024761217118210L)
|
||||
.setSysOrigin(sysOrigin)
|
||||
.setRegion(region)
|
||||
.setCountryCode(countryCode)
|
||||
.setTeamId(teamId)
|
||||
.setUserId(anchorUserId)
|
||||
.setBillBelong(billBelong)
|
||||
.setDailyTargets(List.of(new TeamMemberTargetIndex()
|
||||
.setOwnOnlineTime(717L)
|
||||
.setAcceptGiftValue(15151819L)));
|
||||
TeamSalaryPayment ownerPayment = new TeamSalaryPayment()
|
||||
.setId(ownerPaymentId)
|
||||
.setUserId(ownerUserId)
|
||||
.setDateNumber(billBelong)
|
||||
.setSalarySendDetails(List.of(new TeamSalaryPaymentDetails()
|
||||
.setTeamOwnId(ownerUserId)
|
||||
.setTeamMemberId(anchorUserId)
|
||||
.setTeamRegionId(region)
|
||||
.setPolicyLevel(6)
|
||||
.setAnchor(Boolean.FALSE)
|
||||
.setSalary(new BigDecimal("3.75"))
|
||||
.setRecycled(Boolean.FALSE)));
|
||||
TeamPolicyManager policyManager = new TeamPolicyManager()
|
||||
.setSysOrigin(sysOrigin)
|
||||
.setRegion(region)
|
||||
.setCountryCode(countryCode)
|
||||
.setPolicy(List.of(new TeamPolicy()
|
||||
.setLevel(6)
|
||||
.setTarget(8810000L)
|
||||
.setOnlineTime(10L)
|
||||
.setEffectiveDay(0)
|
||||
.setMemberSalary(BigDecimal.ZERO.setScale(2))
|
||||
.setOwnSalary(new BigDecimal("3.75"))
|
||||
.setTotalSalary(new BigDecimal("3.75"))));
|
||||
|
||||
when(redisService.lock(anyString(), anyLong())).thenReturn(true);
|
||||
when(teamMemberTargetService.listManualSalaryTargets(eq(sysOrigin), eq(countryCode), anySet(),
|
||||
eq(billBelong))).thenReturn(List.of(target));
|
||||
when(teamMemberService.mapByMemberIds(anySet())).thenReturn(Map.of(anchorUserId,
|
||||
new TeamMember().setMemberId(anchorUserId).setTeamId(teamId)
|
||||
.setRole(TeamMemberRole.MEMBER)));
|
||||
when(teamProfileService.mapProfileByIds(anySet())).thenReturn(Map.of(teamId,
|
||||
new TeamProfile().setId(teamId).setOwnUserId(ownerUserId).setRegion(region)));
|
||||
when(teamSalaryPaymentService.listByPaymentOrRecipientUserIdsAndDateNumbers(eq(sysOrigin),
|
||||
anySet(), anySet())).thenReturn(List.of(ownerPayment));
|
||||
when(teamPolicyManagerService.getReleaseByRegionAndType(sysOrigin, region, null, countryCode))
|
||||
.thenReturn(policyManager);
|
||||
when(userBankBalanceClient.getBalance(anchorUserId))
|
||||
.thenReturn(ResultResponse.success(BankBalanceDTO.of(0L)));
|
||||
|
||||
List<TeamManualSalaryPaymentResultDTO> results = service.pay(new TeamManualSalaryPaymentCmd()
|
||||
.setSysOrigin(sysOrigin)
|
||||
.setCountryCode(countryCode)
|
||||
.setUserIds(List.of(anchorUserId)));
|
||||
|
||||
assertEquals(0, results.size());
|
||||
verify(teamSalaryPaymentService, never()).createIfAbsent(anyLong(), any(), anyString());
|
||||
verify(teamSalaryPaymentService, never()).paymentSalary(anyString(), any());
|
||||
}
|
||||
|
||||
private Object paymentSummary(BigDecimal totalIssuedSalary, BigDecimal memberIssuedSalary,
|
||||
BigDecimal agentIssuedSalary) throws Exception {
|
||||
Class<?> summaryClass = Class.forName(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user