laravel 基礎(chǔ)教程 —— 計(jì)費(fèi)

laravel 會(huì)計(jì)員(Cashier)

簡(jiǎn)介

Laravel Cashier 提供了一種表現(xiàn)流利的接口來(lái)支持 StripeBraintree 的計(jì)費(fèi)服務(wù)。它封裝了許多你畏懼編寫(xiě)的認(rèn)購(gòu)計(jì)費(fèi)樣板血公。除了基本的認(rèn)購(gòu)管理,Cashier 還可以處理優(yōu)惠券煞赢、服務(wù)升級(jí)以故、服務(wù)替換屯耸、認(rèn)購(gòu)份額、取消并保留期限內(nèi)可用送丰、甚至是生成 PDF 類(lèi)型的發(fā)票缔俄。

Stripe 配置

Composer

首先,添加 Strpe 的 Cashier 包到你的 composer.json 文件器躏,然后運(yùn)行 composer update 命令:

"laravel/cashier": "~6.0"

服務(wù)提供者

然后在 app 配置文件中注冊(cè) Laravel\Cashier\CashierServiceProvider 服務(wù)提供者俐载。

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

在使用 Cashier 之前,我們也需要去準(zhǔn)備一下數(shù)據(jù)庫(kù)登失。我們需要在 users 表中添加幾列遏佣,并且創(chuàng)建一個(gè)新的 subscriptions 表來(lái)保留客戶(hù)的認(rèn)購(gòu):

