# Laravel 的收費系統 Cashier
- [簡介](#introduction)
- [配置](#configuration)
- [Stripe](#stripe-configuration)
- [Braintree](#braintree-configuration)
- [貨幣配置](#currency-configuration)
- [訂閱](#subscriptions)
- [創建訂閱](#creating-subscriptions)
- [檢查訂閱狀態](#checking-subscription-status)
- [修改訂閱計劃](#changing-plans)
- [訂閱量](#subscription-quantity)
- [訂閱稅額](#subscription-taxes)
- [取消訂閱](#cancelling-subscriptions)
- [恢復訂閱](#resuming-subscriptions)
- [更新信用卡](#updating-credit-cards)
- [試用訂閱](#subscription-trials)
- [有信用卡的情況下](#with-credit-card-up-front)
- [在沒有信用卡的情況下](#without-credit-card-up-front)
- [處理 Stripe Webhooks](#handling-stripe-webhooks)
- [定義 Webhook 事件處理程序](#defining-webhook-event-handlers)
- [訂閱失敗](#handling-failed-subscriptions)
- [處理 Braintree Webhooks ](#handling-braintree-webhooks)
- [定義 Webhook 事件處理程序](#defining-braintree-webhook-event-handlers)
- [訂閱失敗](#handling-braintree-failed-subscriptions)
- [一次性收費](#single-charges)
- [發票](#invoices)
- [生成發票的 PDFs](#generating-invoice-pdfs)
<a name="introduction"></a>
## 簡介
Laravel Cashier 提供了直觀、流暢的接口來接入 [Stripe's](https://stripe.com) and [Braintree's](https://www.braintreepayments.com) 訂閱付費服務。它可以處理幾乎所有你寫起來非常頭疼付費訂閱代碼。除了提供基本的訂閱管理之外,Cashier 還可以幫你處理優惠券,交換訂閱、訂閱“數量”、取消寬限期,甚至還可以生成pdf文檔。
> {note} 如果你只是“一次性”的收費并且不提供訂閱。你就不應該使用 Cashier 。可以直接使用 Stripe 和 Braintree 的 sdk。
<a name="configuration"></a>
## 配置
<a name="stripe-configuration"></a>
### Stripe
#### Composer
首先, 將 Stripe 的 Cashier 包添加到您的依賴項中:
composer require "laravel/cashier":"~7.0"
#### 服務提供者
下一步, 在 `config/app.php` 配置文件中,注冊 `Laravel\Cashier\CashierServiceProvider` [服務提供者](/docs/{{version}}/providers).
#### 數據庫遷移
在使用 Cashier 之前,我們需要 [準備數據庫](/docs/{{version}}/migrations). 我們需要向您的 `users` 表中添加幾個列,并創建一個新的 `subscriptions` 表來保存所有客戶的訂閱:
Schema::table('users', function ($table) {
$table->string('stripe_id')->nullable();
$table->string('card_brand')->nullable();
$table->string('card_last_four')->nullable();
$table->timestamp('trial_ends_at')->nullable();
});
Schema::create('subscriptions', function ($table) {
$table->increments('id');
$table->integer('user_id');
$table->string('name');
$table->string('stripe_id');
$table->string('stripe_plan');
$table->integer('quantity');
$table->timestamp('trial_ends_at')->nullable();
$table->timestamp('ends_at')->nullable();
$table->timestamps();
});
一旦遷移文件建立好后,運行 Artisan 的 `migrate` 命令。
#### Billable 模型
下一步, 需要添加 `Billable` trait 到你的模型定義。trait 提供各種方法讓您執行常見的帳單任務,例如:創建訂閱、應用優惠券和更新信用卡信息:
use Laravel\Cashier\Billable;
class User extends Authenticatable
{
use Billable;
}
#### API Keys
最后, 你需要在 `services.php` 配置文件中設置你的 Stripe key 。 你可以在 Stripe 的控制面板獲取到相關的 API keys。
'stripe' => [
'model' => App\User::class,
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
],
<a name="braintree-configuration"></a>
### Braintree
#### Braintree 注意事項
對于許多操作,Cashier 的 Stripe 和 Braintree 實現都是一樣的。這兩項服務都提供信用卡支付服務,但 Braintree 支持通過 PayPal 支付。然而,Braintree 也缺少一些由 Stripe 支持的功能。當你決定使用 Stripe 或 Braintree 時,你應該記住以下幾點:
<div class="content-list" markdown="1">
- Braintree 支持 PayPal ,而 Stripe 不支持.
- Braintree 不支持訂閱的 `increment` 和 `decrement` 方法。這是 Braintree 的限制,而不是 Cashier 限制。
- Braintree 不支持基于百分比的折扣。這是 Braintree 的限制,而不是 Cashier 限制。
</div>
#### Composer
首先,將 Braintree 的 Cashier 包添加到您的依賴項:
composer require "laravel/cashier-braintree":"~2.0"
#### 服務提供者
下一步, 在 `config/app.php` 配置文件中,注冊 `Laravel\Cashier\CashierServiceProvider` [服務提供者](/docs/{{version}}/providers):
Laravel\Cashier\CashierServiceProvider::class
#### 信用卡優惠計劃
在使用 Cashier 之前,你需要首先在 Braintree 控制面板定義一個 `plan-credit` 折扣。這個折扣會根據用戶選擇的支付選項匹配合適的折扣比例,比如選擇年付還是月付。
在 Braintree 控制面板中配置的折扣總額可以隨意填,Cashier 會在每次使用優惠券的時候根據我們自己的定制覆蓋該默認值。由于 Braintree 不支持在訂閱頻率上來匹配折扣比例,所以這一優惠券是必需的。
#### 數據庫遷移
開始使用 Cashier 之前, 我們需要 [準備一下數據庫](/docs/{{version}}/migrations).我們需要在數據庫的 `users` 表中新增幾列,以及創建一個新的 `subscriptions` 表來存儲客戶的訂閱信息:
Schema::table('users', function ($table) {
$table->string('braintree_id')->nullable();
$table->string('paypal_email')->nullable();
$table->string('card_brand')->nullable();
$table->string('card_last_four')->nullable();
$table->timestamp('trial_ends_at')->nullable();
});
Schema::create('subscriptions', function ($table) {
$table->increments('id');
$table->integer('user_id');
$table->string('name');
$table->string('braintree_id');
$table->string('braintree_plan');
$table->integer('quantity');
$table->timestamp('trial_ends_at')->nullable();
$table->timestamp('ends_at')->nullable();
$table->timestamps();
});
一旦遷移文件建立好后,運行 Artisan 的 `migrate` 命令。
#### Billable 模型
下一步, 添加 `Billable` trait 到你的模型定義 :
use Laravel\Cashier\Billable;
class User extends Authenticatable
{
use Billable;
}
#### API Keys
下一步, 你應該在 `services.php` 文件中,參考下面的配置選項:
'braintree' => [
'model' => App\User::class,
'environment' => env('BRAINTREE_ENV'),
'merchant_id' => env('BRAINTREE_MERCHANT_ID'),
'public_key' => env('BRAINTREE_PUBLIC_KEY'),
'private_key' => env('BRAINTREE_PRIVATE_KEY'),
],
然后,你應該向 `AppServiceProvider` 服務提供商的 `boot` 方法中,添加以下的 Braintree SDK 調用:
\Braintree_Configuration::environment(config('services.braintree.environment'));
\Braintree_Configuration::merchantId(config('services.braintree.merchant_id'));
\Braintree_Configuration::publicKey(config('services.braintree.public_key'));
\Braintree_Configuration::privateKey(config('services.braintree.private_key'));
<a name="currency-configuration"></a>
### 貨幣配置
Cashier 使用美元(USD)作為默認貨幣。你可以通過在服務提供者的 `boot` 方法中調用 `Cashier::useCurrency` 方法來更改默認的貨幣。這個 `useCurrency` 方法接受兩個字符串參數:貨幣和貨幣符號:
use Laravel\Cashier\Cashier;
Cashier::useCurrency('eur', '€');
<a name="subscriptions"></a>
## 訂閱
<a name="creating-subscriptions"></a>
### 創建訂閱
創建訂閱,首先需要獲取到一個 billable 模型實例,這通常是 `App\User` 的一個實例。一旦您獲取了模型實例,您可以使用 `newSubscription` 方法創建模型的訂閱:
$user = User::find(1);
$user->newSubscription('main', 'premium')->create($stripeToken);
`newSubscription` 方法的第一個參數應該是訂閱的名稱。如果您的應用程序只提供一個訂閱,那么您可以將其設置為 `main` or `primary`。
第二個參數是用戶訂閱的 Stripe / Braintree 計劃。這個值應該與 Stripe 或 Braintree 中的標識符對應。
`create` 方法接受一個 Stripe 信用卡 / 源令牌,它將開始訂閱,并使用客戶 ID 和其他相關的賬單信息更新數據庫。
#### 用戶其他的詳細信息
如果您想要指定用戶其他的詳細信息,您可以通過將它們作為第二個參數傳遞給 `create` 方法:
$user->newSubscription('main', 'monthly')->create($stripeToken, [
'email' => $email,
]);
要了解更多關于 Stripe 或 Braintree 支持的額外字段,請查看 Stripe 的內容 [創建客戶文檔](https://stripe.com/docs/api#create_customer) 或對應的 [Braintree 文檔](https://developers.braintreepayments.com/reference/request/customer/create/php)。
#### 優惠券
如果您想在創建訂閱時使用優惠券,您可以使用 `withCoupon` 方法:
$user->newSubscription('main', 'monthly')
->withCoupon('code')
->create($stripeToken);
<a name="checking-subscription-status"></a>
### 檢查訂閱狀態
一旦用戶在您的應用程序訂閱了,您可以使用各種方便的方法輕松地檢查他們的訂閱狀態。首先,如果用戶有一個激活的訂閱,那么 `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()) {
//
}
可以使用 `subscribedToPlan` 方法可以基于給定的 Stripe / Braintree 計劃 ID 來確定用戶是否訂閱了的該計劃,在本例中,我們將確定用戶的 `main` 訂閱是否激活了 `monthly` 計劃:
if ($user->subscribedToPlan('monthly', 'main')) {
//
}
#### 取消訂閱狀態
為了確定用戶是否曾經訂閱,但是已經取消了他們的訂閱,您可以使用 `cancelled` 方法:
if ($user->subscription('main')->cancelled()) {
//
}
您還可以確定用戶是否已經取消了訂閱,但是仍然處于訂閱的「寬限期」,直到訂閱完全過期為止。例如,如果用戶在3月5日取消了原定于3月10日到期的訂閱,那么用戶將在3月10日之前進行「寬限期」。請注意,在此期間,`subscribed` 方法仍然返回 `true` :
if ($user->subscription('main')->onGracePeriod()) {
//
}
<a name="changing-plans"></a>
### 修改訂閱計劃
用戶在您的應用程序中訂閱了之后,他們可能會偶爾想要更改一個新的訂閱計劃。要將一個用戶切換到一個新的訂閱,需將訂閱計劃的標識符傳遞給 `swap` 方法:
$user = App\User::find(1);
$user->subscription('main')->swap('provider-plan-id');
如果用戶在試用期,試用期的期限會被保留。另外,如果訂閱的數量存在「份額」,那么該份額也將保持。
如果你想在更改用戶訂閱計劃的時候取消用戶當前訂閱的試用期,可以使用 `skipTrial` 方法:
$user->subscription('main')
->skipTrial()
->swap('provider-plan-id');
<a name="subscription-quantity"></a>
### 訂閱量
> {note}
訂閱數量僅由 Cashier 的 Stripe 支持。Braintree 沒有一個對應于 Stripe 的「數量」的特性。
有些時候訂閱是會受「數量」影響的。舉個例子,你的應用程序的付費方式可能是每個賬戶 $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);
要獲得更多關于訂閱量的信息,請參考 [Stripe 文檔](https://stripe.com/docs/subscriptions/quantities).
<a name="subscription-taxes"></a>
### 訂閱稅額
要指定用戶在訂閱中支付的稅率百分比,在計費模式上實現 `taxPercentage` 方法,并在0到100之間返回一個數值,不超過2個小數點。
public function taxPercentage() {
return 20;
}
`taxPercentage` 方法使你能夠在模型的基礎上應用稅率,這對于一個跨越多個國家和稅率的用戶群來說可能是有幫助的。
> {note} `taxPercentage` 方法只適用于訂閱付費模式。如果你用 charges 來做 完成一次性收費的,你需要手工指定稅率。
<a name="cancelling-subscriptions"></a>
### 取消訂閱
要取消訂閱,只需在用戶的訂閱上調用 `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();
<a name="resuming-subscriptions"></a>
### 恢復訂閱
如果用戶取消了他們的訂閱,可以使用 `resume` 的方法來恢復他們的訂閱。用戶還 **必須** 在他們的寬限期內才能恢復訂閱:
$user->subscription('main')->resume();
如果用戶取消訂閱,然后在訂閱完全過期之前恢復訂閱,他們將不會立即被計費。相反,他們的訂閱將會被重新激活,需要按照原本的支付流程再次進行支付。
<a name="updating-credit-cards"></a>
### 更新信用卡信息
`updateCard` 方法可以用來更新客戶的信用卡信息。該方法接受一個 Stripe 的 token ,并將新信用卡分配為默認的支付源:
$user->updateCard($stripeToken);
<a name="subscription-trials"></a>
## 試用訂閱
<a name="with-credit-card-up-front"></a>
### 有信用卡的情況下
如果你想要給你的客戶提供試用期,同時還要收集支付方法信息,那么你應該在創建訂閱時使用 `trialDays` 方法:
$user = User::find(1);
$user->newSubscription('main', 'monthly')
->trialDays(10)
->create($stripeToken);
此方法將在數據庫內的訂閱記錄中設置試用期結束日期,并指示 Stripe / Braintree 在此日期之前不開始向客戶收費。
> {note} 如果客戶沒有在試用期結束之前取消訂閱,訂閱會被自動結算,所以需要在試用期結束之前通知你的客戶。
您可以使用用戶實例的 `onTrial` 方法或訂閱實例的 `onTrial` 方法來確定用戶是否處于試用期。下面兩個例子是相同的:
if ($user->onTrial('main')) {
//
}
if ($user->subscription('main')->onTrial()) {
//
}
<a name="without-credit-card-up-front"></a>
### 沒有信用卡的情況下
如果您希望在不收集用戶的支付方法信息的情況下提供試用期,您可以簡單地將用戶記錄的 `trial_ends_at` 列設置為您想要的試用結束日期。這通常是在用戶注冊過程中完成的:
$user = User::create([
// 填充其他用戶屬性...
'trial_ends_at' => Carbon::now()->addDays(10),
]);
> {note}請確保在你的模型中已經為 `trial_ends_at` [日期轉換器](/docs/{{version}}/eloquent-mutators#date-mutators)。
Cashier 把這種類型的試用引用為「generic trial」, 因為它并沒有關聯任何已存在的訂閱。如果當前的日期沒有超過 `trial_ends_at` 的值,那么 `User` 實例上的 `onTrial` 方法將返回 `true` :
if ($user->onTrial()) {
// 用戶在試用期內...
}
如果您希望明確地知道用戶處于「generic」的試用期,并且還沒有創建實際的訂閱,那么您可以使用 `onGenericTrial` 方法:
if ($user->onGenericTrial()) {
// 用戶在 「generic」 試用期內...
}
一旦您準備好為用戶創建實際的訂閱,您可以像往常一樣使用 `newSubscription` 方法:
$user = User::find(1);
$user->newSubscription('main', 'monthly')->create($stripeToken);
<a name="handling-stripe-webhooks"></a>
## 處理 Stripe Webhooks
Stripe 和 Braintree 都可以通過 webhooks 通知你的應用程序。要處理 Stripe Webhooks ,定義一個路由指向 Cashier 的 webhook 控制器的。該控制器將處理所有傳入的 webhook 請求,并將它們發送到適當的控制器方法:
Route::post(
'stripe/webhook',
'\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
);
> {note} 一旦你注冊了你的路由之后,一定要在你的 Stripe 控制面板設置中配置webhook URL。
默認情況下,該控制器將自動處理在多次失敗的支付嘗試后自動取消該訂閱(根據您的 Stripe 設置所定義);但是,我們很快就會發現,您可以擴展這個控制器來處理任何您喜歡的 webhook 事件。
#### Webhooks & CSRF 保護
因為 Stripe webhooks 需要繞過 Laravel 的 [CSRF 保護](/docs/{{version}}/csrf),一定要在 `VerifyCsrfToken` 中間件中列出 URI ,或者列出 `web` 中間件組之外的路由:
protected $except = [
'stripe/*',
];
<a name="defining-webhook-event-handlers"></a>
### 定義 Webhook 事件處理程序
Cashier 對于失敗的支付自動進行取消訂閱的處理,但是如果你有其他的 Stripe webhook 事件,你想要處理,可以簡單地擴展 Webhook 控制器。您的方法名應該與 Cashier 期望的約定相符,具體來說,方法應該是用 `handle` 前綴,和您希望處理的 Stripe webhook 的「駝峰」名稱。例如,如果您希望處理 `invoice.payment_succeeded` webhook ,你應該添加一個 `handleInvoicePaymentSucceeded` 方法到控制器:
<?php
namespace App\Http\Controllers;
use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;
class WebhookController extends CashierController
{
/**
* Handle a Stripe webhook.
*
* @param array $payload
* @return Response
*/
public function handleInvoicePaymentSucceeded($payload)
{
// 處理事件
}
}
<a name="handling-failed-subscriptions"></a>
### 訂閱失敗
如果客戶的信用卡過期了怎么辦?不用擔心,Cashier 會有一個 Webhook 控制器,它可以很容易地取消客戶的訂閱。如上所述,您所需要做的就是指定一個路由到該控制器:
Route::post(
'stripe/webhook',
'\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
);
就是這樣!失敗的支付將被控制器捕獲和處理。當 Stripe 判斷訂閱失敗時,控制器將取消客戶的訂閱(通常是在三次失敗的付款嘗試之后)。
<a name="handling-braintree-webhooks"></a>
## 處理 Braintree Webhooks
Stripe 和 Braintree 都可以通過 webhooks 通知你的應用程序。要處理 Braintree webhook ,可以定義一個路由指向 Cashier 的 webhook 控制器。該控制器將處理所有傳入的 webhook 請求,并將它們發送到適當的控制器方法:
Route::post(
'braintree/webhook',
'\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
);
> {note} 一旦你注冊了你的路由之后,一定要在你的 Braintree 控制面板設置中配置webhook URL。
默認情況下,該控制器將自動處理在多次失敗的支付嘗試后自動取消該訂閱(根據您的 Braintree 設置所定義);但是,我們很快就會發現,您可以擴展這個控制器來處理任何您喜歡的 webhook 事件。
#### Webhooks & CSRF 保護
因為 Braintree webhooks 需要繞過 Laravel 的 [CSRF 保護](/docs/{{version}}/csrf),所以一定要在 `VerifyCsrfToken` 中間件中列出這個 URI ,或者列出 `web` 中間件組之外的路由:
protected $except = [
'braintree/*',
];
<a name="defining-braintree-webhook-event-handlers"></a>
### 定義 Webhook 事件處理程序
Cashier 對于失敗的支付自動進行取消訂閱的處理,但是如果你想對 Braintree webhook 事件進行額外的處理,可以簡單的擴展一下 Webhook 控制器。你的方法名稱應該與 Cashier 的預設慣例一直,特別的是,方法名應該以 `handle` 為前綴,然后以 「駝峰」命名的方式加上你要處理的 Braintree webhook 的名稱。比如,如果你希望去處理 `dispute_opened` webhook, 你應該添加一個 `handleDisputeOpened` 方法到控制器:
<?php
namespace App\Http\Controllers;
use Braintree\WebhookNotification;
use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;
class WebhookController extends CashierController
{
/**
* Handle a Braintree webhook.
*
* @param WebhookNotification $webhook
* @return Response
*/
public function handleDisputeOpened(WebhookNotification $notification)
{
// Handle The Event
}
}
<a name="handling-braintree-failed-subscriptions"></a>
### 訂閱失敗
如果客戶的信用卡過期了怎么辦?不用擔心,Cashier 會有一個 Webhook 控制器,它可以很容易地取消客戶的訂閱。如上所述,您所需要做的就是指定一個路由到該控制器:
Route::post(
'braintree/webhook',
'\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
);
就是這樣!失敗的支付將被控制器捕獲和處理。當 Braintree 判斷訂閱失敗時,控制器將取消客戶的訂閱(通常是在三次失敗的付款嘗試之后)。
<a name="single-charges"></a>
## 一次性收費
### 單次付費
> {note} 當使用 Stripe 時,`charge` 方法會接受你想要在 **應用程序使用的貨幣的最小面值** 中收取的金額。然而,當使用 Braintree 時,您應該將全部的美元金額傳遞給 `charge` 方法:
如果您想要對訂閱的客戶的信用卡進行「一次」的收費,那么您可以在一個 billable 模型實例上使用 `charge` 方法。
// Stripe Accepts Charges In Cents...
$user->charge(100);
// Braintree Accepts Charges In Dollars...
$user->charge(1);
`charge` 方法接受一個數組作為它的第二個參數,允許您將任何您希望的選項傳遞給底層的 Stripe / Braintree 費用創建。在創建收費時,請參考 Stripe 或 Braintree 文檔,了解您可以選擇的選項:
$user->charge(100, [
'custom_option' => $value,
]);
當支付結算失敗是 `charge` 方法會拋出一個異常。如果結算成功,會返回完成的 Stripe / Braintree 響應:
try {
$response = $user->charge(100);
} catch (Exception $e) {
//
}
### 費用與發票
有時候你只是需要完成一個一次性的支付,但也要為收費生成一張發票信息,這樣你可以提供 PDF 的票據給你的客戶。`invoiceFor` 方法就是做這個的。例如,讓我們給客戶開具一個 $5.00 的「一次性費用」發票:
// Stripe 以美分結算...
$user->invoiceFor('One Time Fee', 500);
// Braintree 以美元結算...
$user->invoiceFor('One Time Fee', 5);
生成發票將立即對用戶的信用卡收取費用。invoiceFor 方法可以接受一個數據作為第三個參數,允許你在 Stripe / Braintree 結算時傳遞任何可用的參數:
$user->invoiceFor('One Time Fee', 500, [
'custom-option' => $value,
]);
> {note} `invoiceFor` 方法在當多次嘗試失敗支付后也會產生一個 Stripe 發票。如果你不需要為失敗重試的支付生成發票,你需要在第一次失敗結算是就調用 Stripe 的 API 關閉它們。
<a name="invoices"></a>
## 發票
你可以使用 `invoices` 方法輕松獲取 billable 模型的所有發票信息:
$invoices = $user->invoices();
// Include pending invoices in the results...
$invoices = $user->invoicesIncludingPending();
當將發票信息列出來給用戶時,你可能需要使用發票的輔助函數來顯示相關的發票信息。例如,你可能希望將發票列表以表格的形式顯示,允許用戶輕松的下載它們:
<table>
@foreach ($invoices as $invoice)
<tr>
<td>{{ $invoice->date()->toFormattedDateString() }}</td>
<td>{{ $invoice->total() }}</td>
<td><a href="/user/invoice/{{ $invoice->id }}">Download</a></td>
</tr>
@endforeach
</table>
<a name="generating-invoice-pdfs"></a>
### 生成發票的 PDFs
從路由或控制器中,使用 `downloadInvoice` 方法生成發票的 PDF 下載。該方法將自動生成適當的 HTTP 響應,將下載發送到瀏覽器:
use Illuminate\Http\Request;
Route::get('user/invoice/{invoice}', function (Request $request, $invoiceId) {
return $request->user()->downloadInvoice($invoiceId, [
'vendor' => 'Your Company',
'product' => 'Your Product',
]);
});
## 譯者署名
| 用戶名 | 頭像 | 職能 | 簽名 |
|---|---|---|---|
| [@孤雪飄寒](https://laravel-china.org/users/15752) | <img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/15752_1493141445.jpeg"> | 翻譯 | 全桟工程師,[Github](https://github.com/piaohan),[CSDN](http://blog.csdn.net/msmile_my)|
---
> {note} 歡迎任何形式的轉載,但請務必注明出處,尊重他人勞動共創開源社區。
>
> 轉載請注明:本文檔由 Laravel China 社區 [laravel-china.org](https://laravel-china.org) 組織翻譯,詳見 [翻譯召集帖](https://laravel-china.org/topics/5756/laravel-55-document-translation-call-come-and-join-the-translation)。
>
> 文檔永久地址: https://d.laravel-china.org
- 說明
- 翻譯說明
- 發行說明
- 升級說明
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- HomeStead
- Valet
- 核心架構
- 請求周期
- 服務容器
- 服務提供者
- 門面(Facades)
- Contracts
- 基礎功能
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- 重定向
- Session
- 表單驗證
- 錯誤與日志
- 前端開發
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全
- 用戶認證
- API認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- API 資源
- 序列化
- 測試
- 快速入門
- HTTP 測試
- 瀏覽器測試 Dusk
- 數據庫測試
- 測試模擬器
- 官方擴展包
- Cashier 交易工具包
- Envoy 部署工具
- Horizon
- Passport OAuth 認證
- Scout 全文搜索
- Socialite 社交化登錄
- 交流說明