Files
sundynix-agentix/sundynix-gateway/internal/payment/channel.go
T
Blizzard 3a4e1d53a5 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>
2026-07-18 13:56:24 +08:00

45 lines
2.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package payment
import (
"context"
"net/http"
)
// Channel 是一个「真渠道」充值适配器(设计见 PAYMENT_DESIGN.md §3)。
// 兑换码不走这里(无「待支付」态,核销即入账);本接口面向需要下单-回调/查单确认的渠道。
// 接新渠道(支付宝/Stripe)= 实现这四个方法 + 在 Manager 注册,不动上层充值/入账骨架。
//
// 刻意用基本类型入参(orderID/amountFen)而非 *store.PaymentOrder:让 payment 包不反向依赖
// store,渠道适配层保持纯粹。金额一律以「分」为单位、服务端锁定值,绝不信任客户端。
type Channel interface {
// Name 渠道名,与 store.Channel*"wechat"/"alipay"/"stripe")一致,用于按订单渠道路由。
Name() string
// CreatePay 依据订单生成支付凭据(微信 Native 出 code_url;支付宝/Stripe 可出跳转 URL)。
CreatePay(ctx context.Context, orderID, description string, amountFen int64) (PayIntent, error)
// QueryOrder 主动查单(前端轮询确认 + 掉单补偿共用)。
QueryOrder(ctx context.Context, orderID string) (PayResult, error)
// VerifyCallback 验签并解析渠道回调 → 统一结果。验签失败必须返回 error(回调路由公开,签名是唯一门)。
VerifyCallback(req *http.Request) (PayResult, error)
}
// 渠道名常量(与 store.Channel* 取值一致;此处独立定义以免 payment 反依赖 store)。
const (
ChannelWechat = "wechat"
ChannelAlipay = "alipay" // 预留:未实现
ChannelStripe = "stripe" // 预留:未实现
)
// PayIntent 是下单后给前端的支付凭据(不同渠道形态不同,按需取用)。
type PayIntent struct {
CodeURL string // 微信 Native:二维码内容。其它渠道可放跳转 URL / client_secret。
}
// PayResult 是查单/回调验签解析后的统一结果(各渠道适配器把自家响应归一到这里)。
type PayResult struct {
OrderID string // 商户订单号(out_trade_no
ChannelTxn string // 渠道流水号(transaction_id),入账时落库备查
Paid bool // 支付成功
Closed bool // 关单/撤销/支付失败等终态
AmountFen int64 // 用户实付(分);供与订单金额核对,防金额被篡改
}