Schema::table('users', function ($table) {
  $table->string('stripe_id')->nullable();
  $table->string('card_brand')->nullable();
  $table->string('card_lost_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();
});

一旦遷移表創(chuàng)建完畢,你可以通過(guò) artisan 命令 migrate 進(jìn)行遷移操作壁畸。

模型起步

接著贼急,你需要在你的模型定義中添加 Billable trait:

use Laravel\Cashier\Billable;

class User extends Authenticatable 
{
  use Billable;
}

提供秘鑰

然后你需要在 services.php 配置文件中對(duì)你的 Stripe 進(jìn)行配置:

'stripe' => [
  'model' => App\User::class,
  'secret' => env('SIRIPE_SECRET'),
];

Braintree 配置

注意事項(xiàng)

對(duì)于大多數(shù)的操作茅茂,Stripe 和 Braintree 在 Cashier 中的方法實(shí)現(xiàn)是相同的,兩種服務(wù)都提供了對(duì)使用信用卡進(jìn)行認(rèn)購(gòu)的計(jì)費(fèi)支持太抓。但是 Braintree 也支持通過(guò) PayPal 的支付方式空闲。Braintree 也相應(yīng)的缺乏一些 Stripe 所支持的特性。你需要根據(jù)自身的需求去對(duì)比選擇使用 Stripe 還是 Braintree走敌。

  • Braintree 支持 PayPal 支付碴倾,而 Stripe 不支持。
  • Braintree 在認(rèn)購(gòu)時(shí)不支持 incrementdecrement掉丽,這是 Braintree 自身的限制跌榔,而不是 Cashier 的局限性。
  • Braintree 不支持百分比的折扣捶障。這是 Braintree 自身的限制僧须,而不是 Cashier 所限制的。

Composer

首先项炼,你需要在你的 composer.json 文件中進(jìn)行添加 Cashier 的文件包并使用 composer update 命令進(jìn)行安裝:

"laravel/cashier-braintree": "~1.0"

服務(wù)提供者

接著担平,注冊(cè) laravel\Cashier\CashierServiceProvider 服務(wù)提供者到你的 app 配置文件。

安排信用優(yōu)惠

在你使用 Braintree 的 Cashier 之前锭部,你需要先在你的 Braintree 控制面板中定義一個(gè) plan-credit 折扣暂论。這個(gè)折扣會(huì)被用于正確的按比例從年度改為按月計(jì)費(fèi)或者從月到年計(jì)費(fèi)。你可以在控制面板中定義這個(gè)折扣為任意你所希望的值拌禾,Cashier 會(huì)在我們使用優(yōu)惠時(shí)進(jìn)行正確的結(jié)算取胎。

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

在使用 Cashier 之前,我們也需要預(yù)先構(gòu)建好數(shù)據(jù)庫(kù)湃窍。我們需要在 users 表中添加幾列并且創(chuàng)建一個(gè) subscriptions 表來(lái)處理所有的用戶(hù)認(rèn)購(gòu):

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

一旦遷移的表結(jié)構(gòu)構(gòu)建完成闻蛀,你就可以通過(guò) artisan 命令 migrate 運(yùn)行遷移操作。

模型起步

接著坝咐,在你的模型中添加 Billable trait:

use Laravel\Cashier\Billable;

class User extends Authenticatable
{
  use Billable;
}

提供配置

然后循榆,你需要在你的 services.php 配置文件中進(jìn)行相關(guān)配置:

'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 方法中運(yùn)行下面的 Braintree SDK 的方法:

Braintree_Configuration::environment(env('BRAINTREE_ENV'));
Braintree_Configuration::merchantId(env('BRAINTREE_MERCHANT_ID'));
Braintree_Configuration::publicKey(env('BRAINTREE_PUBLIC_KEY'));
Braintree_Configuration::privateKey(env('BRAINTREE_PRIVATE_KEY'));

訂閱/認(rèn)購(gòu)

創(chuàng)建一個(gè)認(rèn)購(gòu)

為了創(chuàng)建一個(gè)認(rèn)購(gòu),你首先需要先從 billable 模型中提取一個(gè)實(shí)例墨坚,通常情況下它是 App\User 的一個(gè)實(shí)例。一旦你擁有了一個(gè)模型的實(shí)例映挂,你就可以使用 newSubscription 方法來(lái)創(chuàng)建一個(gè)該模型的認(rèn)購(gòu):

$user = User::find(1);

$user->newSubscription('main', 'monthly')->create($creditCardToken);

傳遞到 newSubscription 方法的第一個(gè)參數(shù)應(yīng)該是認(rèn)購(gòu)的名稱(chēng)泽篮。如果你的應(yīng)用僅僅只提供一種單一功能的訂閱,你或許可以定義為 main 或者 primary柑船。而第二個(gè)參數(shù)則是用戶(hù)需要認(rèn)購(gòu)的 Stripe / Braintree 的付費(fèi)計(jì)劃帽撑。這個(gè)值應(yīng)該和你的 Stripe 或者 Braintree 中的計(jì)劃標(biāo)識(shí)相對(duì)應(yīng)。

create 方法會(huì)自動(dòng)的創(chuàng)建一個(gè)認(rèn)購(gòu)鞍时,并且同客戶(hù)的 ID 和 其他賬單相關(guān)的信息更新到數(shù)據(jù)庫(kù)亏拉。

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

如果你需要指定添加一些額外的用戶(hù)信息扣蜻,你可以在 create 方法中傳遞第二個(gè)參數(shù):

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

你可以查看 StripeBraintree 的文檔來(lái)獲取其所支持的額外字段。

優(yōu)惠

如果你需要在創(chuàng)建一個(gè)認(rèn)購(gòu)時(shí)使用優(yōu)惠及塘,你可以使用 withCoupon 方法:

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

檢查認(rèn)購(gòu)狀態(tài)

一旦訂閱了你的應(yīng)用莽使,你可以通過(guò)各種簡(jiǎn)單方便的方法來(lái)檢查他們的認(rèn)購(gòu)狀態(tài)。首先笙僚,你可以通過(guò) subscribed 方法來(lái)檢查用戶(hù)是否激活了認(rèn)購(gòu)芳肌,即使用戶(hù)是在試用期中,該方法也會(huì)返回 true:

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

通過(guò) subscribed 方法肋层,我們可以創(chuàng)建一個(gè)極好的路由中間件亿笤,用來(lái)過(guò)濾只有處于訂閱狀態(tài)的用戶(hù)可以訪問(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);
}

