# 史诗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:创建多租户信用额度模块 **作为** 系统管理员 **我希望** 能够管理用户的信用额度 **以便** 控制用户的支付权限和风险 **验收标准:** - [x] 创建`credit_balance_mt`表,包含租户ID、用户ID、总额度、已用额度、可用额度等字段 - [x] 创建`credit_balance_log_mt`表,记录额度变更历史 - [x] 实现额度管理服务,包含设置额度、扣减额度、查询余额等方法 - [x] 提供额度查询和管理的API接口 - [x] 添加数据库迁移脚本(注:迁移脚本在server包集成模块时创建,不在模块包中创建) - [x] 编写单元测试覆盖核心逻辑 **实现状态**:✅ 已完成 **完成时间**:2025-12-02 **实现详情**: - 创建了完整的多租户信用额度模块包:`@d8d/credit-balance-module-mt` - 实现了两个实体:`CreditBalanceMt`(信用额度实体)和`CreditBalanceLogMt`(额度变更记录实体) - 实现了完整的额度管理服务:`CreditBalanceService`,包含设置额度、调整额度、扣减额度、恢复额度等方法 - 实现了6个API接口:查询额度、设置额度、调整额度、查询变更记录、额度支付、结账恢复额度 - 编写了13个单元测试用例和11个集成测试用例,测试通过率100% - 修复了多个技术问题:PostgreSQL类型兼容性、路由架构重构、测试认证问题、小数精度问题等 ### 故事2:创建多租户信用额度管理UI模块 **作为** 后台管理员 **我希望** 有一个界面来管理用户信用额度 **以便** 方便地设置和调整用户额度 **验收标准:** - [x] 创建用户额度管理对话框组件,显示单个用户的当前额度信息 - [x] 实现额度设置和调整功能 - [x] 提供额度使用记录查询界面 - [x] 显示用户欠款统计信息 - [x] 界面风格与现有后台保持一致 - [x] 添加权限控制,只有管理员可访问 - [x] 组件支持通过props传入用户ID和用户信息 - [x] 组件可独立导出,供用户管理UI包集成使用 **实现状态**:✅ 已完成 **完成时间**:2025-12-04 **实现详情**: - 创建了完整的多租户信用额度管理UI模块包:`@d8d/credit-balance-management-ui-mt` - 实现了对话框组件模式:`CreditBalanceDialog`,包含三个标签页(额度概览、额度操作、变更记录) - 实现了完整的API客户端:基于Hono RPC的`creditBalanceClient.ts`,支持多租户上下文 - 实现了所有功能:额度查询、设置、调整、恢复、记录查询、欠款统计 - 集成了权限控制:只有管理员角色可以访问额度管理功能 - 集成了用户管理UI包:在用户管理界面中添加信用额度管理按钮和对话框 - 编写了6个集成测试用例,测试通过率100% - 修复了多个技术问题:表单验证中文错误消息、Zod类型转换、测试调试、UI集成等 ### 故事3:集成额度支付到现有支付流程 **作为** 小程序用户 **我希望** 可以使用信用额度进行支付 **以便** 在余额不足时也能完成购买 **验收标准:** - [ ] 在支付页面增加"额度支付"选项 - [ ] 实现额度支付订单处理逻辑 - [ ] 额度为0的用户无法使用额度支付 - [ ] 支付成功后更新用户已用额度和可用额度 - [ ] 实现额度恢复机制: - [ ] 结账时恢复相应额度(订单完成) - [ ] 取消订单时恢复全额额度 - [ ] 退款时恢复相应额度 - [ ] 在小程序个人中心显示累计欠款 - [ ] 确保与现有微信支付流程并行工作,互不干扰 ## 技术设计 ### 数据库设计 ```sql -- 用户信用额度表 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. **事务处理**:额度扣减和恢复操作使用数据库事务确保数据一致性