epic-011-mini-payment-refund-flow.md 17 KB

Epic 011 - Mini小程序支付退款完整流程 - Brownfield Enhancement

Epic Status

进度: 50% (2/4 故事完成) 当前状态: Story 1 和 Story 2 已完成,支付回调和订单取消功能已实现并通过测试 下一步: 开始 Story 3 - 集成微信支付退款功能

Epic Goal

跑通当前mini提交创建订单后,调用微信小程序支付,支付回调,更新订单状态。订单支付成功后,在min订单列表进入订单详情,点击取消订单后,可以取消订单并调用微信支付sdk退款,最后更新订单状态。

Epic Description

Existing System Context

Current relevant functionality:

  • 多租户支付模块已实现微信小程序支付功能,支持租户隔离和系统配置集成
  • 多租户订单模块已实现订单创建和管理功能,支持租户隔离
  • 多租户退款模块已实现退款记录管理,但缺少与微信支付SDK的集成
  • 多租户系统配置模块已实现租户隔离的支付配置管理,支付模块已集成
  • Redis缓存已用于session_key存储和系统配置缓存
  • 共享CRUD包已提供完整的多租户支持
  • Mini小程序前端已实现:
    • 订单提交页面(/pages/order-submit/index.tsx)- 支持订单创建,跳转到订单详情
    • 订单列表页面(/pages/order-list/index.tsx)- 支持订单状态显示和筛选,有"去支付"按钮
    • 订单详情页面(/pages/order-detail/index.tsx)- 支持取消订单和申请退款UI
    • 支付工具函数(/utils/payment.ts)- 完整的微信支付工具类,包含支付调用、验证、重试、状态管理等

Technology stack:

  • TypeORM + PostgreSQL (数据库)
  • Hono + Zod OpenAPI (API框架)
  • Redis (缓存)
  • 微信小程序SDK (认证和支付)
  • @d8d/shared-crud (共享CRUD工具包)

Integration points:

  • 多租户支付模块的PaymentMtService (小程序支付,已集成系统配置)
  • 多租户订单模块的OrderMtService (订单管理)
  • 多租户退款模块的UserRefundsMtService (退款记录管理)
  • 多租户系统配置模块的SystemConfigServiceMt (支付配置)
  • Redis缓存工具 (配置缓存)
  • 微信支付SDK (退款功能 - 需要集成)

Enhancement Details

What's being added/changed:

  • 完善支付回调处理逻辑,确保订单状态正确更新(支付模块已有TODO注释)
  • 实现订单取消功能,支持支付订单的取消和退款(当前缺少取消订单功能)
  • 集成微信支付SDK退款功能(支付模块缺少退款功能)
  • 优化订单状态流转逻辑
  • 完善退款记录和状态跟踪(退款模块已有基础功能)
  • Mini小程序前端增强:
    • 添加支付页面(/pages/payment/index.tsx)- 当前缺少支付页面
    • 集成支付工具函数到订单流程中
    • 完善取消订单和退款的前端交互

How it integrates:

  • 复用多租户支付模块的支付功能,扩展退款功能
  • 扩展多租户订单模块支持取消和退款操作
  • 使用多租户系统配置模块获取租户特定的支付配置(已集成)
  • 集成微信支付SDK实现退款功能
  • 使用Redis缓存优化配置访问(已集成)
  • Mini小程序前端集成:
    • 订单提交页面调用支付API获取支付参数
    • 支付页面调用微信支付SDK完成支付
    • 订单详情页面集成取消订单和退款功能
    • 使用现有的支付工具函数库

Success criteria:

  • 用户可以在mini小程序中成功创建订单并支付
  • 支付回调正确更新订单状态
  • 用户可以在订单详情中取消已支付订单
  • 取消订单时自动调用微信支付退款
  • 退款回调正确更新订单和退款状态
  • 整个流程支持多租户隔离

