craftcms / commerce-stripe
为Craft Commerce 5.0+提供的Stripe集成
Requires
- php: ^8.2
- craftcms/cms: ^5.1.0
- craftcms/commerce: ^5.0.13
- stripe/stripe-php: ^13.0
Requires (Dev)
- craftcms/ecs: dev-main
- craftcms/phpstan: dev-main
- 5.x-dev
- 5.0.4.3
- 5.0.4.2
- 5.0.4.1
- 5.0.4
- 5.0.3
- 5.0.2
- 5.0.1.1
- 5.0.1
- 5.0.0
- 4.x-dev
- 4.1.5
- 4.1.4
- 4.1.3
- 4.1.2.3
- 4.1.2.2
- 4.1.2.1
- 4.1.2
- 4.1.1
- 4.1.0
- 4.0.1.1
- 4.0.1
- 4.0.0
- v3.x-dev
- 3.1.3.1
- 3.1.3
- 3.1.2
- 3.1.1
- 3.1.0
- 3.0.3
- 3.0.2
- 3.0.1
- 3.0.0
- 3.0.0-beta.1
- v2.x-dev
- 2.4.5
- 2.4.4.1
- 2.4.4
- 2.4.3
- 2.4.2
- 2.4.1
- 2.4.0
- 2.3.2.2
- 2.3.2.1
- 2.3.2
- 2.3.1.1
- 2.3.1
- 2.3.0
- 2.2.3
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.2
- 2.1.1
- 2.1.0
- 2.0.1.2
- 2.0.1.1
- 2.0.1
- 2.0.0
- 1.2.2
- 1.2.1
- 1.2.0
- 1.1.0
- 1.0.10
- 1.0.9
- 1.0.8
- 1.0.7
- 1.0.6
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
- dev-bugfix/craftnet
- dev-feature/checkout-and-sync
- dev-dependabot/composer/craftcms/cms-4.4.12
- dev-feature/code-cleanup
This package is auto-updated.
Last update: 2024-09-17 02:20:45 UTC
README
Stripe for Craft Commerce
为您的Craft Commerce商店提供灵活的支付处理,由Stripe提供支持。
此插件提供了一种网关,利用支付意向API来支持流行的支付方式,如...
- 主要借记卡和信用卡
- Apple Pay
- Google Pay
- Cash App
- Afterpay、Affirm以及其他分期付款计划
- ECH和直接银行账户转账
...以及更多内容!
注意
需要3.x文档?
要求
- Craft CMS 5.1或更高版本
- Craft Commerce 5.0或更高版本
- Stripe API版本
2022-11-15
安装
您可以从插件商店或使用Composer安装此插件。
从插件商店
前往您的项目控制面板中的插件商店,搜索“Stripe for Craft Commerce”,然后在侧边栏中点击安装。
使用Composer
打开您的终端,并运行以下命令
# Switch your project’s directory: cd /path/to/my-project # Require the package with Composer: composer require craftcms/commerce-stripe # Install the plugin with Craft: php craft install/plugin commerce-stripe
设置
要添加Stripe支付网关,请打开Craft控制面板,导航到Commerce → 系统设置 → 网关,然后点击+ 新网关。
您的网关的名称应使管理员和客户都能理解(特别是如果您正在使用示例模板)。
密钥
从网关下拉菜单中选择Stripe,然后提供以下信息
- 可发布API密钥
- 密钥API密钥
- Webhook签名密钥(有关详细信息,请参阅Webhooks)
您的可发布API密钥和密钥API密钥可以在您的Stripe仪表板中的(或从其中生成)开发者 → API密钥选项卡中找到。有关Stripe API密钥的更多信息。
注意
为了防止密钥泄露到项目配置中,请将它们放入您的.env
文件中,然后在网关设置中使用特殊的环境变量语法。
Stripe提供了不同的测试密钥——在准备发布之前使用这些密钥,然后在实时服务器的.env
文件中替换测试密钥。
Webhooks
一旦网关已保存(并且它有一个ID),重新访问其编辑屏幕将显示一个可以复制到您的Stripe仪表板中新Webhook的Webhook URL。将为您生成一个签名密钥——将其保存到您的.env
文件中与其他密钥一起,然后返回网关设置屏幕,并用变量的名称填充Webhook签名密钥字段。
警告
如果签名密钥缺失或无效,Webhooks将不会处理!
我们建议在Stripe中启用所有可用的webhook事件。插件没有使用的事件将被忽略。
请记住,每个环境的webhook URL都将不同!由于项目配置的工作方式,网关在生产环境和开发环境中的ID可能不同。
本地开发
您的本地环境很少暴露在公共互联网上,因此Stripe无法发送测试webhook。您有两个测试webhook的选项
-
使用Stripe CLI,将以下命令中的URL替换为网关设置屏幕中的URL
stripe listen --forward-to "my-project.ddev.site/index.php?action=commerce/webhooks/process-webhook&gateway=1"
此命令将创建一个临时webhook和签名密钥,您应该将其添加到
.env
文件中,并查看Stripe的测试webhook文章以获取更多信息。 -
使用DDEV的
share
命令,并在Stripe中手动配置webhook时使用公共Ngrok URL。
从4.x升级到5.x
5.0版本在很大程度上与4.x兼容。查看以下部分以确保您的网站(以及任何自定义)保持功能正常。
支付表单
为了支持通过Stripe(如Apple Pay和Google Pay)提供的所有支付方式,该插件专用于使用支付意向API。
历史上,gateway.getPaymentFormHtml()
输出一个用于在客户端标记信用卡的基本表单,然后仅提交结果标记到commerce/payments/pay
操作,并在后端捕获付款。使用此过程的自定义支付表单将继续工作。
现在,输出是一个更灵活的支付元素表单,它利用Stripes的现代支付意向API。过程看起来像这样
- 向后台提交一个请求到
commerce/payments/pay
(没有支付方式); - Commerce创建一个包含订单一些信息的支付意向,然后设置一个内部
Transaction
记录来跟踪其状态; - 支付意向的
client_secret
返回到前端; - 使用密钥初始化Stripe JS SDK,客户可以从可用的支付方式中选择;
有关如何配置新支付表单的详细信息见下文。
API版本
由于某些支付意向功能的可用性,您的Stripe账户必须配置为使用至少版本2022-11-15
的API。
订阅
由于与Stripe处理默认支付方式的兼容性不一致,已在同一请求中创建新支付源以支持订阅的功能已被弃用。在未来版本中,订阅端点将专注于启动订阅,而不是接受付款信息。目前,使用传统费用工作流程的自定义订阅表单将继续工作。
我们建议以下策略之一
-
在选择订阅之前设置支付源。设计您的订阅过程以捕获付款细节,然后选择计划。
-
在同一页面上使用Ajax创建支付源。 这仅应在配置客户的第一个支付方式时受支持。您可以对Commerce的
payment-sources/add
操作进行预先检查Ajax请求以设置支付方式,然后使用正常的订阅表单—Stripe将使用该唯一的支付源与订阅一起使用。 -
向用户展示订阅将关联的支付方式。 这是一个非常好的想法,无论怎样——确认用户将使用他们现有的哪些支付方式。您可以在Twig中找到客户的默认支付方式,如下所示
{# Assuming a `plan` variable exists in this context... #} {% set paymentSources = craft.commerce.paymentSources.getAllGatewayPaymentSourcesByCustomerId(plan.gatewayId, currentUser.id) %} {% set primaryPaymentSource = paymentSources | filter((ps) => ps.getIsPrimary()) | first %} {% if primaryPaymentSource %} {# Show some information about the source: #} This subscription will be billed to: {{ primaryPaymentSource.description }} {# Then, output the form! #} {% else %} <p>You must set up a payment method to start a subscription!</p> {{ tag('a', { href: siteUrl('account/payment-sources'), text: 'Add a payment method', }) }} {% endif %}
[!注意] 如果您的商店使用多个网关,客户的默认支付方式可能不一定属于与计划相同的网关,因此
primaryPaymentSource
可能 为空,即使他们已经选择了一个。
同步
更新后,我们建议运行新的 支付方式同步命令,以确保您的商店数据与Stripe的记录保持最新。
配置设置
这些选项通过 config/commerce-stripe.php
设置。
chargeInvoicesImmediately
对于自动付款的订阅,Stripe会在尝试收费前1-2小时创建账单。通过将此设置为 true
,您可以强制Stripe立即收取此账单。
警告
此设置影响 所有 商业安装中的Stripe网关。
订阅
Stripe插件在商业的订阅系统和Stripe的 计费 API之间提供接口。
创建订阅计划
计划必须首先在 Stripe仪表板 中进行配置。
- 在Craft控制面板中,转到 Commerce → 商店设置 → 计划,然后点击 + 新建订阅计划;
- 从 网关 下拉菜单中选择 Stripe;
- 从 网关计划 下拉菜单中选择计划名称;
注意
Stripe中的计划分别针对实时和测试模式进行配置!您可能看到的计划列表取决于您正在使用哪些密钥。
订阅选项
除了您POST到商业的 commerce/subscriptions/subscribe
动作 的值之外,Stripe网关还支持以下选项
trialDays
试用期天数到期后,将开始第一个完整的计费周期。默认值为 0
。
取消选项
除了您POST到商业的 commerce/subscriptions/cancel
动作 的值之外,Stripe网关还支持以下选项
cancelImmediately
如果此参数设置为 true
,则订阅将立即取消。Stripe将其视为同时取消和“删除”(就webhook而言)——但订阅记录仍然可用。默认情况下,订阅被标记为已取消,并将与当前计费周期一起结束。默认为 false
。
注意
立即取消订阅意味着它不能被重新激活。
计划切换选项
除了您POST到商业的 commerce/subscriptions/switch
动作 的值之外,Stripe网关还支持以下选项
prorate
如果此参数设置为 true
,则订阅切换将 按比例计算。默认为 false
。
billImmediately
如果此参数设置为 true
,则订阅切换将立即计费。否则,成本(或信用,如果切换到更便宜的计划时将 prorate
设置为 true
)将应用于下一个账单。
警告
如果计费周期不同,计划切换将立即计费,此参数将被忽略。
重新激活选项
重新激活订阅时没有可用的自定义选项。
事件
插件提供了您可以使用以修改集成行为的几个事件。
支付事件
buildGatewayRequest
在创建支付意向的过程中与 Stripe 通信时,插件有机会提供额外的元数据。这使您几乎可以完全控制 Stripe 看到的数据,以下是需要考虑的因素:
- 对
Transaction
模型(通过事件的transaction
属性获取)的更改将不会保存; - 网关自动设置
order_id
、order_number
、order_short_number
、transaction_id
、transaction_reference
、description
和client_ip
等元数据键; - 对
request
属性下的amount
和currency
键的更改将被忽略,因为这些是网关以可预测方式运行所必需的;
use craft\commerce\models\Transaction; use craft\commerce\stripe\events\BuildGatewayRequestEvent; use craft\commerce\stripe\gateways\PaymentIntents; use yii\base\Event; Event::on( PaymentIntents::class, PaymentIntents::EVENT_BUILD_GATEWAY_REQUEST, function(BuildGatewayRequestEvent $e) { /** @var Transaction $transaction */ $transaction = $e->transaction; $order = $transaction->getOrder(); $e->request['metadata']['shipping_method'] = $order->shippingMethodHandle; } );
注意
订阅事件 将单独处理。
receiveWebhook
除了通用的 craft\commerce\services\Webhooks::EVENT_BEFORE_PROCESS_WEBHOOK
事件 之外,您还可以监听 craft\commerce\stripe\gateways\PaymentIntents::EVENT_RECEIVE_WEBHOOK
。此事件仅在验证 webhook 的真实性后发出,但它不会对是否采取了对它的响应作出任何指示。
use craft\commerce\stripe\events\ReceiveWebhookEvent; use craft\commerce\stripe\gateways\PaymentIntents; use yii\base\Event; Event::on( PaymentIntents::class, PaymentIntents::EVENT_RECEIVE_WEBHOOK, function(ReceiveWebhookEvent $e) { if ($e->webhookData['type'] == 'charge.dispute.created') { if ($e->webhookData['data']['object']['amount'] > 1000000) { // Be concerned that a USD 10,000 charge is being disputed. } } } );
webhookData
总是包含一个 type
键,它确定了 data
中所有内容的模式。请参阅 Stripe 文档了解预期的数据类型。
订阅事件
createInvoice
当 Stripe 发票创建时,插件有机会执行某些操作。这通常在处理 webhook 的过程中发出。
use craft\commerce\stripe\events\CreateInvoiceEvent; use craft\commerce\stripe\gateways\PaymentIntents; use yii\base\Event; Event::on( PaymentIntents::class, PaymentIntents::EVENT_CREATE_INVOICE, function(CreateInvoiceEvent $e) { if ($e->invoiceData['billing'] === 'send_invoice') { // Forward this invoice to the accounting department. } } );
beforeSubscribe
在订阅时,插件有机会调整订阅参数。
use craft\commerce\stripe\events\SubscriptionRequestEvent; use craft\commerce\stripe\gateways\PaymentIntents; use yii\base\Event; Event::on( PaymentIntents::class, PaymentIntents::EVENT_BEFORE_SUBSCRIBE, function(SubscriptionRequestEvent $e) { /** @var craft\commerce\base\Plan $plan */ $plan = $e->plan; /** @var craft\elements\User $user */ $user = $e->user; // Add something to the metadata: $e->parameters['metadata']['name'] = $user->fullName; unset($e->parameters['metadata']['another_property']); } );
Commerce 还有一个 通用订阅事件,该事件在通过 任何 网关创建的订阅中发出。
计费门户
现在可以为客户生成一个链接到 Stripe 计费门户,以便他们管理自己的信用卡和计划。
<a href="{{ gateway.billingPortalUrl(currentUser) }}">Manage your billing account</a>
传递一个 returnUrl
参数,在客户完成操作后将他们返回到特定的站点页面
{{ gateway.billingPortalUrl(currentUser, 'myaccount') }}
可以使用第三个 configurationId
参数选择特定的 Stripe 客户门户配置。此值必须与在关联的 Stripe 账户中通过 API 创建的现有配置值相匹配;
{{ gateway.billingPortalUrl(currentUser, 'myaccount', 'config_12345') }}
注意
登录用户也可以使用 commerce-stripe/customers/billing-portal-redirect
操作进行重定向。当使用此方法时,不支持 configurationId
参数。
同步客户支付方式
现在将直接在 Stripe 客户门户中创建的支付方式同步回 Commerce。客户的默认支付方式也将同步。
注意
必须配置 webhook 才能按预期工作!
要执行初始同步,请运行 commerce-stripe/sync/payment-sources
控制台命令
php craft commerce-stripe/sync/payment-sources
创建 Stripe 支付表单
要渲染 Stripe Elements 支付表单,获取网关的引用,然后调用其 getPaymentFormHtml()
方法
{% set cart = craft.commerce.carts.cart %} {% set gateway = cart.gateway %} <form method="POST"> {{ csrfInput() }} {{ actionInput('commerce/payments/pay') }} {% namespace gateway.handle|commercePaymentFormNamespace %} {{ gateway.getPaymentFormHtml({})|raw }} {% endnamespace %} <button>Pay</button> </form>
这假设您已在之前的结账步骤中提供了选择网关的方式。如果您的商店只使用单个网关,您可以在支付时静态地获取网关的引用并设置它
{% set gateway = craft.commerce.gateways.getGatewayByHandle('myStripeGateway') %} <form method="POST"> {{ csrfInput() }} {{ actionInput('commerce/payments/pay') }} {# Include *outside* the namespaced form inputs: #} {{ hiddenInput('gatewayId', gateway.id) }} {% namespace gateway.handle|commercePaymentFormNamespace %} {{ gateway.getPaymentFormHtml({})|raw }} {% endnamespace %} <button>Pay</button> </form>
无论您如何使用此输出,它都将自动注册创建支付意向和引导 Stripe Elements 所需的所有必要 JavaScript。
自定义 Stripe 支付表单
getPaymentFormHtml()
接受一个具有以下任一键的数组
paymentFormType
elements
(默认)
渲染包含所有支付方式类型的Stripe Elements表单,这些支付方式已在您的Stripe仪表板上启用。(请参阅此处了解详情)某些方法可能因订单总额或货币不符合该方法的要求,或者在该环境中不支持而隐藏。
{% set params = { paymentFormType: 'elements', } %} {{ cart.gateway.getPaymentFormHtml(params)|raw }}
这是默认的paymentFormType
,大多数安装不需要声明或更改它。
结账
这会生成一个可重定向到托管Stripe Checkout页面的表单。此选项只能用于commerce/payments/pay
表单内部。此选项忽略所有其他参数。
{% set params = { paymentFormType: 'checkout', } %} {{ gateway.getPaymentFormHtml(params)|raw }}
外观
您可以传递一个外观选项数组到stripe.elements()
配置器函数。该函数需要与Elements Appearance API兼容的数据。
{% set params = { appearance: { theme: 'stripe' } } %} {{ cart.gateway.getPaymentFormHtml(params)|raw }}
{% set params = { appearance: { theme: 'night', variables: { colorPrimary: '#0570de' } } } %} {{ cart.gateway.getPaymentFormHtml(params)|raw }}
元素选项
修改传递给elements.create()
工厂函数的支付元素选项。
{% set params = { elementOptions: { layout: { type: 'tabs', defaultCollapsed: false, radios: false, spacedAccordionItems: false } } } %} {{ cart.gateway.getPaymentFormHtml(params)|raw }}
默认的elementOptions
值仅定义了布局
{% set params = { elementOptions: { layout: { type: 'tabs' } } } %}
order
(可选)
order
键应该是对Commerce Order
模型的引用,这通常是在您的模板中的当前cart
变量。
如果提供了,则将账单详情添加到elementOptions
的默认defaultValues
数组中。
{% set params = { order: cart, } %} {{ cart.gateway.getPaymentFormHtml(params)|raw }}
如果您没有将order
传递给支付表单,您可以选择使用elementOptions
的defaultValues
键手动填充账单详情。
{% set params = { elementOptions: { defaultValues: { name: 'Jane Doe', address: { line1: '123 Main St', city: 'Anytown', state: 'NY', postal_code: '12345', country: 'US', }, } ...
errorMessageClasses
错误消息显示在表单上方的容器中。您可以为此元素添加类以更改其样式。
{% set params = {
errorMessageClasses: 'bg-red-200 text-red-600 my-2 p-2 rounded',
} %}
{{ cart.gateway.getPaymentFormHtml(params)|raw }}
submitButtonClasses
和submitButtonText
自定义用于提交支付表单的按钮的样式和文本。
{% set params = { submitButtonClasses: 'cursor-pointer rounded px-4 py-2 inline-block bg-blue-500 hover:bg-blue-600 text-white hover:text-white my-2', submitButtonText: 'Pay', } %} {{ cart.gateway.getPaymentFormHtml(params)|raw }}