epic-004-credit-payment.md 19 KB

史诗004:新增记账(信用额度支付)功能

概述

为多租户电商平台新增信用额度支付功能,允许后台为特定用户设置信用额度,用户可使用额度进行支付,并在小程序个人中心显示累计欠款,与现有微信支付流程并行工作。

业务背景

当前系统仅支持微信支付,缺乏灵活的支付方式。为提升用户体验和业务灵活性,需要引入信用额度支付功能,允许特定用户(如VIP用户、企业用户)使用信用额度进行支付,后台可灵活管理额度。

目标

  1. 新增信用额度支付方式,与现有微信支付流程并行
  2. 后台可设置和查看用户信用额度(用户不可见)
  3. 未授权用户额度为0,点击额度支付无效
  4. 小程序个人中心显示累计欠款信息
  5. 实现多租户余额模块和余额管理UI模块

范围

包含的功能

  1. 多租户余额模块 (credit-balance-module-mt)

    • 余额实体设计(用户额度、已用额度、可用额度)
    • 额度变更记录实体
    • 额度管理服务(设置额度、扣减额度、恢复额度、查询余额)
    • 额度支付API接口
    • 额度恢复API接口(结账、取消订单、退款)
  2. 多租户余额管理UI模块 (credit-balance-management-ui-mt)

    • 用户额度管理界面
    • 额度设置和调整功能
    • 额度使用记录查询
    • 欠款统计和报表
  3. 支付流程集成

    • 扩展支付选项,增加"额度支付"
    • 额度支付订单处理逻辑
    • 额度检查和验证机制
    • 额度恢复机制(结账、取消订单、退款)
    • 小程序个人中心欠款显示

不包含的功能

  1. 额度自动审批和风控系统
  2. 额度利息计算和催收功能
  3. 额度分期还款功能
  4. 额度提现功能

用户故事

故事1:创建多租户信用额度模块

作为 系统管理员 我希望 能够管理用户的信用额度 以便 控制用户的支付权限和风险

验收标准:

  • 创建credit_balance_mt表,包含租户ID、用户ID、总额度、已用额度、可用额度等字段
  • 创建credit_balance_log_mt表,记录额度变更历史
  • 实现额度管理服务,包含设置额度、扣减额度、查询余额等方法
  • 提供额度查询和管理的API接口
  • 添加数据库迁移脚本(注:迁移脚本在server包集成模块时创建,不在模块包中创建)
  • 编写单元测试覆盖核心逻辑

实现状态:✅ 已完成 完成时间:2025-12-02 实现详情

  • 创建了完整的多租户信用额度模块包:@d8d/credit-balance-module-mt
  • 实现了两个实体:CreditBalanceMt(信用额度实体)和CreditBalanceLogMt(额度变更记录实体)
  • 实现了完整的额度管理服务:CreditBalanceService,包含设置额度、调整额度、扣减额度、恢复额度等方法
  • 实现了6个API接口:查询额度、设置额度、调整额度、查询变更记录、额度支付、结账恢复额度
  • 编写了13个单元测试用例和11个集成测试用例,测试通过率100%
  • 修复了多个技术问题:PostgreSQL类型兼容性、路由架构重构、测试认证问题、小数精度问题等

故事2:创建多租户信用额度管理UI模块

作为 后台管理员 我希望 有一个界面来管理用户信用额度 以便 方便地设置和调整用户额度

验收标准:

  • 创建用户额度管理对话框组件,显示单个用户的当前额度信息
  • 实现额度设置和调整功能
  • 提供额度使用记录查询界面
  • 显示用户欠款统计信息
  • 界面风格与现有后台保持一致
  • 添加权限控制,只有管理员可访问
  • 组件支持通过props传入用户ID和用户信息
  • 组件可独立导出,供用户管理UI包集成使用

实现状态:✅ 已完成 完成时间:2025-12-04 实现详情

  • 创建了完整的多租户信用额度管理UI模块包:@d8d/credit-balance-management-ui-mt
  • 实现了对话框组件模式:CreditBalanceDialog,包含三个标签页(额度概览、额度操作、变更记录)
  • 实现了完整的API客户端:基于Hono RPC的creditBalanceClient.ts,支持多租户上下文
  • 实现了所有功能:额度查询、设置、调整、恢复、记录查询、欠款统计
  • 集成了权限控制:只有管理员角色可以访问额度管理功能
  • 集成了用户管理UI包:在用户管理界面中添加信用额度管理按钮和对话框
  • 编写了6个集成测试用例,测试通过率100%
  • 修复了多个技术问题:表单验证中文错误消息、Zod类型转换、测试调试、UI集成等

故事3:集成额度支付到现有支付流程

作为 小程序用户 我希望 可以使用信用额度进行支付 以便 在余额不足时也能完成购买