Stories

  1. Story 1: 完善支付回调处理逻辑 - 确保支付回调正确更新订单状态,支持多租户隔离

    • 修改位置:
      • packages/mini-payment-mt/src/services/payment.mt.service.ts - 修复TODO注释,实现订单状态更新
      • packages/mini-payment-mt/src/routes/payment/callback.mt.ts - 支付回调接口
    • 验收标准:
      • ✅ 支付回调接口正确处理微信支付通知
      • ✅ 订单状态从"待支付"正确更新为"已支付"(支付状态从0更新为2)
      • ✅ 支付时间、支付流水号等字段正确记录
      • ✅ 支持多租户隔离,不同租户的支付回调互不影响
      • ✅ 添加支付回调日志记录
      • ✅ 修复支付模块中的TODO:更新订单状态
    • 完成状态: 所有7个集成测试通过,包括多租户数据隔离验证
  2. Story 2: 实现订单取消功能 - 支持已支付订单的取消和退款流程

    • 修改位置:
      • packages/orders-module-mt/src/services/order.mt.service.ts - 添加cancelOrder方法
      • packages/orders-module-mt/src/routes/user/orders.mt.ts - 添加取消订单API
      • mini/src/pages/order-detail/index.tsx - 集成取消订单UI
    • 验收标准:
      • ✅ 在订单详情页面添加取消订单按钮
      • ✅ 取消订单时验证订单状态(仅允许取消"待支付"和"已支付"订单)
      • ✅ 对于已支付订单,触发退款流程
      • ✅ 订单状态正确更新为"已取消"(支付状态更新为5)
      • ✅ 取消原因和操作时间正确记录
      • ✅ 在OrderMtService中添加cancelOrder方法
    • 完成状态: 所有12个集成测试通过,包括多租户数据隔离和用户权限验证
  3. Story 3: 集成微信支付退款功能 - 调用微信支付SDK实现退款

    • 修改位置:
      • packages/mini-payment-mt/src/services/payment.mt.service.ts - 添加refund方法
      • packages/mini-payment-mt/src/routes/payment/create.mt.ts - 添加退款API
      • packages/mini-payment-mt/src/entities/payment.mt.entity.ts - 可能扩展退款相关字段
    • 验收标准:
      • 在PaymentMtService中添加退款功能
      • 集成微信支付退款SDK
      • 实现退款请求构建和签名
      • 处理退款回调通知
      • 退款状态正确更新到订单和退款记录
      • 退款金额、退款流水号等字段正确记录
      • 支持部分退款和全额退款
  4. Story 4: Mini小程序前端支付页面和流程集成 - 创建支付页面并集成支付流程

    • 修改位置:
      • mini/src/pages/payment/index.tsx - 创建支付页面
      • mini/src/pages/order-submit/index.tsx - 集成支付页面跳转
      • mini/src/pages/order-list/index.tsx - 集成"去支付"按钮功能
      • mini/src/pages/order-detail/index.tsx - 集成取消订单功能
    • 验收标准:
      • 创建完整的支付页面,支持微信支付调用
      • 订单提交页面成功跳转到支付页面
      • 订单列表页面的"去支付"按钮正常工作
      • 订单详情页面支持取消订单操作
      • 支付成功/失败有相应的页面跳转和提示
      • 复用现有的支付工具函数库
      • 实现完整的订单状态机流转
      • 支持退款失败的重试机制

Compatibility Requirements

  • 现有支付API保持不变
  • 现有订单API向后兼容
  • 数据库schema变化向后兼容
  • UI变化遵循现有模式
  • 性能影响最小化

Risk Mitigation

Primary Risk: 退款功能可能影响现有支付流程的稳定性

Mitigation: 分阶段实施,先完善支付回调,再实现退款功能

Rollback Plan: 如果出现问题,可以暂时禁用退款功能,保持现有支付流程正常工作

Definition of Done

  • Story 1完成且验收标准满足
  • Story 2完成且验收标准满足
  • 支付回调功能通过测试验证
  • 订单取消功能通过测试验证
  • 退款功能通过测试验证
  • 订单状态流转正确
  • 多租户隔离正常工作
  • 现有功能无回归

Technical Implementation Details

支付回调处理

// 支付回调接口 - 修复PaymentMtService中的TODO
class PaymentMtService {
  async handlePaymentCallback(callbackData: any, headers: any, rawBody: string): Promise<void> {
    // ... 现有验证逻辑 ...

    // 根据回调结果更新支付状态
    if (parsedData.trade_state === 'SUCCESS') {
      payment.paymentStatus = PaymentStatus.PAID;
      payment.wechatTransactionId = parsedData.transaction_id;

      // TODO: 更新订单状态 - 需要实现
      await this.updateOrderPaymentStatus(payment.tenantId, payment.externalOrderId, 2); // 支付成功
    } else if (parsedData.trade_state === 'FAIL') {
      payment.paymentStatus = PaymentStatus.FAILED;
      await this.updateOrderPaymentStatus(payment.tenantId, payment.externalOrderId, 4); // 支付失败
    } else if (parsedData.trade_state === 'REFUND') {
      payment.paymentStatus = PaymentStatus.REFUNDED;
      await this.updateOrderPaymentStatus(payment.tenantId, payment.externalOrderId, 3); // 已退款
    }

    await paymentRepository.save(payment);
  }
}

