Browse Source

3.17 修改退款原订单状态

milestone-20260224-现金钱包
huangqizhen 3 weeks ago
parent
commit
cd152a3c16
  1. 2
      src/main/java/com/example/demo/mapper/coin/WalletMapper.java
  2. 78
      src/main/java/com/example/demo/serviceImpl/cash/CashRefundServiceImpl.java
  3. 5
      src/main/java/com/example/demo/serviceImpl/coin/AuditServiceImpl.java
  4. 16
      src/main/resources/mapper/WalletMapper.xml

2
src/main/java/com/example/demo/mapper/coin/WalletMapper.java

@ -29,4 +29,6 @@ public interface WalletMapper {
void addUserWalletRecord(UserWalletRecord userWalletRecord); void addUserWalletRecord(UserWalletRecord userWalletRecord);
void insert(UserRegionWallet userRegionWallet); void insert(UserRegionWallet userRegionWallet);
List<UserRegionWallet> selectWalletsByJwcodeAndIds(Integer jwcode, List<Integer> walletIds);
} }

78
src/main/java/com/example/demo/serviceImpl/cash/CashRefundServiceImpl.java

@ -215,7 +215,7 @@ public class CashRefundServiceImpl implements RefundService {
{ {
wallet = 3; wallet = 3;
} }
if (payType.equals("iPay88"))
if (payType.equals("Ipay88"))
{ {
wallet = 4; wallet = 4;
} }
@ -504,67 +504,83 @@ public class CashRefundServiceImpl implements RefundService {
user.setCurrentFreeDecember(BigDecimal.valueOf(-userGoldRecord.getFreeDecember())); //当前十二月免费金币 user.setCurrentFreeDecember(BigDecimal.valueOf(-userGoldRecord.getFreeDecember())); //当前十二月免费金币
auditMapper.updateUserGold(user); auditMapper.updateUserGold(user);
// 钱包更新 - 按原始扣款流水 wallet_id 优先级顺序原路退回1-10越小优先级越高
// 钱包更新 - 按原始充值流水 wallet_id 优先级顺序原路退回1-10越小优先级越高
String orderCodeA = "XJ" + orderCode.substring(4); String orderCodeA = "XJ" + orderCode.substring(4);
// 1. 查询原始扣款流水type=1 消耗status=0 正常
// 1. 查询原始充值流水type=3 充值status=0 正常
List<UserWalletRecord> originalRecords = walletService.selectUserWalletRecord(userGoldRecord.getJwcode(), orderCodeA); List<UserWalletRecord> originalRecords = walletService.selectUserWalletRecord(userGoldRecord.getJwcode(), orderCodeA);
if (!CollectionUtils.isEmpty(originalRecords)) { if (!CollectionUtils.isEmpty(originalRecords)) {
// 过滤扣款记录并按 wallet_id 升序排序1 10越小优先级越高
// 过滤充值记录并按 wallet_id 升序排序
originalRecords = originalRecords.stream() originalRecords = originalRecords.stream()
.filter(r -> r.getType() == 1 && r.getStatus() == 0)
.filter(r -> r.getType() == 3 && r.getStatus() == 0)
.sorted(Comparator.comparing(UserWalletRecord::getWalletId)) .sorted(Comparator.comparing(UserWalletRecord::getWalletId))
.collect(Collectors.toList()); .collect(Collectors.toList());
// 2. 本次退款总金额取绝对值兼容负数
// 2. 本次退款总金额取绝对值
BigDecimal totalRefundAmount = BigDecimal.valueOf(userGoldRecord.getPermanentGold()).abs(); BigDecimal totalRefundAmount = BigDecimal.valueOf(userGoldRecord.getPermanentGold()).abs();
if (totalRefundAmount.compareTo(BigDecimal.ZERO) > 0) { 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; BigDecimal remainingRefund = totalRefundAmount;
// 3. 按原始流水顺序退回支持多钱包部分退款优先退前面的
// 3. 按原始流水顺序退回支持多钱包
for (UserWalletRecord record : originalRecords) { for (UserWalletRecord record : originalRecords) {
if (remainingRefund.compareTo(BigDecimal.ZERO) <= 0) { if (remainingRefund.compareTo(BigDecimal.ZERO) <= 0) {
break; break;
} }
Integer walletId = record.getWalletId(); Integer walletId = record.getWalletId();
// 🔥 关键取绝对值兼容消耗存负数的情况
BigDecimal originalAmount = BigDecimal.valueOf(record.getAmount()).abs(); BigDecimal originalAmount = BigDecimal.valueOf(record.getAmount()).abs();
if (originalAmount.compareTo(BigDecimal.ZERO) <= 0) { if (originalAmount.compareTo(BigDecimal.ZERO) <= 0) {
continue; continue;
} }
// 4. 计算本次退回金额 = min(原扣金额剩余待退金额)
// 4. 计算本次退回金额
BigDecimal refundAmount = originalAmount.min(remainingRefund); BigDecimal refundAmount = originalAmount.min(remainingRefund);
if (refundAmount.compareTo(BigDecimal.ZERO) <= 0) { if (refundAmount.compareTo(BigDecimal.ZERO) <= 0) {
continue; continue;
} }
// 5. 插入退款流水记录type=2 退款amount 存正数
// 5. 插入退款流水amount 存负数表示扣减
UserWalletRecord refundRecord = new UserWalletRecord(); UserWalletRecord refundRecord = new UserWalletRecord();
refundRecord.setType(2);
refundRecord.setType(4); // 充值退款类型
refundRecord.setJwcode(userGoldRecord.getJwcode()); refundRecord.setJwcode(userGoldRecord.getJwcode());
refundRecord.setWalletId(walletId); refundRecord.setWalletId(walletId);
refundRecord.setAmount(refundAmount.intValue()); // 退款存正数
refundRecord.setAmount(refundAmount.negate().intValue()); // 🔥 负数扣款
refundRecord.setOrderCode("TK" + orderCodeA); refundRecord.setOrderCode("TK" + orderCodeA);
refundRecord.setDescription(record.getDescription() + "退款");
refundRecord.setDescription(record.getDescription() + "充值退款");
refundRecord.setStatus(0); refundRecord.setStatus(0);
walletService.addUserWalletRecord(refundRecord); walletService.addUserWalletRecord(refundRecord);
// 6. 查询并更新钱包余额覆盖更新先查后改
// 6. 查询并更新钱包余额
UserRegionWallet currentWallet = walletMapper.selectWallet(userGoldRecord.getJwcode(), walletId); UserRegionWallet currentWallet = walletMapper.selectWallet(userGoldRecord.getJwcode(), walletId);
if (currentWallet == null) { if (currentWallet == null) {
log.error("钱包记录不存在,无法退款 | jwcode={}, walletId={}", userGoldRecord.getJwcode(), walletId); log.error("钱包记录不存在,无法退款 | jwcode={}, walletId={}", userGoldRecord.getJwcode(), walletId);
continue; 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); currentWallet.setCurrentPermanentGold(newBalance);
walletService.updateUserGoldRecord(currentWallet);
walletMapper.updateWallet(currentWallet);
// 8. 更新原流水状态为已退款保持你原有的逻辑
// 8. 更新原流水状态
walletService.updateUserWalletRecord(record.getId()); walletService.updateUserWalletRecord(record.getId());
// 9. 扣减剩余待退金额 // 9. 扣减剩余待退金额
@ -1005,5 +1021,31 @@ public class CashRefundServiceImpl implements RefundService {
// 8. 返回分页结果 // 8. 返回分页结果
return new PageInfo<>(list); 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);
}
} }

5
src/main/java/com/example/demo/serviceImpl/coin/AuditServiceImpl.java

@ -216,10 +216,10 @@ public class AuditServiceImpl implements AuditService {
// 1. 查询原始扣款流水type=1 消耗status=0 正常 // 1. 查询原始扣款流水type=1 消耗status=0 正常
List<UserWalletRecord> originalRecords = walletService.selectUserWalletRecord(order.getJwcode(), oldOrderCode); List<UserWalletRecord> originalRecords = walletService.selectUserWalletRecord(order.getJwcode(), oldOrderCode);
if (!CollectionUtils.isEmpty(originalRecords)) { if (!CollectionUtils.isEmpty(originalRecords)) {
// 过滤扣款记录并按 wallet_id 升序排序1 10越小优先级越高
originalRecords = originalRecords.stream() originalRecords = originalRecords.stream()
.filter(r -> r.getType() == 1 && r.getStatus() == 0) .filter(r -> r.getType() == 1 && r.getStatus() == 0)
.sorted(Comparator.comparing(UserWalletRecord::getWalletId))
// 修改点使用 comparingInt reversed
.sorted(Comparator.comparingInt(UserWalletRecord::getWalletId).reversed())
.collect(Collectors.toList()); .collect(Collectors.toList());
// 2. 本次退款总金额 // 2. 本次退款总金额
@ -269,6 +269,7 @@ public class AuditServiceImpl implements AuditService {
BigDecimal newBalance = currentWallet.getCurrentPermanentGold().add(refundAmount); BigDecimal newBalance = currentWallet.getCurrentPermanentGold().add(refundAmount);
currentWallet.setCurrentPermanentGold(newBalance); currentWallet.setCurrentPermanentGold(newBalance);
walletMapper.updateWallet(currentWallet); walletMapper.updateWallet(currentWallet);
walletService.updateUserWalletRecord(record.getId());
// 8. 扣减剩余待退金额 // 8. 扣减剩余待退金额
remainingRefund = remainingRefund.subtract(refundAmount); remainingRefund = remainingRefund.subtract(refundAmount);

16
src/main/resources/mapper/WalletMapper.xml

@ -74,4 +74,20 @@
FROM wallet FROM wallet
ORDER BY priority ASC ORDER BY priority ASC
</select> </select>
<select id="selectWalletsByJwcodeAndIds" resultType="com.example.demo.domain.entity.UserRegionWallet">
SELECT
id,
jwcode,
wallet_id,
current_permanent_gold,
create_time,
update_time
FROM user_region_wallet
WHERE jwcode = #{jwcode}
AND wallet_id IN
<foreach item="item" index="index" collection="walletIds" separator="," close=")" open="(">
#{item}
</foreach>
/>
</select>
</mapper> </mapper>
Loading…
Cancel
Save