如果你需要判斷用戶(hù)是不是還在試用期之中,你可以使用 onTrial 方法栋猖,該方法通常是用來(lái)向用戶(hù)提醒其還在試用期之中:

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

subscribedToPlan 方法用來(lái)判斷用戶(hù)是否訂閱了所給定的 Stripe / Braintree 計(jì)劃净薛。比如,我們需要判斷用戶(hù)的 main 認(rèn)購(gòu)是不是通過(guò) monthly 計(jì)劃來(lái)進(jìn)行付費(fèi)的:

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

取消認(rèn)購(gòu)狀態(tài)

你可以通過(guò) cancelled 方法來(lái)判斷用戶(hù)是否曾經(jīng)進(jìn)行過(guò)認(rèn)購(gòu)蒲拉,但是卻在使用的過(guò)程中取消了繼續(xù)付費(fèi)訂閱:

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

或許罕拂,你需要判斷一個(gè)用戶(hù)取消了持續(xù)訂閱,但是他的訂閱期還未過(guò)期全陨。比如爆班,一個(gè)用戶(hù)在 3 月 5 號(hào)取消了持續(xù)訂閱,但是他的上次付費(fèi)服務(wù)還可以繼續(xù)使用到 3 月 10 號(hào)辱姨。他還在其可用期內(nèi)柿菩。你應(yīng)該注意只要是在可用期內(nèi),不論是否取消了持續(xù)訂閱或者還是在試用期內(nèi)雨涛,subscribed 方法都會(huì)返回 true :

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

改變付費(fèi)計(jì)劃

在用戶(hù)認(rèn)購(gòu)了你的應(yīng)用之后枢舶,有時(shí)候或許他們想要變更付費(fèi)的計(jì)劃。你可以使用 swap 方法來(lái)變更到一個(gè)新的認(rèn)購(gòu)計(jì)劃替久。比如凉泄,我們可以非常簡(jiǎn)單的切換當(dāng)前用戶(hù)到 premium 認(rèn)購(gòu):

$user = App\User::find(1);

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

如果用戶(hù)還處于試用期之中,那么即使切換付費(fèi)計(jì)劃蚯根,他們的試用期也是會(huì)被保持后众。還有,如果之前認(rèn)購(gòu)的份數(shù)存在颅拦,相應(yīng)的認(rèn)購(gòu)的飛鼠也會(huì)被保持:

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

如果你想要在切換付費(fèi)方案的同時(shí)取消之前的試用期蒂誉,你可以使用 skipTrial 方法:

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

認(rèn)購(gòu)份額

注意:認(rèn)購(gòu)份額只支持 Stripe 版本的 Cashier。Braintree 并沒(méi)有 Stripe 份額的概念距帅。

有時(shí)候認(rèn)購(gòu)時(shí)受份額影響的右锨。比如,你的應(yīng)用可能是按照每用戶(hù)每月 $10 來(lái)進(jìn)行計(jì)費(fèi)的碌秸。要輕松的遞增或遞減認(rèn)購(gòu)的數(shù)量绍移,你可以使用 incrementQuantitydecrementQuantity 方法:

$user = User::find(1);

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

// Add five to the subscription's current quantity...
$user->subscription('main')->incrementQuantity(5);

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

// Subtract five to the subscription's current quantity...

$user->subscription('main')->decrementQuantity(5)

另外悄窃,你也可以通過(guò)使用 updateQuantity 放法來(lái)設(shè)置一個(gè)指定的份額:

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

關(guān)于更多的認(rèn)購(gòu)份額信息,請(qǐng)查看 Strpe documentation蹂窖。

認(rèn)購(gòu)稅率

