10 KiB
10 KiB
📋 钱包支付与订单系统集成方案
日期: 2026-01-23
目标: 将钱包支付功能集成到订单系统
🎯 集成目标
- 订单支付时支持钱包余额支付
- 订单完成后自动结算陪伴员收益
- 订单完成后自动结算管理师提成
- 订单退款时自动返还钱包余额
📋 集成步骤
步骤1: 扩展OrderServiceImpl - 支持钱包支付
在 OrderServiceImpl.java 的 payOrder 方法中添加钱包支付逻辑:
@Autowired
private WalletService walletService;
@Override
@Transactional(rollbackFor = Exception.class)
public boolean payOrder(Long orderId, String paymentMethod) {
log.info("=== 开始处理支付 ===");
log.info("订单ID: {}, 支付方式: {}", orderId, paymentMethod);
Order order = getById(orderId);
if (order == null) {
throw new BusinessException("订单不存在");
}
// 验证状态
if (!isValidStatusTransition(order.getStatus(), 1)) {
throw new BusinessException("订单状态不允许支付");
}
// 🔥 新增:钱包支付逻辑
if ("wallet".equals(paymentMethod)) {
try {
// 使用钱包支付
walletService.consume(order.getUserId(), orderId, order.getPayAmount());
log.info("钱包支付成功,订单ID: {}, 金额: {}", orderId, order.getPayAmount());
} catch (Exception e) {
log.error("钱包支付失败: {}", e.getMessage());
throw new BusinessException("钱包支付失败:" + e.getMessage());
}
}
// 其他支付方式(微信、支付宝等)
else {
// TODO: 调用第三方支付接口
}
// 更新订单状态
order.setStatus(1); // 待接单
order.setPayStatus(1); // 已支付
order.setPayTime(LocalDateTime.now());
order.setPayType(paymentMethod);
// 生成核销码
if (order.getVerificationCode() == null || order.getVerificationCode().isEmpty()) {
order.setVerificationCode(generateVerifyCode());
}
boolean success = updateById(order);
log.info("订单支付完成,状态已更新");
return success;
}
步骤2: 扩展OrderServiceImpl - 订单完成后结算
在 completeService 方法中添加收益结算逻辑:
@Override
@Transactional(rollbackFor = Exception.class)
public boolean completeService(Long orderId) {
Order order = getById(orderId);
if (order == null) {
throw new BusinessException("订单不存在");
}
// 更新订单状态为已完成
order.setStatus(4);
order.setCompleteTime(LocalDateTime.now());
boolean success = updateById(order);
if (success) {
// 🔥 新增:自动结算收益
try {
settleOrderIncome(order);
log.info("订单收益结算完成,订单ID: {}", orderId);
} catch (Exception e) {
log.error("订单收益结算失败: {}", e.getMessage(), e);
// 不影响订单完成,只记录日志
}
}
return success;
}
/**
* 结算订单收益
*
* @param order 订单
*/
private void settleOrderIncome(Order order) {
if (order.getPayAmount() == null || order.getPayAmount().compareTo(BigDecimal.ZERO) <= 0) {
log.warn("订单金额为0,跳过收益结算,订单ID: {}", order.getId());
return;
}
// 1. 计算陪伴员收益(70%)
BigDecimal teacherIncome = order.getPayAmount().multiply(new BigDecimal("0.70"));
if (order.getTeacherId() != null) {
walletService.income(
order.getTeacherId(),
order.getId(),
teacherIncome,
"订单完成-陪伴员收益"
);
log.info("陪伴员收益入账,teacherId: {}, amount: {}", order.getTeacherId(), teacherIncome);
}
// 2. 计算管理师提成(10%)
BigDecimal managerCommission = order.getPayAmount().multiply(new BigDecimal("0.10"));
// TODO: 获取订单的管理师ID
// Long managerId = getManagerIdByOrder(order);
// if (managerId != null) {
// walletService.income(managerId, order.getId(), managerCommission, "订单完成-管理师提成");
// log.info("管理师提成入账,managerId: {}, amount: {}", managerId, managerCommission);
// }
// 3. 平台收益(20%)自动计算
BigDecimal platformIncome = order.getPayAmount().multiply(new BigDecimal("0.20"));
log.info("平台收益: {}", platformIncome);
}
步骤3: 扩展OrderServiceImpl - 订单退款
在 applyRefund 方法中添加钱包退款逻辑:
@Override
@Transactional(rollbackFor = Exception.class)
public boolean applyRefund(Long orderId, String reason) {
Order order = getById(orderId);
if (order == null) {
throw new BusinessException("订单不存在");
}
// 验证是否可以退款
if (order.getPayStatus() != 1) {
throw new BusinessException("订单未支付,无法退款");
}
// 🔥 新增:钱包退款逻辑
if ("wallet".equals(order.getPayType())) {
try {
// 退款到钱包
walletService.refund(order.getUserId(), orderId, order.getPayAmount());
log.info("钱包退款成功,订单ID: {}, 金额: {}", orderId, order.getPayAmount());
} catch (Exception e) {
log.error("钱包退款失败: {}", e.getMessage());
throw new BusinessException("钱包退款失败:" + e.getMessage());
}
}
// 其他支付方式的退款
else {
// TODO: 调用第三方支付退款接口
}
// 更新订单状态
order.setStatus(6); // 已退款
order.setRefundStatus(1); // 退款成功
order.setRefundAmount(order.getPayAmount());
order.setRefundTime(LocalDateTime.now());
order.setCancelReason(reason);
order.setCancelTime(LocalDateTime.now());
return updateById(order);
}
步骤4: 扩展OrderController - 添加钱包余额查询
在 OrderController.java 中添加查询钱包余额的接口:
@Autowired
private WalletService walletService;
/**
* 查询钱包余额(下单前)
*/
@GetMapping("/wallet/balance")
@ApiOperation("查询钱包余额")
public Result<Map<String, Object>> getWalletBalance(@RequestParam Long userId) {
try {
BigDecimal balance = walletService.getBalance(userId);
Map<String, Object> data = new HashMap<>();
data.put("balance", balance);
data.put("hasBalance", balance.compareTo(BigDecimal.ZERO) > 0);
return Result.success(data);
} catch (Exception e) {
log.error("查询钱包余额失败", e);
return Result.error("查询钱包余额失败:" + e.getMessage());
}
}
🔄 业务流程
订单支付流程(使用钱包)
用户下单
↓
选择钱包支付
↓
调用 orderService.payOrder(orderId, "wallet")
↓
调用 walletService.consume(userId, orderId, amount)
↓
检查余额是否充足
↓
扣减钱包余额(使用乐观锁)
↓
创建交易记录
↓
更新订单状态为已支付
↓
生成核销码
↓
返回支付成功
订单完成后结算流程
订单完成
↓
调用 orderService.completeService(orderId)
↓
更新订单状态为已完成
↓
调用 settleOrderIncome(order)
↓
计算陪伴员收益(70%)
↓
调用 walletService.income(teacherId, orderId, amount, "陪伴员收益")
↓
陪伴员钱包余额增加
↓
计算管理师提成(10%)
↓
调用 walletService.income(managerId, orderId, amount, "管理师提成")
↓
管理师钱包余额增加
↓
平台收益(20%)自动计算
↓
结算完成
订单退款流程
用户申请退款
↓
调用 orderService.applyRefund(orderId, reason)
↓
验证订单状态
↓
调用 walletService.refund(userId, orderId, amount)
↓
钱包余额增加
↓
创建退款交易记录
↓
更新订单状态为已退款
↓
返回退款成功
📊 收益分配比例
| 角色 | 比例 | 说明 |
|---|---|---|
| 陪伴员 | 70% | 直接服务提供者 |
| 管理师 | 10% | 订单管理和协调 |
| 平台 | 20% | 平台运营成本 |
示例:
- 订单金额: 100元
- 陪伴员收益: 70元
- 管理师提成: 10元
- 平台收益: 20元
🔐 安全注意事项
1. 事务一致性
所有涉及金额的操作都必须在事务中完成:
@Transactional(rollbackFor = Exception.class)
2. 乐观锁防并发
钱包余额更新使用乐观锁:
@Version
private Integer version;
3. 余额校验
支付前必须检查余额:
if (wallet.getBalance().compareTo(amount) < 0) {
throw new RuntimeException("钱包余额不足");
}
4. 异常处理
支付失败时必须回滚:
try {
walletService.consume(...);
} catch (Exception e) {
throw new BusinessException("支付失败:" + e.getMessage());
}
🧪 测试建议
1. 单元测试
@Test
public void testWalletPayment() {
// 1. 创建订单
Order order = createTestOrder();
// 2. 充值钱包
walletService.recharge(userId, new BigDecimal("100"), "wechat", null);
// 3. 使用钱包支付
boolean success = orderService.payOrder(order.getId(), "wallet");
assertTrue(success);
// 4. 验证余额
BigDecimal balance = walletService.getBalance(userId);
assertEquals(new BigDecimal("50"), balance);
}
2. 集成测试
@Test
public void testOrderCompleteSettlement() {
// 1. 创建并支付订单
Order order = createAndPayOrder();
// 2. 完成订单
orderService.completeService(order.getId());
// 3. 验证陪伴员收益
BigDecimal teacherBalance = walletService.getBalance(teacherId);
assertEquals(new BigDecimal("70"), teacherBalance);
}
📝 下一步
- ✅ 创建数据库表
- ⏳ 修改OrderServiceImpl(本步骤)
- ⏳ 修改OrderController
- ⏳ 编译测试
- ⏳ 实现前端页面
创建时间: 2026-01-23
下一步: 修改OrderServiceImpl添加钱包支付逻辑