refactor(payment): 渠道抽象成 Channel 接口 —— 接新渠道=加 adapter 不动骨架

PAYMENT_DESIGN §3 承诺的 internal/payment/channel.go 适配器接口此前不存在,微信硬编码在
manager/handler 里。补齐抽象:

- channel.go:Channel 接口(Name/CreatePay/QueryOrder/VerifyCallback)+ 统一 PayIntent/PayResult
  + 渠道名常量。入参用基本类型不吃 *store.PaymentOrder,payment 包不反依赖 store。
- Wechat 实现 Channel(编译期断言 var _ Channel);QueryResult 归一为 PayResult;CreatePay 返回 PayIntent。
- Manager 从「持一个 *Wechat」改为渠道注册表:Get(name)/Available()/Status(name)/ReloadWechat;
  按渠道名持有已装配实例,热重载不变。
- 回调路由收敛 /billing/callback/wechat → /billing/callback/:channel 按名路由(旧 notify URL 仍匹配);
  查单/掉单补偿据 order.Channel 路由,不再写死微信。下单支持可选 channel(缺省 wechat)。
- 支付宝/Stripe 现在真·只差一个 adapter+注册。唯一未泛化:回调 ack 应答格式(现微信态,注释标明)。
- payment 包首个测试:Manager 注册表 4 用例(空/注册摘除/空配置/配置不全)。build/vet/test/lint 全绿。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-07-18 13:56:24 +08:00
parent 86e79d76ac
commit 3a4e1d53a5
10 changed files with 261 additions and 80 deletions
+13 -8
View File
@@ -43,18 +43,23 @@
| **微信支付 Native**(P5.2) | 企业主体 + 商户号 | 二维码(code_url | ✅ 已拍板 |
| 支付宝 / Stripe | — | — | 不做,留 adapter 位 |
Adapter 接口(`internal/payment/channel.go`):
Adapter 接口(`internal/payment/channel.go`**已落地**
```go
type Channel interface {
Name() string
// CreatePay 依据订单生成支付凭据(二维码内容/跳转 URL/兑换码提示
CreatePay(ctx, o *PaymentOrder) (PayIntent, error)
// VerifyCallback 验签并解析回调 → (orderID, channelTxnID, paidAmountFen, error)
VerifyCallback(req *http.Request) (CallbackResult, error)
// QueryOrder 主动查单(掉单补偿用
QueryOrder(ctx, orderID string) (OrderStatus, error)
Name() string // 与 store.Channel*wechat/alipay/stripe)一致,按订单渠道路由
// CreatePay 依据订单生成支付凭据(微信 Native 出 code_url;其它渠道可出跳转 URL
CreatePay(ctx, orderID, description string, amountFen int64) (PayIntent, error)
// QueryOrder 主动查单(前端轮询确认 + 掉单补偿共用)
QueryOrder(ctx, orderID string) (PayResult, error)
// VerifyCallback 验签并解析回调 → 统一 PayResult(验签失败必返 error
VerifyCallback(req *http.Request) (PayResult, error)
}
```
实现说明(2026-07-18):入参用基本类型(orderID/amountFen)而非 `*store.PaymentOrder`,让
`payment` 包不反依赖 `store`,渠道适配层保持纯粹。`Manager` 是渠道注册表(`Get(name)`/`Available()`/
`Status(name)`/`ReloadWechat`),回调路由收敛为 `POST /billing/callback/:channel` 按名路由;
查单/补偿据 `order.Channel` 路由。微信是当前唯一真渠道,支付宝/Stripe = 实现本接口 + 注册即接入。
唯一未泛化的是回调 **ack 应答格式**(现为微信 `{code:SUCCESS}`,其它渠道接入时按渠道分应答)。
## 3b. 两层汇率,各管各的(用户 2026-07-17 强调:积分↔token 必须可动态调)