docs: 更新 OpenAPI 文档及提案任务清单,新增 payment_voucher_key 字段
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m26s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m26s
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-04-17
|
||||
57
openspec/changes/agent-recharges-payment-voucher/design.md
Normal file
57
openspec/changes/agent-recharges-payment-voucher/design.md
Normal file
@@ -0,0 +1,57 @@
|
||||
## Context
|
||||
|
||||
`POST /api/admin/agent-recharges` 是平台管理员为代理商创建线下充值订单的接口。当 `payment_method=offline` 时,代表平台已收到代理商的线下转账,此时应同步录入支付凭证(如银行转账截图的对象存储 key),以便后续对账审计。
|
||||
|
||||
充值流程分两个阶段:
|
||||
1. **创建阶段**(`POST /api/admin/agent-recharges`):平台录入充值单 + 上传凭证
|
||||
2. **确认阶段**(`POST /api/admin/agent-recharges/:id/offline-pay`):财务二次确认,凭证已在创建时录入,无需重复上传
|
||||
|
||||
凭证文件本身通过已有的 `/storage/upload-url` 预签名 URL 上传至对象存储(OSS),后端仅存储 `file_key`。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- `Create` 接口在 `payment_method=offline` 时强制要求传入 `payment_voucher_key`
|
||||
- 凭证 key 随充值记录一起写入数据库
|
||||
- 响应 DTO 返回凭证 key 供前端展示
|
||||
- `OfflinePay` 接口不做任何凭证相关改动
|
||||
|
||||
**Non-Goals:**
|
||||
- 不涉及文件上传本身(OSS 预签名链路已有)
|
||||
- 不修改 `OfflinePay` 接口(财务确认流程独立于凭证管理)
|
||||
- 不做凭证有效性验证(文件是否真实存在于 OSS)
|
||||
- `payment_method=wechat` 时 `payment_voucher_key` 无需传,应忽略
|
||||
|
||||
## Decisions
|
||||
|
||||
### 决策1:凭证在创建时收集,而非确认时
|
||||
|
||||
**选择**:在 `Create` 时收集凭证,因为平台管理员在录入线下充值单时就已持有转账凭证。
|
||||
|
||||
**理由**:线下充值的业务含义是"平台已收到转账,现在录入系统"。凭证是这次录入的必要信息。`OfflinePay` 是财务的二次确认操作,凭证应已在录入时保存,财务只负责审核确认。
|
||||
|
||||
### 决策2:字段命名与 orders 保持一致
|
||||
|
||||
**选择**:使用 `payment_voucher_key`,与 `order.payment_voucher_key` 完全一致。
|
||||
|
||||
**理由**:统一命名降低认知负担,前端可复用同一组件。
|
||||
|
||||
### 决策3:`wechat` 支付方式时字段可选
|
||||
|
||||
**选择**:`payment_voucher_key` 使用 `validate:"omitempty,max=500"`,仅在 Service 层对 `offline` 方式做非空校验。
|
||||
|
||||
**理由**:微信在线支付无需凭证,不应因为加了字段就破坏微信支付的调用契约。
|
||||
|
||||
### 决策4:凭证随 Create 直接写入
|
||||
|
||||
**选择**:在 `Create` 方法构建 `AgentRechargeRecord` 时直接赋值 `PaymentVoucherKey`,与记录创建同一个 `agentRechargeStore.Create()` 调用写入。
|
||||
|
||||
**理由**:凭证是充值记录的组成部分,不需要单独事务,最简路径。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
**[风险] 历史记录无凭证**
|
||||
→ 历史已创建的线下充值记录 `payment_voucher_key` 为空,属正常情况,不补录。
|
||||
|
||||
**[风险] 数据库迁移**
|
||||
→ 新列 `VARCHAR(500)` 允许 NULL(兼容历史数据),新接口 Service 层对 `offline` 方式强制非空。迁移简单,无需锁表。
|
||||
32
openspec/changes/agent-recharges-payment-voucher/proposal.md
Normal file
32
openspec/changes/agent-recharges-payment-voucher/proposal.md
Normal file
@@ -0,0 +1,32 @@
|
||||
## Why
|
||||
|
||||
`/api/admin/agent-recharges` 线下充值确认接口(`OfflinePay`)未要求上传支付凭证,而同类的 `/api/admin/orders` 线下支付已强制上传凭证。两个业务场景均涉及线下资金流转,审计和对账需要同等的凭证留存能力。
|
||||
|
||||
## What Changes
|
||||
|
||||
- `CreateAgentRechargeRequest` DTO 新增 `payment_voucher_key` 字段(`payment_method=offline` 时必填)
|
||||
- `AgentRechargeResponse` DTO 新增 `payment_voucher_key` 响应字段
|
||||
- `AgentRechargeRecord` Model 新增 `payment_voucher_key` 数据库列
|
||||
- `Create` Service 方法新增:当 `payment_method=offline` 时校验凭证非空,并将凭证写入充值记录
|
||||
- 数据库迁移:`tb_agent_recharge_record` 表新增 `payment_voucher_key` 列
|
||||
- `OfflinePay` 接口不涉及凭证(财务确认流程,凭证已在创建时录入)
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `agent-recharge-payment-voucher`:代理充值线下支付凭证上传与存储能力,对齐 orders 接口的凭证管理标准
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
(无已有 spec 变更)
|
||||
|
||||
## Impact
|
||||
|
||||
| 层级 | 文件 | 变更类型 |
|
||||
|------|------|---------|
|
||||
| DTO | `internal/model/dto/agent_recharge_dto.go` | `CreateAgentRechargeRequest` + `AgentRechargeResponse` 新增字段 |
|
||||
| Model | `internal/model/agent_wallet.go` | `AgentRechargeRecord` 新增字段 |
|
||||
| Service | `internal/service/agent_recharge/service.go` | `Create` 方法新增校验与保存逻辑 |
|
||||
| DB | `migrations/` | 新增迁移文件 |
|
||||
| Handler | `internal/handler/admin/agent_recharge.go` | 无需改动(透传) |
|
||||
@@ -0,0 +1,43 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 创建线下充值订单时必须上传支付凭证
|
||||
|
||||
系统 SHALL 在 `POST /api/admin/agent-recharges` 接口中,当 `payment_method=offline` 时强制要求 `payment_voucher_key` 字段非空。凭证 key 为通过 `/storage/upload-url` 上传至对象存储后获得的文件标识符。当 `payment_method=wechat` 时,`payment_voucher_key` 字段忽略。
|
||||
|
||||
#### Scenario: 线下支付缺少凭证时拒绝创建
|
||||
|
||||
- **WHEN** 调用 `POST /api/admin/agent-recharges`,`payment_method=offline` 且 `payment_voucher_key` 为空或未传
|
||||
- **THEN** 系统返回 400,错误码 `CodeInvalidParam`,消息"线下充值必须上传支付凭证"
|
||||
|
||||
#### Scenario: 线下支付有凭证时创建成功
|
||||
|
||||
- **WHEN** 调用 `POST /api/admin/agent-recharges`,`payment_method=offline` 且 `payment_voucher_key` 非空
|
||||
- **THEN** 系统创建充值记录,凭证 key 写入 `tb_agent_recharge_record.payment_voucher_key`,返回 200
|
||||
|
||||
#### Scenario: 微信支付不需要凭证
|
||||
|
||||
- **WHEN** 调用 `POST /api/admin/agent-recharges`,`payment_method=wechat`,不传 `payment_voucher_key`
|
||||
- **THEN** 系统正常创建充值记录,不做凭证校验,返回 200
|
||||
|
||||
### Requirement: 充值记录存储支付凭证
|
||||
|
||||
系统 SHALL 将 `payment_voucher_key` 持久化到 `tb_agent_recharge_record` 表的 `payment_voucher_key` 列,与充值记录创建在同一个数据库操作内完成。
|
||||
|
||||
#### Scenario: 凭证随记录创建写入
|
||||
|
||||
- **WHEN** `Create` 方法执行创建充值记录
|
||||
- **THEN** `payment_voucher_key` 与其他字段一同写入数据库,不可分割
|
||||
|
||||
### Requirement: 充值记录响应包含凭证信息
|
||||
|
||||
系统 SHALL 在 `AgentRechargeResponse` 中返回 `payment_voucher_key` 字段,允许为空(历史记录及微信支付无凭证)。
|
||||
|
||||
#### Scenario: 已上传凭证的线下充值记录查询
|
||||
|
||||
- **WHEN** 查询已创建的线下充值记录
|
||||
- **THEN** 响应 `payment_voucher_key` 字段返回非空的对象存储 key
|
||||
|
||||
#### Scenario: 微信支付记录无凭证字段
|
||||
|
||||
- **WHEN** 查询微信支付的充值记录
|
||||
- **THEN** 响应 `payment_voucher_key` 字段为空字符串或 omitempty(前端不展示)
|
||||
32
openspec/changes/agent-recharges-payment-voucher/tasks.md
Normal file
32
openspec/changes/agent-recharges-payment-voucher/tasks.md
Normal file
@@ -0,0 +1,32 @@
|
||||
## 1. 数据库迁移
|
||||
|
||||
- [x] 1.1 在 `migrations/` 目录创建迁移文件,为 `tb_agent_recharge_record` 表添加 `payment_voucher_key VARCHAR(500)` 列(允许 NULL,兼容历史数据)
|
||||
- [x] 1.2 执行迁移,验证 `tb_agent_recharge_record` 表已包含 `payment_voucher_key` 列(使用 PostgreSQL MCP 查询 `information_schema.columns` 确认)
|
||||
|
||||
## 2. Model 层
|
||||
|
||||
- [x] 2.1 在 `internal/model/agent_wallet.go` 的 `AgentRechargeRecord` 结构体中添加 `PaymentVoucherKey string` 字段,包含 gorm tag 和中文注释
|
||||
- [x] 2.2 运行 `lsp_diagnostics` 确认 `agent_wallet.go` 无错误
|
||||
|
||||
## 3. DTO 层
|
||||
|
||||
- [x] 3.1 在 `internal/model/dto/agent_recharge_dto.go` 的 `CreateAgentRechargeRequest` 中添加 `PaymentVoucherKey` 字段(`validate:"omitempty,max=500"`,含 description 标签,注明 `payment_method=offline` 时必填)
|
||||
- [x] 3.2 在 `AgentRechargeResponse` 中添加 `PaymentVoucherKey` 响应字段(`omitempty`)
|
||||
- [x] 3.3 运行 `lsp_diagnostics` 确认 `agent_recharge_dto.go` 无错误
|
||||
|
||||
## 4. Service 层
|
||||
|
||||
- [x] 4.1 在 `internal/service/agent_recharge/service.go` 的 `Create` 方法中,在支付方式判断逻辑后添加凭证非空检查:当 `req.PaymentMethod == "offline"` 且 `strings.TrimSpace(req.PaymentVoucherKey) == ""` 时返回 `errors.New(errors.CodeInvalidParam, "线下充值必须上传支付凭证")`
|
||||
- [x] 4.2 在 `Create` 方法构建 `AgentRechargeRecord` 的赋值块中添加 `PaymentVoucherKey: strings.TrimSpace(req.PaymentVoucherKey)` 字段
|
||||
- [x] 4.3 在 `toResponse`(或等价的响应构建函数)中将 `record.PaymentVoucherKey` 映射到 `AgentRechargeResponse.PaymentVoucherKey`
|
||||
- [x] 4.4 运行 `lsp_diagnostics` 确认 `agent_recharge/service.go` 无错误
|
||||
|
||||
## 5. 文档生成器更新
|
||||
|
||||
- [x] 5.1 检查 `cmd/api/docs.go` 和 `cmd/gendocs/main.go` 中 `AgentRechargeHandler` 的注册方式(本次未新增 Handler,仅修改已有请求体,确认无需额外改动)
|
||||
|
||||
## 6. 接口验证
|
||||
|
||||
- [x] 6.1 调用 `POST /api/admin/agent-recharges`(`payment_method=offline`,不传凭证),验证返回 400"线下充值必须上传支付凭证"
|
||||
- [x] 6.2 调用 `POST /api/admin/agent-recharges`(`payment_method=offline`,传入合法凭证 key),验证返回 200,使用 PostgreSQL MCP 查询 `tb_agent_recharge_record` 确认 `payment_voucher_key` 字段已写入正确值
|
||||
- [x] 6.3 调用 `POST /api/admin/agent-recharges`(`payment_method=wechat`,不传凭证),验证正常创建成功,无凭证校验报错
|
||||
Reference in New Issue
Block a user