docs: 新增 OpenSpec 提案 add-payment-config-management

包含 proposal.md、design.md、tasks.md 及各模块 spec 文件(微信配置管理、富友支付、代理充值、订单支付、资产充值适配、微信支付留桩)

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-03-16 23:30:39 +08:00
parent 429edf0d19
commit 63ca12393b
10 changed files with 2797 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
## Goal 1微信参数配置管理 + 支付流程改造
### 1.1 前置准备:常量重命名
- [x] 1.1.1 `pkg/constants/wallet.go`:将 `Card*` 前缀常量重命名为 `Asset*`CardWalletResourceType* → AssetWalletResourceType*、CardWalletStatus* → AssetWalletStatus*、CardTransactionType* → AssetTransactionType*、CardRechargeOrderPrefix → AssetRechargeOrderPrefix、CardRechargeMinAmount → AssetRechargeMinAmount、CardRechargeMaxAmount → AssetRechargeMaxAmount段落标题 `卡钱包常量``资产钱包常量`
- [x] 1.1.2 旧 `Card*` 常量保留为废弃别名(`const CardRechargeOrderPrefix = AssetRechargeOrderPrefix`),更新废弃注释中的引用
- [x] 1.1.3 全局替换引用:将所有使用 `Card*` 常量的代码替换为 `Asset*`
### 1.1b 删除 YAML 支付配置遗留代码
> **必须在 1.3 之前完成**:这些是原有方案的残留,新方案部署后若不删除,配置和行为会产生歧义。
- [x] 1.1b.1 修改 `pkg/config/config.go`:删除 `PaymentConfig` 结构体(整体删除,含 `AppID`/`MchID`/`APIV3Key`/`APIV2Key`/`CertPath`/`KeyPath`/`SerialNo`/`NotifyURL`/`HttpDebug`/`Timeout` 所有字段);删除 `WechatConfig.Payment PaymentConfig` 字段;删除对应注释
- [x] 1.1b.2 修改 `pkg/config/defaults/config.yaml`:删除 `wechat.payment:` 整个配置节(约 10 行),**保留** `wechat.official_account:` 节不变OAuth 仍使用 YAML 配置)
- [x] 1.1b.3 修改 `pkg/wechat/config.go`:删除 `NewPaymentApp(cfg *config.Config, ...)` 函数(从 YAML CertPath/KeyPath 文件路径创建 Payment 实例的方式已被 DB Base64 方案完全取代)
- [x] 1.1b.4 修改 `cmd/api/main.go`:从 `validateWechatConfig` 中删除所有 `wechatCfg.Payment.*` 相关校验代码(包括对 `CertPath`/`KeyPath``os.Stat` 检查、缺失字段的 `appLogger.Fatal`**保留**对 `wechatCfg.OfficialAccount` 的校验不变
- [x] 1.1b.5 确认编译通过:删除后运行 `go build ./...` 确保无编译错误(此时 `wechatPayment` 相关代码仍保留,因为留桩期间仍在用单例)
### 1.2 数据库与基础模型
- [x] 1.2.1 创建数据库迁移文件:新建 `tb_wechat_config`基础字段、OAuth 公众号字段、OAuth 小程序字段、微信直连支付字段、富友支付字段),`is_active` 默认 `false`
- [x] 1.2.2 创建数据库迁移文件:`tb_order` 新增 `payment_config_id`bigint, nullable, 带索引)
- [x] 1.2.3 创建数据库迁移文件:`tb_asset_recharge_record` 新增 `payment_config_id`bigint, nullable, 带索引)
- [ ] 1.2.4 执行迁移,确认表结构正确
- [x] 1.2.5 创建 `internal/model/wechat_config.go`WechatConfig 模型GORM 标签、TableName、渠道类型常量 `ProviderTypeWechat` / `ProviderTypeFuiou`
- [x] 1.2.6 修改 `internal/model/order.go`Order 模型新增 `PaymentConfigID *uint` 字段
- [x] 1.2.7 修改 `internal/model/asset_wallet.go`AssetRechargeRecord 模型新增 `PaymentConfigID *uint` 字段
- [x] 1.2.8 创建 `internal/model/dto/wechat_config_dto.go`:请求 DTOCreate/Update/List、响应 DTO含脱敏逻辑方法详细字段定义见 spec
- [x] 1.2.9 在 `pkg/constants/redis.go` 新增 `RedisWechatConfigActiveKey()` 函数
- [x] 1.2.10 在 `pkg/errors/codes.go` 新增错误码:`CodeWechatConfigNotFound=1170``CodeWechatConfigActive=1171``CodeWechatConfigHasPendingOrders=1172``CodeFuiouPayFailed=1173``CodeFuiouCallbackInvalid=1174``CodeNoPaymentConfig=1175`
### 1.3 微信参数配置 CRUDStore + Service + Handler
- [x] 1.3.1 创建 `internal/store/postgres/wechat_config_store.go`:实现 Create、GetByID、GetByIDUnscoped含软删除、List分页+筛选、Update、SoftDelete、GetActive、ActivateInTx事务内停用所有+激活指定、Deactivate、CountPendingOrdersByConfigID、CountPendingRechargesByConfigID
- [x] 1.3.2 创建 `internal/service/wechat_config/service.go`:实现 CRUD 业务逻辑,包含按 provider_type 校验必填字段、激活/停用(含 Redis 缓存清除)、删除保护(检查激活状态 + 在途订单 + 在途充值、GetActiveConfigRedis 缓存 + DB 回源 + 空标记)、更新脱敏字段处理、审计日志记录
- [x] 1.3.3 创建 `internal/handler/admin/wechat_config.go`:实现 Create、List、Get、Update、Delete、Activate、Deactivate、GetActive 共 8 个 Handler 方法
- [x] 1.3.4 创建 `internal/routes/wechat_config.go`:注册路由到 `/api/admin/wechat-configs/*`,包含平台用户权限中间件
- [x] 1.3.5 更新 `internal/bootstrap/`types.go、stores.go、services.go、handlers.go注册 WechatConfigStore、WechatConfigService、WechatConfigHandler
- [x] 1.3.6 更新 `cmd/api/docs.go``cmd/gendocs/main.go`:注册 WechatConfigHandler 到文档生成器
### 1.4 富友支付 SDK
- [x] 1.4.1 创建 `pkg/fuiou/types.go`:定义 WxPreCreateRequest/Response、NotifyRequest 等 XML 结构体
- [x] 1.4.2 创建 `pkg/fuiou/client.go`:实现 Client 结构体(持有配置和 RSA 密钥对、NewClient从 WechatConfig 模型构造)、签名算法(字典序 → GBK → MD5 → RSA → Base64、验签算法、HTTP 请求XML + GBK + 双 URL 编码、响应解码URL 解码 → GBK→UTF-8 → XML 解析)
- [x] 1.4.3 创建 `pkg/fuiou/wxprecreate.go`:实现 WxPreCreate 方法(公众号 JSAPI + 小程序支付下单),支持 trade_typeJSAPI / LETPAY和 sub_appid / sub_openid 参数
- [x] 1.4.4 创建 `pkg/fuiou/notify.go`:实现 VerifyNotify 方法GBK→UTF-8 + XML 解析 + RSA 验签BuildNotifyResponse 成功/失败响应构建
- [x] 1.4.5 在 `go.mod` 添加 `golang.org/x/text` 依赖GBK 编解码)
### 1.5 订单支付流程改造
- [x] 1.5.1 改造 `internal/service/order/service.go``CreateH5Order``CreateAdminOrder`:注入 `wechatConfigService`(新增字段),下单时查询 active 配置 → 无配置则拒绝第三方支付 → 有配置则记录 `payment_config_id` 到订单
- [x] 1.5.2 改造 `WechatPayJSAPI` 方法(**留桩**):添加 TODO 注释 `// TODO: 从 payment_config_id 加载配置动态创建 Payment 实例`,本次保留现有 `s.wechatPayment` 单例调用不变;同时在构造函数中保留 `wechatPayment` 参数(留桩期间仍需注入)
- [x] 1.5.3 改造 `WechatPayH5` 方法(**留桩**):同 1.5.2,添加 TODO 注释,保留 `s.wechatPayment` 调用
- [x] 1.5.4 新增富友支付发起方法桩:`FuiouPayJSAPI`(返回 "富友支付发起暂未实现" 错误)和 `FuiouPayMiniApp`(同上),标记 TODO
> **留桩期间的 Bootstrap 注入**:任务 1.5.2/1.5.3 的留桩意味着 `internal/bootstrap/dependencies.go` 的 `WechatPayment` 字段、`services.go` 和 `handlers.go` 的 `deps.WechatPayment` 注入**暂时不改动**。当 WechatPayJSAPI/WechatPayH5 完成动态加载改造(留桩解除)后,再删除 `WechatPayment` 字段和所有注入点。
### 1.6 回调处理改造
- [x] 1.6.1 改造 `internal/handler/callback/payment.go``WechatPayCallback`:解析订单号 → 按前缀分发(`ORD`/`CRCH`/`ARCH`)→ 查询对应表取 `payment_config_id` → 按配置加载验签(本次留桩:验签仍用现有 `wechatPayment` 单例,添加 TODO `// TODO: 按 payment_config_id 加载配置验签`**订单分发逻辑必须完整实现**(不是留桩),三种订单类型必须全部支持
- [x] 1.6.2 修复回调中的前缀匹配:将 `constants.RechargeOrderPrefix("RCH")` 替换为分别匹配 `constants.AssetRechargeOrderPrefix("CRCH")``constants.AgentRechargeOrderPrefix("ARCH")`;同时修复 `AlipayCallback` 中同样使用 `RechargeOrderPrefix` 的问题(第 84 行)
- [x] 1.6.3 新增 `FuiouPayCallback` Handler接收富友回调 → 解析 XMLGBK→UTF-8→ 按订单号前缀分发 → 查询对应记录 → 加载配置 → 验签 → 调用对应 Service.HandlePaymentCallback → 返回 XML 响应
- [x] 1.6.4 在 `internal/routes/order.go` 注册富友回调路由 `POST /api/callback/fuiou-pay`(无需认证)
- [x] 1.6.5 更新 `internal/bootstrap/handlers.go``NewPaymentHandler` 新增 `agentRechargeService` 参数(用于 `ARCH` 前缀分发);`WechatPayment` 参数留桩期间保留
### 1.7 资产充值模块适配
- [x] 1.7.1 改造 `internal/service/recharge/service.go``Create` 方法:创建充值订单时查询 active 配置,记录 `payment_config_id`
- [x] 1.7.2 改造 `internal/service/recharge/service.go``HandlePaymentCallback` 方法:回调时按 `payment_config_id` 加载配置验签(留桩)
### 1.8 集成验证与文档
- [ ] 1.8.1 验证完整流程:创建微信支付配置 → 激活 → 确认缓存生效 → 停用 → 确认降级为钱包支付
- [ ] 1.8.2 验证配置切换:激活配置 A → 创建订单(记录 payment_config_id=A→ 切换到配置 B → 新订单使用 B
- [ ] 1.8.3 验证权限控制:代理/企业账号无法访问微信参数配置管理接口
- [ ] 1.8.4 验证审计日志CRUD 和激活/停用操作产生审计记录
- [ ] 1.8.5 创建功能文档 `docs/wechat-config-management/功能总结.md`
---
## Goal 2代理预充值系统
### 2.1 数据库与模型
- [x] 2.1.1 创建数据库迁移文件:`tb_agent_recharge_record` 新增 `payment_config_id`bigint, nullable, 带索引)
- [x] 2.1.2 修改 `internal/model/agent_wallet.go`AgentRechargeRecord 模型新增 `PaymentConfigID *uint` 字段
- [x] 2.1.3 创建 `internal/model/dto/agent_recharge_dto.go`CreateAgentRechargeRequest、AgentOfflinePayRequest、AgentRechargeResponse、AgentRechargeListRequest、AgentRechargeListResponse详细字段定义见 spec
### 2.2 代理充值 Service
- [x] 2.2.1 创建 `internal/service/agent_recharge/service.go`
- `Create`:验证权限(代理只能充自己店铺,平台可指定)→ 验证金额范围 → 查找 main 钱包 → 查询 active 配置wechat 时必须有)→ 创建充值订单 → 记录 payment_config_id
- `OfflinePay`:验证平台权限 → 验证操作密码 → 事务内更新订单状态 + 增加钱包余额(乐观锁)+ 创建交易记录 → 审计日志
- `HandlePaymentCallback`:幂等检查 → 按 payment_config_id 验签 → 事务内更新订单状态 + 增加余额 + 创建交易记录
- `GetByID``List`:查询充值订单
### 2.3 代理充值 Handler + 路由
- [x] 2.3.1 创建 `internal/handler/admin/agent_recharge.go`:实现 Create、List、Get、OfflinePay 共 4 个 Handler 方法
- [x] 2.3.2 创建 `internal/routes/agent_recharge.go`:注册路由到 `/api/admin/agent-recharges/*`
- [x] 2.3.3 更新 `internal/bootstrap/`types.go、stores.go、services.go、handlers.go注册 AgentRechargeService、AgentRechargeHandler
- [x] 2.3.4 更新 `cmd/api/docs.go``cmd/gendocs/main.go`:注册 AgentRechargeHandler 到文档生成器
### 2.4 代理充值回调集成
- [x] 2.4.1 在回调 Handler1.6.2 已完成的前缀分发逻辑)中接入代理充值回调:`"ARCH"` 前缀 → `agentRechargeService.HandlePaymentCallback()`
- [x] 2.4.2 确认富友回调 Handler 也支持 `"ARCH"` 前缀分发
### 2.5 集成验证与文档
- [ ] 2.5.1 验证微信支付充值流程创建充值订单wechat→ 确认 payment_config_id 记录 → 模拟回调 → 确认余额增加
- [ ] 2.5.2 验证线下充值流程平台创建充值订单offline→ 确认线下支付 → 验证操作密码 → 确认余额增加
- [ ] 2.5.3 验证权限控制:代理只能充自己店铺、非平台不能线下充值、操作密码错误拒绝
- [ ] 2.5.4 验证审计日志:线下充值操作产生审计记录
- [ ] 2.5.5 创建功能文档 `docs/agent-recharge/功能总结.md`