国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Laravel 5.8 中文文檔手冊(cè) / Cashier 交易工具包

Cashier 交易工具包

Cashier 交易工具包


Laravel Cashier

簡(jiǎn)介

Laravel Cashier 提供了直觀、流暢的接口來(lái)接入 Stripe'sBraintree's 的付費(fèi)訂閱服務(wù)。它可以處理幾乎讓您頭疼的付費(fèi)訂閱代碼。除了提供基本的訂閱管理之外,Cashier 還可以幫您處理優(yōu)惠券、交換訂閱、訂閱 “數(shù)量”、取消寬限期,甚至還可以生成 PDF 發(fā)票。

{注意} 如果您只是需要 “一次性” 的收費(fèi)并且不提供訂閱,就不應(yīng)該使用 Cashier。建議您使用 Stripe 和 Braintree 的 SDK。

升級(jí) Cashier

當(dāng)您從舊版本升級(jí)到最新版本的 Cashier 前,建議您優(yōu)先閱讀 Cashier 升級(jí)指南.

配置

Stripe

Composer

首先,將 Stripe 的 Cashier 包添加到您的項(xiàng)目依賴項(xiàng)中:

composer require laravel/cashier

數(shù)據(jù)庫(kù)遷移

在使用 Cashier 之前,需要 準(zhǔn)備數(shù)據(jù)庫(kù)。 Cashier 需要向您的 users 表中添加幾個(gè)列,并創(chuàng)建一個(gè)新的 subscriptions 表來(lái)保存所有客戶的訂閱:

Schema::table('users', function ($table) {
    $table->string('stripe_id')->nullable()->collation('utf8mb4_bin');    
    $table->string('card_brand')->nullable();    
    $table->string('card_last_four', 4)->nullable();    
    $table->timestamp('trial_ends_at')->nullable();
   });
Schema::create('subscriptions', function ($table) { 
   $table->increments('id');    
   $table->unsignedInteger('user_id');    
   $table->string('name');    
   $table->string('stripe_id')->collation('utf8mb4_bin');    
   $table->string('stripe_plan');    
   $table->integer('quantity');    
   $table->timestamp('trial_ends_at')->nullable();    
   $table->timestamp('ends_at')->nullable();    
   $table->timestamps();
 });

一旦遷移文件建立好后,運(yùn)行 Artisan 的 migrate 命令。

Billable 模型

接下來(lái),添加 Billable Trait 到您的模型定義。這個(gè) Trait 提供了多個(gè)方法以便執(zhí)行常用支付任務(wù),例如創(chuàng)建訂閱、使用優(yōu)惠券以及更新信用卡信息:

use Laravel\Cashier\Billable;class User extends Authenticatable{
    use Billable;
  }

API Keys

最后,在配置文件 services.php 中配置 Stripe 的 Key,您可以在 Stripe 官網(wǎng)個(gè)人控制面板中獲取這些 Stripe API Key 信息:

'stripe' => [
    'model'  => App\User::class,    
    'key' => env('STRIPE_KEY'),    
    'secret' => env('STRIPE_SECRET'),
  ],

Braintree

Braintree 注意事項(xiàng)

在很多情況下,Stripe 和 Braintree 實(shí)現(xiàn) Cashier 的功能都是一樣的,兩者都提供了通過(guò)信用卡進(jìn)行訂閱支付的功能, Braintree 還額外支持通過(guò) PayPal 支付。但 Braintree 也缺失一些 Stripe 支持的功能,在決定使用 Stripe 或 Braintree 之前,您需要考慮以下幾點(diǎn):

  • Braintree 支持 PayPal 而 Stripe 不支持。
  • Braintree 不支持 incrementdecrement 方法,這是 Braintree 的限制,而不是 Cashier 限制。
  • Braintree 不支持基于百分比的折扣。這是 Braintree 的限制,而不是 Cashier 限制。

Composer

首先,將 Braintree 的 Cashier 包添加到您項(xiàng)目的依賴項(xiàng)中:

composer require "laravel/cashier-braintree":"~2.0"