订单取消和退款

// 订单取消服务 - 需要在OrderMtService中添加
class OrderMtService {
  async cancelOrder(tenantId: number, orderId: number, reason: string, userId: number) {
    const order = await this.repository.findOne({
      where: { id: orderId, tenantId }
    });

    if (!order) {
      throw new Error('订单不存在');
    }

    // 验证订单状态
    if (order.payState !== 0 && order.payState !== 2) {
      throw new Error('该订单状态不允许取消');
    }

    if (order.payState === 2) {
      // 已支付订单,触发退款
      const paymentService = new PaymentMtService(this.dataSource);
      const refundResult = await paymentService.refund(
        tenantId,
        order.orderNo,
        order.payAmount
      );

      // 创建退款记录
      const refundService = new UserRefundsMtService(this.dataSource);
      await refundService.createUserRefund({
        orderNo: order.orderNo,
        refundOrderNo: refundResult.refund_id,
        refundAmount: order.payAmount,
        state: 1 // 退款中
      }, userId, tenantId);
    }

    // 更新订单状态
    order.payState = 5; // 订单关闭
    order.closeTime = new Date();
    order.remark = `用户取消: ${reason}`;
    order.updatedBy = userId;

    await this.repository.save(order);
  }
}

退款功能集成

// 在PaymentMtService中添加退款功能
class PaymentMtService {
  async refund(tenantId: number, orderNo: string, refundAmount: number): Promise<{
    refund_id: string;
    out_refund_no: string;
  }> {
    await this.initializeWxPay(tenantId);

    const result = await this.wxPay.refund({
      out_trade_no: orderNo,
      out_refund_no: `REFUND_${orderNo}_${Date.now()}`,
      amount: {
        refund: refundAmount,
        total: refundAmount,
        currency: 'CNY'
      }
    });

    return {
      refund_id: result.refund_id,
      out_refund_no: result.out_refund_no
    };
  }
}

订单状态机(基于现有PayStatus枚举)

  • 0未支付2支付成功 (支付成功)
  • 0未支付5订单关闭 (用户取消)
  • 2支付成功5订单关闭 (用户取消 + 退款)
  • 2支付成功3已退款 (退款成功)
  • 1支付中4支付失败 (支付失败)

支付退款流程时序图

sequenceDiagram
    participant User as 用户
    participant Mini as Mini小程序
    participant OrderAPI as 订单API
    participant PaymentAPI as 支付API
    participant WechatPay as 微信支付
    participant RefundAPI as 退款API

    %% 支付流程
    User->>Mini: 提交订单
    Mini->>OrderAPI: 创建订单
    OrderAPI-->>Mini: 返回订单ID
    Mini->>PaymentAPI: 请求支付参数
    PaymentAPI-->>Mini: 返回支付参数
    Mini->>WechatPay: 调用微信支付
    WechatPay-->>Mini: 支付结果

    %% 支付回调
    WechatPay->>PaymentAPI: 支付回调通知
    PaymentAPI->>OrderAPI: 更新订单状态(已支付)
    OrderAPI-->>PaymentAPI: 状态更新成功
    PaymentAPI-->>WechatPay: 回调响应

    %% 退款流程
    User->>Mini: 取消订单
    Mini->>OrderAPI: 请求取消订单
    OrderAPI->>RefundAPI: 发起退款
    RefundAPI->>WechatPay: 调用退款API
    WechatPay-->>RefundAPI: 退款结果
    RefundAPI->>OrderAPI: 更新订单状态(已退款)
    OrderAPI-->>Mini: 取消成功
    Mini-->>User: 显示取消结果

    %% 退款回调
    WechatPay->>RefundAPI: 退款回调通知
    RefundAPI->>OrderAPI: 确认退款状态
    OrderAPI-->>RefundAPI: 状态确认成功
    RefundAPI-->>WechatPay: 回调响应

Mini小程序前端实现

// 支付页面 - 需要创建 /pages/payment/index.tsx
class PaymentPage {
  async handlePayment(orderId: number) {
    // 1. 调用后端API获取支付参数
    const paymentParams = await orderClient['create-payment']['$post']({
      json: { orderId }
    });

    // 2. 使用现有支付工具函数调用微信支付
    const result = await requestWechatPayment(paymentParams);

    // 3. 处理支付结果
    if (result.success) {
      // 支付成功,跳转到支付成功页面
      Taro.redirectTo({ url: '/pages/payment-success/index' });
    } else {
      // 支付失败,显示错误信息
      Taro.showToast({ title: result.message, icon: 'none' });
    }
  }
}

