# Laravel Cashier - [简介](#introduction) - [升级 Cashier](#upgrading-cashier) - [安装](#installation) - [配置](#configuration) - [Billable 模型](#billable-model) - [API Keys](#api-keys) - [货币配置](#currency-configuration) - [客户](#customers) - [创建客户](#creating-customers) - [支付方式](#payment-methods) - [存储支付方式](#storing-payment-methods) - [获取支付方式](#retrieving-payment-methods) - [确认用户是否拥有支付方式](#check-for-a-payment-method) - [更新默认支付方式](#updating-the-default-payment-method) - [添加支付方式](#adding-payment-methods) - [删除支付方式](#deleting-payment-methods) - [订阅](#subscriptions) - [创建订阅](#creating-subscriptions) - [检查订阅状态](#checking-subscription-status) - [修改订阅计划](#changing-plans) - [订阅量](#subscription-quantity) - [订阅税额](#subscription-taxes) - [订阅锚定日期](#subscription-anchor-date) - [取消订阅](#cancelling-subscriptions) - [恢复订阅](#resuming-subscriptions) - [订阅试用](#subscription-trials) - [预付款方式](#with-payment-method-up-front) - [非预付款方式](#without-payment-method-up-front) - [处理 Stripe Webhooks](#handling-stripe-webhooks) - [定义 Webhook 事件句柄](#defining-webhook-event-handlers) - [订阅失败](#handling-failed-subscriptions) - [验证 Webhook 签名](#verifying-webhook-signatures) - [一次性支付](#single-charges) - [简单支付](#simple-charge) - [费用与发票](#charge-with-invoice) - [关于退款](#refunding-charges) - [发票](#invoices) - [生成电子发票](#generating-invoice-pdfs) - [强客户身份验证 (SCA)](#strong-customer-authentication) - [需求额外验证的支付](#payments-requiring-additional-confirmation) - [无会话(Off-session) 支付通知](#off-session-payment-notifications) ## 简介 Laravel Cashier 提供了直观而流畅的接口来接入 [Stripe](https://stripe.com) 付费订阅服务,它可以处理几乎所有的让你头疼的付费订阅代码。除了基本的订阅管理之外,Cashier 还可以帮你处理优惠券、交换订阅、订阅数量、取消宽限期,甚至还可以生成 PDF 电子发票。 > {注意} 为防止破坏性的更改,Cashier 使用固定的 Stripe API 版本。Cashier 10.1 利用 Stripe API `2019-08-14` 版本。Stripe API 版本将在次要分发上更新以便使用新的 Stripe 特性和改进。 ## 升级 Cashier 当你升级到新版本 Cashier 时,,请务必仔细阅读 [Cashier 升级指南](https://github.com/laravel/cashier/blob/master/UPGRADE.md)。 ## 安装 首先,使用 composer 将 Stripe 的 Cashier 包添加到项目依赖中: composer require laravel/cashier > {注意} 为确保 Cashier 正确的处理所有的 Stripe 事件,请记得 [配置 Cashier webhook 处理](#handling-stripe-webhooks)。 #### 数据库迁移 Cashier 服务提供者注册了自己的数据库迁移目录,请记住在安装完包后迁移你的数据库。Cashier 迁移会在你的 `users` 表中增加几列并创建一个新的 `subscriptions` 表来保存你所有客户的订阅: php artisan migrate 如果你需要覆盖 Cashier 包附带的迁移,可以使用 `vendor:publish` Artisan 命令发布它们: php artisan vendor:publish --tag="cashier-migrations" 如果你想阻止 Cashier 迁移完全运行,可以使用 Cashier 提供的 `ignoreMigrations` 。通常,你应该在 `AppServiceProvider` 的 `register` 方法中调用这个方法: use Laravel\Cashier\Cashier; Cashier::ignoreMigrations(); > {注意} Stripe 建议用来存储 stripe 标识符的所有列应该大小写敏感。因此,以 MySQL 数据库为例,你应该确保 `stripe_id` 列的列排序规则设置为 `utf8_bin` ,更多信息可以在 [Stripe 文档](https://stripe.com/docs/upgrades#what-changes-does-stripe-consider-to-be-backwards-compatible) 中找到。 ## 配置 ### Billable 模型 在使用 Cashier 之前, 添加 `Billable` Trait 到你的模型定义中。 这个 Trait 提供了多种方法以便你执行常见的支付任务,如创建订阅、申请优惠券以及更新支付方式信息: use Laravel\Cashier\Billable; class User extends Authenticatable { use Billable; } Cashier 暂定你的 Billable 模型是 Laravel 附带的 `App\User` 类,如果你想修改请在你的 `.env` 文件中指定一个不同的模型: CASHIER_MODEL=App\User > {注意} 如果你使用的不是 Laravel 提供的 `App\User` 模型,你应该发布并更改提供的 [migrations](#installation) 以匹配你的代替模型数据表名。 ### API 密钥 接下来,您需要在 `.env` 中配置您的 Stripe 密钥。您可以在 Stripe 的控制面板中获取 Stripe API 密钥. STRIPE_KEY=your-stripe-key STRIPE_SECRET=your-stripe-secret ### 货币配置 Cashier 的默认货币是美元 (USD)。您可以设置 `CASHIER_CURRENCY` 来更改默认的货币: CASHIER_CURRENCY=eur 为了配置 Cashier 使用的货币,您也许需要指定一个额外的 Locale(本地化) 参数,用于格式化在账单上面显示的金额。Cashier 内部使用 [PHP 的 `NumberFormatter` 类](https://www.php.net/manual/en/class.numberformatter.php) 来格式化数字: CASHIER_CURRENCY_LOCALE=nl_BE > {note} 要使用除了 `en` 之外的 Locale,确保 `ext-intl` 扩展在服务器上安装并配置好。 ## 客户 ### 创建客户 有时,您可能希望在未订阅的情况下创建 Stripe 客户。您可以使用 `createAsStripeCustomer` 方法完成此操作: $user->createAsStripeCustomer(); 一旦在 Stripe 中创建了客户,您可以稍后便可开始订阅。 ## 支付方式 ### 储存支付方式 为了使用 Stripe 创建订阅或是一次性扣费,您将需要从 Stripe 获取支付方式并储存他的识别码。基于您计划使用的支付方式是用来一次性扣费还是订阅,我们有两种方案来达成,接下来我们一起来看一下这两种方法。 #### 用于订阅制的支付方法 为了储存用户的信用卡供以后使用,Stripe 的 “Setup Intent” API 需要安全的获取用户的信用卡信息。“Setup Intent” 指示 Stripe 用户支付方式的意象。Cashier 的`Blillable` trait 包含了 `createSetupIntent` 方法来快速创建一个 “Setup Intent”。 您应该在路由或者控制器调用这个方法来获取用户的支付方式意象: return view('update-payment-method', [ 'intent' => $user->createSetupIntent() ]); 当您创建完 “Setup Intent” 并传递给视图后,您应该将它的密钥元素附加到获取用户支付信息的表单中。如下面这个“更新支付方式”表单:
接下来,Stripe.js 库会调用这个密钥并安全地抓取用户的支付信息: 然后,卡片会被校验且您可以使用 [Stripe 的 `handleCardSetup` 方法] (https://stripe.com/docs/stripe-js/reference#stripe-handle-card-setup)来获取一个安全的“支付方式识别码”: const cardHolderName = document.getElementById('card-holder-name'); const cardButton = document.getElementById('card-button'); const clientSecret = cardButton.dataset.secret; cardButton.addEventListener('click', async (e) => { const { setupIntent, error } = await stripe.handleCardSetup( clientSecret, cardElement, { payment_method_data: { billing_details: { name: cardHolderName.value } } } ); if (error) { // 显示错误信息 } else { // 卡片已成功验证 } }); 当 Stripe 完成对客户支付方式的校验后,您可以将`setupIntent.payment_method` 识别码返回给您的应用并附加给客户。这次支付使用的支付方式可 [被添加为新的支付方式](#adding-payment-methods) 或者 [用于更新默认支付方式](#updating-the-default-payment-method)。您可以立即使用这个识别码来 [创建一个订阅](#creating-subscriptions). > {tip} 如果您希望了解更多有关 “Setup Intent” 与获取收集用户支付详情的信息,请参阅 [Stripe 的文档](https://stripe.com/docs/payments/cards/saving-cards#saving-card-without-payment). #### 用于一次性收费的支付方式 当然,用于一次性收费的支付识别码我们只需要使用一次。由于 Stripe 的限制,您无法使用客户的一次性收费的支付方式。您需要用 Stripe.js 库来让客户填写他们的支付详情。让我们来看一下下面这个支付表单: 接下来,Stripe.js 可用来附加一个 Stripe 元素用于加密用户的支付方式详情: 然后,卡片会被校验且您可以使用 [Stripe 的 `createPaymentMethod` 方法](https://stripe.com/docs/stripe-js/reference#stripe-create-payment-method): 来获取一个安全的“支付方式识别码”: const cardHolderName = document.getElementById('card-holder-name'); const cardButton = document.getElementById('card-button'); cardButton.addEventListener('click', async (e) => { const { paymentMethod, error } = await stripe.createPaymentMethod( 'card', cardElement, { billing_details: { name: cardHolderName.value } } ); if (error) { // 错误信息 } else { // 卡片验证成功 } }); 如果卡片验证成功,您可以将 `paymentMethod.id` 传递给您的应用并进行 [一次性付费](#simple-charge). ### 获取支付方式 `Billable` 模块实例上的 `paymentMethods` 方法将返回一组 `Laravel\Cashier\PaymentMethod` 实例: $paymentMethods = $user->paymentMethods(); 要获取默认的支付方式,可以使用 `defaultPaymentMethod`方法: $paymentMethod = $user->defaultPaymentMethod(); ### 确认用户是否拥有支付方式 要确认一个`Billable` 模型是否拥有一个支付方式,使用 `hasPaymentMethod` 方法: if ($user->hasPaymentMethod()) { // } ### 更新默认的支付方式 `updateDefaultPaymentMethod` 可用来更新用户的默认支付方式。这个方法接受 Stripe 的支付方式识别码并且会将新分配的识别码设为默认的支付方式: $user->updateDefaultPaymentMethod($paymentMethod); 要在 Stripe 内同步您与客户的默认支付方式,您可以使用 `updateDefaultPaymentMethodFromStripe` 方法: $user->updateDefaultPaymentMethodFromStripe(); > {note} 客户的默认支付方式只能用户创建发票或订阅,由于 Stripe 的限制,某些支付方式不适用于一次性收费 ### 添加支付方式 要添加新的支付方式,您可以在(可收费的) `Billable` 用户上调用 `addPaymentMethod` 方法,并传递支付方式识别码: $user->addPaymentMethod($paymentMethod); > {tip} 要学习如何获取并储存支付方式识别码,请参阅 [支付方式储存](#storing-payment-methods). ### 删除支付方式 要删除一个支付方式,你可以调用 `Laravel\Cashier\PaymentMethod` 上的 `delete` 方法进行删除: $paymentMethod->delete(); `deletePaymentMethods` 方法将删除Billable模型的所有相关付款方式的信息: $user->deletePaymentMethods(); > 注意:如果用户的订阅比较活跃,那么应该阻止他们删除默认的付款方式。 ## 订阅 ### 创建订阅 创建订阅,首先需要获取到一个 Billable 模型实例,这通常是 `App\User` 的一个实例。一旦您获取了模型实例,您可以使用 `newSubscription` 方法创建模型的订阅: $user = User::find(1); $user->newSubscription('main', 'premium')->create($paymentMethod); `newSubscription` 方法的第一个参数应该是订阅的名称。如果您的应用程序只提供一个订阅,那么您可以将其设置为 `main` or `primary`。第二个参数是用户订阅的 Stripe 计划。这个值应该与 Stripe 或 Braintree 中的标识符对应。 `create` 方法接受一个 [支付方法标识符](#storing-payment-methods)或者 Stripe `PaymentMethod` 对象后将开始订阅, 并使用客户 ID 和其他相关的账单信息更新数据库。 > 注意:直接传递支付方法标识符到 `create()` 方法也可以将用户的付款方式储存到数据库。 #### 用户其他的详细信息 如果您想要指定用户其他的详细信息,您可以通过将它们作为第二个参数传递给 `create` 方法: $user->newSubscription('main', 'monthly')->create($paymentMethod, [ 'email' => $email, ]); 要了解更多关于 Stripe 支持的额外字段,请查看 Stripe 的[内容创建客户文档](https://stripe.com/docs/api#create_customer)。 #### 优惠券 如果您想在创建订阅时使用优惠券,您可以使用 `withCoupon` 方法: $user->newSubscription('main', 'monthly') ->withCoupon('code') ->create($paymentMethod); ### 检查订阅状态 一旦用户在您的应用程序订阅了,您可以使用各种方便的方法轻松地检查他们的订阅状态。首先,如果用户有一个激活的订阅,那么 `subscribed` 的方法将返回 `true` ,即使订阅当前处于试用阶段: if ($user->subscribed('main')) { // } 这个 `subscribed` 方法还可以在 [路由中间件](/docs/{{version}}/middleware)使用,允许您根据用户的订阅状态对路由和控制器进行访问: public function handle($request, Closure $next) { if ($request->user() && ! $request->user()->subscribed('main')) { // 该用户不是付费客户...... return redirect('billing'); } return $next($request); } 如果您想要确定用户是否仍然处于试用阶段,您可以使用 `onTrial` 方法。这个方法对于向用户显示他们仍然处于试用期的警告是很有用的: if ($user->subscription('main')->onTrial()) { // } 基于给定的 Stripe 计划 ID,可以使用 `subscribedToPlan` 方法来确定用户是否订阅了该计划。在本例中,我们将确定用户的 `main` 订阅是否激活了 `monthly` 计划: if ($user->subscribedToPlan('monthly', 'main')) { // } `recurring` 方法可用于确定用户当前是否已订阅,并且不再处于试用阶段: if ($user->subscription('main')->recurring()) { // } #### 取消订阅状态 为了确定用户是否曾经订阅,但是已经取消了他们的订阅,您可以使用 `cancelled` 方法: if ($user->subscription('main')->cancelled()) { // } 您还可以确定用户是否已经取消了订阅,但是仍然处于订阅的「宽限期」,直到订阅完全过期为止。例如,如果用户在 3 月 5 日取消了原定于 3 月 10 日到期的订阅,那么用户将在 3 月 10 日之前进行「宽限期」。请注意,在此期间 `subscribed` 方法仍然返回 `true`: if ($user->subscription('main')->onGracePeriod()) { // } 如果要确定用户取消订阅的时间是否已不在其「宽限期」 内,可以使用 `ended` 方法: if ($user->subscription('main')->ended()) { // } #### 不完整和过期状态 如果订阅需要在创建后进行二次付款操作,则订阅将被标记为 `incomplete` 。订阅状态存储在 `stripe_status` Cashier `subscriptions` 数据库表的列中。 同样,如果在交换计划时需要进行二次付款操作,则订阅将被标记为 `past_due` 。当您的订阅处于这两种状态时,在客户确认付款之前,它将不会处于活动状态。检查订阅是否有不完整的付款可以使用 `hasIncompletePayment` Billable模型或订阅实例上的方法完成: if ($user->hasIncompletePayment('main')) { // } if ($user->subscription('main')->hasIncompletePayment()) { // } 如果订阅的付款不完整,您应该将用户定向到收银员的付款确认页面,并传递`latestPayment` 标识符。您可以使用 `latestPayment` 订阅实例上的可用方法来检索此标识符: Please confirm your payment. > 注意:订阅处于某种 `incomplete` 状态时,在确认付款之前无法更改。因此,当订阅处于某种状态时, `swap` 和 `updateQuantity` 方法将抛出异常 `incomplete` 。 ### 修改订阅计划 用户在您的应用程序中订阅了之后,他们可能会偶尔想要更改一个新的订阅计划。要将一个用户切换到一个新的订阅,需将订阅计划的标识符传递给 `swap` 方法: $user = App\User::find(1); $user->subscription('main')->swap('provider-plan-id'); 如果用户在试用期,试用期的期限会被保留。另外,如果订阅的数量存在「份额」,那么该份额也将保持。 如果你想在更改用户订阅计划的时候取消用户当前订阅的试用期,可以使用 `skipTrial` 方法: $user->subscription('main') ->skipTrial() ->swap('provider-plan-id'); 如果你想在更改用户订阅计划的时候就为用户开具发票信息,而不是等待下一个结算周期, 你可以使用 `swapAndInvoice` 方法: $user = App\User::find(1); $user->subscription('main')->swapAndInvoice('provider-plan-id'); ### 订阅量 有些时候订阅是会受「数量」影响的。举个例子,你的应用程序的付费方式可能是**每个账户** $10 / 月。你可以使用 `incrementQuantity` 和 `decrementQuantity` 方法轻松地增加或减少你的订阅量: $user = User::find(1); $user->subscription('main')->incrementQuantity(); // 对当前的订阅量加5... $user->subscription('main')->incrementQuantity(5); $user->subscription('main')->decrementQuantity(); // 对当前的订阅量减5... $user->subscription('main')->decrementQuantity(5); 或者,你可以使用 `updateQuantity` 方法设定一个特定的数量: $user->subscription('main')->updateQuantity(10); `noProrate` 方法可用于更新订阅的数量,而不会对收费进行定价: $user->subscription('main')->noProrate()->updateQuantity(10); 要获得更多关于订阅量的信息,请参考 [Stripe 文档](https://stripe.com/docs/subscriptions/quantities). ### 订阅税额 在计费模式上实现 `taxPercentage` 方法,并且返回一个 0 到 100 不超过 2 位小数的数字,用来指定用户在订阅中支付的税率百分比。 public function taxPercentage() { return 20; } `taxPercentage` 方法使你能够在模型的基础上应用税率,这对于一个跨越多个国家和税率的用户群可能有帮助。 > 注意:`taxPercentage` 方法只适用于付费订阅模式。如果你用 charges 来做「一次性」收费,你需要同时手工指定税率。 #### 同步税率百分比 当更改 `taxPercentage` 方法返回的硬编码值时,用户的任何现有订阅的税率设置将保持不变。如果要用返回的 `taxPercentage` 值更新现有订阅的税率,应在用户的订阅实例上调用 `syncTaxPercentage` 方法: $user->subscription('main')->syncTaxPercentage(); ### 订阅锚定日期 默认情况下,计费周期锚定是创建订阅的日期,如果使用试用期,则是试用结束的日期。如果要修改账单锚定日期,可以使用 `anchorBillingCycleOn` 方法: use App\User; use Carbon\Carbon; $user = User::find(1); $anchor = Carbon::parse('first day of next month'); $user->newSubscription('main', 'premium') ->anchorBillingCycleOn($anchor->startOfDay()) ->create($paymentMethod); 有关管理订阅计费周期的详细信息,请参阅 [Stripe 计划周期文档](https://stripe.com/docs/billing/subscriptions/billing-cycle) ### 取消订阅 在用户订阅上调用 `cancel` 方法用来取消订阅: $user->subscription('main')->cancel(); 当一个订阅被取消时,Cashier 将会自动在你的数据库中设置 `ends_at` 列。这个列经常被用来获悉 `subscribed` 字段何时应该开始返回 `false` 。例如,如果客户在 3 月 1 日取消订阅,但是订阅计划直到 3 月 5 日才结束,`subscribed` 方法将会继续返回 `true` 一直到 3 月 5 日。 你可以使用 `onGracePeriod` 方法确定用户是否确定订阅,但是仍然存在一个「宽限期」: if ($user->subscription('main')->onGracePeriod()) { // } 如果你想马上取消订阅,请在用户的订阅中调用 cancelNow 方法: $user->subscription('main')->cancelNow(); ### 恢复订阅 如果一个用已经取消订阅,你可以在你希望恢复它的时候使用 resume 方法。用户 **必须** 仍然在他们的宽限期内才可以恢复订阅: $user->subscription('main')->resume(); 如果用户已取消订阅,然后在订阅宽限期前恢复该订阅,他们将不会被立即计费。相反,他们的订阅将会被重新激活,需要按照原来的支付流程再次进行支付。 ## 试用订阅 ### 以信用卡订阅 如果你想给你的顾客提供试用期,同时收集支付方法信息,那么你应该在创建订阅使用 `trialDays` 方法: $user = User::find(1); $user->newSubscription('main', 'monthly') ->trialDays(10) ->create($paymentMethod); 该方法会在数据库订阅记录上设置订阅期结束时间,以便告知 Sripe 在此之前不要计算用户的账单信息。当使用 `trialDays` 方法时,Cashier将覆盖 Stripe 中配置的所有默认试用期。 > 注意:如果顾客没有在试用期结束前取消订阅,订阅会被自动结算,所以你应该确保告知你的用户他们的试用结束期。 `trialUntil` 方法允许提供 `DateTime` 实例指定试用结束期: use Carbon\Carbon; $user->newSubscription('main', 'monthly') ->trialUntil(Carbon::now()->addDays(10)) ->create($paymentMethod); 你可以使用用户实例的 `onTrial` 方法或者订阅实例的 `onTrial` 方法判断用户是否处于试用期。下面两个示例等价: if ($user->onTrial('main')) { // } if ($user->subscription('main')->onTrial()) { // } ### 非信用卡订阅 如果你不想在提供试用期的时候收集用户支付方式信息,只需设置用户记录的 `trial_ends_at` 列为期望的试用期结束日期即可,这通常在用户注册期间完成: $user = User::create([ // 填充其他用户属性…… 'trial_ends_at' => now()->addDays(10), ]); > 注意:确保已添加 `trial_ends_at` [日期修改器](/docs/{{version}}/eloquent-mutators#date-mutators) 到模型定义。 Cashier 把这种类型的引用称为「一般体验」,因为它没有关联任何已存在的订阅。如果当前的日期没有超过 `trail_ends_at` 值, `User` 实例的 `onTrial` 方法将会返回 `true` : if ($user->onTrial()) { // 用户在他们的试用期内... } 如果你希望明确的知道用户处于「一般」试用期,并且还未创建实际的订阅,那么你可以使用 `onGenericTrial` 方法: if ($user->onGenericTrial()) { // 用户在他们「一般」试用期... } 如果你准备给用户创建实际的订阅,通常你可以使用 `newSubsription` 方法: $user = User::find(1); $user->newSubscription('main', 'monthly')->create($paymentMethod); ## 处理 Stripe Webhooks > 提示:你可以使用 [Laravel Valet's](/docs/{{version}}/valet)中的 `valet share` 命令来帮助你在本地开发期间测试webhook。 Stripe可以通过webhooks通知应用各种各样的事件。 默认情况下,需要定义一个 Cashier 的 webhook 控制器的路由。这个控制器用来处理所有传入的webhook请求。 默认情况下,这个控制器将会自动对支付失败次数过多(这个次数可以在 Stripe 设置中定义)的订阅进行取消;此外,我们很快会发现,你可以扩展这个控制器去处理任何你想要处理的 webhook 事件。 为了确保您的应用可以处理Stripe webhook,请务必在Stripe控制面板中配置webhook URL。Stripe 控制面板中应该配置的所有webhook完整列表如下: - `customer.subscription.updated` - `customer.subscription.deleted` - `customer.updated` - `customer.deleted` - `invoice.payment_action_required` > 注意:请确保使用 Cashier 的 [webhook 验签](/docs/{{version}}/billing#verifying-webhook-signatures) 中间件来保护传入请求。 #### Webhooks & CSRF 保护 因为 Stripe webhooks 需要绕过 Laraval 的 [CSRF 保护](/docs/{{version}}/csrf), 请确保在您的 `VerifyCsrfToken` 中间件含有 URI ,或者将其置于 `web` 中间件组之外: protected $except = [ 'stripe/*', ]; ### 定义 Webhook 事件处理程序 Cashier 对于失败支付自动进行取消订阅,但是如果您有其他的 Stripe Webhook 事件希望去处理,可以扩展 Webhook 控制器。您的方法名应该与 Cashier 期望的约定相符,更具体的说,您希望处理 Stripe webhook 的方法应该以 `handle` 和 「驼峰」 名为前缀。举例来说,如果您希望处理 `invoice.payment_succeeded` 的 webhook,您应该在控制器添加`handleInvoicePaymentSucceeded` 方法: ### 订阅失败 如果用户的信用卡过期怎么办?不用担心 - Cashier 包含了一个 Webhook 控制器可以轻松为您取消用户的订阅。 该控制器会在 Stripe 判断订阅失败后(通常尝试支付失败 3 次及以上)取消用户的订阅。 ### Webhook 验签 为了保护 Webhook,您需要使用 [Stripe 的 Webhook 签名](https://stripe.com/docs/webhooks/signatures)。为了方便,Cashier 包含一个中间件,用于验证传入 Stripe webhook 的请求是否有效。 如果要启用 Webhook 验证,请确保在 `.env` 配置文件中设置了 `STRIPE_WEBHOOK_SECRET` 的值。 Webhook的 `secret` 可以从 Stripe 用户控制面板中找到。 ## 一次性支付 ### 简单支付 > {note} `charge` 方法接收您想支付于 **应用程序使用的货币的最小单位 的金额**。 如果您想对订阅客户的信用卡收取「一次性」费用,可以在可计费模型实例上使用 `charge` 方法。 您需要将 [支付方式识别码](#storing-payment-methods) 作为第二个参数: // Stripe 接收分为单位的费用... $stripeCharge = $user->charge(100, $paymentMethod); `charge` 方法接受一个数组作为它的第三个参数, 允许您创建支付时将任何您想要的选项传递给底层的 Stripe。有关在创建支付时可用的选项,请参阅 Stripe 文档: $user->charge(100, $paymentMethod, [ 'custom_option' => $value, ]); 如果支付失败, `charge` 方法将会抛出异常。如果支付成功,一个 `Laravel\Cashier\Payment` 实例会从该方法返回: try { $payment = $user->charge(100, $paymentMethod); } catch (Exception $e) { // } ### 发票 有时您可能需要支付一次性费用同时也需要生成费用发票,以便可以向客户提供 PDF 文件格式的收据。 `invoiceFor` 方法可以让您做到这一点。 例如,向客户开具 5.00 美元的「一次性费用」发票: // Stripe 接收分为单位的费用... $user->invoiceFor('One Time Fee', 500); 账单会立刻向用户的默认支付方式收取费用。 `invoiceFor` 方法接收一个数组作为第三个参数,这个数组包含了所购内容的账单选项。接收的第四个参数也是一个数组, 这最后一个参数包含了发票自身的一些选项: $user->invoiceFor('Stickers', 500, [ 'quantity' => 50, ], [ 'tax_percent' => 21, ]); > {note} `invoiceFor` 方法将会创建 Stripe 发票,该发票将会在支付失败后重试。如果您不想失败后重试,您需要在第一次支付失败后调用 Stripe API 关闭它。 ### 关于退款 如果您需要处理退款,您可以使用 `refund` 方法。此方法接受 Stripe Payment Intent ID 作为其第一个参数: $payment = $user->charge(100, $paymentMethod); $user->refund($payment->id); ## 发票 您可以使用 `invoices` 方法轻松获取账单模型的发票数组: $invoices = $user->invoices(); // 结果包含处理中的发票... $invoices = $user->invoicesIncludingPending(); 当列出客户发票清单时,可以使用发票辅助函数来显示相关的发票信息。例如,您可能希望在表格中列出每张发票,从而方便客户下载它们:{{ $invoice->date()->toFormattedDateString() }} | {{ $invoice->total() }} | Download |