peixue-dev/peidu/docs/fixes/2026-01-23-钱包支付集成/📋集成方案.md

10 KiB
Raw Blame History

📋 钱包支付与订单系统集成方案

日期: 2026-01-23
目标: 将钱包支付功能集成到订单系统


🎯 集成目标

  1. 订单支付时支持钱包余额支付
  2. 订单完成后自动结算陪伴员收益
  3. 订单完成后自动结算管理师提成
  4. 订单退款时自动返还钱包余额

📋 集成步骤

步骤1: 扩展OrderServiceImpl - 支持钱包支付

OrderServiceImpl.javapayOrder 方法中添加钱包支付逻辑:

@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);
}

📝 下一步

  1. 创建数据库表
  2. 修改OrderServiceImpl本步骤
  3. 修改OrderController
  4. 编译测试
  5. 实现前端页面

创建时间: 2026-01-23
下一步: 修改OrderServiceImpl添加钱包支付逻辑