信用卡優(yōu)惠計(jì)劃

在使用 Cashier 之前,你需要首先在 Braintree 控制面板中定義一個(gè) plan-credit 折扣。這個(gè)折扣會(huì)根據(jù)用戶選擇的支付選項(xiàng)匹配合適的折扣比例,比如選擇年付或者月付。

在 Braintree 控制面板中配置的折扣總額可以隨意填寫(xiě),Cashier 會(huì)在每次使用優(yōu)惠券的時(shí)候根據(jù)您的配置來(lái)覆蓋該默認(rèn)值。由于 Braintree 不支持使用訂閱頻率來(lái)匹配折扣比例,所以這個(gè)優(yōu)惠券是必需的。

數(shù)據(jù)庫(kù)遷移

開(kāi)始使用 Cashier 之前,需要 準(zhǔn)備數(shù)據(jù)庫(kù)。Cashier 需要在您的數(shù)據(jù)庫(kù) users 表中新增幾個(gè)列,以及創(chuàng)建一個(gè)新的 subscriptions 表來(lái)存儲(chǔ)客戶的訂閱信息:

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->unsignedInteger('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();
   });

一旦遷移文件建立好后,運(yùn)行 Artisan 的 migrate  命令。

Billable 模型

然后,添加 Billable Trait 到你的模型定義中:

use Laravel\Cashier\Billable;
class User extends Authenticatable{ 
   use Billable;
  }

API Keys

緊接著,您應(yīng)該在 services.php 文件中配置以下選項(xiàng):

'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 服務(wù)提供者的 boot 方法中,添加以下的 Braintree SDK 調(diào)用:

\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'));

貨幣配置

Cashier 使用美元(USD)作為默認(rèn)貨幣。您可以通過(guò)在服務(wù)提供者的 boot 方法中調(diào)用 Cashier::useCurrency 方法來(lái)更改默認(rèn)的貨幣。這個(gè) useCurrency 方法接受兩個(gè)字符串參數(shù):貨幣和貨幣符號(hào):

use Laravel\Cashier\Cashier;
Cashier::useCurrency('eur', '€');

訂閱

創(chuàng)建訂閱

創(chuàng)建訂閱,首先需要獲取到一個(gè) Billable 模型實(shí)例,這通常是 App\User 的一個(gè)實(shí)例。一旦您獲取了模型實(shí)例,您可以使用 newSubscription 方法創(chuàng)建模型的訂閱:

$user = User::find(1);
$user->newSubscription('main', 'premium')->create($stripeToken);

newSubscription 方法的第一個(gè)參數(shù)應(yīng)該是訂閱的名稱(chēng)。如果您的應(yīng)用程序只提供一個(gè)訂閱,那么您可以將其設(shè)置為 main or primary。第二個(gè)參數(shù)是用戶訂閱的 Stripe / Braintree 計(jì)劃。這個(gè)值應(yīng)該與 Stripe 或 Braintree 中的標(biāo)識(shí)符對(duì)應(yīng)。

create 方法接受一個(gè) Stripe 信用卡 / 源令牌,它將開(kāi)始訂閱,并使用客戶 ID 和其他相關(guān)的賬單信息更新數(shù)據(jù)庫(kù)。

用戶其他的詳細(xì)信息

如果您想要指定用戶其他的詳細(xì)信息,您可以通過(guò)將它們作為第二個(gè)參數(shù)傳遞給 create 方法:

$user->newSubscription('main', 'monthly')->create($stripeToken, [
    'email' => $email,
   ]);

要了解更多關(guān)于 Stripe 或 Braintree 支持的額外字段,請(qǐng)查看 Stripe 的 內(nèi)容創(chuàng)建客戶文檔 或?qū)?yīng)的 Braintree 文檔。

優(yōu)惠券

如果您想在創(chuàng)建訂閱時(shí)使用優(yōu)惠券,您可以使用 withCoupon 方法:

$user->newSubscription('main', 'monthly')  
   ->withCoupon('code')     
   ->create($stripeToken);

檢查訂閱狀態(tài)

