Commit 557e35d4 by jianan

Merge branch 'refs/heads/test' into dev

# Conflicts:
#	yd-csf-service/src/main/java/com/yd/csf/service/service/impl/CommissionServiceImpl.java
parents bcd2540e b81c107f
......@@ -398,13 +398,13 @@ public class ApiFortuneController {
}
/**
* 更新保单发佣(检核操作)
* 更新
*
* @param fortuneUpdateRequest
* @return
*/
@PostMapping("/update")
@Operation(summary = "更新保单发佣信息(检核操作)")
@Operation(summary = "更新")
public Result<Boolean> updateFortune(@RequestBody FortuneUpdateRequest fortuneUpdateRequest) {
if (fortuneUpdateRequest == null || fortuneUpdateRequest.getFortuneBizId() == null) {
return Result.fail(ErrorCode.PARAMS_ERROR.getCode(), "fortuneBizId不能为空");
......
......@@ -668,7 +668,7 @@ public class ApiExpectedFortuneServiceImpl implements ApiExpectedFortuneService
//原币种
updateObj.setOriginalCurrency(policyCurrency);
//原币种金额
BigDecimal ruleAmount = expectedFortune.getRuleAmount();
BigDecimal ruleAmount = expectedFortune.getRuleAmount().setScale(4, RoundingMode.HALF_UP);
updateObj.setOriginalAmount(ruleAmount);
//原币种 -> 港币汇率
updateObj.setOriginalToHkdRate(originalToHkdRate);
......@@ -676,22 +676,22 @@ public class ApiExpectedFortuneServiceImpl implements ApiExpectedFortuneService
updateObj.setRuleCurrency(policyCurrency);
//默认保单币种 -> 港币汇率
updateObj.setDefaultExchangeRate(originalToHkdRate);
//应发港币金额(估)(标准发佣金额 * 默认保单币种 -> 港币汇率)
//应发港币金额(估)(标准发佣金额 * 默认保单币种 -> 港币汇率);出的钱保留整数
BigDecimal hkdAmount = ruleAmount.multiply(originalToHkdRate);
updateObj.setHkdAmount(hkdAmount);
updateObj.setHkdAmount(hkdAmount.setScale(0, RoundingMode.HALF_UP));
//发放币种
updateObj.setPayoutCurrency(currency);
//发放币种金额
updateObj.setPayoutAmount(hkdAmount.multiply(hkdToPayoutRate));
//发放币种金额;出的钱保留整数
updateObj.setPayoutAmount(hkdAmount.multiply(hkdToPayoutRate).setScale(0, RoundingMode.HALF_UP));
//港币 -> 发放币种汇率
updateObj.setHkdToPayoutRate(hkdToPayoutRate);
//默认值
updateObj.setPaidRuleAmount(BigDecimal.ZERO);
updateObj.setUnpaidRuleAmount(ruleAmount);
updateObj.setUnpaidRuleAmountHkd(hkdAmount);
updateObj.setUnpaidRuleAmountHkd(hkdAmount.setScale(0, RoundingMode.HALF_UP));
updateObj.setPaidAmount(BigDecimal.ZERO);
updateObj.setPaidRatio(BigDecimal.ZERO);
updateObj.setUnpaidAmount(expectedFortune.getHkdAmount());
updateObj.setUnpaidAmount(hkdAmount.setScale(0, RoundingMode.HALF_UP));
updateObj.setUnpaidRatio(BigDecimal.valueOf(100));
}
......
......@@ -44,7 +44,7 @@ public class XxlJobConfig {
@Value("${xxl.job.executor.logretentiondays:30}")
private int logRetentionDays;
@Bean(initMethod = "start", destroyMethod = "destroy")
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
log.info(">>>>>>>>>>> xxl-job config init. adminAddresses={}, appname={}, ip={}, port={}",
adminAddresses, appname, StringUtils.defaultIfBlank(ip, "auto"), port);
......
......@@ -482,7 +482,8 @@ public class CommissionServiceImpl extends ServiceImpl<CommissionMapper, Commiss
// 查询入账币种到港币的汇率
BigDecimal exchangeRate = queryExchangeRateByFeign(currency, "HKD");
return requestAmount.multiply(exchangeRate);
// 来的钱(入账/来佣)保留2位小数
return requestAmount.multiply(exchangeRate).setScale(2, RoundingMode.HALF_UP);
}
private CommissionExpected getCommissionExpectedBizId(Commission commission) {
......@@ -811,19 +812,21 @@ public class CommissionServiceImpl extends ServiceImpl<CommissionMapper, Commiss
// 入账检核汇率 — 仅审计追溯,始终写入
fortune.setExchangeRate(exchangeRate);
// 判断 入账币种-fortune.currency 是否等于 HKD
// 判断来佣入账币种-Commission.currency 是否为 HKD
Commission matchedCommission = commissionByPolicyPeriod.get(key);
boolean isAllHkd = matchedCommission != null
&& "HKD".equalsIgnoreCase(matchedCommission.getCurrency());
if (isAllHkd) {
// 原币种 = HKD 时,exchangeRate = 保单币种 → 港币,可安全使用
// 入账币种 = HKD 时,exchangeRate = 保单币种 → 港币
fortune.setOriginalToHkdRate(exchangeRate);
BigDecimal hkdAmount = fortune.getRuleAmount().multiply(exchangeRate);
BigDecimal hkdAmount = fortune.getRuleAmount()
.multiply(exchangeRate).setScale(0, RoundingMode.HALF_UP);
fortune.setHkdAmount(hkdAmount);
fortune.setCurrentPaymentAmount(fortune.getRuleAmount());
fortune.setCurrentPaymentHkdAmount(hkdAmount);
BigDecimal payoutAmount = hkdAmount.multiply(expectedFortune.getHkdToPayoutRate());
BigDecimal payoutAmount = hkdAmount
.multiply(expectedFortune.getHkdToPayoutRate()).setScale(0, RoundingMode.HALF_UP);
fortune.setPayoutAmount(payoutAmount);
ExpectedFortune update = new ExpectedFortune();
......
......@@ -500,14 +500,16 @@ public class FortuneAccountServiceImpl extends ServiceImpl<FortuneAccountMapper,
BigDecimal paidRule = paidRuleMap.getOrDefault(ef.getExpectedFortuneBizId(), BigDecimal.ZERO);
BigDecimal unpaidRule = ef.getRuleAmount().subtract(paidRule);
// 剩余发放折合港币金额
BigDecimal unpaidRuleAmountHkd = unpaidRule.multiply(ef.getDefaultExchangeRate());
// 剩余发放折合港币金额;出的钱保留整数
BigDecimal unpaidRuleAmountHkd = unpaidRule.multiply(ef.getDefaultExchangeRate())
.setScale(0, RoundingMode.HALF_UP);
// 应发港币金额(估)
BigDecimal hkdAmount = hkdAmountMap.getOrDefault(ef.getExpectedFortuneBizId(), BigDecimal.ZERO);
BigDecimal expectedHKD = hkdAmount.add(unpaidRuleAmountHkd);
// 发放币种金额 = 港币 × 港币兑发放币种汇率
BigDecimal expectedPayout = expectedHKD.multiply(ef.getHkdToPayoutRate());
// 发放币种金额 = 港币 × 港币兑发放币种汇率;出的钱保留整数
BigDecimal expectedPayout = expectedHKD.multiply(ef.getHkdToPayoutRate())
.setScale(0, RoundingMode.HALF_UP);
// 累计出账港币金额
BigDecimal paid = paidMap.getOrDefault(ef.getExpectedFortuneBizId(), BigDecimal.ZERO);
......
......@@ -11,7 +11,6 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Joiner;
import com.yd.auth.core.dto.AuthUserDto;
import com.yd.auth.core.utils.SecurityUtil;
import com.yd.base.feign.client.exchangerate.ApiExchangeRateFeignClient;
import com.yd.common.enums.CommonEnum;
import com.yd.common.enums.ResultCode;
import com.yd.common.exception.BusinessException;
......@@ -70,10 +69,6 @@ public class FortuneServiceImpl extends ServiceImpl<FortuneMapper, Fortune>
@Resource
private ApiSysDictFeignClient apiSysDictFeignClient;
@Resource
private RedisUtil redisUtil;
@Resource
private ApiExchangeRateFeignClient apiExchangeRateFeignClient;
@Resource
private IAgentAccumulatedFycService iAgentAccumulatedFycService;
@Override
......@@ -254,117 +249,9 @@ public class FortuneServiceImpl extends ServiceImpl<FortuneMapper, Fortune>
// 检核人
fortune.setReconciliationOperator(currentLoginUser.getRealName());
// 如果传入了金额
if (currentPaymentHkdAmount != null && currentPaymentHkdAmount.compareTo(BigDecimal.ZERO) != 0) {
splitFortune(fortune, currentPaymentHkdAmount, expectedFortune, loginUserId, fortuneUpdateRequest);
} else {
// 如果未传入金额,全额发放,出账状态为已出帐
totalFortune(fortune, expectedFortune, loginUserId, fortuneUpdateRequest);
}
// 更新 expected_fortune 出账状态
expectedFortuneService.lambdaUpdate()
.set(ExpectedFortune::getStatus, fortuneUpdateRequest.getStatus())
.eq(ExpectedFortune::getId, expectedFortune.getId())
.update();
return true;
}
private void totalFortune(Fortune fortune, ExpectedFortune expectedFortune, String loginUserId, FortuneUpdateRequest fortuneUpdateRequest) {
AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
// 1. 更新fortune记录为全额发放状态
fortune.setCurrentPaymentHkdAmount(fortune.getHkdAmount());
fortune.setCurrentPaymentRatio(BigDecimal.valueOf(100));
fortune.setStatus(FortuneStatusEnum.CHECKED.getItemValue());
fortune.setReconciliationOperator(currentLoginUser.getRealName());
fortune.setUpdaterId(loginUserId);
fortune.setUpdateTime(new Date());
this.updateById(fortune);
}
/**
* 保单币种对预计来佣的结算币种的默认汇率
*
* @param policyCurrency 保单币种
* @param currency 预计来佣的结算币种
* @return 汇率
*/
private BigDecimal queryExchangeRateByFeign(String policyCurrency, String currency) {
if (policyCurrency.equalsIgnoreCase(currency)) {
return BigDecimal.ONE;
}
// 调用Feign客户端查询汇率
Result<BigDecimal> result = apiExchangeRateFeignClient.getExchangeRate(policyCurrency, currency, "");
if (result != null && result.getData() != null) {
return result.getData();
}
return BigDecimal.ONE;
}
/**
* 拆分发放(按本次发放金额拆)
*/
@Transactional(rollbackFor = Exception.class)
public void splitFortune(Fortune main, BigDecimal currentPaymentHkdAmount, ExpectedFortune expectedFortune, String loginUserId, FortuneUpdateRequest fortuneUpdateRequest) {
if (!main.getStatus().equals(FortuneStatusEnum.CAN_SEND.getItemValue()))
throw new BusinessException("只有可出账记录才能修改金额");
BigDecimal fullAmount = main.getHkdAmount();
if (currentPaymentHkdAmount.compareTo(main.getCurrentPaymentHkdAmount()) > 0)
throw new BusinessException("本次发放金额不能大于可出账金额");
// 获取当前登录用户的ID
AuthUserDto currentLoginUser = SecurityUtil.getCurrentLoginUser();
// 1. 更新主行 = 本次发放金额
main.setCurrentPaymentAmount(null);
main.setCurrentPaymentHkdAmount(currentPaymentHkdAmount);
main.setCurrentPaymentRatio(currentPaymentHkdAmount
.divide(expectedFortune.getHkdAmount(), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
main.setStatus(FortuneStatusEnum.CHECKED.getItemValue());
main.setReconciliationOperator(currentLoginUser.getRealName());
main.setUpdaterId(loginUserId);
main.setUpdateTime(new Date());
this.updateById(main);
// 2. 剩余金额生成新行
BigDecimal leftAmount = fullAmount.subtract(currentPaymentHkdAmount);
if (leftAmount.compareTo(BigDecimal.ZERO) > 0) {
Fortune part = new Fortune();
BeanUtils.copyProperties(main, part, "id", "fortuneBizId", "currentPaymentAmount", "status", "isPart", "payoutDate");
part.setFortuneBizId(RandomStringGenerator.generateBizId16(CommonEnum.UID_TYPE_FORTUNE.getCode()));
part.setCurrentPaymentAmount(null);
part.setCurrentPaymentHkdAmount(leftAmount);
part.setCurrentPaymentRatio(leftAmount
.divide(expectedFortune.getHkdAmount(), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)));
part.setStatus(FortuneStatusEnum.RESERVED.getItemValue());
part.setIsPart(1);
part.setPayoutDate(LocalDate.now().plusMonths(1)); // 次月
part.setReconciliationOperator(currentLoginUser.getRealName());
part.setCreatorId(loginUserId);
part.setCreateTime(new Date());
this.save(part);
}
}
private BigDecimal calculateExpectedFortunePaidAmount(ExpectedFortune expectedFortune) {
// 查询所有已出账的记录
List<Fortune> paidList = this.list(new QueryWrapper<Fortune>()
.eq("expected_fortune_biz_id", expectedFortune.getExpectedFortuneBizId())
.eq("fortune_period", expectedFortune.getFortunePeriod())
.eq("status", FortuneStatusEnum.CHECKED.getItemValue()));
// 计算已出账金额
return paidList.stream()
.map(Fortune::getCurrentPaymentHkdAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
@Override
public void downloadFortune(FortuneDownloadRequest fortuneDownloadRequest, HttpServletResponse response) throws IOException {
List<String> fortuneBizIdList = fortuneDownloadRequest.getFortuneBizIdList();
......@@ -963,30 +850,44 @@ public class FortuneServiceImpl extends ServiceImpl<FortuneMapper, Fortune>
}
List<FortuneSplitDto> splitList = fortuneSplitRequest.getFortuneSplitDtoList();
// 3. 金额验证
BigDecimal totalSplitOriginalAmount = splitList.stream()
.map(FortuneSplitDto::getOriginalAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal totalSplitRatio = splitList.stream()
.map(FortuneSplitDto::getSplitRatio)
// 分期出账按财务习惯的「原币种金额」originalAmount 守恒(其他接口仍以 ruleAmount 为锚,不在此改动)。
BigDecimal baseOriginalAmount = originalFortune.getOriginalAmount();
int lastIndex = splitList.size() - 1;
// 3. 原币种金额守恒:Σ各期 originalAmount 必须等于原记录 originalAmount。
// 各期金额由财务人工维护;总平不上时只给出末期找平金额,帮其通过校验。
BigDecimal totalOriginalAmount = splitList.stream()
.map(FortuneSplitDto::getOriginalAmount)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal tolerance = new BigDecimal("0.01");
BigDecimal originalDifference = originalFortune.getOriginalAmount().subtract(totalSplitOriginalAmount).abs();
if (originalDifference.compareTo(tolerance) > 0) {
throw new BusinessException(ResultCode.PARAM_CHECK_ERROR.getCode(),
String.format("分期原始金额总和(%s)与原记录原始金额(%s)不匹配", totalSplitOriginalAmount, originalFortune.getOriginalAmount()));
}
if (totalSplitRatio.compareTo(BigDecimal.ZERO) > 0) {
BigDecimal ratioDifference = new BigDecimal("100").subtract(totalSplitRatio).abs();
if (ratioDifference.compareTo(new BigDecimal("0.1")) > 0) {
throw new BusinessException(ResultCode.PARAM_CHECK_ERROR.getCode(),
String.format("分期比例总和(%s%%)应为100%%", totalSplitRatio));
if (totalOriginalAmount.compareTo(baseOriginalAmount) != 0) {
BigDecimal sumBeforeLast = BigDecimal.ZERO;
for (int i = 0; i < lastIndex; i++) {
if (splitList.get(i).getOriginalAmount() != null) {
sumBeforeLast = sumBeforeLast.add(splitList.get(i).getOriginalAmount());
}
}
// 末期找平金额 = 原记录原币种金额 - Σ前n-1期(精确到2位,填此值必能过校验)
BigDecimal lastLevelAmount = baseOriginalAmount.subtract(sumBeforeLast)
.setScale(2, RoundingMode.HALF_UP);
String tip = lastLevelAmount.signum() >= 0
? String.format("「原币种金额」不平:各期合计 %s,应等于 %s。请将最后一期(第%d期)的「原币种金额」改为 %s 后提交",
totalOriginalAmount, baseOriginalAmount, splitList.size(), lastLevelAmount.toPlainString())
: String.format("前%d期「原币种金额」合计 %s,已超过应发金额 %s,请调减前期金额后提交",
lastIndex, sumBeforeLast, baseOriginalAmount);
throw new BusinessException(ResultCode.PARAM_CHECK_ERROR.getCode(), tip);
}
// 4. 每期港币必须为非负整数(元)。各期汇率可能不同、港币可手改,港币合计不卡总额。
for (FortuneSplitDto dto : splitList) {
if (dto.getHkdAmount() == null || dto.getHkdAmount().signum() < 0
|| dto.getHkdAmount().stripTrailingZeros().scale() > 0) {
throw new BusinessException(ResultCode.PARAM_CHECK_ERROR.getCode(), "每期港币金额必须为非负整数(元)");
}
}
// 比例不再校验合计=100:金额由人工维护,比例仅作前端算金额的输入与记录参考;
// 若同时卡比例=100,会与金额守恒在舍入场景下互斥(如33.33×3金额合计差0.01),无法提交。
// 4. 生成新记录
List<Fortune> newFortuneList = new ArrayList<>();
......
......@@ -84,8 +84,20 @@
<if test="request.policyStatus != null and request.policyStatus != ''">
AND p.status = #{request.policyStatus}
</if>
<!-- 对账类型:表里 reconciliation_type 没数据,用 current_issue_number 判断 -->
<!-- SQ_BF_DZ=首期,current_issue_number=1;XQ_BF_DZ=续期,current_issue_number>1 -->
<if test="request.reconciliationType != null and request.reconciliationType != ''">
AND pr.reconciliation_type = #{request.reconciliationType}
<choose>
<when test="request.reconciliationType == 'SQ_BF_DZ'">
AND CAST(pr.current_issue_number AS UNSIGNED) = 1
</when>
<when test="request.reconciliationType == 'XQ_BF_DZ'">
AND CAST(pr.current_issue_number AS UNSIGNED) &gt; 1
</when>
<otherwise>
AND pr.reconciliation_type = #{request.reconciliationType}
</otherwise>
</choose>
</if>
<!-- 投保人查询:支持中文繁/简体和英文大小写 -->
<if test="request.policyHolderNameSc != null and request.policyHolderNameSc != ''
......@@ -121,4 +133,4 @@
</if>
ORDER BY pr.create_time DESC
</select>
</mapper>
\ No newline at end of file
</mapper>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment