|
|
|
@ -215,7 +215,7 @@ public class CashRefundServiceImpl implements RefundService { |
|
|
|
{ |
|
|
|
wallet = 3; |
|
|
|
} |
|
|
|
if (payType.equals("iPay88")) |
|
|
|
if (payType.equals("Ipay88")) |
|
|
|
{ |
|
|
|
wallet = 4; |
|
|
|
} |
|
|
|
@ -504,67 +504,83 @@ public class CashRefundServiceImpl implements RefundService { |
|
|
|
user.setCurrentFreeDecember(BigDecimal.valueOf(-userGoldRecord.getFreeDecember())); //当前十二月免费金币 |
|
|
|
auditMapper.updateUserGold(user); |
|
|
|
|
|
|
|
// 钱包更新 - 按原始扣款流水 wallet_id 优先级顺序原路退回(1-10,越小优先级越高) |
|
|
|
// 钱包更新 - 按原始充值流水 wallet_id 优先级顺序原路退回(1-10,越小优先级越高) |
|
|
|
String orderCodeA = "XJ" + orderCode.substring(4); |
|
|
|
|
|
|
|
// 1. 查询原始扣款流水(type=1 消耗,status=0 正常) |
|
|
|
// 1. 查询原始充值流水(type=3 充值,status=0 正常) |
|
|
|
List<UserWalletRecord> originalRecords = walletService.selectUserWalletRecord(userGoldRecord.getJwcode(), orderCodeA); |
|
|
|
if (!CollectionUtils.isEmpty(originalRecords)) { |
|
|
|
// 过滤扣款记录并按 wallet_id 升序排序(1 到 10,越小优先级越高) |
|
|
|
// 过滤充值记录并按 wallet_id 升序排序 |
|
|
|
originalRecords = originalRecords.stream() |
|
|
|
.filter(r -> r.getType() == 1 && r.getStatus() == 0) |
|
|
|
.filter(r -> r.getType() == 3 && r.getStatus() == 0) |
|
|
|
.sorted(Comparator.comparing(UserWalletRecord::getWalletId)) |
|
|
|
.collect(Collectors.toList()); |
|
|
|
|
|
|
|
// 2. 本次退款总金额(取绝对值,兼容负数) |
|
|
|
// 2. 本次退款总金额(取绝对值) |
|
|
|
BigDecimal totalRefundAmount = BigDecimal.valueOf(userGoldRecord.getPermanentGold()).abs(); |
|
|
|
|
|
|
|
if (totalRefundAmount.compareTo(BigDecimal.ZERO) > 0) { |
|
|
|
|
|
|
|
// 🔥【新增】预校验:检查用户余额是否足够退款 |
|
|
|
BigDecimal userTotalBalance = getUserTotalBalance(userGoldRecord.getJwcode(), originalRecords); |
|
|
|
if (userTotalBalance.compareTo(totalRefundAmount) < 0) { |
|
|
|
// 🔥 余额不足,直接报错返回(根据项目规范选择抛异常或返回错误码) |
|
|
|
String errorMsg = String.format("退款失败:用户余额不足 | jwcode=%s, 待退金额=%s, 当前余额=%s", |
|
|
|
userGoldRecord.getJwcode(), totalRefundAmount, userTotalBalance); |
|
|
|
log.error(errorMsg); |
|
|
|
throw new BusinessException("WALLET_REFUND_INSUFFICIENT"+ errorMsg); |
|
|
|
// 或者:return Result.fail("WALLET_REFUND_INSUFFICIENT", "余额不足,无法退款"); |
|
|
|
} |
|
|
|
|
|
|
|
BigDecimal remainingRefund = totalRefundAmount; |
|
|
|
|
|
|
|
// 3. 按原始流水顺序退回(支持多钱包,部分退款优先退前面的) |
|
|
|
// 3. 按原始流水顺序退回(支持多钱包) |
|
|
|
for (UserWalletRecord record : originalRecords) { |
|
|
|
if (remainingRefund.compareTo(BigDecimal.ZERO) <= 0) { |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
Integer walletId = record.getWalletId(); |
|
|
|
// 🔥 关键:取绝对值,兼容消耗存负数的情况 |
|
|
|
BigDecimal originalAmount = BigDecimal.valueOf(record.getAmount()).abs(); |
|
|
|
if (originalAmount.compareTo(BigDecimal.ZERO) <= 0) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
// 4. 计算本次退回金额 = min(原扣金额,剩余待退金额) |
|
|
|
// 4. 计算本次退回金额 |
|
|
|
BigDecimal refundAmount = originalAmount.min(remainingRefund); |
|
|
|
if (refundAmount.compareTo(BigDecimal.ZERO) <= 0) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
// 5. 插入退款流水记录(type=2 退款,amount 存正数) |
|
|
|
// 5. 插入退款流水(amount 存负数,表示扣减) |
|
|
|
UserWalletRecord refundRecord = new UserWalletRecord(); |
|
|
|
refundRecord.setType(2); |
|
|
|
refundRecord.setType(4); // 充值退款类型 |
|
|
|
refundRecord.setJwcode(userGoldRecord.getJwcode()); |
|
|
|
refundRecord.setWalletId(walletId); |
|
|
|
refundRecord.setAmount(refundAmount.intValue()); // 退款存正数 |
|
|
|
refundRecord.setAmount(refundAmount.negate().intValue()); // 🔥 负数扣款 |
|
|
|
refundRecord.setOrderCode("TK" + orderCodeA); |
|
|
|
refundRecord.setDescription(record.getDescription() + "退款"); |
|
|
|
refundRecord.setDescription(record.getDescription() + "充值退款"); |
|
|
|
refundRecord.setStatus(0); |
|
|
|
walletService.addUserWalletRecord(refundRecord); |
|
|
|
|
|
|
|
// 6. 查询并更新钱包余额(覆盖更新,先查后改) |
|
|
|
// 6. 查询并更新钱包余额 |
|
|
|
UserRegionWallet currentWallet = walletMapper.selectWallet(userGoldRecord.getJwcode(), walletId); |
|
|
|
if (currentWallet == null) { |
|
|
|
log.error("钱包记录不存在,无法退款 | jwcode={}, walletId={}", userGoldRecord.getJwcode(), walletId); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
// 7. 计算新余额 + 覆盖更新 |
|
|
|
BigDecimal newBalance = currentWallet.getCurrentPermanentGold().add(refundAmount); |
|
|
|
// 7. 扣减余额 |
|
|
|
BigDecimal newBalance = currentWallet.getCurrentPermanentGold().subtract(refundAmount); |
|
|
|
// 🔥 兜底:理论上预校验已通过,这里不会再出现负数,但保留防御式编程 |
|
|
|
if (newBalance.compareTo(BigDecimal.ZERO) < 0) { |
|
|
|
log.warn("退款后余额为负,强制置零 | jwcode={}, walletId={}", userGoldRecord.getJwcode(), walletId); |
|
|
|
newBalance = BigDecimal.ZERO; |
|
|
|
} |
|
|
|
currentWallet.setCurrentPermanentGold(newBalance); |
|
|
|
walletService.updateUserGoldRecord(currentWallet); |
|
|
|
walletMapper.updateWallet(currentWallet); |
|
|
|
|
|
|
|
// 8. 更新原流水状态为已退款(保持你原有的逻辑) |
|
|
|
// 8. 更新原流水状态 |
|
|
|
walletService.updateUserWalletRecord(record.getId()); |
|
|
|
|
|
|
|
// 9. 扣减剩余待退金额 |
|
|
|
@ -1005,5 +1021,31 @@ public class CashRefundServiceImpl implements RefundService { |
|
|
|
// 8. 返回分页结果 |
|
|
|
return new PageInfo<>(list); |
|
|
|
} |
|
|
|
/** |
|
|
|
* 计算用户指定钱包列表的总可用余额 |
|
|
|
* @param jwcode 用户标识 |
|
|
|
* @param records 原始充值流水列表(用于提取 wallet_id 列表) |
|
|
|
* @return 总余额(BigDecimal) |
|
|
|
*/ |
|
|
|
private BigDecimal getUserTotalBalance(Integer jwcode, List<UserWalletRecord> records) { |
|
|
|
// 提取涉及到的 wallet_id 列表(去重) |
|
|
|
List<Integer> walletIds = records.stream() |
|
|
|
.map(UserWalletRecord::getWalletId) |
|
|
|
.distinct() |
|
|
|
.collect(Collectors.toList()); |
|
|
|
|
|
|
|
if (CollectionUtils.isEmpty(walletIds)) { |
|
|
|
return BigDecimal.ZERO; |
|
|
|
} |
|
|
|
|
|
|
|
// 批量查询钱包当前余额(避免 N+1 查询) |
|
|
|
List<UserRegionWallet> wallets = walletMapper.selectWalletsByJwcodeAndIds(jwcode, walletIds); |
|
|
|
|
|
|
|
// 汇总余额 |
|
|
|
return wallets.stream() |
|
|
|
.map(UserRegionWallet::getCurrentPermanentGold) |
|
|
|
.filter(Objects::nonNull) |
|
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add); |
|
|
|
} |
|
|
|
|
|
|
|
} |