一旦用戶在您的應(yīng)用程序訂閱了,您可以使用各種方便的方法輕松地檢查他們的訂閱狀態(tài)。首先,如果用戶有一個(gè)激活的訂閱,那么 subscribed 的方法將返回 true ,即使訂閱當(dāng)前處于試用階段:

if ($user->subscribed('main')) {
    //
  }

這個(gè) subscribed 方法還可以在 路由中間件 使用,允許您根據(jù)用戶的訂閱狀態(tài)對(duì)路由和控制器進(jìn)行訪問(wèn):

public function handle($request, Closure $next){
    if ($request->user() && ! $request->user()->subscribed('main')) {
      // This user is not a paying customer...        
      return redirect('billing');   
     }    
    return $next($request);
 }

如果您想要確定用戶是否仍然處于試用階段,您可以使用 onTrial 方法。這個(gè)方法對(duì)于向用戶顯示他們?nèi)匀惶幱谠囉闷诘木媸呛苡杏玫模?/p>

if ($user->subscription('main')->onTrial()) {
    //
   }

基于給定的 Stripe / Braintree 計(jì)劃 ID,可以使用 subscribedToPlan 方法來(lái)確定用戶是否訂閱了該計(jì)劃。在本例中,我們將確定用戶的 main 訂閱是否激活了 monthly 計(jì)劃:

if ($user->subscribedToPlan('monthly', 'main')) {
    //
   }

recurring 方法可用于確定用戶當(dāng)前是否已訂閱,并且不再處于試用階段:

if ($user->subscription('main')->recurring()) {
    //
   }

取消訂閱狀態(tài)

為了確定用戶是否曾經(jīng)訂閱,但是已經(jīng)取消了他們的訂閱,您可以使用 cancelled 方法:

if ($user->subscription('main')->cancelled()) {
    //
   }

您還可以確定用戶是否已經(jīng)取消了訂閱,但是仍然處于訂閱的「寬限期」,直到訂閱完全過(guò)期為止。例如,如果用戶在 3 月 5 日取消了原定于 3 月 10 日到期的訂閱,那么用戶將在 3 月 10 日之前進(jìn)行「寬限期」。請(qǐng)注意,在此期間 subscribed 方法仍然返回 true

if ($user->subscription('main')->onGracePeriod()) {
    //
  }

如果要確定用戶取消訂閱的時(shí)間是否已不在其 “寬限期” 內(nèi),可以使用 ended 方法:

if ($user->subscription('main')->ended()) {
    //
  }

修改訂閱計(jì)劃

用戶在您的應(yīng)用程序中訂閱了之后,他們可能會(huì)偶爾想要更改一個(gè)新的訂閱計(jì)劃。要將一個(gè)用戶切換到一個(gè)新的訂閱,需將訂閱計(jì)劃的標(biāo)識(shí)符傳遞給 swap 方法:

$user = App\User::find(1);
$user->subscription('main')->swap('provider-plan-id');

如果用戶在試用期,試用期的期限會(huì)被保留。另外,如果訂閱的數(shù)量存在「份額」,那么該份額也將保持。

如果你想在更改用戶訂閱計(jì)劃的時(shí)候取消用戶當(dāng)前訂閱的試用期,可以使用 skipTrial 方法:

$user->subscription('main')    
    ->skipTrial()        
    ->swap('provider-plan-id');

訂閱量

{注意} 訂閱量?jī)H由 Cashier 的 Stripe 支持。Braintree 沒(méi)有一個(gè)對(duì)應(yīng)于 Stripe 的「數(shù)量」的特性。

有些時(shí)候訂閱是會(huì)受「數(shù)量」影響的。舉個(gè)例子,你的應(yīng)用程序的付費(fèi)方式可能是每個(gè)賬戶 $10 / 月。你可以使用 incrementQuantity 和  decrementQuantity 方法輕松地增加或減少你的訂閱量:

$user = User::find(1);
$user->subscription('main')->incrementQuantity();
// 對(duì)當(dāng)前的訂閱量加5...
$user->subscription('main')->incrementQuantity(5);
$user->subscription('main')->decrementQuantity();
// 對(duì)當(dāng)前的訂閱量減5...
$user->subscription('main')->decrementQuantity(5);

或者,你可以使用 updateQuantity 方法設(shè)定一個(gè)特定的數(shù)量:

$user->subscription('main')->updateQuantity(10);

noProrate 方法可用于更新訂閱的數(shù)量,而不會(huì)對(duì)收費(fèi)進(jìn)行定價(jià):

$user->subscription('main')->noProrate()->updateQuantity(10);

要獲得更多關(guān)于訂閱量的信息,請(qǐng)參考 Stripe 文檔.

訂閱稅額

在計(jì)費(fèi)模式上實(shí)現(xiàn) taxPercentage 方法,并且返回一個(gè) 0 到 100 不超過(guò) 2 位小數(shù)的數(shù)字,用來(lái)指定用戶在訂閱中支付的稅率百分比。

public function taxPercentage() {
    return 20;
   }

taxPercentage 方法使你能夠在模型的基礎(chǔ)上應(yīng)用稅率,這對(duì)于一個(gè)跨越多個(gè)國(guó)家和稅率的用戶群可能有幫助。

{注意} taxPercentage 方法只適用于付費(fèi)訂閱模式。如果你用  charges 來(lái)做「一次性」收費(fèi),你需要同時(shí)手工指定稅率。

同步稅率百分比

當(dāng)更改 taxPercentage 方法返回的硬編碼值時(shí),用戶的任何現(xiàn)有訂閱的稅率設(shè)置將保持不變。如果要用返回的 taxPercentage 值更新現(xiàn)有訂閱的稅率,應(yīng)在用戶的訂閱實(shí)例上調(diào)用 syncTaxPercentage 方法:

$user->subscription('main')->syncTaxPercentage();

訂閱錨定日期

{注意} Cashier 中只有 Stripe 支持修改訂閱錨定日期。

默認(rèn)情況下,計(jì)費(fèi)周期錨定是創(chuàng)建訂閱的日期,如果使用試用期,則是試用結(jié)束的日期。如果要修改賬單錨定日期,可以使用 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($stripeToken);

有關(guān)管理訂閱計(jì)費(fèi)周期的詳細(xì)信息,請(qǐng)參閱 Stripe 計(jì)費(fèi)周期文檔

取消訂閱

在用戶訂閱上調(diào)用 cancel 方法用來(lái)取消訂閱:

$user->subscription('main')->cancel();

當(dāng)一個(gè)訂閱被取消時(shí),Cashier 將會(huì)自動(dòng)在你的數(shù)據(jù)庫(kù)中設(shè)置  ends_at 列。這個(gè)列經(jīng)常被用來(lái)獲悉 subscribed 字段何時(shí)應(yīng)該開(kāi)始返回 false 。例如,如果客戶在 3 月 1 日取消訂閱,但是訂閱計(jì)劃直到 3  月 5 日才結(jié)束,subscribed 方法將會(huì)繼續(xù)返回 true 一直到 3 月 5 日。

你可以使用 onGracePeriod 方法確定用戶是否確定訂閱,但是仍然存在一個(gè)「寬限期」:

if ($user->subscription('main')->onGracePeriod()) {
    //
   }

