Skip to content

💰 支付基础能力

SunAdmin 支付能力分为两层:

  • System 提供支付基础能力:统一支付单、退款单、回调日志、支付结果分发、业务处理器注册。
  • 支付通道由独立模块提供:例如微信支付模块注册 WechatPay 驱动,后续支付宝等通道也按同一方式扩展。

框架本身不直接依赖某个支付渠道。没有安装对应支付模块时,业务仍可创建自己的订单,但发起该渠道支付会得到“支付驱动未安装或未启用”的明确提示。

本页讲支付基础能力的组成、驱动契约、默认驱动选择和回调流程。业务模块如何调用支付、注册处理器、走退款流程详见 支付业务对接

🎯 本页目标

读完本章节后,应能掌握:

  • 支付基础能力由哪些服务、注册表与数据表组成。
  • 支付通道模块需要实现哪些契约才能被识别和调用。
  • 默认支付驱动如何在后台维护、如何被业务读取。
  • 渠道回调如何从支付模块流向 System 基础能力再分发给业务模块。

🧱 核心组成

能力位置说明
支付单服务modules/System/Application/Services/Pay/PayOrderService.php创建支付单、发起支付、主动查单、写统一状态
退款服务modules/System/Application/Services/Pay/PayRefundService.php创建退款单、提交退款、处理退款中心操作
支付驱动接口PaymentDriverInterface.php约束支付模块必须实现的 payrefundsyncPaid 和后台配置能力
支付驱动注册表PaymentDriverRegistry.phpconfig('sunadmin.pay.drivers') 读取已启用模块注册的驱动
默认驱动解析PaymentDriverResolver.php读取“应用接入 / 支付接入”中的默认支付驱动,业务未指定时自动补齐
渠道回调分发PaymentCallbackRegistry.php分发支付、退款等渠道回调
业务结果分发PayBusinessRegistry.php把已支付、已退款事件交给业务模块处理
退款中心modules/System/.../Finance/Refund*后台“财务管理 / 退款中心”统一处理退款单

🗃️ 数据表

说明
pay_orders统一支付单,记录业务归属、支付驱动、渠道流水和支付状态
pay_refunds统一退款单,支持部分退款和多次退款
pay_callback_logs渠道回调日志,保存验签结果、原始载荷和处理状态

🔌 支付驱动

支付驱动是支付通道模块暴露给框架的统一入口。业务模块不直接调用微信、支付宝或其他 SDK,而是调用 PayOrderService。业务没有显式传入 driver 时,系统会读取“应用接入 / 支付接入”中选择的默认支付驱动,并写入 pay_orders.driver

php
use Modules\System\Application\Services\Pay\Contracts\PaymentDriverInterface;
use Modules\System\Domain\Models\Pay\PayOrder;

class ExamplePaymentDriver implements PaymentDriverInterface
{
    public function driver(): string
    {
        return 'example';
    }

    public function name(): string
    {
        return '示例支付';
    }

    public function channels(): array
    {
        return ['mini', 'mp', 'h5', 'app'];
    }

    public function configured(): bool
    {
        return true;
    }

    public function configFields(): array
    {
        return [];
    }

    public function configValues(): array
    {
        return [];
    }

    public function saveConfig(array $data): void
    {
        // 保存支付模块自己的商户号、密钥、证书等参数。
    }

    public function pay(PayOrder $order, array $extraPayload = []): array
    {
        // 调用第三方预支付接口,返回前端调起支付需要的数据。
    }

    public function refund(PayOrder $order, array $data = []): array
    {
        // 调用第三方退款接口,返回渠道退款受理结果。
    }

    public function syncPaid(PayOrder $order): array
    {
        // 主动查单,返回 paid、payload、query 等标准字段。
    }
}

支付模块在自己的服务提供者中注册驱动:

php
namespace Modules\ExamplePay\Providers;

use Illuminate\Support\ServiceProvider;
use Modules\ExamplePay\Application\Services\Pay\ExamplePaymentDriver;

class ExamplePayServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $drivers = config('sunadmin.pay.drivers', []);
        $drivers[] = ExamplePaymentDriver::class;

        config()->set('sunadmin.pay.drivers', array_values(array_unique($drivers)));
    }
}

只有模块启用后,模块服务提供者才会加载,对应支付驱动才会进入 PaymentDriverRegistry

⚙️ 默认支付驱动

默认支付驱动在后台“支付接入”中维护:

text
应用接入 / 支付接入 / 默认支付驱动

配置项保存到:

text
configs.group = pay
configs.key = default_driver

支付模块安装后会把自己的驱动注册到 PaymentDriverRegistry,支付接入页会动态读取已安装驱动作为下拉选项。页面上方选择默认支付驱动,下方按支付模块生成配置标签页。业务模块只需要调用统一支付服务,不需要在每个业务里写死微信支付、支付宝支付或其他支付通道。

🧩 微信支付模块

微信支付由独立模块提供,是支付驱动的参考实现:

bash
# 安装微信支付模块:注册 wechat 驱动、提供微信支付配置项、写入模块状态
php artisan module:install WechatPay

安装后提供:

能力说明
支付驱动wechat
后台配置入口应用接入 / 支付接入 / 微信支付
配置分组wechat_pay
支付回调POST /api/wechat-pay/notify/pay
退款回调POST /api/wechat-pay/notify/refund

微信支付配置读取 .env 中的 APP_URL 生成回调地址,当 APP_URL 为空则自动获取当前服务器部署域名地址。测试环境或内网穿透环境都应填写微信可访问的 HTTP 域名:

env
APP_URL=https://example.com

修改 APP_URL 后,如果项目启用了配置缓存,需要清理缓存:

bash
# 清理 Laravel 配置、路由、视图等优化缓存,让新的 APP_URL 生效
php artisan optimize:clear

🔁 回调流程

支付模块负责渠道验签、解密和标准化,System 支付基础能力负责写统一支付单、统一退款单和分发业务处理器。

业务模块不需要自己写渠道回调入口,也不要在业务模块里手写微信验签和解密。业务模块对接已支付、已退款事件的方式详见 支付业务对接 / 业务处理器

✨ 接入规范

  • 所有业务支付先写 pay_orders
  • out_trade_no 使用 pay_orders.order_no
  • 业务单号写入 biz_no
  • 业务类型写入 biz_type
  • 业务场景写入 scene
  • 业务模块通常不需要传 driver,支付基础能力会按系统配置写入默认支付驱动。
  • 特殊业务需要覆盖默认驱动时,可以显式传入 driver,例如 wechat
  • 支付通道写入 channel,例如 minimph5appscan
  • 支付模块负责第三方 SDK、配置页、验签解密和渠道回调入口。
  • System 支付基础能力负责统一支付单、统一退款单、回调日志和业务分发。
  • 业务模块只注册自己的业务处理器,不把业务逻辑写入 System。
  • 回调中的业务处理必须幂等。
  • 支付回调域名来自 .envAPP_URL,不要依赖前端请求域名。