文档目录
支付插件开发指南

简介

本指南面向DouPHP支付插件开发者,围绕Provider与Service职责分离、统一支付接口、插件注册机制、状态机与事务、对账与轮询、退款分账、安全校验、测试与发布等主题,提供从架构到落地的完整说明。文中所有实现细节均基于仓库内现有代码进行归纳与解读,便于快速上手并保证与系统演进一致。

项目结构

DouPHP的支付能力由“核心支付服务 + 插件Provider/Service”构成:

  • 核心层:PaymentService负责订单支付台账、状态机推进、钱包支付腿、退款分账、幂等与事务保障。
  • 插件层:每个支付渠道(如alipay、wxpay)提供Provider与Service,Provider暴露统一接口,Service对接具体SDK与回调处理。
  • 配置与注册:manifest.php声明插件分组与Provider类;框架通过接口契约识别可查询、可轮询的支付能力。
graph TB
A["前端/业务调用"] --> B["支付入口(路由/控制器)"]
B --> C["Provider(统一接口)"]
C --> D["Service(渠道逻辑)"]
D --> E["第三方SDK(支付宝/微信)"]
D --> F["核心PaymentService"]
F --> G["订单状态机/钱包/退款"]

核心组件

  • PaymentService:创建支付台账行、推进支付成功/失败/关闭、合并多支付腿(网关+钱包)、尝试将订单推进至已支付、退款分账、记录回调原文与凭证、按订单查询历史等。
  • Provider:定义插件ID、元信息、start/notify/finish/query/status等统一方法,委托给对应Service。
  • Service:封装具体渠道SDK调用、验签、参数构建、回调处理、主动对账或轮询结果映射到PaymentService。
  • 接口契约:ReconcilablePaymentProviderInterface(支持主动对账)、PollablePaymentProviderInterface(支持轮询)。

架构总览

支付流程分为两条主线:

  • 下单发起:Provider.start -> Service.start -> 第三方SDK生成支付链接/二维码/JS参数 -> 返回前端引导支付。
  • 回调与对账:第三方通知/轮询 -> Provider.notify/status -> Service验签与解析 -> PaymentService.markSucceeded -> 订单状态推进。
sequenceDiagram
participant U as "用户"
participant P as "Provider"
participant S as "Service"
participant SDK as "第三方SDK"
participant Core as "PaymentService"
participant O as "订单状态机"
U->>P : 发起支付(start)
P->>S : start(request)
S->>SDK : 创建订单/获取支付参数
SDK-->>S : 支付URL/二维码/JS参数
S-->>P : 返回渲染内容
P-->>U : 展示支付页面
SDK-->>S : 异步通知(notify)
S->>Core : markSucceeded(paymentSn, transactionId, raw)
Core->>O : changeStatus(PAID)
O-->>Core : 确认状态
Core-->>S : 成功
S-->>SDK : 返回成功响应

详细组件分析

支付服务(PaymentService)

  • 职责
    • 为订单创建pending支付台账行,生成唯一payment_sn。
    • 幂等推进支付成功:校验状态迁移、累计已付金额、尝试收尾订单。
    • 混合支付:支持钱包与网关多腿,凑满才推进订单PAID。
    • 退款分账:优先网关后钱包,区分同步成功与待人工收尾。
    • 终态标记:失败/关闭,记录回调原文与凭证。
  • 关键特性
    • 幂等:DB唯一键、状态机约束、重复回调不重复联动。
    • 事务:钱包扣款/入账/累计在同一事务中,避免并发超扣。
    • 容差:金额比较使用固定容差避免浮点误差。
flowchart TD
Start(["进入markSucceeded"]) --> Find["按payment_sn查找支付记录"]
Find --> Exists{"记录存在?"}
Exists -- 否 --> LogErr["记录错误并返回false"]
Exists -- 是 --> CheckState{"状态可迁移到成功?"}
CheckState -- 否 --> LogIllegal["非法迁移日志并返回false"]
CheckState -- 是 --> OrderCheck["检查订单是否可收款"]
OrderCheck --> UpdatePay["更新支付状态/交易号/时间"]
UpdatePay --> AccAmt["累计网关已付金额"]
AccAmt --> TryFinalize["尝试收尾订单(凑满则推进PAID)"]
TryFinalize --> End(["结束"])

支付宝插件(alipay)

  • Provider
    • 实现ReconcilablePaymentProviderInterface,暴露pluginId、meta、start、notify、finish、query。
    • meta中声明配置字段(APPID、私钥、公钥),供后台配置。
  • Service
    • start:构造支付宝网页支付请求,返回支付页面URL。
    • notify/finish:验签通过后调用PaymentService.markSucceeded,finish时发送邮件通知。
    • query:主动对账,根据trade_status映射为成功/关闭/待支付。
  • 配置
    • manifest.php声明插件分组与Provider类路径。
classDiagram
class AlipayProvider {
+pluginId() string
+meta() array
+start(request) string
+notify(payload) string
+finish(payload) string
+query(request) PaymentQueryResult
}
class AlipayService {
+start(request) string
+notify(payload) string
+finish(payload) string
+query(request) PaymentQueryResult
-buildConfig() array
}
AlipayProvider --> AlipayService : "委托"

