PAYATHON 2026

如何为 Pinnacle Cart 添加自定义 payment gateway?

支付老李

结论

Pinnacle Cart 通常无法通过后台表单添加默认列表以外的 payment gateway。接入自定义网关需要开发与当前 Pinnacle Cart 版本兼容的支付模块。如果当前部署版本未开放支付模块接口或结账流程源码,就需要联系 Pinnacle Cart 官方支持,确认是否能提供开发接口、定制集成服务,或将新网关加入支持列表。

不要直接修改现有网关文件来”套用”新接口。这些改动可能在升级后被覆盖,还可能导致重复扣款、订单状态错误或敏感信息泄露。

建议的处理步骤

1. 先确认部署方式和扩展能力

向 Pinnacle Cart 支持团队确认以下事项:

  • 当前版本是否允许安装第三方 payment module。
  • 是否提供 payment gateway SDK、模块模板或开发者接口。
  • 自定义模块应放在哪个目录,如何注册和启用。
  • 支持哪些支付方式:redirect、hosted checkout、iframe 或 server-to-server API。
  • 可以使用哪些订单创建、状态更新、退款和 webhook 接口。
  • 系统升级是否会覆盖自定义文件。
  • 托管版账户是否允许修改结账流程。

如果官方没有提供公开的模块规范,不要直接参照其他版本的目录结构或社区示例开发。不同 Pinnacle Cart 版本和部署方式可能具有不同的扩展能力。

2. 选择合适的集成方式

优先考虑网关提供的托管支付页或 redirect 模式:

  1. 商城创建待付款订单。
  2. 后端向网关创建支付请求。
  3. 将顾客重定向到网关的支付页面。
  4. 网关通过 webhook 通知支付结果。
  5. 商城后端验证通知并更新订单状态。
  6. 顾客返回商城结果页。

采用这种方式,商城通常不需要直接处理银行卡号,PCI DSS 的合规范围也相对较小。只有 Pinnacle Cart 和支付服务商均明确支持时,才应考虑由商城直接收集卡片信息。

3. 实现网关适配层

具体类名和方法必须以当前 Pinnacle Cart 版本提供的接口为准。以下代码仅用于说明结构,不能直接作为 Pinnacle Cart 的真实 API 使用:

<?php

final class CustomGateway
{
    public function __construct(
        private string $apiKey,
        private string $webhookSecret,
        private bool $sandbox
    ) {
    }

    public function createPayment(array $order): array
    {
        $payload = [
            'merchant_reference' => (string) $order['id'],
            'amount'             => $this->toMinorUnits($order['total']),
            'currency'           => strtoupper($order['currency']),
            'return_url'         => $order['return_url'],
            'cancel_url'         => $order['cancel_url'],
            'webhook_url'        => $order['webhook_url'],
        ];

        // 使用支付服务商的官方 SDK 或后端 HTTP 客户端发送请求。
        // API key 只能保存在服务器端,不能输出到浏览器。
        $response = $this->sendRequest('/payments', $payload);

        return [
            'gateway_payment_id' => $response['id'],
            'redirect_url'       => $response['checkout_url'],
        ];
    }

    public function verifyWebhook(
        string $rawBody,
        string $signature
    ): bool {
        $expected = hash_hmac('sha256', $rawBody, $this->webhookSecret);

        return hash_equals($expected, $signature);
    }

    private function toMinorUnits(string $amount): int
    {
        return (int) bcmul($amount, '100', 0);
    }

    private function sendRequest(string $path, array $payload): array
    {
        throw new RuntimeException(
            'Implement this method with the gateway official SDK.'
        );
    }
}

后台配置通常至少包含:

  • Merchant ID 或 Account ID
  • API key
  • Webhook secret
  • Sandbox/Production 模式
  • 支持的币种
  • 超时时间
  • 支付成功、失败和取消状态的映射

实际配置项名称应以支付服务商和 Pinnacle Cart 的模块规范为准。

正确处理 webhook

不能只根据浏览器返回页面判断付款成功。用户可能关闭页面或伪造请求,网络也可能在付款完成后中断。订单状态应以通过签名验证的 webhook 或服务端查询结果为准。

处理流程示例如下:

<?php

$rawBody  = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_GATEWAY_SIGNATURE'] ?? '';

if (!$gateway->verifyWebhook($rawBody, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

$event = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);

if ($event['type'] === 'payment.succeeded') {
    $orderId = $event['data']['merchant_reference'];

    // 再次核对金额、币种、商户号和 gateway payment ID。
    // 仅当订单尚未支付时执行状态变更,保证幂等性。
    markOrderAsPaid($orderId, $event['data']['id']);
}

http_response_code(200);
echo 'OK';

X-Gateway-Signature、事件名称和字段结构均为占位示例,必须替换为目标网关文档中规定的真实值。

必须验证的场景

上线前至少应测试:

  • 支付成功、失败、取消和超时
  • webhook 重复发送及乱序到达
  • 用户付款后没有返回商城
  • 金额或币种与订单不一致
  • 同一订单被重复提交
  • 已付款订单再次收到成功通知
  • 全额退款和部分退款
  • API 超时后的状态查询
  • 测试环境与生产环境凭证隔离
  • 日志脱敏,确保不记录 API secret、完整卡号或 CVV

计算金额时不要使用普通浮点数。应按照网关要求使用最小货币单位,或采用 BCMath 等十进制定点方式,以免产生舍入误差。

如果没有开放的模块接口

如果 Pinnacle Cart 支持团队确认当前方案不允许安装自定义 payment gateway,可以选择:

  • 申请官方定制集成。
  • 请求官方将该网关加入支持列表。
  • 使用网关提供的 hosted payment page,并通过 Pinnacle Cart 允许的外部支付方式连接。
  • 增加独立的支付中间层,由其处理签名、webhook、退款和状态同步。
  • 改用 Pinnacle Cart 已支持且符合业务需求的支付服务商。

在没有官方扩展点的情况下,直接修改核心结账代码风险很高。除了改动可能被升级覆盖,还可能影响订单、税费、库存、优惠券和退款流程。开发前,最好先取得当前版本的模块接口说明,并要求官方书面确认自定义代码的支持范围。

备注:内容仅供参考。