## Context 代理在线充值现有 `OnlinePaymentPort` 抽象只有微信直连 H5/MWEB 与支付宝 WAP 两个 Adapter;`payment-methods` 只调用 `wechat.Available` 与 `alipay.Available`。当前生效配置为富友时,微信 Adapter 因 `provider_type=fuiou` 判定不可用,导致只返回 `alipay`。富友本质是微信支付上游通道,`pkg/fuiou` 已具备 XML/GBK/双重 URL 编码/RSA 签名验签与回调解析能力,但缺少主扫下单与订单查询。参见 proposal.md - Why。 ## Goals / Non-Goals **Goals:** - 对外支付方式枚举保持 `wechat` / `alipay`,不暴露 `fuiou`。 - 富友配置下 `wechat` 走富友主扫统一下单,复用现有 `qr_content` 契约。 - 富友通道下主动查单通过 `/commonQuery` 收敛状态,不重建支付链接。 - 回调与确认校验接受 `channel=fuiou` 对应业务方式 `wechat`。 **Non-Goals:** - 不新增对外 `fuiou` 支付方式,不改前端枚举。 - 不接入富友退款、撤销、条码支付(商户扫用户)等其它交易类型。 - 不改支付宝通道(仍走直接支付宝 WAP)。 ## Decisions ### 新增富友扫码 Adapter 而非扩展微信 Adapter 新增 `FuiouScanAdapter` 实现 `OnlinePaymentPort`,`Available` 判定 `provider_type==fuiou` 且富友字段完整;`CreatePaymentURL` 调主扫下单返回 `qr_code`;`Query` 调订单查询映射 `trans_stat`。备选方案是在 `WechatWebAdapter` 内部分支,但会混淆微信直连与富友的日志提供方、错误语义与恢复策略,故放弃。 ### Adapter 选择改为配置感知 `OnlineCreationService` 与 `RecoverOnlinePaymentService` 的 `adapter()` 增加 `config` 参数:`wechat` 方法 + `provider_type==fuiou` 返回富友 Adapter,否则返回微信 Adapter。恢复阶段富友与微信一致只查单不重建链接。 ### 业务方式与渠道分离存储 `Payment.PaymentMethod` 与充值记录 `PaymentMethod` 保持 `wechat`(业务语义),充值记录 `PaymentChannel` 存 `fuiou`(实际渠道);`paymentMerchantIdentity` 在富友下返回 `FyMchntCd`。回调 `PaymentMethod=fuiou` 在确认入口归一化为业务方式 `wechat`,领域校验允许 `channel=fuiou` 映射到 `method=wechat`。 ### 复用现有富友回调 异步通知复用 `FuiouPayCallback` 与 `VerifyNotify`,`NotifyRequest` 字段与主扫通知报文一致,不做改动。 ## Risks / Trade-offs - [富友主扫 `mchnt_order_no` 必须全局唯一,重复会被拒绝] → 复用本地 `payment_no` 作为商户订单号,且恢复阶段只查单不重建链接。 - [富友查询 `trans_stat` 为 `9999`/空/`1010` 时状态未知] → 映射为 unknown,保持待恢复继续查,不确认收款也不关闭。 - [富友 `reserved_*` 字段不参与签名且渠道会新增] → 复用 `pkg/fuiou` 现有 `structToMap` 排除 reserved 前缀的签名规则。 - [回调无支付时间或金额不一致] → 现有确认用例已校验金额、配置身份与支付时间,富友金额用 `order_amt`(分)、时间用 `reserved_txn_fin_ts`。 ## Migration Plan 无数据库迁移、无新外部依赖。代码上线后,将生效支付配置切为富友即可使代理在线充值展示微信扫码;回滚为恢复生效配置为微信直连或回退代码,不改变既有数据语义。