微信支付插件(wxpay)

  • Provider
    • 同时实现ReconcilablePaymentProviderInterface与PollablePaymentProviderInterface,支持主动对账与扫码轮询。
    • 暴露status用于Native扫码轮询。
  • Service
    • start:按UA自动选择JSAPI/H5/NATIVE模式。
    • notify:统一验签回调,内部NotifyCallback处理成功后调用PaymentService.markSucceeded。
    • status:按paymentSn轮询微信订单状态,命中SUCCESS即推进。
    • query:主动对账,映射trade_state为成功/关闭/待支付。
  • 配置
    • 动态加载SDK文件,注入全局配置,写入日志路径。
sequenceDiagram
participant U as "用户"
participant WxP as "WxpayProvider"
participant WxS as "WxpayService"
participant WX as "微信SDK"
participant Core as "PaymentService"
U->>WxP : start
WxP->>WxS : start(request)
WxS->>WX : 统一下单(JSAPI/H5/Native)
WX-->>WxS : 支付参数/二维码
WxS-->>WxP : 返回渲染内容
WX-->>WxS : 异步通知
WxS->>Core : markSucceeded(paymentSn, transactionId, raw)
Core-->>WxS : 成功
WxS-->>WX : 返回成功

插件注册机制

  • manifest.php声明插件分组与Provider类名,框架据此发现并挂载插件。
  • 接口契约决定插件能力:
    • ReconcilablePaymentProviderInterface:具备query主动对账能力。
    • PollablePaymentProviderInterface:具备status轮询能力(如微信Native扫码)。

依赖关系分析

  • Provider依赖Service:统一对外接口,内部委托Service完成渠道逻辑。
  • Service依赖PaymentService:所有成功回调统一走核心服务,确保状态机与订单联动的一致性。
  • PaymentService依赖订单状态机与钱包服务:在事务内推进订单状态、扣减余额、累计已付金额。
graph LR
Prov["Provider"] --> Svc["Service"]
Svc --> Core["PaymentService"]
Core --> OS["订单状态机"]
Core --> WAL["钱包服务"]

性能与一致性

  • 幂等性
    • 支付台账表通过(gateway, transaction_id)唯一键防止重复入账。
    • markSucceeded对已成功的payment直接返回true,避免重复联动订单。
  • 事务与锁
    • 钱包支付在事务中使用FOR UPDATE锁定订单行,防止并发超扣。
    • 退款分账逐腿加锁,确保状态迁移原子性。
  • 金额容差
    • 使用固定容差避免decimal精度导致的“未付满”误判。
  • 对账与轮询
    • 支付宝/微信均提供query主动对账;微信Native额外支持status轮询,提高成功率与时效性。

安全机制

  • 签名验证
    • 支付宝:使用SDK的check方法进行验签,仅验签通过才推进支付成功。
    • 微信:通过WxPayNotify进行验签,统一回调入口确保安全。
  • 数据加密与密钥管理
    • 支付宝:配置应用私钥与支付宝公钥,服务端使用RSA2签名。
    • 微信:配置商户号、API密钥、证书路径,确保通信安全。
  • 防重放攻击
    • 幂等设计:同一transaction_id不会重复入账;重复回调直接返回成功。
    • 原始回调留底:raw_callback字段记录第三方原始报文,便于审计与排错。
  • 日志记录
    • 微信插件将SDK日志输出到storage/log/payment/wxpay目录,便于问题定位。

测试方法

  • 单元测试
    • 针对Service的buildConfig、encodeRaw、responseToArray等方法进行断言,确保配置与序列化正确。
    • 模拟PaymentService的返回值,验证Provider委托逻辑。
  • 集成测试
    • 使用沙箱环境调用支付宝/微信SDK,验证start/notify/query流程。
    • 构造重复回调与异常响应,验证幂等与错误分支。
  • 模拟支付环境
    • 本地搭建Webhook监听,模拟第三方通知;或使用Mock对象替换外部SDK。
    • 利用PaymentService的recordCallback与attachPayEvidence,回放与补充调试信息。

发布与分发

  • 版本管理
    • 在Provider.meta中维护ver字段,便于后台显示与升级提示。
  • 兼容性考虑
    • 保持接口契约稳定(start/notify/finish/query/status),避免破坏已有调用方。
    • 对SDK升级进行兼容适配,必要时在Service内部做版本判断。
  • 文档编写
    • 在meta.description中清晰描述插件用途与适用端(PC/移动/全部)。
    • 配置项需包含field、name、desc、value,便于后台可视化配置。
  • 安装与启用
    • 将插件目录放入plugin下,确保manifest.php正确声明provider路径。
    • 在后台启用插件并填写配置(APPID、密钥、证书等)。

故障排查

  • 常见问题
    • 配置不完整:Service在start时校验必要配置,缺失会抛出异常并提示管理员。
    • 验签失败:notify/finish中验签失败直接返回fail或跳转订单页,需检查密钥与回调地址。
    • 订单不可收款:PaymentService在markSucceeded前校验订单状态,非可收款状态保持payment pending,等待对账兜底。
    • 退款未完成:网关退款登记为pending,需管理员在网关后台完成后调用markRefundSucceeded收尾。
  • 定位手段
    • 查看raw_callback与pay_evidence,结合日志定位问题。
    • 使用query主动对账核对第三方状态,必要时触发重试或人工干预。

结论

DouPHP支付体系通过Provider与Service的职责分离、统一的接口契约与核心PaymentService的状态机,实现了高内聚、低耦合的可扩展支付架构。借助幂等、事务、对账与轮询机制,保障了支付数据的准确性与一致性。遵循本指南进行插件开发与配置,可快速接入新支付渠道并确保与系统整体行为一致。

添加日期:2026-10-05