|
|
@@ -365,16 +365,21 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
if (chargeOrder != null) {
|
|
|
throw new BusinessException("存在未完结的订单,请等待所有订单完结之后重试");
|
|
|
}
|
|
|
+
|
|
|
var account = accountService.getAccountByUserId(userId);
|
|
|
if (account.getBalance() <= 0) {
|
|
|
throw new BusinessException("账户余额不足,无需退款");
|
|
|
}
|
|
|
+ // 校验余额大于优惠金额
|
|
|
+ if (account.getBalance() <= account.getDiscountAmount()) {
|
|
|
+ throw new BusinessException("不可退金额高于钱包余额,不支持退款");
|
|
|
+ }
|
|
|
|
|
|
// 将余额转移至冻结余额
|
|
|
- accountService.lambdaUpdate().setSql(" frozen_amount = (frozen_amount + balance) ,balance = 0").eq(Account::getUserId, userId).update();
|
|
|
+ accountService.lambdaUpdate().setSql(" frozen_amount = (frozen_amount + (balance - discount_amount)) ,balance = 0").eq(Account::getUserId, userId).update();
|
|
|
|
|
|
- // 余额作为退款金额
|
|
|
- AtomicInteger refundAmount = new AtomicInteger(account.getBalance());
|
|
|
+ // 余减去优惠金额作为退款金额
|
|
|
+ AtomicInteger refundAmount = new AtomicInteger(account.getBalance() - account.getDiscountAmount());
|
|
|
// 充值记录
|
|
|
var payLogs = payLogService.lambdaQuery().eq(PayLog::getUserId, userId).eq(PayLog::getTradeState, RefundLog.STATUS_退款成功).orderByDesc(PayLog::getSuccessTime).list();
|
|
|
// 充值金额综合不足以支付余额退款
|
|
|
@@ -388,7 +393,10 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
// 最后一次的充值金额可以覆盖退款金额
|
|
|
if (!CommUtil.isEmptyOrNull(payLogs) && payLogs.get(0).getTotal() >= refundAmount.get()) {
|
|
|
// 退款日志
|
|
|
- createRefundLog(payLogs.get(0));
|
|
|
+ new RefundLog().setUserId(payLogs.get(0).getUserId()).setOutTradeNo(payLogs.get(0).getOutTradeNo())
|
|
|
+ .setTotal(payLogs.get(0).getTotal()).setRefund(payLogs.get(0).getTotal() - account.getDiscountAmount())
|
|
|
+ .setDiscountAmount(account.getDiscountAmount()).setOutRefundNo(OrderUtils.getOrderNo());
|
|
|
+
|
|
|
} else if (!CommUtil.isEmptyOrNull(payLogs) && payLogs.get(0).getTotal() < refundAmount.get()) {
|
|
|
// 最后一次的充值金额不能覆盖退款金额,拆分成多笔退款
|
|
|
int amount = 0;
|
|
|
@@ -402,16 +410,37 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
}
|
|
|
// 需要退款的记录数量
|
|
|
var size = refundPayLogs.size();
|
|
|
+
|
|
|
+ var refundLogList = new ArrayList<RefundLog>(size);
|
|
|
+
|
|
|
refundPayLogs.forEach(LambadaTools.forEachWithIndex((item, index) -> {
|
|
|
// 如果不是最后一笔,金额全退,最后一笔退剩余的金额
|
|
|
if (index < size) {
|
|
|
- createRefundLog(item);
|
|
|
+ refundLogList.add(new RefundLog().setUserId(item.getUserId()).setOutTradeNo(item.getOutTradeNo())
|
|
|
+ .setTotal(item.getTotal()).setRefund(item.getTotal()).setOutRefundNo(OrderUtils.getOrderNo()));
|
|
|
refundAmount.addAndGet(-item.getTotal());
|
|
|
} else {
|
|
|
item.setTotal(refundAmount.get());
|
|
|
- createRefundLog(item);
|
|
|
+ refundLogList.add(new RefundLog().setUserId(item.getUserId()).setOutTradeNo(item.getOutTradeNo())
|
|
|
+ .setTotal(item.getTotal()).setRefund(refundAmount.get()).setOutRefundNo(OrderUtils.getOrderNo()));
|
|
|
}
|
|
|
}));
|
|
|
+
|
|
|
+ // 不可退金额按退款金额比例放入每笔退款中
|
|
|
+ refundLogList.forEach(LambadaTools.forEachWithIndex((refundLog, index) -> {
|
|
|
+ refundLogList.remove(index.intValue());
|
|
|
+ int discountAmount;
|
|
|
+ if (index < size) {
|
|
|
+ discountAmount = account.getDiscountAmount() * (refundLog.getRefund() / refundAmount.get());
|
|
|
+ } else {
|
|
|
+ // 签名存在精度误差,最后一个元素用总数详见最精确
|
|
|
+ discountAmount = account.getDiscountAmount() - refundLogList.stream().mapToInt(RefundLog::getDiscountAmount).sum();
|
|
|
+ }
|
|
|
+ refundLog.setDiscountAmount(discountAmount);
|
|
|
+ refundLogList.add(index, refundLog);
|
|
|
+ }));
|
|
|
+
|
|
|
+ refundLogService.saveBatch(refundLogList);
|
|
|
} else {
|
|
|
// 退款异常
|
|
|
LOGGER.error("退款异常:userId:{},余额:{},payLogs:{}", userId, refundAmount.get(), payLogs);
|
|
|
@@ -419,22 +448,6 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 创建退款申请记录
|
|
|
- *
|
|
|
- * @param payLog
|
|
|
- */
|
|
|
- public void createRefundLog(PayLog payLog) {
|
|
|
- // 退款日志
|
|
|
- var refundLog = new RefundLog()
|
|
|
- .setUserId(payLog.getUserId())
|
|
|
- .setOutTradeNo(payLog.getOutTradeNo())
|
|
|
- .setOutRefundNo(OrderUtils.getOrderNo())
|
|
|
- .setTotal(payLog.getTotal())
|
|
|
- .setRefund(payLog.getTotal());
|
|
|
- refundLogService.save(refundLog);
|
|
|
- }
|
|
|
-
|
|
|
|
|
|
/**
|
|
|
* 处理退款
|
|
|
@@ -513,6 +526,7 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
|
|
|
//退款日志在申请时插入,接收通知时更新
|
|
|
var refundLog = refundLogService.lambdaQuery().eq(RefundLog::getOutRefundNo, refundNotification.getOutRefundNo()).one();
|
|
|
+ // 防止重复处理消息
|
|
|
if (RefundLog.STATUS_退款成功.equals(refundLog.getStatus())) {
|
|
|
return;
|
|
|
}
|
|
|
@@ -532,8 +546,11 @@ public class WxPayServiceImpl implements WxPayService {
|
|
|
refundLogService.updateById(refundLog);
|
|
|
|
|
|
if (RefundLog.STATUS_退款成功.equals(refundNotification.getRefundStatus().name())) {
|
|
|
- // 冻结金额扣减此次退款金额
|
|
|
- accountService.lambdaUpdate().setSql(" frozen_amount = (frozen_amount - %d)".formatted(refundNotification.getAmount().getRefund().intValue())).eq(Account::getUserId, refundLog.getUserId()).update();
|
|
|
+ // 冻结金额扣减此次退款金额,优惠金额字段减去申请退款时的优惠金额
|
|
|
+ accountService.lambdaUpdate().setSql("frozen_amount = (frozen_amount - %d) , discount_amount = (discount_amount - %d)"
|
|
|
+ .formatted(refundNotification.getAmount().getRefund().intValue()), refundLog.getDiscountAmount())
|
|
|
+ .eq(Account::getUserId, refundLog.getUserId()).update();
|
|
|
+
|
|
|
// 更新资金流水
|
|
|
var walletDetail = walletDetailService.getWalletDetailByOrderNo(refundNotification.getOutRefundNo(), WalletDetail.TYPE_提现);
|
|
|
walletDetail.setStatus(WalletDetail.STATUS_已确认) //已确认
|