如果你想馬上取消訂閱,請(qǐng)?jiān)谟脩舻挠嗛喼姓{(diào)用 cancelNow 方法:

$user->subscription('main')->cancelNow();

恢復(fù)訂閱

如果一個(gè)用已經(jīng)取消訂閱,你可以在你希望恢復(fù)它的時(shí)候使用 resume 方法。用戶 必須 仍然在他們的寬限期內(nèi)才可以恢復(fù)訂閱:

$user->subscription('main')->resume();

如果用戶已取消訂閱,然后在訂閱寬限期前恢復(fù)該訂閱,他們將不會(huì)被立即計(jì)費(fèi)。相反,他們的訂閱將會(huì)被重新激活,需要按照原來(lái)的支付流程再次進(jìn)行支付。

試用訂閱

以信用卡訂閱

如果你想給你的顧客提供試用期,同時(shí)收集支付方法信息,那么你應(yīng)該在創(chuàng)建訂閱使用 trialDays 方法:

$user = User::find(1);$user->newSubscription('main', 'monthly')    
        ->trialDays(10)            
        ->create($stripeToken);

該方法會(huì)在數(shù)據(jù)庫(kù)訂閱記錄上設(shè)置訂閱期結(jié)束時(shí)間,以便告知 Sripe / Braintree 在此之前不要計(jì)算用戶的賬單信息。

{注意} 如果顧客沒(méi)有在試用期結(jié)束前取消訂閱,訂閱會(huì)被自動(dòng)結(jié)算,所以你應(yīng)該確保告知你的用戶他們的試用結(jié)束期。

trialUntil 方法允許提供 DateTime 實(shí)例指定試用結(jié)束期:

use Carbon\Carbon;$user->newSubscription('main', 'monthly')        
    ->trialUntil(Carbon::now()->addDays(10))            
    ->create($stripeToken);

你可以使用用戶實(shí)例的 onTrial 方法或者訂閱實(shí)例的 onTrial 方法判斷用戶是否處于試用期。下面兩個(gè)示例等價(jià):

if ($user->onTrial('main')) { 
   //
  }
if ($user->subscription('main')->onTrial()) {  
  //
 }

非信用卡訂閱

如果你不想在提供試用期的時(shí)候收集用戶支付方式信息,只需設(shè)置用戶記錄的 trial_ends_at 列為期望的試用期結(jié)束日期即可,這通常在用戶注冊(cè)期間完成:

$user = User::create([ 
   // Populate other user properties...    
   'trial_ends_at' => now()->addDays(10),
 ]);

{注意}  確保已添加 trial_ends_at 日期修改器  到模型定義。

Cashier 把這種類(lèi)型的引用稱(chēng)為「一般體驗(yàn)」,因?yàn)樗鼪](méi)有關(guān)聯(lián)任何已存在的訂閱。如果當(dāng)前的日期沒(méi)有超過(guò) trail_ends_at 值, User 實(shí)例的 onTrial 方法將會(huì)返回 true

if ($user->onTrial()) { 
   // 用戶在他們的試用期內(nèi)...
  }

如果你希望明確的知道用戶處于「一般」試用期,并且還未創(chuàng)建實(shí)際的訂閱,那么你可以使用 onGenericTrial 方法:

if ($user->onGenericTrial()) {
    // 用戶在他們「一般」試用期...
   }

如果你準(zhǔn)備給用戶創(chuàng)建實(shí)際的訂閱,通常你可以使用 newSubsription 方法:

$user = User::find(1);
$user->newSubscription('main', 'monthly')->create($stripeToken);

客戶

創(chuàng)建客戶

有時(shí),您可能希望在未訂閱的情況下創(chuàng)建 Stripe 客戶。您可以使用 createAsStripeCustomer 方法完成此操作:

$user->createAsStripeCustomer();

一旦在 Stripe 中創(chuàng)建了客戶,您可以稍后開(kāi)始訂閱。

{提示} 在 Braintree 中創(chuàng)建客戶使用的是 createAsBraintreeCustomer 方法。

銀行卡

接收信用卡

可計(jì)費(fèi)模型實(shí)例上的 cards 方法返回 Laravel\Cashier\Card 實(shí)例的集合:

$cards = $user->cards();

要檢索默認(rèn)卡,可以使用 defaultCard 方法;

$card = $user->defaultCard();

確定卡號(hào)存檔

您可以使用 hasCardOnFile 方法檢查客戶是否在其帳戶上儲(chǔ)存了信用卡:

if ($user->hasCardOnFile()) {
    //
   }

更新信用卡

updateCard 方法可用于更新用戶的信用卡信息,該方法接受一個(gè) Stripe 令牌并設(shè)置一個(gè)新的信用卡作為默認(rèn)支付源:

$user->updateCard($stripeToken);