验收标准:

  • 在支付页面增加"额度支付"选项
  • 实现额度支付订单处理逻辑
  • 额度为0的用户无法使用额度支付
  • 支付成功后更新用户已用额度和可用额度
  • 实现额度恢复机制:
    • 结账时恢复相应额度(订单完成)
    • 取消订单时恢复全额额度
    • 退款时恢复相应额度
  • 在小程序个人中心显示累计欠款
  • 确保与现有微信支付流程并行工作,互不干扰

技术设计

数据库设计

-- 用户信用额度表
CREATE TABLE credit_balance_mt (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  tenant_id INT UNSIGNED NOT NULL COMMENT '租户ID',
  user_id INT UNSIGNED NOT NULL COMMENT '用户ID',
  total_limit DECIMAL(10,2) DEFAULT 0.00 COMMENT '总额度',
  used_amount DECIMAL(10,2) DEFAULT 0.00 COMMENT '已用额度',
  available_amount DECIMAL(10,2) GENERATED ALWAYS AS (total_limit - used_amount) STORED COMMENT '可用额度',
  is_enabled TINYINT DEFAULT 1 COMMENT '是否启用(0:禁用,1:启用)',
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY uk_tenant_user (tenant_id, user_id),
  INDEX idx_tenant_id (tenant_id),
  INDEX idx_user_id (user_id)
) COMMENT='用户信用额度表';

-- 额度变更记录表
CREATE TABLE credit_balance_log_mt (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  tenant_id INT UNSIGNED NOT NULL COMMENT '租户ID',
  user_id INT UNSIGNED NOT NULL COMMENT '用户ID',
  change_type VARCHAR(20) NOT NULL COMMENT '变更类型: SET_LIMIT(设置额度), PAYMENT(支付扣减), CHECKOUT(结账恢复), CANCEL_ORDER(取消订单恢复), REFUND(退款恢复), ADJUST(调整额度)',
  change_amount DECIMAL(10,2) NOT NULL COMMENT '变更金额(正数表示增加额度,负数表示减少额度)',
  before_total DECIMAL(10,2) COMMENT '变更前总额度',
  after_total DECIMAL(10,2) COMMENT '变更后总额度',
  before_used DECIMAL(10,2) COMMENT '变更前已用额度',
  after_used DECIMAL(10,2) COMMENT '变更后已用额度',
  reference_id VARCHAR(100) COMMENT '关联ID(订单号等)',
  remark VARCHAR(500) COMMENT '备注',
  operator_id INT UNSIGNED COMMENT '操作人ID',
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  INDEX idx_tenant_user (tenant_id, user_id),
  INDEX idx_reference (reference_id),
  INDEX idx_created (created_at)
) COMMENT='额度变更记录表';

迁移脚本说明: 根据项目架构,TypeORM迁移脚本应在server包集成@d8d/credit-balance-module-mt模块时创建,而不是在模块包中创建。模块包只包含实体定义,迁移脚本由使用该模块的应用层(server包)负责创建和管理。

模块结构

packages/
├── @d8d/credit-balance-module-mt/     # 多租户余额模块
│   ├── src/
│   │   ├── entities/                  # 实体定义
│   │   │   ├── credit-balance.mt.entity.ts
│   │   │   └── credit-balance-log.mt.entity.ts
│   │   │   └── index.ts
│   │   ├── services/                  # 服务层
│   │   │   ├── credit-balance.service.ts
│   │   │   └── index.ts
│   │   ├── schemas/                   # 数据验证
│   │   │   └── index.ts
│   │   ├── routes/                    # API路由
│   │   │   └── index.ts
│   │   ├── types/                     # 类型定义
│   │   │   └── index.ts
│   │   └── index.ts                   # 主入口文件
│   ├── tests/                         # 测试文件
│   ├── tsconfig.json                  # TypeScript配置
│   ├── vitest.config.ts               # 测试配置
│   └── package.json
└── @d8d/credit-balance-management-ui-mt/   # 余额管理UI模块
    ├── src/
    │   ├── api/                       # API客户端
    │   │   ├── index.ts
    │   │   └── creditBalanceClient.ts
    │   ├── components/                # 组件
    │   │   ├── CreditBalanceManagement.tsx
    │   │   └── index.ts
    │   ├── hooks/                     # React hooks
    │   │   └── index.ts
    │   ├── types/                     # 类型定义
    │   │   ├── index.ts
    │   │   └── creditBalance.ts
    │   └── index.ts                   # 主入口文件
    ├── tests/                         # 测试文件
    ├── eslint.config.js               # ESLint配置
    ├── tsconfig.json                  # TypeScript配置
    ├── vitest.config.ts               # 测试配置
    └── package.json

API设计