在 Cashier 中轧抗,可以非常簡(jiǎn)單的提供 tax_percent 值到 Stripe / Braintree。為了指定用戶(hù)支付認(rèn)購(gòu)時(shí)的稅率百分比恼策,你需要實(shí)現(xiàn) taxPercentage 方法到你的 billable 模型中鸦致,并且在該方法中返回一個(gè) 0 - 100 的值,該值不應(yīng)該多于 2 個(gè)小數(shù):

public function taxPercentage() {
  return 20;
}

這使你可以應(yīng)用在多種模型間計(jì)算不同的稅率,這意味著你可以跨越多個(gè)國(guó)家的用戶(hù)群來(lái)設(shè)置結(jié)算稅率涣楷。

取消訂閱

你可以簡(jiǎn)單的調(diào)用 cancel 方法來(lái)取消用戶(hù)訂閱:

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

當(dāng)認(rèn)購(gòu)被取消時(shí)分唾,Cashier 會(huì)自動(dòng)的設(shè)置 ends_at 列到數(shù)據(jù)庫(kù)中。該列會(huì)被用來(lái)了解當(dāng)調(diào)用 subscribed 方法時(shí)何時(shí)應(yīng)該返回 false狮斗。比如绽乔,如果用戶(hù)在 3 月 1 號(hào)取消了認(rèn)購(gòu),但是上一次認(rèn)購(gòu)期應(yīng)該是在 3 月 5 號(hào)結(jié)束碳褒,所以折砸, subscribed 方法會(huì)持續(xù)返回 true 直到 3 月 5 號(hào)。

你可以通過(guò) onGracePeriod 方法來(lái)判斷一個(gè)已經(jīng)取消訂閱的用戶(hù)是否還在其可用期內(nèi):

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

恢復(fù)訂閱

如果用戶(hù)取消了其訂閱沙峻,并且想要恢復(fù)訂閱睦授,那么你可以使用 resume 方法。用戶(hù)必須是在其可用期內(nèi)才可以恢復(fù)訂閱:

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

如果用戶(hù)取消了訂閱摔寨,并在其可用期內(nèi)恢復(fù)了訂閱去枷,那么認(rèn)購(gòu)不會(huì)立即進(jìn)行計(jì)費(fèi)支付。訂閱只是被重新激活是复,其付費(fèi)周期還是基于原先的計(jì)費(fèi)周期删顶。

試用

提供試用并記錄信用卡信息

如果你想要在提供試用期的同時(shí)還收集支付方式的信息。你應(yīng)該在你創(chuàng)建用戶(hù)認(rèn)購(gòu)時(shí)使用 trialDays 方法:

$user = User::find(1);

$user->newSubscription('main', 'monthly')
     ->trialDays(10)
     ->create($creditCardToken);

該方法會(huì)設(shè)置一個(gè)試用結(jié)束日期到數(shù)據(jù)庫(kù)的認(rèn)購(gòu)記錄中淑廊。并且會(huì)通知 Stripe / Braintree 暫不計(jì)費(fèi)逗余,直到超過(guò)了該日期才開(kāi)始進(jìn)行計(jì)費(fèi)。

注意:如果你的客戶(hù)并沒(méi)有在試用期結(jié)束之前取消訂閱季惩,那么他們會(huì)在試用期結(jié)束時(shí)自動(dòng)扣費(fèi)录粱,所以你應(yīng)該在試用期結(jié)束前那天進(jìn)行用戶(hù)通知。

你可以通過(guò)用戶(hù)實(shí)例的 onTrial 方法或者認(rèn)購(gòu)實(shí)例的 onTrial 方法來(lái)判斷用戶(hù)是否在試用期:

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

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

提供試用的同時(shí)不記錄支付信息

如果你想要在提供試用期的同時(shí)而不收集用戶(hù)的支付方法信息蜀备,你可以簡(jiǎn)單的設(shè)置 trial_ends_at 列到你的用戶(hù)記錄中关摇。你應(yīng)該在該列中設(shè)置你所期望的試用結(jié)束的日期。比如碾阁,這一般是用戶(hù)注冊(cè)過(guò)程中的典型做法:

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

