|
|
@@ -2258,46 +2258,109 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
|
|
|
@Transactional(rollbackFor = Throwable.class)
|
|
|
public void clearBalanceToRefundMoney(OrderBalanceRefundReq refundReq) throws Exception {
|
|
|
Long refundOrderId = refundReq.getRefundOrderId();
|
|
|
- BigDecimal refundMoney = refundReq.getRefundMoney();
|
|
|
RefundOrderDon refundOrderDon = refundOrderDonMapper.selectById(refundOrderId);
|
|
|
- if (!"balance".equals(refundOrderDon.getRefundMethod())) {
|
|
|
- throw BusinessRuntimeException.getInstance("该记录不是余额退款类型");
|
|
|
+ if (refundOrderDon == null) {
|
|
|
+ throw BusinessRuntimeException.getInstance("退款记录不存在");
|
|
|
+ }
|
|
|
+ String refundMethod = refundOrderDon.getRefundMethod();
|
|
|
+ boolean balanceRefund = OrderRefundReq.RefundType.balance.name().equals(refundMethod);
|
|
|
+ boolean mixedRefund = OrderRefundReq.RefundType.bxj.name().equals(refundMethod);
|
|
|
+ if (!balanceRefund && !mixedRefund) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该记录不包含可转现金的退款余额");
|
|
|
}
|
|
|
+ if (Boolean.TRUE.equals(refundOrderDon.getIsClearBalance())) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该笔退款余额记录已转为现金");
|
|
|
+ }
|
|
|
+
|
|
|
+ // balance 类型的余额金额保存在 refundFee;bxj 只转换其中的 refundBalance,
|
|
|
+ // 不能把 bxj 已经退过的现金 refundFee 再退一次。
|
|
|
+ BigDecimal refundableBalance = balanceRefund
|
|
|
+ ? Optional.ofNullable(refundOrderDon.getRefundFee()).orElse(BigDecimal.ZERO)
|
|
|
+ : Optional.ofNullable(refundOrderDon.getRefundBalance()).orElse(BigDecimal.ZERO);
|
|
|
+ if (refundableBalance.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该记录没有可转现金的退款余额");
|
|
|
+ }
|
|
|
+
|
|
|
Long orderId = refundOrderDon.getOrderId();
|
|
|
OrderDon orderDon = orderDonMapper.selectById(orderId);
|
|
|
if (orderDon == null) {
|
|
|
- throw BusinessRuntimeException.getInstance("Order does not exist");
|
|
|
+ throw BusinessRuntimeException.getInstance("订单不存在");
|
|
|
}
|
|
|
if (orderDonTicketRecordService.exists(orderId)) {
|
|
|
throw BusinessRuntimeException.getInstance("Multi-quantity orders only support whole-order refunds");
|
|
|
}
|
|
|
- if (orderDon.getMoney().compareTo(BigDecimal.ZERO) == 0) {
|
|
|
+ BigDecimal orderMoney = Optional.ofNullable(orderDon.getMoney()).orElse(BigDecimal.ZERO);
|
|
|
+ if (orderMoney.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
throw BusinessRuntimeException.getInstance("该记录对应的订单无实际支付金额");
|
|
|
}
|
|
|
- if (refundOrderDon.getIsClearBalance()) {
|
|
|
- throw BusinessRuntimeException.getInstance("该笔退款余额记录已退款");
|
|
|
+
|
|
|
+ BigDecimal orderRefundMoney = Optional.ofNullable(orderDon.getRefundMoney()).orElse(BigDecimal.ZERO);
|
|
|
+ BigDecimal orderRefundBalance = Optional.ofNullable(orderDon.getRefundBalance()).orElse(BigDecimal.ZERO);
|
|
|
+ BigDecimal remainingCash = orderMoney.subtract(orderRefundMoney);
|
|
|
+ if (remainingCash.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该订单实际支付金额已全部退款");
|
|
|
}
|
|
|
- BigDecimal refundFee = refundOrderDon.getRefundFee();
|
|
|
- //默认退全部余额
|
|
|
- if (refundMoney != null) {
|
|
|
- refundFee = refundMoney;
|
|
|
+
|
|
|
+ BigDecimal requestedMoney = refundReq.getRefundMoney();
|
|
|
+ if (requestedMoney != null && requestedMoney.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ throw BusinessRuntimeException.getInstance("退款金额必须大于0");
|
|
|
}
|
|
|
- BigDecimal money = orderDon.getMoney();
|
|
|
- //若退款余额 大于退款金额 将退款余额至为 退款金额
|
|
|
- if (refundFee.compareTo(money) > 0) {
|
|
|
- refundFee = money;
|
|
|
+ if (requestedMoney != null && requestedMoney.compareTo(refundableBalance) > 0) {
|
|
|
+ throw BusinessRuntimeException.getInstance("退款金额不能大于该记录的退款余额");
|
|
|
+ }
|
|
|
+ if (requestedMoney != null && requestedMoney.compareTo(remainingCash) > 0) {
|
|
|
+ throw BusinessRuntimeException.getInstance("退款金额不能大于订单剩余可退现金金额");
|
|
|
}
|
|
|
+
|
|
|
+ // 未指定金额时尽量转换整笔,但不得超过支付渠道剩余可退现金。
|
|
|
+ BigDecimal refundFee = requestedMoney == null
|
|
|
+ ? refundableBalance.min(remainingCash)
|
|
|
+ : requestedMoney;
|
|
|
+ if (refundFee.compareTo(orderRefundBalance) > 0) {
|
|
|
+ throw BusinessRuntimeException.getInstance("订单剩余退款余额不足,无法转为现金");
|
|
|
+ }
|
|
|
+
|
|
|
User user = userMapper.selectById(orderDon.getUserId());
|
|
|
- if (user.getBalance().compareTo(refundFee) < 0) {
|
|
|
+ if (user == null) {
|
|
|
+ throw BusinessRuntimeException.getInstance("用户不存在");
|
|
|
+ }
|
|
|
+ BigDecimal userBalance = Optional.ofNullable(user.getBalance()).orElse(BigDecimal.ZERO);
|
|
|
+ if (userBalance.compareTo(refundFee) < 0) {
|
|
|
throw BusinessRuntimeException.getInstance("用户余额不足,无法扣除对应退款余额");
|
|
|
}
|
|
|
int update = userMapper.update(null, Wrappers.lambdaUpdate(User.class)
|
|
|
- .set(User::getBalance, user.getBalance().subtract(refundFee))
|
|
|
+ .set(User::getBalance, userBalance.subtract(refundFee))
|
|
|
.eq(User::getId, user.getId())
|
|
|
- .eq(User::getBalance, user.getBalance()));
|
|
|
+ .eq(User::getBalance, userBalance));
|
|
|
if (update == 0) {
|
|
|
throw BusinessRuntimeException.getInstance("扣除用户退款余额失败,请重试...");
|
|
|
}
|
|
|
+
|
|
|
+ // 先用条件更新占住退款记录和订单金额;后续渠道退款失败时由事务统一回滚。
|
|
|
+ int refundRecordUpdate = refundOrderDonMapper.update(null, Wrappers.lambdaUpdate(RefundOrderDon.class)
|
|
|
+ .set(RefundOrderDon::getIsClearBalance, true)
|
|
|
+ .set(mixedRefund, RefundOrderDon::getRefundBalance, refundableBalance.subtract(refundFee))
|
|
|
+ .eq(RefundOrderDon::getId, refundOrderId)
|
|
|
+ .and(wrapper -> wrapper.eq(RefundOrderDon::getIsClearBalance, false)
|
|
|
+ .or().isNull(RefundOrderDon::getIsClearBalance)));
|
|
|
+ if (refundRecordUpdate == 0) {
|
|
|
+ throw BusinessRuntimeException.getInstance("该笔退款余额已处理,请勿重复操作");
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal newRefundBalance = orderRefundBalance.subtract(refundFee);
|
|
|
+ BigDecimal newRefundMoney = orderRefundMoney.add(refundFee);
|
|
|
+ int orderUpdate = orderDonMapper.update(null, Wrappers.lambdaUpdate(OrderDon.class)
|
|
|
+ .set(OrderDon::getRefundBalance, newRefundBalance)
|
|
|
+ .set(OrderDon::getRefundMoney, newRefundMoney)
|
|
|
+ .eq(OrderDon::getId, orderId)
|
|
|
+ .eq(orderDon.getRefundBalance() != null, OrderDon::getRefundBalance, orderDon.getRefundBalance())
|
|
|
+ .isNull(orderDon.getRefundBalance() == null, OrderDon::getRefundBalance)
|
|
|
+ .eq(orderDon.getRefundMoney() != null, OrderDon::getRefundMoney, orderDon.getRefundMoney())
|
|
|
+ .isNull(orderDon.getRefundMoney() == null, OrderDon::getRefundMoney));
|
|
|
+ if (orderUpdate == 0) {
|
|
|
+ throw BusinessRuntimeException.getInstance("订单退款金额已发生变化,请重试");
|
|
|
+ }
|
|
|
+
|
|
|
OrderRefundReq orderRefundReq = new OrderRefundReq();
|
|
|
orderRefundReq.setOrderId(orderId);
|
|
|
orderRefundReq.setRefundMoney(refundFee);
|
|
|
@@ -2305,14 +2368,31 @@ public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon>
|
|
|
|
|
|
String outNo = orderRefundService.centerRefund(orderRefundReq, orderDon);
|
|
|
|
|
|
- orderDon.setRefundBalance(orderDon.getRefundBalance().subtract(refundFee));
|
|
|
- BigDecimal orderRefundMoney = Optional.ofNullable(orderDon.getRefundMoney()).orElse(BigDecimal.ZERO);
|
|
|
- orderDon.setRefundMoney(orderRefundMoney.add(refundFee));
|
|
|
- orderDonMapper.updateById(orderDon);
|
|
|
-
|
|
|
- refundOrderDon.setOutRefundNo(outNo);
|
|
|
- refundOrderDon.setIsClearBalance(true);
|
|
|
- refundOrderDonMapper.updateById(refundOrderDon);
|
|
|
+ if (mixedRefund) {
|
|
|
+ // bxj 原记录的 outRefundNo 属于首次现金退款,不能覆盖;单独记录本次转换流水。
|
|
|
+ RefundOrderDon conversionRecord = new RefundOrderDon();
|
|
|
+ conversionRecord.setUserId(refundOrderDon.getUserId());
|
|
|
+ conversionRecord.setOrderId(orderId);
|
|
|
+ conversionRecord.setGoodsType(refundOrderDon.getGoodsType());
|
|
|
+ conversionRecord.setOutRefundNo(outNo);
|
|
|
+ conversionRecord.setGoodsId(refundOrderDon.getGoodsId());
|
|
|
+ conversionRecord.setSkuId(refundOrderDon.getSkuId());
|
|
|
+ conversionRecord.setGoodsTitle(refundOrderDon.getGoodsTitle());
|
|
|
+ conversionRecord.setSpecVal(refundOrderDon.getSpecVal());
|
|
|
+ conversionRecord.setTotalFee(refundOrderDon.getTotalFee());
|
|
|
+ conversionRecord.setRefundFee(refundFee);
|
|
|
+ conversionRecord.setRefundBalance(BigDecimal.ZERO);
|
|
|
+ conversionRecord.setRefundDesc("混合退款余额转现金");
|
|
|
+ conversionRecord.setRefundMethod(OrderRefundReq.RefundType.money.name());
|
|
|
+ conversionRecord.setIsClearBalance(true);
|
|
|
+ conversionRecord.setOperator(refundOrderDon.getOperator());
|
|
|
+ conversionRecord.setChatImg(refundOrderDon.getChatImg());
|
|
|
+ refundOrderDonMapper.insert(conversionRecord);
|
|
|
+ } else {
|
|
|
+ refundOrderDonMapper.update(null, Wrappers.lambdaUpdate(RefundOrderDon.class)
|
|
|
+ .set(RefundOrderDon::getOutRefundNo, outNo)
|
|
|
+ .eq(RefundOrderDon::getId, refundOrderId));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|