將您的卡信息與客戶的默認(rèn)卡信息進(jìn)行 Stripe 同步,可以使用 updateCardFromStripe 方法:

$user->updateCardFromStripe();

刪除信用卡

要?jiǎng)h除卡,應(yīng)首先使用 cards 方法檢索客戶的卡。然后,可以調(diào)用要?jiǎng)h除的卡實(shí)例上的 delete 方法:

foreach ($user->cards() as $card) {
    $card->delete();
  }

{注意} 如果要?jiǎng)h除默認(rèn)卡,請(qǐng)確保使用 updateCardFromStripe 方法將新的默認(rèn)卡與數(shù)據(jù)庫(kù)同步。

deleteCards 方法將刪除應(yīng)用程序存儲(chǔ)的用戶的所有卡信息:

$user->deleteCards();

{注意} 如果用戶已有訂閱,則應(yīng)考慮阻止他們刪除最后剩余的付款方式。

處理 Stripe Webhooks

Stripe 和 Braintree 都可以通過(guò) webhook 通知應(yīng)用各種各樣的事件。要處理 Stripe webhook,需要定義一個(gè) Cashier 的 webhook 控制器的路由。這個(gè)控制器可以處理所有進(jìn)入 webhook 的請(qǐng)求并將他們分發(fā)到合適的控制器方法中:

Route::post( 
   'stripe/webhook',    
   '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
   );

{注意} 一旦注冊(cè)了路由,確保在您的 Stripe 控制面板配置了 webhook URL。

默認(rèn)情況下,這個(gè)控制器將會(huì)自動(dòng)對(duì)支付失敗次數(shù)過(guò)多(這個(gè)次數(shù)可以在 Stripe 設(shè)置中定義)的訂閱進(jìn)行取消;此外,我們很快會(huì)發(fā)現(xiàn),你可以擴(kuò)展這個(gè)控制器去處理任何你想要處理的 webhook 事件。

{注意} 請(qǐng)確保使用 Cashier 的 webhook 驗(yàn)簽 中間件來(lái)保護(hù)傳入請(qǐng)求。

Webhooks & CSRF 保護(hù)

因?yàn)?Stripe webhooks 需要繞過(guò) Laraval 的 CSRF 保護(hù),請(qǐng)確保在你的 VerifyCsrfToken 中間件含有 URI ,或者將其置于 web 中間件組之外:

protected $except = [
    'stripe/*',
   ];

定義 Webhook 事件處理程序

Cashier 對(duì)于失敗支付自動(dòng)進(jìn)行取消訂閱,但是如果你有其他的 Stripe webhook 事件希望去處理,可以擴(kuò)展 Webhook 控制器。你的方法名應(yīng)該與 Cashier 期望的約定相符,更具體的說(shuō),你希望處理 Stripe webhook 的方法應(yīng)該以 handle 和 「駝峰」 名為前綴。舉例來(lái)說(shuō),如果你希望處理 invoice.payment_succeeded 的 webhook,你應(yīng)該在控制器添加 handleInvoicePaymentSucceeded 方法:

<?php
    namespace App\Http\Controllers;
    use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;
    class WebhookController extends CashierController{  
      /**
     * Handle invoice payment succeeded.
     *
     * @param  array  $payload
     * @return \Symfony\Component\HttpFoundation\Response
     */   
      public function handleInvoicePaymentSucceeded($payload)  
        {     
           // 此處處理事件   
         }
      }

接下來(lái),在 routes/web.php 文件中定義 Cashier 控制器的路由:

Route::post( 
   'stripe/webhook',    
   '\App\Http\Controllers\WebhookController@handleWebhook'
  );

訂閱失敗

如果用戶的信用卡過(guò)期怎么辦?不用擔(dān)心 - Cashier 包含了一個(gè) Webhook 控制器可以輕松為你取消用戶的訂閱。正如上文所述,你需要做的只是將路由指向控制器:

Route::post( 
   'stripe/webhook',    
   '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
  );

就是這樣!失敗的支付將會(huì)被控制器捕獲并處理,該控制器會(huì)在 Stripe 判斷訂閱失敗后(通常嘗試支付失敗 3 次及以上)取消用戶的訂閱。