Cashier 會(huì)認(rèn)為這中類(lèi)型的試用是一種通用的試用期,因?yàn)檫@個(gè)日期并不會(huì)被關(guān)聯(lián)到任何已有的訂閱中些楣。如果當(dāng)前日期并沒(méi)有超過(guò) trial_ends_at 所設(shè)置的值脂凶,在 User 實(shí)例中的 onTrial 方法將會(huì)返回為 true:

if ($user->onTrial()) {
  // User is within their trial period...
}

你也可以通過(guò) onGenericTrial 方法來(lái)判斷用戶(hù)是否還沒(méi)有進(jìn)行任何認(rèn)購(gòu)宪睹,并且還在通用期內(nèi):

if ($user->onGenericTrial()) {
  // User is within their 'generic' trial period...
}

一旦你準(zhǔn)備好去創(chuàng)建一個(gè)真實(shí)的認(rèn)購(gòu)到用戶(hù),你通常應(yīng)該使用 newSubscription 方法:

$user = User::find(1);

$user->newSubscription('main', 'monthly')->create($creditCardToken);

處理 Stripe Webhooks

失敗的認(rèn)購(gòu)

如果用戶(hù)的信用卡過(guò)期了怎么辦蚕钦?不用擔(dān)心亭病,Cashier 為你提供了便捷的取消用戶(hù)訂閱的 Webhook 控制器。你只需要將控制器添加到路由就可以了:

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

就那么簡(jiǎn)單嘶居!失敗的支付會(huì)在這個(gè)控制器中捕獲和處理罪帖。這個(gè)控制器會(huì)在 Stripe 確定用戶(hù)的訂閱支付失敗時(shí)(通常是在三次支付失敗)取消用戶(hù)的訂閱邮屁。不要忘記在你的 Stripe 控制面板中配置 webhook 的 URI整袁。

因?yàn)?Stripe webhooks 需要穿過(guò) laravel 的 CSRF 中間件,所以你應(yīng)該將你的路由抽離出 web 中間件組佑吝,或者在你的 VerifyCsrfToken 中間件中添加排除的 URI:

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

其他 Webhooks

如果你想要處理額外的 Stripe webhook 事件坐昙,你可以簡(jiǎn)單的繼承 Webhook 控制器。你所繼承的控制器名中的方法名稱(chēng)應(yīng)該與 Cashier 的預(yù)期約定想對(duì)應(yīng)芋忿。特別的炸客,方法名稱(chēng)應(yīng)該有 handle 前綴,并且以大寫(xiě)駝峰的方式命名你所期望捕獲的 Stripe webhook 事件名稱(chēng)戈钢。比如痹仙,你想要處理 invoice.payment_succeeded webhook, 那么你應(yīng)該在控制器中添加 handleInvociePaymentSucceeded 方法:

<?php

namespace App\Http\Controllers;

use Laravel\Cashier\Http\Controllers\WebhookController as BaseController;

class WebhookController extends BaseController
{
  /**
   * Handle a Stripe webhook.
   *
   * @param array $payload
   * @return Response
   */
   public function handleInvoicePaymentSucceeded($payload)
   {
     // Handle The Event
   }
}

處理 Braintree Webhooks

失敗的訂閱

如果用戶(hù)的信用卡過(guò)期了怎么辦?不用擔(dān)心殉了,Cashier 為你提供了便捷的取消用戶(hù)訂閱的 Webhook 控制器开仰。你只需要將控制器添加到路由就可以了:

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

就那么簡(jiǎn)單!失敗的支付會(huì)在這個(gè)控制器中捕獲和處理宣渗。這個(gè)控制器會(huì)在 Braintree 確定用戶(hù)的訂閱支付失敗時(shí)(通常是在三次支付失敹端)取消用戶(hù)的訂閱。不要忘記在你的 Braintree 控制面板中配置 webhook 的 URI痕囱。