对外API(供UI调用)

  1. GET /api/credit-balance/{userId} - 查询用户额度
  2. PUT /api/credit-balance/{userId} - 设置用户额度
  3. POST /api/credit-balance/{userId}/adjust - 调整用户额度
  4. GET /api/credit-balance/{userId}/logs - 查询额度变更记录
  5. POST /api/credit-balance/payment - 额度支付
  6. POST /api/credit-balance/checkout - 结账恢复额度(供信用管理UI调用)

服务接口(供其他模块调用)

  1. CreditBalanceService.restoreBalanceForCancelOrder(orderId, userId, amount) - 取消订单恢复额度
  2. CreditBalanceService.restoreBalanceForRefund(orderId, userId, refundAmount) - 退款恢复额度

设计说明:

  • 结账恢复:需要人工确认,因此通过信用管理UI手动触发,调用/api/credit-balance/checkout接口
  • 取消订单恢复:自动触发,订单模块在取消订单时直接调用CreditBalanceService.restoreBalanceForCancelOrder()方法
  • 退款恢复:自动触发,支付模块在退款处理时直接调用CreditBalanceService.restoreBalanceForRefund()方法
  • 模块间调用:使用PNPM工作空间,通过@d8d/credit-balance-module-mt包名导入服务类进行直接调用

集成点

与现有系统集成

  1. 用户模块集成:通过user_id关联用户信息
  2. 订单模块集成
    • 扩展orders_mt表的pay_type字段,新增额度支付类型
    • 订单模块导入@d8d/credit-balance-module-mt包,直接调用CreditBalanceService.restoreBalanceForCancelOrder()方法处理取消订单时的额度恢复
  3. 支付模块集成
    • @d8d/mini-payment-mt中新增额度支付处理逻辑
    • 支付模块导入@d8d/credit-balance-module-mt包,直接调用CreditBalanceService.restoreBalanceForRefund()方法处理退款时的额度恢复
  4. 信用管理UI集成
    • 信用管理UI调用额度模块的/api/credit-balance/checkout接口处理结账时的额度恢复
  5. 小程序集成:更新支付页面和个人中心页面

数据流

正向流程(支付扣减)

  1. 后台管理员设置用户额度 → 更新credit_balance_mt
  2. 用户选择额度支付 → 检查可用额度 → 创建订单 → 扣减额度
  3. 支付成功 → 更新订单状态 → 记录额度变更日志(PAYMENT类型)
  4. 小程序查询欠款 → 调用额度查询接口 → 显示欠款信息

反向流程(额度恢复)

  1. 结账恢复:订单完成结账 → 信用管理UI调用/api/credit-balance/checkout → 恢复相应额度 → 记录日志(CHECKOUT类型)
  2. 取消订单恢复:用户取消订单 → 订单模块调用CreditBalanceService.restoreBalanceForCancelOrder() → 恢复全额额度 → 记录日志(CANCEL_ORDER类型)
  3. 退款恢复:管理员处理退款 → 支付模块调用CreditBalanceService.restoreBalanceForRefund() → 恢复相应额度 → 记录日志(REFUND类型)

额度恢复逻辑

恢复场景定义

  1. 结账恢复(CHECKOUT)

    • 触发条件:订单完成所有流程,用户确认收货
    • 恢复金额:订单实际支付金额
    • 业务意义:订单交易完成,额度占用解除
    • 实现方式:信用管理UI手动触发,调用/api/credit-balance/checkout接口
  2. 取消订单恢复(CANCEL_ORDER)

    • 触发条件:用户在支付后、发货前取消订单
    • 恢复金额:订单全额支付金额
    • 业务意义:交易未发生,全额恢复额度
    • 实现方式:订单模块在取消订单时自动调用CreditBalanceService.restoreBalanceForCancelOrder()方法
  3. 退款恢复(REFUND)

    • 触发条件:管理员处理用户退款申请
    • 恢复金额:实际退款金额(可能部分退款)
    • 业务意义:交易撤销,按退款金额恢复额度
    • 实现方式:支付模块在退款处理时自动调用CreditBalanceService.restoreBalanceForRefund()方法

恢复规则

  1. 幂等性保证:同一订单只能恢复一次额度,防止重复恢复
  2. 金额验证:恢复金额不能超过原支付金额
  3. 状态检查:只有特定订单状态才能触发恢复
  4. 日志记录:每次恢复都记录详细的变更日志
  5. 事务处理:额度恢复与订单状态更新在同一事务中

兼容性要求

  1. API兼容性:新增API端点,不影响现有API
  2. 数据库兼容性:新增表,不影响现有表结构
  3. UI兼容性:新增页面和组件,遵循现有UI规范
  4. 支付流程兼容性:额度支付与微信支付并行,互不干扰

风险与缓解

风险1:额度支付逻辑错误导致财务数据不一致

  • 缓解措施:使用数据库事务处理额度扣减和订单创建
  • 验证机制:添加额度检查和余额验证
  • 监控:记录详细的额度变更日志