Webhook 驗(yàn)簽

為了保護(hù) Webhook,你需要使用 Stripe 的 webhook 簽名。為了方便起見(jiàn),Cashier 包含一個(gè)中間件,用于驗(yàn)證傳入 Stripe webhook 的請(qǐng)求是否有效。

如果要啟用 Webhook 驗(yàn)證,請(qǐng)確保在 services 配置文件中設(shè)置了 stripe.webhook.secret 的值。 Webhook 的 secret 可以從 Stripe 用戶控制面板中找到。

處理 Braintree Webhooks

Stripe 和 Braintree 都可以通過(guò) webhooks 通知應(yīng)用各種各樣的事件。要處理 Braintree webhooks,需要定義一個(gè) Cashier webhook 控制器的路由。這個(gè)控制器可以處理所有傳入 webhook 的請(qǐng)求并將它們分發(fā)到合適的路由器方法中:

Route::post(
    'braintree/webhook',    
    '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
    );

{注意} 一旦注冊(cè)了路由,確保在 Braintree 控制器面板配置了 webhook URL。

默認(rèn)情況下,這個(gè)控制器將會(huì)自動(dòng)對(duì)支付失敗次數(shù)過(guò)多(這個(gè)次數(shù)可以在 Braintree 設(shè)置中定義)的訂閱進(jìn)行取消;此外,我們很快會(huì)發(fā)現(xiàn),你可以擴(kuò)展這控制器去處理任何你想要處理的 webhook 事件。

Webhooks & CSRF 保護(hù)

因?yàn)?Braintree webhooks 需要繞過(guò) Laravel 的 CSRF 保護(hù),請(qǐng)確保在你的 VerifyCsrfToken 中間件列表中含有 URI ,或者將其置于 web 中間件組之外:

protected $except = [ 
   'braintree/*',
  ];

定義 Webhook 事件處理程序

Cashier 對(duì)于失敗支付自動(dòng)進(jìn)行取消訂閱,但是如果你有其他的 Braintree webhook 事件希望去處理,可以擴(kuò)展 Webhook 控制器。你的方法名應(yīng)該與 Cashier 期望的約定相符,更具體的說(shuō),你希望處理 Braintree webhook 的方法應(yīng)該以 handle 和「駝峰」名為前綴。舉例來(lái)說(shuō),如果你希望處理 dispute_opened 這個(gè) webhook,你應(yīng)該在控制器添加 handleDisputeOpened 方法:

<?php
    namespace App\Http\Controllers;
    use Braintree\WebhookNotification;
    use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;
    class WebhookController extends CashierController{ 
       /**
     * Handle a new dispute.
     *
     * @param  \Braintree\WebhookNotification  $webhook
     * @return \Symfony\Component\HttpFoundation\Responses
     */  
      public function handleDisputeOpened(WebhookNotification $webhook)  
        {    
            // 此處處理時(shí)事件... 
         }
     }

訂閱失敗

如果用戶的信用卡過(guò)期怎么辦?不用擔(dān)心 - Cashier 包含了一個(gè) Webhook 控制器可以輕松為你取消用戶的訂閱。只需要將路由指向控制器中:

Route::post(
    'braintree/webhook',    
    '\Laravel\Cashier\Http\Controllers\WebhookController@handleWebhook'
  );

就是這樣!失敗的支付將會(huì)被控制器捕獲和處理,該控制器會(huì)在 Braintree 判斷訂閱失敗后(通常嘗試支付失敗 3 次及以上)取消用戶的訂閱。 不要忘記:在你的 Braintree 控制器面板中配置 webhook URI。

一次性支付

簡(jiǎn)單支付

{注意} 當(dāng)使用 Stripe 時(shí),charge 方法接收你想支付于 應(yīng)用程序使用的貨幣的最小單位 的金額。然而,當(dāng)使用 Braintree 時(shí),你應(yīng)該將全部的美元金額傳入 charge 方法:

如果你想對(duì)訂閱客戶的信用卡收取「一次性」費(fèi)用,可以在可計(jì)費(fèi)模型實(shí)例上使用 charge 方法:

// Stripe 接收分為單位的費(fèi)用...
$stripeCharge = $user->charge(100);
// Braintree 接收美元為單位的費(fèi)用...
$user->charge(1);

charge 方法接受一個(gè)數(shù)組作為它的第二個(gè)參數(shù),允許你創(chuàng)建支付時(shí)將任何你想要的選項(xiàng)傳遞給底層的 Stripe / Braintree 。 有關(guān)在創(chuàng)建支付時(shí)可用的選項(xiàng),請(qǐng)參閱 Stripe 或 Braintree 文檔:

$user->charge(100, [ 
   'custom_option' => $value,
  ]);

如果支付失敗,charge 方法將會(huì)拋出異常。如果支付成功,該方法將會(huì)返回完整的 Stripe / Braintree 響應(yīng):

try { 
   $response = $user->charge(100);
   } 
catch (Exception $e) {
    //
    }

費(fèi)用與發(fā)票

有時(shí)你可能需要支付一次性費(fèi)用同時(shí)也需要生成費(fèi)用發(fā)票,以便可以向客戶提供 PDF 文件格式的收據(jù)。 invoiceFor 方法可以讓你做到這一點(diǎn)。 例如,向客戶開(kāi)具 5.00 美元的「一次性費(fèi)用」發(fā)票:

// Stripe 接收分為單位的費(fèi)用...
$user->invoiceFor('One Time Fee', 500);
// Braintree 接收美元為單位的費(fèi)用...
$user->invoiceFor('One Time Fee', 5);

該發(fā)票會(huì)立即通過(guò)用戶信用卡支付。 invoiceFor 方法接收一個(gè)數(shù)組作為第三個(gè)參數(shù),允許你在創(chuàng)建支付時(shí)將任何你想要的選項(xiàng)傳遞給底層的 Stripe / Braintree :

$user->invoiceFor('Stickers', 500,
 [
    'quantity' => 50,
 ], 
 [  
      'tax_percent' => 21,
 ]);

如果你使用 Braintree 作為你的賬單提供者,你在調(diào)用 invoiceFor 方法時(shí)必須包含 description 選項(xiàng):

$user->invoiceFor('One Time Fee', 500,
 [
     'description' => 'your invoice description here',
 ]);

{注意} invoiceFor 方法將會(huì)創(chuàng)建 Stripe 發(fā)票,該發(fā)票將會(huì)在支付失敗后重試。如果你不想失敗后重試,你需要在第一次支付失敗后調(diào)用 Stripe API 關(guān)閉它。

關(guān)于退款

如果您需要處理退款,您可以使用 refund 方法。此方法接受 Stripe charge ID 作為其唯一參數(shù):

$stripeCharge = $user->charge(100);
$user->refund($stripeCharge->id);

發(fā)票

您可以使用 invoices 方法輕松獲取賬單模型的發(fā)票數(shù)組:

$invoices = $user->invoices();
// 結(jié)果包含處理中的發(fā)票...
$invoices = $user->invoicesIncludingPending();

當(dāng)列出客戶發(fā)票清單時(shí),可以使用發(fā)票輔助函數(shù)來(lái)顯示相關(guān)的發(fā)票信息。例如,您可能希望在表格中列出每張發(fā)票,從而方便客戶下載它們:

<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>

生成 PDF 發(fā)票

在路由或控制器中,使用 downloadInvoice 方法生成一個(gè)發(fā)票的 PDF 下載。這個(gè)方法會(huì)自動(dòng)給瀏覽器生成合適的 HTTP 下載響應(yīng):

use Illuminate\Http\Request;
Route::get('user/invoice/{invoice}', function (Request $request, $invoiceId) {
    return $request->user()->downloadInvoice($invoiceId, [ 
           'vendor'  => 'Your Company',        
           'product' => 'Your Product',    
         ]);
     });
本文章首發(fā)在 LearnKu.com 網(wǎng)站上。