因?yàn)?Stripe webhooks 需要穿過(guò) laravel 的 CSRF 中間件田轧,所以你應(yīng)該將你的路由抽離出 web 中間件組,或者在你的 VerifyCsrfToken 中間件中添加排除的 URI:

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

其他 Webhooks

如果你想要處理額外的 Braintree webhook 事件鞍恢,你可以簡(jiǎn)單的繼承 Webhook 控制器傻粘。你所繼承的控制器名中的方法名稱(chēng)應(yīng)該與 Cashier 的預(yù)期約定想對(duì)應(yīng)。特別的帮掉,方法名稱(chēng)應(yīng)該有 handle 前綴弦悉,并且以大寫(xiě)駝峰的方式命名你所期望捕獲的 Stripe webhook 事件名稱(chēng)。比如蟆炊,你想要處理 dispute_opened webhook, 那么你應(yīng)該在控制器中添加 handleDisputeOpened 方法:

<?php

namespace App\Http\Controllers;

use Braintree\WebhookNotification;
use Laravel\Cashier\Http\Controllers\WebhookController as BaseController;

class WebhookController extends BaseController
{
  /**
   * Handle a Braintree webhook.
   *
   * @param WebhookNotification $webhook
   * @return Response
   */
   public function handleDisputeOpened(WebhookNotification $notification)
   {
     // Handle The Event
   }
}

一次性付費(fèi)

簡(jiǎn)單的付費(fèi)

注意:在使用 Stripe 時(shí)稽莉,charge 方法接收的金額可以是相應(yīng)貨幣的最小單位。而 Braintree涩搓,你應(yīng)該傳遞美元到 charge 方法:

如果你想要對(duì)訂閱的用戶(hù)施行一次性付費(fèi)污秆,你可以使用 charge 方法:

// Stripe Accepts Charges In Cents...
$user->charge(100);

// Braintree Accepts Charges In Dollars...
$user->charge(1);

charge 方法也可以接收一個(gè)數(shù)組作為其第二個(gè)參數(shù)劈猪,這個(gè)參數(shù)將傳遞給底層的 Stripe / Braintree 用于支付賬單的創(chuàng)建:

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

當(dāng)支付失敗時(shí),charge 方法將會(huì)拋出一個(gè)異常良拼,如果支付成功則完整的 Stripe / Braintree 響應(yīng)將會(huì)被返回:

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

支付并提供發(fā)票

有時(shí)候战得,你可能需要做一次性的支付,并且也要生成一個(gè)發(fā)票給用戶(hù)庸推。你可以使用 invoiceFor 方法來(lái)生成發(fā)票并提供一個(gè) PDF 的收據(jù)給用戶(hù):

// Stripe Accepts Charges In Cents...
$user->invoiceFor('One Time Fee', 500);

// Braintree Accepts Charges In Dollars...
$user->invoiceFor('One Time Fee', 5);

開(kāi)具發(fā)票會(huì)立即向用戶(hù)的信用卡進(jìn)行收費(fèi)常侦。invoiceFor 方法也接收一個(gè)數(shù)組作為第三個(gè)參數(shù),用于傳遞給底層的 Stripe / Braintree 支付賬單創(chuàng)建時(shí)使用:

$user->invoiceFor('One Time Fee', 500, [
  'custom-option' => $value,
]);

注意:invoiceFor 方法會(huì)創(chuàng)建 Stripe 發(fā)票贬媒,這將重新嘗試失敗的計(jì)費(fèi)聋亡。如果你不希望開(kāi)具發(fā)票的同時(shí)嘗試失敗的支付,你需要使用 Stripe API 在他們首次失敗時(shí)就關(guān)閉這個(gè)支付掖蛤。

發(fā)票

你可以通過(guò)使用 invoices 方法來(lái)檢索一個(gè)可計(jì)費(fèi)模型的發(fā)票數(shù)組:

$invoices = $user->invoices();

