bugfix balance refund duplicate risk

This commit is contained in:
Guoqs
2026-06-17 09:15:44 +08:00
parent 44f18acb6b
commit e3ba0641b7
6 changed files with 272 additions and 14 deletions

View File

@@ -0,0 +1,103 @@
# Plan: 余额支付退款重复退款优化
## 背景
余额支付订单退款当前允许同一订单产生多条钱包进账流水,这是合理的:客户投诉、人工补退、重算补退等场景都可能需要追加退款。
本次优化不采用“一单只能插一次”的唯一约束,而是改为累计金额控制:
- 同一订单余额退款可以多次发生。
- 累计退款金额不能超过该订单余额支付金额。
- 自动结算重复执行时,只能退到订单当前目标退款金额,不能重复按全量退款。
- 钱包余额更新失败时,不能继续插入钱包流水。
## 风险点
### 风险 1余额退款按全量重算
`balancePaymentOrderRefund``balancePaymentOrderRefundV2` 当前会按订单支付记录与消费金额重新计算本次退款金额。
如果同一订单已经存在部分退款流水,再次执行时没有按“目标退款金额 - 已退金额”计算差额,存在重复退款风险。
### 风险 2钱包更新失败后仍可能插流水
`MemberBasicInfoServiceImpl.updateMemberBalance` 使用 `version` 更新钱包余额,但当更新返回 `0` 时只打印日志,后续仍可能插入 `member_wallet_log`
这会造成余额与流水不一致,也会影响后续已退款金额判断。
### 风险 3balancePaymentOrderRefundV2 无幂等校验
`OrderBasicInfoServiceImpl.balancePaymentOrderRefundV2` 没有已退金额校验,也没有累计退款上限。
重复调用时可能持续向会员钱包退款。
## 优化原则
1. 不限制同一订单只能插入一条退款流水。
2. 同一订单累计余额退款总额不能超过余额支付总额。
3. 自动结算退款以 `order_basic_info.refund_amount` 作为当前目标退款金额;如果需要客户投诉补退,应先把目标退款金额调整到新的业务目标,且不能超过支付总额。
4. 本金与赠送金分别受各自支付金额上限约束。
5. 钱包余额更新与钱包流水必须保持事务一致。
## 子任务
### BR-001
- 优先级P0
- 状态done
- 目标:补 `balancePaymentOrderRefundV2` 累计退款上限与差额退款。
- 设计:
- 查询订单已退本金、已退赠送金。
- 订单目标退款金额取 `min(order.refundAmount, balancePayTotal)`
- 本次退款金额取 `目标退款金额 - 已退总额` 范围内的金额。
- 本金累计退款不能超过本金支付金额,赠送金累计退款不能超过赠送金支付金额。
- 验收:
- 同一订单重复调用 V2不会超过当前目标退款金额。
- 如果目标退款金额被业务调整变大,可以继续补退,但累计不超过余额支付总额。
### BR-002
- 优先级P1
- 状态done
- 目标:统一新旧余额退款逻辑。
- 设计:
-`OrderBasicInfoService` 提供统一的余额退款额度裁剪方法。
- `DelayMerchantProgramLogic.balancePaymentOrderRefund``NotDelayMerchantProgramLogic.balancePaymentOrderRefund``OrderBasicInfoServiceImpl.balancePaymentOrderRefundV2` 都复用同一套累计上限判断。
- 验收:
- 三条余额支付退款路径的已退金额口径一致。
### BR-003
- 优先级P2
- 状态done
- 目标:修复钱包更新事务一致性。
- 设计:
- `updateMemberBalance` 增加事务。
- `memberBasicInfoMapper.updateMemberBalance(...)` 返回 `0` 时抛异常。
- 钱包余额更新失败时不插入 `member_wallet_log`
- 验收:
- 乐观锁失败时不会产生钱包流水。
### BR-004
- 优先级P3
- 状态done
- 目标:补充验证。
- 设计:
- 编译受影响模块。
- 对重复调用、目标退款金额调整、钱包乐观锁失败做回归验证。
- 验收:
- 编译通过,关键路径验证结果记录到本文档。
- 当前进展:
- 使用 JDK 8 执行 `mvn -pl jsowell-pile -am compile -DskipTests` 通过。
- 当前默认 JDK 21 执行 Maven 会在 `jsowell-common` 编译阶段触发老 Lombok/javac 兼容性错误,未进入本次改动编译。
## 执行日志
- 2026-06-15创建优化方案文档开始执行 BR-001。
- 2026-06-15BR-001 已完成,`balancePaymentOrderRefundV2` 接入累计退款额度裁剪。
- 2026-06-15开始执行 BR-002统一新旧余额退款路径的累计校验口径。
- 2026-06-15BR-002 已完成,延迟、非延迟和 V2 余额退款路径复用同一套额度裁剪逻辑。
- 2026-06-15BR-003 已完成,`updateMemberBalance` 增加事务,钱包余额更新失败时抛异常并阻止插入流水。
- 2026-06-15开始执行 BR-004进行编译检查。
- 2026-06-15BR-004 已完成JDK 8 环境下受影响模块编译通过。

