docs: 更新 OpenAPI 文档及提案任务清单,新增 payment_voucher_key 字段
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:
2026-04-17 18:29:42 +08:00
parent ad30f5d41b
commit 6e15e1b853
6 changed files with 172 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-04-17

View 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` 方式强制非空。迁移简单,无需锁表。

View 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` | 无需改动(透传) |

View File

@@ -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前端不展示

View 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`,不传凭证),验证正常创建成功,无凭证校验报错