fix manual salary settlement net payable

This commit is contained in:
hy001 2026-05-21 13:46:33 +08:00
parent a48fddb613
commit 3cef4fc322
7 changed files with 300 additions and 88 deletions

View File

@ -31,4 +31,14 @@ public class TeamManualSalaryPaymentQryCmd extends PageCommand {
* 用户 id. * 用户 id.
*/ */
private Long userId; private Long userId;
/**
* 排序字段.
*/
private String sortField;
/**
* 排序方向.
*/
private String sortOrder;
} }

View File

@ -82,7 +82,12 @@ public class TeamManualSalaryPaymentDTO implements Serializable {
private Boolean satisfyLevel; private Boolean satisfyLevel;
/** /**
* 应发工资. * 当前账期按积分档位计算出的工资.
*/
private BigDecimal expectedSalary;
/**
* 待结算工资 = 当前账期应发工资 - 当前账期实收工资.
*/ */
private BigDecimal payableSalary; private BigDecimal payableSalary;
@ -91,6 +96,11 @@ public class TeamManualSalaryPaymentDTO implements Serializable {
*/ */
private BigDecimal totalIssuedSalary; private BigDecimal totalIssuedSalary;
/**
* 当前账期多发工资.
*/
private BigDecimal overIssuedSalary;
/** /**
* 当前工资余额. * 当前工资余额.
*/ */

View File

@ -215,8 +215,10 @@ public class TeamSalaryBackServiceImpl implements TeamSalaryBackService {
.setCurrentTarget(dto.getCurrentTarget()) .setCurrentTarget(dto.getCurrentTarget())
.setPolicyLevel(dto.getPolicyLevel()) .setPolicyLevel(dto.getPolicyLevel())
.setSatisfyLevel(dto.getSatisfyLevel()) .setSatisfyLevel(dto.getSatisfyLevel())
.setExpectedSalary(dto.getExpectedSalary())
.setPayableSalary(dto.getPayableSalary()) .setPayableSalary(dto.getPayableSalary())
.setTotalIssuedSalary(dto.getTotalIssuedSalary()) .setTotalIssuedSalary(dto.getTotalIssuedSalary())
.setOverIssuedSalary(dto.getOverIssuedSalary())
.setCurrentSalaryBalance(dto.getCurrentSalaryBalance()) .setCurrentSalaryBalance(dto.getCurrentSalaryBalance())
.setPaid(dto.getPaid()); .setPaid(dto.getPaid());
} }

View File

@ -39,8 +39,10 @@ public class TeamManualSalaryCO implements Serializable {
private Long currentTarget; private Long currentTarget;
private Integer policyLevel; private Integer policyLevel;
private Boolean satisfyLevel; private Boolean satisfyLevel;
private BigDecimal expectedSalary;
private BigDecimal payableSalary; private BigDecimal payableSalary;
private BigDecimal totalIssuedSalary; private BigDecimal totalIssuedSalary;
private BigDecimal overIssuedSalary;
private BigDecimal currentSalaryBalance; private BigDecimal currentSalaryBalance;
private Boolean paid; private Boolean paid;
} }

View File