View File

@@ -482,6 +482,13 @@ public interface OrderBasicInfoService{
*/ */
BigDecimal getOrderRefundedAmount(String orderCode); BigDecimal getOrderRefundedAmount(String orderCode);
/**
* 计算余额支付订单本次允许退款金额
*/
Map<String, BigDecimal> calculateAllowableBalanceRefund(String orderCode, BigDecimal refundAmount,
BigDecimal principalPay, BigDecimal giftPay,
BigDecimal returnPrincipal, BigDecimal returnGift);
/** /**
* 通过orderCode获取退款明细列表 * 通过orderCode获取退款明细列表
* @param orderCode * @param orderCode

View File

@@ -35,6 +35,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.*; import java.util.*;
@@ -213,6 +214,7 @@ public class MemberBasicInfoServiceImpl implements MemberBasicInfoService {
* 接收的金额都是正数,通过操作类型判断 充值还是扣减 * 接收的金额都是正数,通过操作类型判断 充值还是扣减
*/ */
@Override @Override
@Transactional(rollbackFor = Exception.class)
public int updateMemberBalance(UpdateMemberBalanceDTO dto) { public int updateMemberBalance(UpdateMemberBalanceDTO dto) {
String memberId = dto.getMemberId(); // 会员id String memberId = dto.getMemberId(); // 会员id
BigDecimal updateGiftBalance = dto.getUpdateGiftBalance() != null ? dto.getUpdateGiftBalance() : BigDecimal.ZERO; // 更新赠送金额 BigDecimal updateGiftBalance = dto.getUpdateGiftBalance() != null ? dto.getUpdateGiftBalance() : BigDecimal.ZERO; // 更新赠送金额
@@ -412,6 +414,7 @@ public class MemberBasicInfoServiceImpl implements MemberBasicInfoService {
i = memberBasicInfoMapper.updateMemberBalance(memberId, walletCode, newPrincipalBalance, newGiftBalance, walletInfo.getVersion()); i = memberBasicInfoMapper.updateMemberBalance(memberId, walletCode, newPrincipalBalance, newGiftBalance, walletInfo.getVersion());
if (i == 0) { if (i == 0) {
log.info("修改用户余额-修改余额失败, memberId:{}", memberId); log.info("修改用户余额-修改余额失败, memberId:{}", memberId);
throw new BusinessException("", "修改用户余额失败,请重试");
} }
} }
// 插入 member_wallet_log 表 // 插入 member_wallet_log 表

View File

@@ -1584,32 +1584,55 @@ public class OrderBasicInfoServiceImpl implements OrderBasicInfoService {
public void balancePaymentOrderRefundV2(OrderBasicInfo orderBasicInfo) { public void balancePaymentOrderRefundV2(OrderBasicInfo orderBasicInfo) {
// 订单编号 // 订单编号
String orderCode = orderBasicInfo.getOrderCode(); String orderCode = orderBasicInfo.getOrderCode();
BigDecimal refundAmount = orderBasicInfo.getRefundAmount();
if (refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) {
logger.info("balancePaymentOrderRefundV2-退款金额小于等于0orderCode:{}, 退款金额:{}", orderCode, refundAmount);
return;
}
// 订单消费金额 // 订单消费金额
BigDecimal orderAmount = orderBasicInfo.getOrderAmount(); BigDecimal orderAmount = orderBasicInfo.getOrderAmount() == null ? BigDecimal.ZERO : orderBasicInfo.getOrderAmount();
// 查支付记录 // 查支付记录
List<OrderPayRecord> payRecordList = orderPayRecordService.getOrderPayRecordList(orderCode); List<OrderPayRecord> payRecordList = orderPayRecordService.getOrderPayRecordList(orderCode);
if (CollectionUtils.isEmpty(payRecordList)) {
logger.info("balancePaymentOrderRefundV2-订单支付记录为空orderCode:{}", orderCode);
return;
}
// Map<String, OrderPayRecord> payRecordMap = payRecordList.stream() // Map<String, OrderPayRecord> payRecordMap = payRecordList.stream()
// .collect(Collectors.toMap(OrderPayRecord::getPayMode, Function.identity(), (k1, k2) -> k1)); // .collect(Collectors.toMap(OrderPayRecord::getPayMode, Function.identity(), (k1, k2) -> k1));
Map<String, List<OrderPayRecord>> payRecordMap = payRecordList.stream().collect(Collectors.groupingBy(OrderPayRecord::getPayMode)); Map<String, List<OrderPayRecord>> payRecordMap = payRecordList.stream().collect(Collectors.groupingBy(OrderPayRecord::getPayMode));
// 获取本金支付的记录 // 获取本金支付的记录
List<OrderPayRecord> orderPayRecordList = payRecordMap.get(Constants.ONE); List<OrderPayRecord> principalPayRecordList = payRecordMap.get(OrderPayRecordEnum.PRINCIPAL_BALANCE_PAYMENT.getValue());
BigDecimal principalPay = orderPayRecordList.stream().map(OrderPayRecord::getPayAmount).reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal principalPay = null;
if (CollectionUtils.isNotEmpty(principalPayRecordList)) {
principalPay = principalPayRecordList.stream().map(OrderPayRecord::getPayAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
}
// 取出本金支付金额 // 获取赠送金支付的记录
// BigDecimal principalPay = null; List<OrderPayRecord> giftPayRecordList = payRecordMap.get(OrderPayRecordEnum.GIFT_BALANCE_PAYMENT.getValue());
BigDecimal giftPay = null;
// if (principalPayRecord != null) { if (CollectionUtils.isNotEmpty(giftPayRecordList)) {
// principalPay = principalPayRecord.getPayAmount(); giftPay = giftPayRecordList.stream().map(OrderPayRecord::getPayAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
// } }
// 计算需要退回的金额 // 计算需要退回的金额
Map<String, BigDecimal> returnAmountMap = calculateReturnAmount(principalPay, null, orderAmount); Map<String, BigDecimal> returnAmountMap = calculateReturnAmount(principalPay, giftPay, orderAmount);
logger.info("结算订单:{}, 剩余金额退回余额, 订单消费金额:{}, 本金支付金额:{}, 赠送支付金额:{}, 退回金额map:{}", logger.info("结算订单:{}, 剩余金额退回余额, 订单消费金额:{}, 本金支付金额:{}, 赠送支付金额:{}, 退回金额map:{}",
orderCode, orderAmount, principalPay, null, JSON.toJSONString(returnAmountMap)); orderCode, orderAmount, principalPay, giftPay, JSON.toJSONString(returnAmountMap));
// 需要退回本金的金额 // 需要退回本金的金额
BigDecimal returnPrincipal = returnAmountMap.get("returnPrincipal"); BigDecimal returnPrincipal = returnAmountMap.get("returnPrincipal");
// 需要退回赠送金的金额
BigDecimal returnGift = returnAmountMap.get("returnGift");
Map<String, BigDecimal> allowableRefundMap = calculateAllowableBalanceRefund(orderCode, refundAmount,
principalPay, giftPay, returnPrincipal, returnGift);
returnPrincipal = allowableRefundMap.get("returnPrincipal");
returnGift = allowableRefundMap.get("returnGift");
if (returnPrincipal.compareTo(BigDecimal.ZERO) <= 0 && returnGift.compareTo(BigDecimal.ZERO) <= 0) {
logger.info("balancePaymentOrderRefundV2-订单:{}本次可退金额为0不执行退款", orderCode);
return;
}
// 更新会员钱包/余额退回到钱包 // 更新会员钱包/余额退回到钱包
UpdateMemberBalanceDTO updateMemberBalanceDTO = UpdateMemberBalanceDTO.builder() UpdateMemberBalanceDTO updateMemberBalanceDTO = UpdateMemberBalanceDTO.builder()
@@ -1617,6 +1640,7 @@ public class OrderBasicInfoServiceImpl implements OrderBasicInfoService {
.type(MemberWalletEnum.TYPE_IN.getValue()) // 进账 .type(MemberWalletEnum.TYPE_IN.getValue()) // 进账
.subType(MemberWalletEnum.SUBTYPE_ORDER_SETTLEMENT_REFUND.getValue()) // 订单结算退款 .subType(MemberWalletEnum.SUBTYPE_ORDER_SETTLEMENT_REFUND.getValue()) // 订单结算退款
.updatePrincipalBalance(returnPrincipal) .updatePrincipalBalance(returnPrincipal)
.updateGiftBalance(returnGift)
.relatedOrderCode(orderCode) .relatedOrderCode(orderCode)
.build(); .build();
memberBasicInfoService.updateMemberBalance(updateMemberBalanceDTO); memberBasicInfoService.updateMemberBalance(updateMemberBalanceDTO);
@@ -5618,6 +5642,102 @@ public class OrderBasicInfoServiceImpl implements OrderBasicInfoService {
return orderBasicInfoMapper.queryRepayOrder(memberId); return orderBasicInfoMapper.queryRepayOrder(memberId);
} }
/**
* 计算余额支付订单本次允许退款金额
*/
@Override
public Map<String, BigDecimal> calculateAllowableBalanceRefund(String orderCode, BigDecimal refundAmount,
BigDecimal principalPay, BigDecimal giftPay,
BigDecimal returnPrincipal, BigDecimal returnGift) {
Map<String, BigDecimal> resultMap = Maps.newHashMap();
resultMap.put("returnPrincipal", BigDecimal.ZERO);
resultMap.put("returnGift", BigDecimal.ZERO);
principalPay = positiveOrZero(principalPay);
giftPay = positiveOrZero(giftPay);
returnPrincipal = positiveOrZero(returnPrincipal);
returnGift = positiveOrZero(returnGift);
BigDecimal balancePayTotal = principalPay.add(giftPay);
BigDecimal targetRefundAmount = positiveOrZero(refundAmount);
if (StringUtils.isBlank(orderCode) || balancePayTotal.compareTo(BigDecimal.ZERO) <= 0
|| targetRefundAmount.compareTo(BigDecimal.ZERO) <= 0) {
logger.info("余额退款额度裁剪-参数不足orderCode:{}, 目标退款金额:{}, 余额支付总额:{}",
orderCode, targetRefundAmount, balancePayTotal);
return resultMap;
}
if (targetRefundAmount.compareTo(balancePayTotal) > 0) {
logger.info("余额退款额度裁剪-orderCode:{}, 目标退款金额:{}大于余额支付总额:{},按余额支付总额限制",
orderCode, targetRefundAmount, balancePayTotal);
targetRefundAmount = balancePayTotal;
}
Map<String, BigDecimal> refundedAmountMap = getBalanceRefundedAmountByCategory(orderCode);
BigDecimal refundedPrincipal = refundedAmountMap.get("refundedPrincipal");
BigDecimal refundedGift = refundedAmountMap.get("refundedGift");
BigDecimal refundedTotal = refundedPrincipal.add(refundedGift);
BigDecimal remainingTargetAmount = targetRefundAmount.subtract(refundedTotal);
if (remainingTargetAmount.compareTo(BigDecimal.ZERO) <= 0) {
logger.info("余额退款额度裁剪-orderCode:{}, 目标退款金额:{}, 已退总额:{},不再退款",
orderCode, targetRefundAmount, refundedTotal);
return resultMap;
}
BigDecimal remainingPrincipalPay = positiveOrZero(principalPay.subtract(refundedPrincipal));
BigDecimal remainingGiftPay = positiveOrZero(giftPay.subtract(refundedGift));
BigDecimal allowedPrincipal = min(returnPrincipal, remainingPrincipalPay, remainingTargetAmount);
remainingTargetAmount = remainingTargetAmount.subtract(allowedPrincipal);
BigDecimal allowedGift = min(returnGift, remainingGiftPay, remainingTargetAmount);
resultMap.put("returnPrincipal", allowedPrincipal);
resultMap.put("returnGift", allowedGift);
logger.info("余额退款额度裁剪-orderCode:{}, 目标退款金额:{}, 支付本金:{}, 支付赠送:{}, 已退本金:{}, 已退赠送:{}, 原计算本金:{}, 原计算赠送:{}, 本次本金:{}, 本次赠送:{}",
orderCode, targetRefundAmount, principalPay, giftPay, refundedPrincipal, refundedGift,
returnPrincipal, returnGift, allowedPrincipal, allowedGift);
return resultMap;
}
private Map<String, BigDecimal> getBalanceRefundedAmountByCategory(String orderCode) {
Map<String, BigDecimal> resultMap = Maps.newHashMap();
BigDecimal refundedPrincipal = BigDecimal.ZERO;
BigDecimal refundedGift = BigDecimal.ZERO;
List<MemberWalletLog> walletLogs = memberWalletLogService.getOrderRecord(orderCode, MemberWalletEnum.TYPE_IN.getValue());
if (CollectionUtils.isNotEmpty(walletLogs)) {
for (MemberWalletLog walletLog : walletLogs) {
String subType = walletLog.getSubType();
if (StringUtils.isNotBlank(subType)
&& !StringUtils.equals(subType, MemberWalletEnum.SUBTYPE_ORDER_SETTLEMENT_REFUND.getValue())) {
continue;
}
BigDecimal amount = walletLog.getAmount() == null ? BigDecimal.ZERO : walletLog.getAmount().abs();
if (StringUtils.equals(Constants.TWO, walletLog.getCategory())) {
refundedGift = refundedGift.add(amount);
} else {
refundedPrincipal = refundedPrincipal.add(amount);
}
}
}
resultMap.put("refundedPrincipal", refundedPrincipal);
resultMap.put("refundedGift", refundedGift);
return resultMap;
}
private BigDecimal positiveOrZero(BigDecimal amount) {
if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
return BigDecimal.ZERO;
}
return amount;
}
private BigDecimal min(BigDecimal first, BigDecimal second, BigDecimal third) {
return first.min(second).min(third);
}
/** /**
* 获取订单已退款金额 * 获取订单已退款金额
*/ */
@@ -6735,4 +6855,3 @@ public class OrderBasicInfoServiceImpl implements OrderBasicInfoService {
return total; return total;
} }
} }

View File

@@ -1076,6 +1076,7 @@ public class DelayMerchantProgramLogic extends AbstractProgramLogic {
} }
BigDecimal discountAmount = orderBasicInfo.getDiscountAmount() == null ? BigDecimal.ZERO : orderBasicInfo.getDiscountAmount(); BigDecimal discountAmount = orderBasicInfo.getDiscountAmount() == null ? BigDecimal.ZERO : orderBasicInfo.getDiscountAmount();
BigDecimal insuranceAmount = orderBasicInfo.getInsuranceAmount() == null ? BigDecimal.ZERO : orderBasicInfo.getInsuranceAmount();
// 计算需要退回的金额 // 计算需要退回的金额
Map<String, BigDecimal> returnAmountMap = calculateReturnAmount(principalPay, giftPay, orderAmount, discountAmount); Map<String, BigDecimal> returnAmountMap = calculateReturnAmount(principalPay, giftPay, orderAmount, discountAmount);
@@ -1102,14 +1103,14 @@ public class DelayMerchantProgramLogic extends AbstractProgramLogic {
.build(); .build();
// 判断消费金额,如果消费金额 - 折扣金额小于 1 元,则将保险费也进行退回 // 判断消费金额,如果消费金额 - 折扣金额小于 1 元,则将保险费也进行退回
if (orderBasicInfo.getOrderAmount().subtract(orderBasicInfo.getDiscountAmount()).compareTo(BigDecimal.ONE) < 0) { if (orderAmount.subtract(discountAmount).compareTo(BigDecimal.ONE) < 0) {
// 判断是否需要退保险费用 // 判断是否需要退保险费用
boolean checkResult = orderBasicInfoService.checkRefundInsuranceAmount(orderBasicInfo); boolean checkResult = orderBasicInfoService.checkRefundInsuranceAmount(orderBasicInfo);
if (checkResult) { if (checkResult) {
// 退保险, 使用 calculateBalanceRefund 重新计算完整的退款金额(电费退款+保险费退款) // 退保险, 使用 calculateBalanceRefund 重新计算完整的退款金额(电费退款+保险费退款)
// 注意:不能在 calculateReturnAmount 的基础上叠加保险费,因为 calculateReturnAmount 不感知保险费, // 注意:不能在 calculateReturnAmount 的基础上叠加保险费,因为 calculateReturnAmount 不感知保险费,
// 算出的退款金额中已包含保险费部分,叠加会导致保险费被重复退还 // 算出的退款金额中已包含保险费部分,叠加会导致保险费被重复退还
Map<String, BigDecimal> refundMap = calculateBalanceRefund(principalPay, giftPay, orderBasicInfo.getOrderAmount(), orderBasicInfo.getDiscountAmount(), orderBasicInfo.getInsuranceAmount()); Map<String, BigDecimal> refundMap = calculateBalanceRefund(principalPay, giftPay, orderAmount, discountAmount, insuranceAmount);
BigDecimal refundPrincipal = refundMap.get("returnPrincipal"); BigDecimal refundPrincipal = refundMap.get("returnPrincipal");
BigDecimal refundGift = refundMap.get("returnGift"); BigDecimal refundGift = refundMap.get("returnGift");
BigDecimal returnPrincipalForInsurance = refundMap.get("returnPrincipalForInsurance"); BigDecimal returnPrincipalForInsurance = refundMap.get("returnPrincipalForInsurance");
@@ -1121,6 +1122,16 @@ public class DelayMerchantProgramLogic extends AbstractProgramLogic {
updateMemberBalanceDTO.setUpdateGiftBalance(refundGift.add(returnGiftForInsurance)); updateMemberBalanceDTO.setUpdateGiftBalance(refundGift.add(returnGiftForInsurance));
} }
} }
Map<String, BigDecimal> allowableRefundMap = orderBasicInfoService.calculateAllowableBalanceRefund(orderCode, refundAmount,
principalPay, giftPay, updateMemberBalanceDTO.getUpdatePrincipalBalance(), updateMemberBalanceDTO.getUpdateGiftBalance());
updateMemberBalanceDTO.setUpdatePrincipalBalance(allowableRefundMap.get("returnPrincipal"));
updateMemberBalanceDTO.setUpdateGiftBalance(allowableRefundMap.get("returnGift"));
if (updateMemberBalanceDTO.getUpdatePrincipalBalance().compareTo(BigDecimal.ZERO) <= 0
&& updateMemberBalanceDTO.getUpdateGiftBalance().compareTo(BigDecimal.ZERO) <= 0) {
logger.info("balancePaymentOrderRefund-订单:{}本次可退金额为0不执行退款", orderCode);
return;
}
// 统一退款 // 统一退款
memberBasicInfoService.updateMemberBalance(updateMemberBalanceDTO); memberBasicInfoService.updateMemberBalance(updateMemberBalanceDTO);

View File

@@ -755,6 +755,11 @@ public class NotDelayMerchantProgramLogic extends AbstractProgramLogic {
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void balancePaymentOrderRefund(OrderBasicInfo orderBasicInfo) { public void balancePaymentOrderRefund(OrderBasicInfo orderBasicInfo) {
logger.info("【{}】-余额支付订单退款start orderBasicInfo:{}", this.getClass().getSimpleName(), JSON.toJSONString(orderBasicInfo)); logger.info("【{}】-余额支付订单退款start orderBasicInfo:{}", this.getClass().getSimpleName(), JSON.toJSONString(orderBasicInfo));
BigDecimal refundAmount = orderBasicInfo.getRefundAmount();
if (refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) {
logger.info("balancePaymentOrderRefund-退款金额小于等于0orderCode:{}, 退款金额:{}", orderBasicInfo.getOrderCode(), refundAmount);
return;
}
// 订单编号 // 订单编号
String orderCode = orderBasicInfo.getOrderCode(); String orderCode = orderBasicInfo.getOrderCode();
// 订单消费金额 // 订单消费金额
@@ -801,6 +806,16 @@ public class NotDelayMerchantProgramLogic extends AbstractProgramLogic {
.updateGiftBalance(returnGift) .updateGiftBalance(returnGift)
.relatedOrderCode(orderCode) .relatedOrderCode(orderCode)
.build(); .build();
Map<String, BigDecimal> allowableRefundMap = orderBasicInfoService.calculateAllowableBalanceRefund(orderCode, refundAmount,
principalPay, giftPay, updateMemberBalanceDTO.getUpdatePrincipalBalance(), updateMemberBalanceDTO.getUpdateGiftBalance());
updateMemberBalanceDTO.setUpdatePrincipalBalance(allowableRefundMap.get("returnPrincipal"));
updateMemberBalanceDTO.setUpdateGiftBalance(allowableRefundMap.get("returnGift"));
if (updateMemberBalanceDTO.getUpdatePrincipalBalance().compareTo(BigDecimal.ZERO) <= 0
&& updateMemberBalanceDTO.getUpdateGiftBalance().compareTo(BigDecimal.ZERO) <= 0) {
logger.info("balancePaymentOrderRefund-订单:{}本次可退金额为0不执行退款", orderCode);
return;
}
memberBasicInfoService.updateMemberBalance(updateMemberBalanceDTO); memberBasicInfoService.updateMemberBalance(updateMemberBalanceDTO);
// 更新order_pay_record, 解冻部分 // 更新order_pay_record, 解冻部分