From cd152a3c16dcaeca133922f5770baeff5a93d998 Mon Sep 17 00:00:00 2001 From: huangqizhen <15552608129@163.com> Date: Wed, 18 Mar 2026 10:08:58 +0800 Subject: [PATCH] =?UTF-8?q?3.17=20=E4=BF=AE=E6=94=B9=E9=80=80=E6=AC=BE?= =?UTF-8?q?=E5=8E=9F=E8=AE=A2=E5=8D=95=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/demo/mapper/coin/WalletMapper.java | 2 + .../serviceImpl/cash/CashRefundServiceImpl.java | 78 +++++++++++++++++----- .../demo/serviceImpl/coin/AuditServiceImpl.java | 5 +- src/main/resources/mapper/WalletMapper.xml | 16 +++++ 4 files changed, 81 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/example/demo/mapper/coin/WalletMapper.java b/src/main/java/com/example/demo/mapper/coin/WalletMapper.java index baf76f7..d418d19 100644 --- a/src/main/java/com/example/demo/mapper/coin/WalletMapper.java +++ b/src/main/java/com/example/demo/mapper/coin/WalletMapper.java @@ -29,4 +29,6 @@ public interface WalletMapper { void addUserWalletRecord(UserWalletRecord userWalletRecord); void insert(UserRegionWallet userRegionWallet); + + List selectWalletsByJwcodeAndIds(Integer jwcode, List walletIds); } diff --git a/src/main/java/com/example/demo/serviceImpl/cash/CashRefundServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/cash/CashRefundServiceImpl.java index 470bc9d..3315d64 100644 --- a/src/main/java/com/example/demo/serviceImpl/cash/CashRefundServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/cash/CashRefundServiceImpl.java @@ -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 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 records) { + // 提取涉及到的 wallet_id 列表(去重) + List walletIds = records.stream() + .map(UserWalletRecord::getWalletId) + .distinct() + .collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(walletIds)) { + return BigDecimal.ZERO; + } + + // 批量查询钱包当前余额(避免 N+1 查询) + List wallets = walletMapper.selectWalletsByJwcodeAndIds(jwcode, walletIds); + + // 汇总余额 + return wallets.stream() + .map(UserRegionWallet::getCurrentPermanentGold) + .filter(Objects::nonNull) + .reduce(BigDecimal.ZERO, BigDecimal::add); + } } diff --git a/src/main/java/com/example/demo/serviceImpl/coin/AuditServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/coin/AuditServiceImpl.java index 46e5142..8f8be0d 100644 --- a/src/main/java/com/example/demo/serviceImpl/coin/AuditServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/coin/AuditServiceImpl.java @@ -216,10 +216,10 @@ public class AuditServiceImpl implements AuditService { // 1. 查询原始扣款流水(type=1 消耗,status=0 正常) List originalRecords = walletService.selectUserWalletRecord(order.getJwcode(), oldOrderCode); if (!CollectionUtils.isEmpty(originalRecords)) { - // 过滤扣款记录并按 wallet_id 升序排序(1 到 10,越小优先级越高) originalRecords = originalRecords.stream() .filter(r -> r.getType() == 1 && r.getStatus() == 0) - .sorted(Comparator.comparing(UserWalletRecord::getWalletId)) + // 修改点:使用 comparingInt 并 reversed + .sorted(Comparator.comparingInt(UserWalletRecord::getWalletId).reversed()) .collect(Collectors.toList()); // 2. 本次退款总金额 @@ -269,6 +269,7 @@ public class AuditServiceImpl implements AuditService { BigDecimal newBalance = currentWallet.getCurrentPermanentGold().add(refundAmount); currentWallet.setCurrentPermanentGold(newBalance); walletMapper.updateWallet(currentWallet); + walletService.updateUserWalletRecord(record.getId()); // 8. 扣减剩余待退金额 remainingRefund = remainingRefund.subtract(refundAmount); diff --git a/src/main/resources/mapper/WalletMapper.xml b/src/main/resources/mapper/WalletMapper.xml index 9187dfd..7a6d01d 100644 --- a/src/main/resources/mapper/WalletMapper.xml +++ b/src/main/resources/mapper/WalletMapper.xml @@ -74,4 +74,20 @@ FROM wallet ORDER BY priority ASC + \ No newline at end of file