@ -6,6 +6,7 @@ import com.red.circle.other.infra.database.mongo.entity.team.team.TeamPolicyMana
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamSalaryPayment; import com.red.circle.other.infra.database.mongo.entity.team.team.TeamSalaryPayment;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* 团队工资实时支付记录. * 团队工资实时支付记录.
@ -82,6 +83,12 @@ public interface TeamSalaryPaymentService {
*/ */
TeamSalaryPayment getOneById(String id); TeamSalaryPayment getOneById(String id);
/**
* 按用户和账期批量获得数据.
*/
Map<String, TeamSalaryPayment> mapByUserIdsAndDateNumbers(String sysOrigin, Set<Long> userIds,
Set<Integer> dateNumbers);
/** /**
* 基于父ID修改子记录状态为已退款. * 基于父ID修改子记录状态为已退款.
* *

View File

@ -17,6 +17,8 @@ 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.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.MongoTemplate;
@ -183,6 +185,26 @@ public class TeamSalaryPaymentServiceImpl implements TeamSalaryPaymentService {
return mongoTemplate.findOne(Query.query(Criteria.where("id").is(id)), TeamSalaryPayment.class); return mongoTemplate.findOne(Query.query(Criteria.where("id").is(id)), TeamSalaryPayment.class);
} }
@Override
public Map<String, TeamSalaryPayment> mapByUserIdsAndDateNumbers(String sysOrigin,
Set<Long> userIds, Set<Integer> dateNumbers) {
if (StringUtils.isBlank(sysOrigin) || CollectionUtils.isEmpty(userIds)
|| CollectionUtils.isEmpty(dateNumbers)) {
return Maps.newHashMap();
}
Criteria criteria = Criteria.where("sysOrigin").is(sysOrigin)
.and("userId").in(userIds)
.and("dateNumber").in(dateNumbers);
return mongoTemplate.find(Query.query(criteria), TeamSalaryPayment.class)
.stream()
.filter(payment -> StringUtils.isNotBlank(payment.getId()))
.collect(Collectors.toMap(TeamSalaryPayment::getId, payment -> payment,
(first, second) -> first));
}
@Override @Override
public void updateDetails(String id, List<TeamSalaryPaymentDetails> salarySendDetails) { public void updateDetails(String id, List<TeamSalaryPaymentDetails> salarySendDetails) {

View File

@ -44,6 +44,7 @@ import java.math.RoundingMode;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -65,6 +66,11 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
private static final String MANUAL_SALARY_LOCK_PREFIX = "TeamManualSalaryPayment:"; private static final String MANUAL_SALARY_LOCK_PREFIX = "TeamManualSalaryPayment:";
private static final int LOCK_SECONDS = 300; private static final int LOCK_SECONDS = 300;
private static final String SORT_FIELD_CURRENT_SALARY_BALANCE = "currentSalaryBalance";
private static final String SORT_FIELD_PAYABLE_SALARY = "payableSalary";
private static final String SORT_FIELD_TOTAL_ISSUED_SALARY = "totalIssuedSalary";
private static final String SORT_ORDER_ASCEND = "ascend";
private static final int LEGACY_HALF_MONTH_COMPAT_BILL_BELONG = 202605;
private final RedisService redisService; private final RedisService redisService;
private final TeamMemberService teamMemberService; private final TeamMemberService teamMemberService;
@ -81,6 +87,7 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
List<ManualSalaryRow> rows = buildRows(cmd.getSysOrigin(), cmd.getCountryCode(), List<ManualSalaryRow> rows = buildRows(cmd.getSysOrigin(), cmd.getCountryCode(),
singletonUserId(cmd.getUserId()), TeamBillCycleUtils.getCalcBillBelong()); singletonUserId(cmd.getUserId()), TeamBillCycleUtils.getCalcBillBelong());
rows = sortRows(rows, cmd.getSortField(), cmd.getSortOrder());
int cursor = 1; int cursor = 1;
int limit = 20; int limit = 20;
@ -132,18 +139,28 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
continue; continue;
} }
BigDecimal issueSalary = policyPayment.getSalary().compareTo(BigDecimal.ZERO) > 0
? policyPayment.getSalary()
: BigDecimal.ZERO.setScale(2, RoundingMode.DOWN);
BigDecimal beforeBalance = getAccurateBalance(row.getUserId()); BigDecimal beforeBalance = getAccurateBalance(row.getUserId());
String detailsId = IdWorkerUtils.getIdStr(); String detailsId = IdWorkerUtils.getIdStr();
if (issueSalary.compareTo(BigDecimal.ZERO) > 0) {
Boolean incrSuccess = ResponseAssert.requiredSuccess(userBankBalanceClient.incr(new UserBankBalanceIncrCmd() Boolean incrSuccess = ResponseAssert.requiredSuccess(userBankBalanceClient.incr(new UserBankBalanceIncrCmd()
.setUserId(row.getUserId()) .setUserId(row.getUserId())
.setSysOrigin(row.getSysOrigin()) .setSysOrigin(row.getSysOrigin())
.setAmount(PennyAmount.ofDollar(policyPayment.getSalary())))); .setAmount(PennyAmount.ofDollar(issueSalary))));
ResponseAssert.isTrue(CommonErrorCode.OPERATION_CONFLICT, Boolean.TRUE.equals(incrSuccess)); ResponseAssert.isTrue(CommonErrorCode.OPERATION_CONFLICT, Boolean.TRUE.equals(incrSuccess));
}
BigDecimal afterBalance = getAccurateBalance(row.getUserId()); BigDecimal afterBalance = getAccurateBalance(row.getUserId());
if (issueSalary.compareTo(BigDecimal.ZERO) > 0) {
addRunningWater(detailsId, row.getUserId(), row.getSysOrigin(), addRunningWater(detailsId, row.getUserId(), row.getSysOrigin(),
policyPayment.getSalary(), afterBalance, cmd.getOperationUserId()); issueSalary, afterBalance, cmd.getOperationUserId());
}
String settlementRemark = issueSalary.compareTo(BigDecimal.ZERO) > 0
? "后台手动发放主播工资"
: "后台手动结算主播工资实收已大于等于应发本次发放0";
teamSalaryPaymentService.paymentSalary(payment.getId(), new TeamSalaryPaymentDetails() teamSalaryPaymentService.paymentSalary(payment.getId(), new TeamSalaryPaymentDetails()
.setId(detailsId) .setId(detailsId)
@ -155,12 +172,12 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
.setTeamBillId(Long.valueOf(billBelong)) .setTeamBillId(Long.valueOf(billBelong))
.setTeamRegionId(row.getRegion()) .setTeamRegionId(row.getRegion())
.setRemarks(List.of(new TeamSalaryPaymentRemark() .setRemarks(List.of(new TeamSalaryPaymentRemark()
.setRemark("后台手动发放主播工资") .setRemark(settlementRemark)
.setCreateTime(TimestampUtils.now()))) .setCreateTime(TimestampUtils.now())))
.setAnchor(Boolean.TRUE) .setAnchor(Boolean.TRUE)
.setHostSalaryToAgent(Boolean.FALSE) .setHostSalaryToAgent(Boolean.FALSE)
.setTarget(row.getCurrentTarget()) .setTarget(row.getCurrentTarget())
.setSalary(policyPayment.getSalary()) .setSalary(issueSalary)
.setPolicyLevel(policyPayment.getLevel()) .setPolicyLevel(policyPayment.getLevel())
.setPolicy(policyPayment.getPolicy())); .setPolicy(policyPayment.getPolicy()));
@ -177,7 +194,7 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
.setBillBelong(billBelong) .setBillBelong(billBelong)
.setBeforeSalaryBalance(beforeBalance) .setBeforeSalaryBalance(beforeBalance)
.setAfterSalaryBalance(afterBalance) .setAfterSalaryBalance(afterBalance)
.setIssuedSalary(policyPayment.getSalary()) .setIssuedSalary(issueSalary)
.setCurrentTarget(row.getCurrentTarget()) .setCurrentTarget(row.getCurrentTarget())
.setPolicyLevel(policyPayment.getLevel())); .setPolicyLevel(policyPayment.getLevel()));
} }
@ -215,17 +232,55 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Map<Long, TeamMember> memberMap = teamMemberService.mapByMemberIds(memberIds); Map<Long, TeamMember> memberMap = teamMemberService.mapByMemberIds(memberIds);
Map<Long, TeamProfile> teamProfileMap = teamProfileService.mapProfileByIds(teamIds); Map<Long, TeamProfile> teamProfileMap = teamProfileService.mapProfileByIds(teamIds);
Map<String, TeamSalaryPayment> salaryPaymentMap =
teamSalaryPaymentService.mapByUserIdsAndDateNumbers(sysOrigin, memberIds,
getMergedSalaryPaymentBillBelongs(billBelong));
Map<String, TeamPolicyManager> policyCache = CollectionUtils.newHashMap(); Map<String, TeamPolicyManager> policyCache = CollectionUtils.newHashMap();
return targets.stream() return targets.stream()
.map(target -> buildRow(target, memberMap, teamProfileMap, policyCache, billBelong, .map(target -> buildRow(target, memberMap, teamProfileMap, policyCache, billBelong,
countryCode)) countryCode, salaryPaymentMap))
.filter(Objects::nonNull) .filter(Objects::nonNull)
.sorted(Comparator.comparing(ManualSalaryRow::getCurrentTarget).reversed() .sorted(Comparator.comparing(ManualSalaryRow::getCurrentTarget).reversed()
.thenComparing(ManualSalaryRow::getUserId)) .thenComparing(ManualSalaryRow::getUserId))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
private List<ManualSalaryRow> sortRows(List<ManualSalaryRow> rows, String sortField,
String sortOrder) {
if (CollectionUtils.isEmpty(rows) || StringUtils.isBlank(sortField)
|| StringUtils.isBlank(sortOrder)) {
return rows;
}
Comparator<ManualSalaryRow> comparator = getSalarySortComparator(sortField);
if (Objects.isNull(comparator)) {
return rows;
}
if (!SORT_ORDER_ASCEND.equalsIgnoreCase(sortOrder)) {
comparator = comparator.reversed();
}
return rows.stream()
.sorted(comparator.thenComparing(ManualSalaryRow::getUserId))
.collect(Collectors.toList());
}
private Comparator<ManualSalaryRow> getSalarySortComparator(String sortField) {
if (SORT_FIELD_PAYABLE_SALARY.equals(sortField)) {
return Comparator.comparing(row -> decimalValue(row.getPayableSalary()));
}
if (SORT_FIELD_TOTAL_ISSUED_SALARY.equals(sortField)) {
return Comparator.comparing(row -> decimalValue(row.getTotalIssuedSalary()));
}
if (SORT_FIELD_CURRENT_SALARY_BALANCE.equals(sortField)) {
return Comparator.comparing(row -> decimalValue(row.getCurrentSalaryBalance()));
}
return null;
}
private BigDecimal decimalValue(BigDecimal value) {
return Objects.isNull(value) ? BigDecimal.ZERO : value;
}
private Set<Long> singletonUserId(Long userId) { private Set<Long> singletonUserId(Long userId) {
if (Objects.isNull(userId)) { if (Objects.isNull(userId)) {
return Set.of(); return Set.of();
@ -242,9 +297,36 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
private Set<Integer> getMergedSalaryPaymentBillBelongs(Integer billBelong) {
if (Objects.isNull(billBelong)) {
return Set.of();
}
Set<Integer> billBelongs = new HashSet<>();
billBelongs.add(billBelong);
Integer month = TeamBillCycleUtils.extractMonth(billBelong);
if (Objects.equals(month, LEGACY_HALF_MONTH_COMPAT_BILL_BELONG)) {
billBelongs.add(month);
billBelongs.add(month * 100 + 1);
billBelongs.add(month * 100 + 16);
}
return billBelongs;
}
private List<TeamSalaryPayment> listCyclePayments(
Map<String, TeamSalaryPayment> salaryPaymentMap, Long userId, Integer billBelong) {
if (Objects.isNull(userId) || CollectionUtils.isEmpty(salaryPaymentMap)) {
return List.of();
}
return getMergedSalaryPaymentBillBelongs(billBelong).stream()
.map(item -> salaryPaymentMap.get(paymentId(userId, item)))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
private ManualSalaryRow buildRow(TeamMemberTarget target, Map<Long, TeamMember> memberMap, private ManualSalaryRow buildRow(TeamMemberTarget target, Map<Long, TeamMember> memberMap,
Map<Long, TeamProfile> teamProfileMap, Map<String, TeamPolicyManager> policyCache, Map<Long, TeamProfile> teamProfileMap, Map<String, TeamPolicyManager> policyCache,
Integer billBelong, String requestedCountryCode) { Integer billBelong, String requestedCountryCode,
Map<String, TeamSalaryPayment> salaryPaymentMap) {
TeamMember member = memberMap.get(target.getUserId()); TeamMember member = memberMap.get(target.getUserId());
TeamProfile teamProfile = teamProfileMap.get(target.getTeamId()); TeamProfile teamProfile = teamProfileMap.get(target.getTeamId());
if (Objects.isNull(member) || Objects.isNull(teamProfile) if (Objects.isNull(member) || Objects.isNull(teamProfile)
@ -264,14 +346,16 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
policyCache); policyCache);
TeamBillMemberTarget billTarget = calculateBillTarget(target, policyManager); TeamBillMemberTarget billTarget = calculateBillTarget(target, policyManager);
TeamSalaryPayment payment = teamSalaryPaymentService.getOneById(paymentId(target.getUserId(), List<TeamSalaryPayment> cyclePayments = listCyclePayments(salaryPaymentMap,
billBelong)); target.getUserId(), billBelong);
List<PolicyPayment> policyPayments = listUnpaidPolicyPayments(policyManager, billTarget, PaymentSummary paymentSummary = summarizePayments(cyclePayments);
payment, target.getUserId(), region); BigDecimal expectedSalary = expectedMemberSalary(billTarget);
BigDecimal payableSalary = policyPayments.stream() BigDecimal payableSalary = expectedSalary.subtract(paymentSummary.getTotalIssuedSalary())
.map(PolicyPayment::getSalary)
.reduce(BigDecimal.ZERO, BigDecimal::add)
.setScale(2, RoundingMode.DOWN); .setScale(2, RoundingMode.DOWN);
boolean currentLevelSettled = isCurrentLevelSettled(cyclePayments, target.getUserId(), region,
billTarget.getLevel(), payableSalary);
List<PolicyPayment> policyPayments = buildSettlementPayments(policyManager, billTarget,
payableSalary, currentLevelSettled);
TeamManualSalaryPaymentDTO dto = new TeamManualSalaryPaymentDTO() TeamManualSalaryPaymentDTO dto = new TeamManualSalaryPaymentDTO()
.setId(target.getId()) .setId(target.getId())
@ -282,15 +366,16 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
.setTeamOwnId(teamProfile.getOwnUserId()) .setTeamOwnId(teamProfile.getOwnUserId())
.setUserId(target.getUserId()) .setUserId(target.getUserId())
.setBillBelong(billBelong) .setBillBelong(billBelong)
.setLastSettlementTarget(getLastSettlementTarget(payment)) .setLastSettlementTarget(getLastSettlementTarget(cyclePayments))
.setCurrentTarget(target.sumAcceptGiftValue()) .setCurrentTarget(target.sumAcceptGiftValue())
.setPolicyLevel(billTarget.getLevel()) .setPolicyLevel(billTarget.getLevel())
.setSatisfyLevel(billTarget.getSatisfyLevel()) .setSatisfyLevel(billTarget.getSatisfyLevel())
.setExpectedSalary(expectedSalary)
.setPayableSalary(payableSalary) .setPayableSalary(payableSalary)
.setTotalIssuedSalary(getTotalIssuedSalary(payment)) .setTotalIssuedSalary(paymentSummary.getTotalIssuedSalary())
.setOverIssuedSalary(paymentSummary.getOverIssuedSalary())
.setCurrentSalaryBalance(getAccurateBalance(target.getUserId())) .setCurrentSalaryBalance(getAccurateBalance(target.getUserId()))
.setPaid(Objects.nonNull(billTarget.getLevel()) .setPaid(currentLevelSettled);
&& BigDecimal.ZERO.compareTo(payableSalary) == 0);
return new ManualSalaryRow(dto, target, teamProfile, policyManager, billTarget, policyPayments); return new ManualSalaryRow(dto, target, teamProfile, policyManager, billTarget, policyPayments);
} }
@ -345,51 +430,55 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
.setSatisfyLevel(Boolean.FALSE); .setSatisfyLevel(Boolean.FALSE);
} }
private List<PolicyPayment> listUnpaidPolicyPayments(TeamPolicyManager policyManager, private BigDecimal expectedMemberSalary(TeamBillMemberTarget billTarget) {
TeamBillMemberTarget billTarget, TeamSalaryPayment payment, Long userId, String region) { return Optional.ofNullable(billTarget)
if (Objects.isNull(policyManager) || CollectionUtils.isEmpty(policyManager.getPolicy()) .map(TeamBillMemberTarget::getMemberSalary)
.orElse(BigDecimal.ZERO)
.setScale(2, RoundingMode.DOWN);
}
private List<PolicyPayment> buildSettlementPayments(TeamPolicyManager policyManager,
TeamBillMemberTarget billTarget, BigDecimal payableSalary, boolean currentLevelSettled) {
if (currentLevelSettled || Objects.isNull(billTarget)
|| Objects.isNull(billTarget.getLevel())) { || Objects.isNull(billTarget.getLevel())) {
return List.of(); return List.of();
} }
List<TeamPolicy> completePolicies = policyManager.getPolicy().stream() BigDecimal issueSalary = payableSalary.compareTo(BigDecimal.ZERO) > 0
.filter(policy -> Objects.nonNull(policy.getLevel())) ? payableSalary.setScale(2, RoundingMode.DOWN)
.filter(policy -> policy.getLevel() <= billTarget.getLevel()) : BigDecimal.ZERO.setScale(2, RoundingMode.DOWN);
.sorted(Comparator.comparing(TeamPolicy::getLevel)) return List.of(new PolicyPayment(findPolicy(policyManager, billTarget.getLevel()),
.collect(Collectors.toList()); billTarget.getLevel(), issueSalary));
if (CollectionUtils.isEmpty(completePolicies)) {
return List.of();
} }
List<PolicyPayment> payments = new ArrayList<>(); private TeamPolicy findPolicy(TeamPolicyManager policyManager, Integer level) {
for (int i = 0; i < completePolicies.size(); i++) { if (Objects.isNull(policyManager) || CollectionUtils.isEmpty(policyManager.getPolicy())
TeamPolicy policy = completePolicies.get(i); || Objects.isNull(level)) {
if (Objects.nonNull(payment) && Boolean.TRUE.equals( return null;
teamSalaryPaymentService.checkRepeatPayment(payment.getId(), userId, region, }
policy.getLevel(), Boolean.TRUE))) { return policyManager.getPolicy().stream()
continue; .filter(policy -> Objects.equals(policy.getLevel(), level))
.findFirst()
.orElse(null);
} }
BigDecimal salary = Optional.ofNullable(policy.getMemberSalary()).orElse(BigDecimal.ZERO); private boolean isCurrentLevelSettled(List<TeamSalaryPayment> cyclePayments, Long userId,
if (i > 0) { String region, Integer policyLevel, BigDecimal payableSalary) {
salary = salary.subtract(Optional.ofNullable(completePolicies.get(i - 1).getMemberSalary()) return Objects.nonNull(policyLevel)
.orElse(BigDecimal.ZERO)); && payableSalary.compareTo(BigDecimal.ZERO) <= 0
} && hasPaidPolicy(cyclePayments, userId, region, policyLevel);
salary = salary.setScale(2, RoundingMode.DOWN);
if (salary.compareTo(BigDecimal.ZERO) <= 0) {
continue;
} }
payments.add(new PolicyPayment(policy, policy.getLevel(), salary)); private boolean hasPaidPolicy(List<TeamSalaryPayment> cyclePayments, Long userId, String region,
} Integer policyLevel) {
return payments; return listValidAnchorDetails(cyclePayments).stream()
.anyMatch(details -> Objects.equals(details.getTeamMemberId(), userId)
&& Objects.equals(details.getTeamRegionId(), region)
&& Objects.equals(details.getPolicyLevel(), policyLevel));
} }
private Long getLastSettlementTarget(TeamSalaryPayment payment) { private Long getLastSettlementTarget(List<TeamSalaryPayment> cyclePayments) {
return Optional.ofNullable(payment) return listValidAnchorDetails(cyclePayments).stream()
.map(TeamSalaryPayment::getSalarySendDetails)
.stream()
.flatMap(List::stream)
.filter(this::validAnchorDetails) .filter(this::validAnchorDetails)
.max(Comparator.comparing(details -> Optional.ofNullable(details.getCreateTime()) .max(Comparator.comparing(details -> Optional.ofNullable(details.getCreateTime())
.orElse(new Timestamp(0)))) .orElse(new Timestamp(0))))
@ -397,15 +486,54 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
.orElse(0L); .orElse(0L);
} }
private BigDecimal getTotalIssuedSalary(TeamSalaryPayment payment) { private PaymentSummary summarizePayments(List<TeamSalaryPayment> cyclePayments) {
return Optional.ofNullable(payment) List<TeamSalaryPaymentDetails> details = listValidAnchorDetails(cyclePayments);
.map(TeamSalaryPayment::getSalarySendDetails) BigDecimal totalIssuedSalary = details.stream()
.stream() .map(detail -> Optional.ofNullable(detail.getSalary()).orElse(BigDecimal.ZERO))
.flatMap(List::stream)
.filter(this::validAnchorDetails)
.map(details -> Optional.ofNullable(details.getSalary()).orElse(BigDecimal.ZERO))
.reduce(BigDecimal.ZERO, BigDecimal::add) .reduce(BigDecimal.ZERO, BigDecimal::add)
.setScale(2, RoundingMode.DOWN); .setScale(2, RoundingMode.DOWN);
return new PaymentSummary(totalIssuedSalary, getOverIssuedSalary(details));
}
private BigDecimal getOverIssuedSalary(List<TeamSalaryPaymentDetails> details) {
if (CollectionUtils.isEmpty(details)) {
return BigDecimal.ZERO.setScale(2, RoundingMode.DOWN);
}
Set<String> issuedKeys = new HashSet<>();
return details.stream()
.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> listValidAnchorDetails(
List<TeamSalaryPayment> cyclePayments) {
if (CollectionUtils.isEmpty(cyclePayments)) {
return List.of();
}
return cyclePayments.stream()
.filter(Objects::nonNull)
.flatMap(payment -> Optional.ofNullable(payment.getSalarySendDetails())
.stream()
.flatMap(List::stream))
.filter(this::validAnchorDetails)
.collect(Collectors.toList());
} }
private boolean validAnchorDetails(TeamSalaryPaymentDetails details) { private boolean validAnchorDetails(TeamSalaryPaymentDetails details) {
@ -471,6 +599,25 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
return userId + "_" + billBelong; return userId + "_" + billBelong;
} }
private static class PaymentSummary {
private final BigDecimal totalIssuedSalary;
private final BigDecimal overIssuedSalary;
private PaymentSummary(BigDecimal totalIssuedSalary, BigDecimal overIssuedSalary) {
this.totalIssuedSalary = totalIssuedSalary;
this.overIssuedSalary = overIssuedSalary;
}
private BigDecimal getTotalIssuedSalary() {
return totalIssuedSalary;
}
private BigDecimal getOverIssuedSalary() {
return overIssuedSalary;
}
}
private static class ManualSalaryRow { private static class ManualSalaryRow {
private final TeamManualSalaryPaymentDTO dto; private final TeamManualSalaryPaymentDTO dto;
@ -527,6 +674,18 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
return dto.getCurrentTarget(); return dto.getCurrentTarget();
} }
private BigDecimal getPayableSalary() {
return dto.getPayableSalary();
}
private BigDecimal getTotalIssuedSalary() {
return dto.getTotalIssuedSalary();
}
private BigDecimal getCurrentSalaryBalance() {
return dto.getCurrentSalaryBalance();
}
private TeamPolicyManager getPolicyManager() { private TeamPolicyManager getPolicyManager() {
return policyManager; return policyManager;
} }