當(dāng)你為客戶(hù)列出其發(fā)票時(shí)杀捻,你可以使用 invoice 幫助方法來(lái)顯示相應(yīng)的發(fā)票詳情。比如蚓庭,你想要在表格中列出所有的發(fā)票致讥,從而允許用戶(hù)方便的下載:

<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 類(lèi)型的發(fā)票

你需要安裝 dompdf PHP 類(lèi)庫(kù)來(lái)生成 PDF:

composer require dompdf/dompdf

在路由或者控制器中,使用 downloadInvoice 方法來(lái)生成一個(gè)供下載的 PDF 類(lèi)型的發(fā)票器赞。該方法會(huì)自動(dòng)的生成正確的下載響應(yīng)到瀏覽器中:

Route::get('user/invoice/{invoice}', function ($invoiceId) {
  return Auth::user()->downloadInvoice($invoiceId, [
    'vendor' => 'Your Company',
    'product' => 'Your Product',
  ]); 
});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末垢袱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子港柜,更是在濱河造成了極大的恐慌请契,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夏醉,死亡現(xiàn)場(chǎng)離奇詭異爽锥,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)畔柔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)氯夷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人靶擦,你說(shuō)我怎么就攤上這事腮考。” “怎么了玄捕?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵踩蔚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我枚粘,道長(zhǎng)馅闽,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮捞蛋,結(jié)果婚禮上孝冒,老公的妹妹穿的比我還像新娘柬姚。我一直安慰自己拟杉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布量承。 她就那樣靜靜地躺著搬设,像睡著了一般。 火紅的嫁衣襯著肌膚如雪撕捍。 梳的紋絲不亂的頭發(fā)上拿穴,一...
    開(kāi)封第一講書(shū)人閱讀 49,821評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音忧风,去河邊找鬼默色。 笑死,一個(gè)胖子當(dāng)著我的面吹牛狮腿,可吹牛的內(nèi)容都是我干的腿宰。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼缘厢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吃度!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起贴硫,我...
    開(kāi)封第一講書(shū)人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤椿每,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后英遭,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體间护,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年挖诸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了汁尺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡税灌,死狀恐怖均函,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情菱涤,我是刑警寧澤苞也,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站粘秆,受9級(jí)特大地震影響如迟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一殷勘、第九天 我趴在偏房一處隱蔽的房頂上張望此再。 院中可真熱鬧,春花似錦玲销、人聲如沸输拇。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)策吠。三九已至,卻和暖如春瘩绒,著一層夾襖步出監(jiān)牢的瞬間猴抹,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工锁荔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蟀给,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓阳堕,卻偏偏與公主長(zhǎng)得像跋理,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嘱丢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • 社交紅利閱讀筆記 書(shū)名:社交紅利(修訂升級(jí)版) 作者:徐志斌 出版社:中信出版社 正文前筆記: 推薦序1摘要 社交...
    鳧水閱讀 8,917評(píng)論 4 26
  • 平生樂(lè)事 聽(tīng)琴西澗里薪介,牧鳥(niǎo)北山顛。 志淺常知樂(lè)越驻,詩(shī)吟半畝田汁政。 ——靜坐的行者 云 云從龍門(mén)起,云起崖山低缀旁。云低風(fēng)雨...
    蘿莉禪貓閱讀 770評(píng)論 17 13
  • 下班路過(guò)軍藝 迅速搜索了一下 不知道誰(shuí)是軍藝的 學(xué)校門(mén)口有妹子穿軍裝拍照 腦補(bǔ)了一群美人的樣子 又是早上補(bǔ) 因?yàn)橄?..
    咸酥閱讀 145評(píng)論 0 0
  • 梅花香自苦寒來(lái)记劈,笑傲一方風(fēng)雪。 繪畫(huà)工具材料:硯臺(tái)并巍,白盤(pán)目木,筆洗,墨懊渡,水刽射,毛筆(狼毫與兼毫),宣紙剃执,國(guó)畫(huà)顏料誓禁。
    若水國(guó)畫(huà)閱讀 1,150評(píng)論 26 25