// 订单详情页面 - 集成取消订单功能
class OrderDetailPage {
  async handleCancelOrder(orderId: number, reason: string) {
    try {
      // 调用后端取消订单API
      await orderClient['cancel-order']['$post']({
        json: { orderId, reason }
      });

      Taro.showToast({ title: '订单取消成功', icon: 'success' });
      // 刷新页面或返回订单列表
    } catch (error) {
      Taro.showToast({ title: error.message, icon: 'none' });
    }
  }
}

Validation Checklist

Scope Validation

  • Epic可以在5个故事内完成
  • 不需要架构文档
  • 增强遵循现有模式
  • 集成复杂度可控

Risk Assessment

  • 对现有系统风险可控
  • 回滚计划可行
  • 测试方法覆盖现有功能
  • 团队对集成点有足够了解

Completeness Check

  • Epic目标清晰可实现
  • 故事范围适当
  • 成功标准可衡量
  • 依赖项已识别

Story Manager Handoff:

"请为这个棕地史诗开发详细的用户故事。关键考虑因素:

  • 这是对运行TypeORM + PostgreSQL + Hono + Redis + @d8d/shared-crud的多租户系统的增强
  • 核心简化: 复用多租户支付模块和订单模块,扩展退款功能
  • Mini小程序前端: 已有订单提交、列表、详情页面和支付工具函数,需要添加支付页面和集成支付流程
  • 集成点:多租户支付模块的PaymentMtService、多租户订单模块的OrderMtService、多租户退款模块的UserRefundsMtService、多租户系统配置模块的SystemConfigServiceMt、微信支付SDK、Mini小程序前端
  • 要遵循的现有模式:多租户支付模块的支付流程、多租户订单模块的CRUD模式、多租户实体模式、Mini小程序前端架构
  • 关键兼容性要求:现有支付API保持不变,订单API向后兼容,Mini小程序现有页面功能无影响
  • 每个故事必须包括验证现有功能保持完整的验证
  • 特别注意:支付模块中已有TODO需要更新订单状态,需要实现
  • Mini小程序前端关键点:
    • 订单提交页面(mini/src/pages/order-submit/index.tsx)需要集成支付页面跳转
    • 订单列表页面(mini/src/pages/order-list/index.tsx)的"去支付"按钮需要集成支付功能
    • 需要创建支付页面(mini/src/pages/payment/index.tsx
    • 订单详情页面(mini/src/pages/order-detail/index.tsx)需要集成取消订单功能
    • 复用现有的支付工具函数库(mini/src/utils/payment.ts

该史诗应在保持系统完整性的同时交付完整的支付退款流程功能。"

Epic Completion Summary

Story 1 完成情况总结

  • 支付回调处理逻辑 - 完全实现并通过所有测试
  • 多租户数据隔离 - 验证通过,不同租户支付回调互不影响
  • 订单状态同步 - 支付成功/失败/退款状态正确更新到订单
  • 日志记录 - 完整的调试日志记录,便于问题排查
  • 测试覆盖 - 7个集成测试全部通过,覆盖各种场景

Story 2 完成情况总结

  • 订单取消功能 - 完全实现并通过所有测试
  • 订单状态验证 - 仅允许取消"待支付"和"已支付"订单
  • 退款流程集成 - 已支付订单触发退款流程占位符
  • 多租户数据隔离 - 验证通过,不同租户订单数据完全隔离
  • 用户权限验证 - 用户只能取消自己的订单
  • 测试覆盖 - 12个集成测试全部通过,覆盖各种场景

技术实现亮点

  1. 实体元数据修复 - 解决了DeliveryAddressMt、UserEntityMt、AreaEntityMt等实体的依赖问题
  2. 模块导入优化 - 确保多租户版本正确导入,避免路径冲突
  3. 测试数据工厂 - 创建了PaymentTestFactory和OrdersTestFactory简化测试数据创建
  4. 回调数据处理 - 修复了商户订单号获取顺序和订单状态更新逻辑
  5. 多租户隔离验证 - 通过特定回调数据确保租户间数据完全隔离
  6. TypeScript类型安全 - 修复了测试工厂中的字段定义错误,确保类型安全
  7. API响应验证 - 使用parseWithAwait确保API响应格式与Schema一致

下一步计划

  • Story 3: 集成微信支付退款功能,调用微信支付SDK实现退款
  • Story 4: Mini小程序前端支付页面和流程集成