Commit bd974d0b by zhangxingmin

push

parent 88b0ab3b
...@@ -745,126 +745,299 @@ public class ApiPremiumReconciliationServiceImpl implements ApiPremiumReconcilia ...@@ -745,126 +745,299 @@ public class ApiPremiumReconciliationServiceImpl implements ApiPremiumReconcilia
throw new BusinessException("保单币种不能为空"); throw new BusinessException("保单币种不能为空");
} }
//验证保单币种是否支持 - 通过Feign客户端调用 //获取当次认定币种和金额
Result<Boolean> currencySupportedResult = apiExchangeRateFeignClient.isCurrencySupportedResult(policyCurrency);
if (currencySupportedResult.getCode() != 200 || Boolean.FALSE.equals(currencySupportedResult.getData())) {
throw new BusinessException("保单币种不支持: " + policyCurrency);
}
//将当次保司认定金额转换为保单币种的金额
String recognizedCurrency = request.getRecognizedCurrency(); String recognizedCurrency = request.getRecognizedCurrency();
if (StringUtils.isBlank(recognizedCurrency)) { if (StringUtils.isBlank(recognizedCurrency)) {
throw new BusinessException("当次保司认定币种不能为空"); throw new BusinessException("当次保司认定币种不能为空");
} }
//验证认定币种是否支持 - 通过Feign客户端调用
Result<Boolean> recognizedCurrencySupportedResult = apiExchangeRateFeignClient.isCurrencySupportedResult(recognizedCurrency);
if (recognizedCurrencySupportedResult.getCode() != 200 || Boolean.FALSE.equals(recognizedCurrencySupportedResult.getData())) {
throw new BusinessException("认定币种不支持: " + recognizedCurrency);
}
//转换当次保司认定金额到保单币种的金额 - 通过Feign客户端调用
BigDecimal currentRecognizedAmount = request.getRecognizedAmount(); BigDecimal currentRecognizedAmount = request.getRecognizedAmount();
BigDecimal currentRecognizedAmountInPolicyCurrency; if (currentRecognizedAmount == null) {
throw new BusinessException("当次保司认定金额不能为空");
if (recognizedCurrency.equalsIgnoreCase(policyCurrency)) { }
// 币种相同,直接使用原金额
currentRecognizedAmountInPolicyCurrency = currentRecognizedAmount;
} else {
// 币种不相同,调用汇率服务进行转换
ApiExchangeRateConvertRequest convertRequest = new ApiExchangeRateConvertRequest();
//被转换金额
convertRequest.setAmount(currentRecognizedAmount);
//被转换币种
convertRequest.setFromCurrency(recognizedCurrency);
//转换币种
convertRequest.setToCurrency(policyCurrency);
// 可以根据需要设置交易日期或汇率日期,这里null查询最新汇率日期的汇率转换
convertRequest.setTransactionDate(null);
// convertRequest.setTransactionDate(request.getTransactionDate());
Result<ApiExchangeRateConvertResponse> convertResult = apiExchangeRateFeignClient.convert(convertRequest);
if (convertResult.getCode() != 200) {
throw new BusinessException("币种转换失败: " + convertResult.getMsg());
}
currentRecognizedAmountInPolicyCurrency = convertResult.getData().getConvertedAmount(); log.info("计算待付金额 - 保单号: {}, 保单币种: {}, 认定币种: {}, 认定金额: {}",
premiumReconciliation.getPolicyNo(), policyCurrency, recognizedCurrency, currentRecognizedAmount);
//==============================================
// 优化后的汇率转换逻辑 - 与page方法保持一致
//==============================================
// 构建转换请求列表(与其他对账记录一起批量转换)
List<ApiExchangeRateConvertRequest> convertRequests = new ArrayList<>();
List<ConvertInfo> convertInfoList = new ArrayList<>();
// 1. 首先处理当前认定金额的转换
if (!recognizedCurrency.equalsIgnoreCase(policyCurrency)) {
ApiExchangeRateConvertRequest currentConvertRequest = new ApiExchangeRateConvertRequest();
currentConvertRequest.setAmount(currentRecognizedAmount);
currentConvertRequest.setFromCurrency(recognizedCurrency);
currentConvertRequest.setToCurrency(policyCurrency);
currentConvertRequest.setRequestId("current_" + request.getPremiumReconciliationBizId());
ConvertInfo currentInfo = new ConvertInfo();
currentInfo.reconciliationBizId = request.getPremiumReconciliationBizId();
currentInfo.originalAmount = currentRecognizedAmount;
currentInfo.originalCurrency = recognizedCurrency;
currentInfo.targetCurrency = policyCurrency;
currentInfo.requestId = currentConvertRequest.getRequestId();
convertRequests.add(currentConvertRequest);
convertInfoList.add(currentInfo);
log.info("添加当前认定金额转换请求: {} {} -> {}, requestId: {}",
currentRecognizedAmount, recognizedCurrency, policyCurrency, currentConvertRequest.getRequestId());
} }
//根据当前期数和保单号,查询非当前保费对账记录的保司认定金额之和 // 2. 获取其他对账记录需要转换的金额
List<PremiumReconciliation> premiumReconciliationList = iPremiumReconciliationService.queryList(PremiumReconciliationDto.builder() List<PremiumReconciliation> premiumReconciliationList = iPremiumReconciliationService.queryList(PremiumReconciliationDto.builder()
.premiumReconciliationBizId(request.getPremiumReconciliationBizId()) .premiumReconciliationBizId(request.getPremiumReconciliationBizId())
.policyNo(premiumReconciliation.getPolicyNo())
.currentIssueNumber(premiumReconciliation.getCurrentIssueNumber()) .currentIssueNumber(premiumReconciliation.getCurrentIssueNumber())
.isExcludeMy(true) .isExcludeMy(true)
.build()); .build());
//计算非当前保费对账记录的保司认定金额之和(转换为保单币种) if (!CollectionUtils.isEmpty(premiumReconciliationList)) {
BigDecimal otherRecognizedAmountSumInPolicyCurrency = BigDecimal.ZERO; log.info("找到 {} 条其他对账记录需要处理", premiumReconciliationList.size());
for (int i = 0; i < premiumReconciliationList.size(); i++) {
PremiumReconciliation pr = premiumReconciliationList.get(i);
if (pr.getRecognizedAmount() != null && StringUtils.isNotBlank(pr.getRecognizedCurrency())) {
String otherCurrency = pr.getRecognizedCurrency();
BigDecimal otherAmount = pr.getRecognizedAmount();
if (!otherCurrency.equalsIgnoreCase(policyCurrency)) {
// 需要汇率转换
ApiExchangeRateConvertRequest otherConvertRequest = new ApiExchangeRateConvertRequest();
otherConvertRequest.setAmount(otherAmount);
otherConvertRequest.setFromCurrency(otherCurrency);
otherConvertRequest.setToCurrency(policyCurrency);
otherConvertRequest.setRequestId("other_" + pr.getPremiumReconciliationBizId());
ConvertInfo otherInfo = new ConvertInfo();
otherInfo.reconciliationBizId = request.getPremiumReconciliationBizId(); // 注意:这里使用当前对账ID,用于累加
otherInfo.originalAmount = otherAmount;
otherInfo.originalCurrency = otherCurrency;
otherInfo.targetCurrency = policyCurrency;
otherInfo.requestId = otherConvertRequest.getRequestId();
convertRequests.add(otherConvertRequest);
convertInfoList.add(otherInfo);
log.info("添加其他记录转换请求[{}]: {} {} -> {}, requestId: {}",
i, otherAmount, otherCurrency, policyCurrency, otherConvertRequest.getRequestId());
}
}
}
}
// 3. 执行汇率转换
BigDecimal totalRecognizedAmountInPolicyCurrency = BigDecimal.ZERO;
// 先累加币种相同的金额
// 当前认定金额(如果币种相同)
if (recognizedCurrency.equalsIgnoreCase(policyCurrency)) {
totalRecognizedAmountInPolicyCurrency = totalRecognizedAmountInPolicyCurrency.add(currentRecognizedAmount);
log.info("当前认定金额币种相同,直接累加: {}", currentRecognizedAmount);
}
// 其他记录的币种相同金额
if (!CollectionUtils.isEmpty(premiumReconciliationList)) {
for (PremiumReconciliation pr : premiumReconciliationList) {
if (pr.getRecognizedAmount() != null && StringUtils.isNotBlank(pr.getRecognizedCurrency())) {
if (pr.getRecognizedCurrency().equalsIgnoreCase(policyCurrency)) {
totalRecognizedAmountInPolicyCurrency = totalRecognizedAmountInPolicyCurrency.add(pr.getRecognizedAmount());
log.info("其他记录[{}]币种相同,直接累加: {}", pr.getPremiumReconciliationBizId(), pr.getRecognizedAmount());
}
}
}
}
// 4. 批量转换需要转换的金额
if (!CollectionUtils.isEmpty(convertRequests)) {
try {
log.info("开始批量汇率转换,共 {} 条请求", convertRequests.size());
Result<List<ApiExchangeRateConvertResponse>> batchResult =
apiExchangeRateFeignClient.batchConvert(convertRequests);
if (batchResult != null && batchResult.getCode() == 200 &&
!CollectionUtils.isEmpty(batchResult.getData())) {
List<ApiExchangeRateConvertResponse> responses = batchResult.getData();
log.info("汇率转换返回 {} 条结果", responses.size());
// 匹配转换结果
for (ApiExchangeRateConvertResponse convertResponse : responses) {
if (convertResponse.getConvertedAmount() != null) {
// 查找匹配的ConvertInfo
ConvertInfo matchedInfo = null;
// 先尝试通过requestId匹配
if (StringUtils.isNotBlank(convertResponse.getRequestId())) {
for (ConvertInfo info : convertInfoList) {
if (convertResponse.getRequestId().equals(info.requestId)) {
matchedInfo = info;
break;
}
}
}
// 如果通过requestId没有匹配到,尝试通过金额和币种匹配
if (matchedInfo == null) {
for (ConvertInfo info : convertInfoList) {
if (convertResponse.getOriginalAmount() != null &&
convertResponse.getOriginalAmount().compareTo(info.originalAmount) == 0 &&
convertResponse.getOriginalCurrency().equalsIgnoreCase(info.originalCurrency) &&
convertResponse.getTargetCurrency().equalsIgnoreCase(info.targetCurrency)) {
matchedInfo = info;
break;
}
}
}
if (matchedInfo != null) {
BigDecimal convertedAmount = convertResponse.getConvertedAmount()
.setScale(2, RoundingMode.HALF_EVEN);
totalRecognizedAmountInPolicyCurrency = totalRecognizedAmountInPolicyCurrency.add(convertedAmount);
log.info("汇率转换成功: {} {} -> {} {}, 汇率: {}, 转换后金额: {}",
convertResponse.getOriginalAmount(), convertResponse.getOriginalCurrency(),
convertedAmount, convertResponse.getTargetCurrency(),
convertResponse.getExchangeRate(), convertedAmount);
} else {
log.warn("无法匹配转换结果: requestId={}, 原金额={} {}, 目标币种={}",
convertResponse.getRequestId(), convertResponse.getOriginalAmount(),
convertResponse.getOriginalCurrency(), convertResponse.getTargetCurrency());
}
}
}
} else {
log.error("批量汇率转换失败: code={}, msg={}",
batchResult != null ? batchResult.getCode() : "null",
batchResult != null ? batchResult.getMsg() : "null");
// 如果汇率转换失败,可以尝试使用单个转换作为备选方案
return fallbackSingleConvert(request, premiumReconciliation, policy, policyCurrency,
recognizedCurrency, currentRecognizedAmount, premiumReconciliationList);
}
} catch (Exception e) {
log.error("批量汇率转换异常", e);
// 异常情况下的备选方案
return fallbackSingleConvert(request, premiumReconciliation, policy, policyCurrency,
recognizedCurrency, currentRecognizedAmount, premiumReconciliationList);
}
}
// 5. 计算总保费和剩余待付金额
BigDecimal paymentPremium = policy.getPaymentPremium() != null ?
policy.getPaymentPremium() : BigDecimal.ZERO;
BigDecimal policyLevy = BigDecimal.ZERO;
if (StringUtils.isNotBlank(policy.getPolicyLevy())) {
try {
policyLevy = new BigDecimal(policy.getPolicyLevy().trim());
} catch (NumberFormatException e) {
log.error("保单征费格式错误: {}", policy.getPolicyLevy(), e);
}
}
BigDecimal totalPremium = paymentPremium.add(policyLevy);
BigDecimal remainingUnpaidAmount = totalPremium.subtract(totalRecognizedAmountInPolicyCurrency);
// 设置精度
remainingUnpaidAmount = remainingUnpaidAmount.setScale(2, RoundingMode.HALF_EVEN);
log.info("计算结果 - 总保费: {}, 总认定金额: {}, 剩余待付金额: {}",
totalPremium, totalRecognizedAmountInPolicyCurrency, remainingUnpaidAmount);
//构建响应对象
ApiCalculateRemainingUnpaidAmountResponse response = new ApiCalculateRemainingUnpaidAmountResponse();
response.setRemainingUnpaidAmount(remainingUnpaidAmount);
response.setRemainingUnpaidCurrency(policyCurrency);
return Result.success(response);
}
/**
* 备选方案:使用单次汇率转换
*/
private Result<ApiCalculateRemainingUnpaidAmountResponse> fallbackSingleConvert(
ApiCalculateRemainingUnpaidAmountRequest request,
PremiumReconciliation premiumReconciliation,
Policy policy,
String policyCurrency,
String recognizedCurrency,
BigDecimal currentRecognizedAmount,
List<PremiumReconciliation> premiumReconciliationList) {
log.info("使用备选方案:单次汇率转换");
BigDecimal totalRecognizedAmountInPolicyCurrency = BigDecimal.ZERO;
// 1. 转换当前认定金额
BigDecimal currentConvertedAmount;
if (recognizedCurrency.equalsIgnoreCase(policyCurrency)) {
currentConvertedAmount = currentRecognizedAmount;
} else {
ApiExchangeRateConvertRequest currentRequest = new ApiExchangeRateConvertRequest();
currentRequest.setAmount(currentRecognizedAmount);
currentRequest.setFromCurrency(recognizedCurrency);
currentRequest.setToCurrency(policyCurrency);
Result<ApiExchangeRateConvertResponse> currentResult = apiExchangeRateFeignClient.convert(currentRequest);
if (currentResult.getCode() != 200 || currentResult.getData() == null) {
throw new BusinessException("当前认定金额汇率转换失败: " + currentResult.getMsg());
}
currentConvertedAmount = currentResult.getData().getConvertedAmount();
}
totalRecognizedAmountInPolicyCurrency = totalRecognizedAmountInPolicyCurrency.add(currentConvertedAmount);
// 2. 转换其他记录认定金额
if (!CollectionUtils.isEmpty(premiumReconciliationList)) { if (!CollectionUtils.isEmpty(premiumReconciliationList)) {
for (PremiumReconciliation pr : premiumReconciliationList) { for (PremiumReconciliation pr : premiumReconciliationList) {
if (pr.getRecognizedAmount() != null && StringUtils.isNotBlank(pr.getRecognizedCurrency())) { if (pr.getRecognizedAmount() != null && StringUtils.isNotBlank(pr.getRecognizedCurrency())) {
//将每条记录的认定金额转换为保单币种 BigDecimal otherConvertedAmount;
BigDecimal convertedAmount;
if (pr.getRecognizedCurrency().equalsIgnoreCase(policyCurrency)) { if (pr.getRecognizedCurrency().equalsIgnoreCase(policyCurrency)) {
// 币种相同,直接使用 otherConvertedAmount = pr.getRecognizedAmount();
convertedAmount = pr.getRecognizedAmount();
} else { } else {
// 调用汇率服务进行转换 ApiExchangeRateConvertRequest otherRequest = new ApiExchangeRateConvertRequest();
ApiExchangeRateConvertRequest prConvertRequest = new ApiExchangeRateConvertRequest(); otherRequest.setAmount(pr.getRecognizedAmount());
prConvertRequest.setAmount(pr.getRecognizedAmount()); otherRequest.setFromCurrency(pr.getRecognizedCurrency());
prConvertRequest.setFromCurrency(pr.getRecognizedCurrency()); otherRequest.setToCurrency(policyCurrency);
prConvertRequest.setToCurrency(policyCurrency);
Result<ApiExchangeRateConvertResponse> otherResult = apiExchangeRateFeignClient.convert(otherRequest);
Result<ApiExchangeRateConvertResponse> prConvertResult = apiExchangeRateFeignClient.convert(prConvertRequest); if (otherResult.getCode() == 200 && otherResult.getData() != null) {
if (prConvertResult.getCode() != 200) { otherConvertedAmount = otherResult.getData().getConvertedAmount();
log.warn("保费对账记录币种转换失败,记录ID: {}, 原因: {}", } else {
pr.getPremiumReconciliationBizId(), prConvertResult.getMsg()); log.warn("其他记录汇率转换失败,跳过: {}", pr.getPremiumReconciliationBizId());
continue; // 跳过转换失败的记录 continue;
} }
convertedAmount = prConvertResult.getData().getConvertedAmount();
} }
otherRecognizedAmountSumInPolicyCurrency = otherRecognizedAmountSumInPolicyCurrency.add(convertedAmount); totalRecognizedAmountInPolicyCurrency = totalRecognizedAmountInPolicyCurrency.add(otherConvertedAmount);
} }
} }
} }
//计算总认定金额(保单币种) // 3. 计算剩余待付金额
BigDecimal totalRecognizedAmountInPolicyCurrency =
otherRecognizedAmountSumInPolicyCurrency.add(currentRecognizedAmountInPolicyCurrency);
//获取期交保费(如果为空则设为0)
BigDecimal paymentPremium = policy.getPaymentPremium() != null ? BigDecimal paymentPremium = policy.getPaymentPremium() != null ?
policy.getPaymentPremium() : BigDecimal.ZERO; policy.getPaymentPremium() : BigDecimal.ZERO;
//获取保单征费(转换为BigDecimal)
BigDecimal policyLevy = BigDecimal.ZERO; BigDecimal policyLevy = BigDecimal.ZERO;
if (StringUtils.isNotBlank(policy.getPolicyLevy())) { if (StringUtils.isNotBlank(policy.getPolicyLevy())) {
try { try {
// 注意:保单征费的币种应该与保单币种一致,但这里可以再次确认 policyLevy = new BigDecimal(policy.getPolicyLevy().trim());
String policyLevyStr = policy.getPolicyLevy().trim();
// 如果保单征费包含币种信息,需要解析,这里假设是纯数字字符串
policyLevy = new BigDecimal(policyLevyStr);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
log.error("保单征费格式错误,policyLevy: {}", policy.getPolicyLevy()); log.error("保单征费格式错误", e);
throw new BusinessException("保单征费格式错误,无法计算");
} }
} }
//计算总额和剩余待付金额(均为保单币种)
BigDecimal totalPremium = paymentPremium.add(policyLevy); BigDecimal totalPremium = paymentPremium.add(policyLevy);
BigDecimal remainingUnpaidAmount = totalPremium.subtract(totalRecognizedAmountInPolicyCurrency); BigDecimal remainingUnpaidAmount = totalPremium.subtract(totalRecognizedAmountInPolicyCurrency);
//如果剩余待付金额为负数,说明已超额支付,可以设为0或负数,根据业务需求
// 如果要求不能为负数,则取最大值
// remainingUnpaidAmount = remainingUnpaidAmount.max(BigDecimal.ZERO);
// 设置精度,保留2位小数,银行家舍入法
remainingUnpaidAmount = remainingUnpaidAmount.setScale(2, RoundingMode.HALF_EVEN); remainingUnpaidAmount = remainingUnpaidAmount.setScale(2, RoundingMode.HALF_EVEN);
//构建响应对象
ApiCalculateRemainingUnpaidAmountResponse response = new ApiCalculateRemainingUnpaidAmountResponse(); ApiCalculateRemainingUnpaidAmountResponse response = new ApiCalculateRemainingUnpaidAmountResponse();
response.setRemainingUnpaidAmount(remainingUnpaidAmount); response.setRemainingUnpaidAmount(remainingUnpaidAmount);
response.setRemainingUnpaidCurrency(policyCurrency); response.setRemainingUnpaidCurrency(policyCurrency);
......
package com.yd.csf.service.dto; package com.yd.csf.service.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
...@@ -12,6 +13,11 @@ import lombok.NoArgsConstructor; ...@@ -12,6 +13,11 @@ import lombok.NoArgsConstructor;
public class PremiumReconciliationDto { public class PremiumReconciliationDto {
/** /**
* 保单号
*/
private String policyNo;
/**
* 保费对账记录表唯一业务ID * 保费对账记录表唯一业务ID
*/ */
private String premiumReconciliationBizId; private String premiumReconciliationBizId;
......
...@@ -44,6 +44,7 @@ public class PremiumReconciliationServiceImpl extends ServiceImpl<PremiumReconci ...@@ -44,6 +44,7 @@ public class PremiumReconciliationServiceImpl extends ServiceImpl<PremiumReconci
List<PremiumReconciliation> list = baseMapper.selectList(new LambdaQueryWrapper<PremiumReconciliation>() List<PremiumReconciliation> list = baseMapper.selectList(new LambdaQueryWrapper<PremiumReconciliation>()
.eq(StringUtils.isNotBlank(dto.getPremiumReconciliationBizId()) && !dto.getIsExcludeMy(),PremiumReconciliation::getPremiumReconciliationBizId,dto.getPremiumReconciliationBizId()) .eq(StringUtils.isNotBlank(dto.getPremiumReconciliationBizId()) && !dto.getIsExcludeMy(),PremiumReconciliation::getPremiumReconciliationBizId,dto.getPremiumReconciliationBizId())
.eq(StringUtils.isNotBlank(dto.getCurrentIssueNumber()),PremiumReconciliation::getCurrentIssueNumber,dto.getCurrentIssueNumber()) .eq(StringUtils.isNotBlank(dto.getCurrentIssueNumber()),PremiumReconciliation::getCurrentIssueNumber,dto.getCurrentIssueNumber())
.eq(StringUtils.isNotBlank(dto.getPolicyNo()),PremiumReconciliation::getPolicyNo,dto.getPolicyNo())
.ne(dto.getIsExcludeMy(),PremiumReconciliation::getPremiumReconciliationBizId,dto.getPremiumReconciliationBizId()) .ne(dto.getIsExcludeMy(),PremiumReconciliation::getPremiumReconciliationBizId,dto.getPremiumReconciliationBizId())
); );
return list; return list;
......
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