风险2:额度被恶意使用

  • 缓解措施:后台控制额度启用状态,默认禁用
  • 权限控制:只有管理员可设置和调整额度
  • 额度限制:设置单次支付和累计欠款上限

风险3:额度恢复逻辑错误导致额度重复恢复

  • 缓解措施:实现幂等性检查,同一订单只能恢复一次
  • 验证机制:添加恢复前状态检查,防止重复恢复
  • 日志审计:详细记录每次恢复操作,便于审计追踪

风险4:影响现有支付流程

  • 缓解措施:额度支付作为可选功能,默认不启用
  • 测试策略:充分测试与现有支付流程的兼容性
  • 回滚计划:可禁用额度支付功能,恢复原有流程

测试策略

单元测试

  • 额度计算逻辑测试
  • 额度扣减和恢复测试
  • 额度验证测试
  • 额度恢复场景测试:
    • 结账恢复额度测试
    • 取消订单恢复额度测试
    • 退款恢复额度测试

集成测试

  • 额度支付流程测试
  • 额度恢复流程测试:
    • 结账时额度恢复测试
    • 取消订单时额度恢复测试
    • 退款时额度恢复测试
  • 与订单模块集成测试
  • 与用户模块集成测试

E2E测试

  • 后台额度管理流程测试
  • 小程序额度支付流程测试
  • 额度恢复场景测试:
    • 结账后额度恢复验证
    • 取消订单后额度恢复验证
    • 退款后额度恢复验证
  • 欠款显示功能测试

部署计划

阶段1:开发环境部署

  1. 创建数据库迁移脚本
  2. 部署余额模块和UI模块
  3. 配置额度支付功能(默认禁用)

阶段2:测试环境验证

  1. 功能测试和集成测试
  2. 性能测试和压力测试
  3. 安全测试和权限测试

阶段3:生产环境部署

  1. 执行数据库迁移
  2. 部署新模块
  3. 灰度启用额度支付功能
  4. 监控系统运行状态

成功指标

  1. 功能指标

    • 后台可成功设置和调整用户额度
    • 用户可使用额度完成支付
    • 额度恢复功能正常工作:
      • 结账时正确恢复额度
      • 取消订单时正确恢复额度
      • 退款时正确恢复额度
    • 小程序正确显示欠款信息
    • 额度为0的用户无法使用额度支付
  2. 性能指标

    • 额度查询响应时间 < 100ms
    • 额度支付处理时间 < 500ms
    • 系统可用性 > 99.9%
  3. 业务指标

    • 额度支付成功率 > 95%
    • 用户满意度提升
    • 支付方式多样性增加

后续优化建议

  1. 额度自动审批流程
  2. 额度风控和预警系统
  3. 额度分期和还款功能
  4. 额度提现和转账功能
  5. 额度积分和奖励机制

创建时间:2025-12-01 负责人:产品经理 状态:进行中(故事1、故事2已完成) 优先级:高

开发进度

已完成

  1. 故事1:创建多租户信用额度模块(2025-12-02完成)

    • 创建了完整的多租户信用额度模块包:@d8d/credit-balance-module-mt
    • 实现了所有核心功能:实体、服务、API接口、测试
    • 测试通过率100%,代码质量符合项目标准
  2. 故事2:创建多租户信用额度管理UI模块(2025-12-04完成)

    • 创建了完整的多租户信用额度管理UI模块包:@d8d/credit-balance-management-ui-mt
    • 实现了对话框组件模式:CreditBalanceDialog,包含三个标签页(额度概览、额度操作、变更记录)
    • 实现了完整的API客户端:基于Hono RPC的creditBalanceClient.ts,支持多租户上下文
    • 实现了所有功能:额度查询、设置、调整、恢复、记录查询、欠款统计
    • 集成了权限控制:只有管理员角色可以访问额度管理功能
    • 集成了用户管理UI包:在用户管理界面中添加信用额度管理按钮和对话框
    • 编写了6个集成测试用例,测试通过率100%
    • 修复了多个技术问题:表单验证中文错误消息、Zod类型转换、测试调试、UI集成等

待完成

  1. 🔄 故事3:集成额度支付到现有支付流程

技术实现亮点

  1. 多租户架构:严格遵循项目多租户包架构模式,使用-mt后缀和租户ID隔离
  2. 路由架构:参照订单模块采用链式聚合模式,支持RPC风格API调用
  3. 测试策略:使用测试数据工厂模式,真实JWT令牌认证,确保测试可靠性
  4. 错误处理:完整的OpenAPI错误响应定义,符合项目标准
  5. 数据库设计:PostgreSQL兼容性优化,解决tinyint类型和decimal精度问题
  6. 事务处理:额度扣减和恢复操作使用数据库事务确保数据一致性