鍍金池/ 教程/ PHP/ Laravel Cashier(訂購(gòu)&支付&發(fā)票)
門面
Laravel Homestead
安裝及配置
測(cè)試
HTTP 中間件
加密
升級(jí)指南
幫助函數(shù)
應(yīng)用目錄結(jié)構(gòu)
集合
新手入門指南-簡(jiǎn)單任務(wù)管理系統(tǒng)
任務(wù)調(diào)度
查詢構(gòu)建器
視圖
驗(yàn)證
Laravel Cashier(訂購(gòu)&支付&發(fā)票)
本地化
隊(duì)列
調(diào)整器
分頁(yè)
文件系統(tǒng)/云存儲(chǔ)
貢獻(xiàn)代碼
哈希
HTTP 控制器
緩存
遷移
HTTP 請(qǐng)求
Laravel Elixir
發(fā)行版本說(shuō)明
Envoy 任務(wù)運(yùn)行器(SSH任務(wù))
序列化
Session
起步
帶用戶功能的任務(wù)管理系統(tǒng)
起步
用戶授權(quán)
郵件
事件
填充數(shù)據(jù)
HTTP 路由
服務(wù)提供者
Blade 模板引擎
包開(kāi)發(fā)
用戶認(rèn)證
Artisan 控制臺(tái)
HTTP 響應(yīng)
集合
服務(wù)容器
關(guān)聯(lián)關(guān)系
一次請(qǐng)求的生命周期
契約
Redis
錯(cuò)誤&日志

Laravel Cashier(訂購(gòu)&支付&發(fā)票)

1、簡(jiǎn)介

Laravel CashierStripe 的訂購(gòu)單據(jù)服務(wù)提供了一個(gè)優(yōu)雅的、平滑的接口。它處理了幾乎所有你恐懼編寫的樣板化的訂購(gòu)單據(jù)代碼。除了基本的訂購(gòu)管理外,Cashier 還支持處理優(yōu)惠券、交換訂購(gòu)、訂購(gòu)“數(shù)量”、取消寬限期,甚至生成PDF發(fā)票。

1.1 配置

1.1.1 Composer

首先,添加 Cashier 包到 composer.json 文件并運(yùn)行 composer update 命令:

"laravel/cashier": "~5.0" (For Stripe SDK ~2.0, and Stripe APIs on 2015-02-18 version and later)
"laravel/cashier": "~4.0" (For Stripe APIs on 2015-02-18 version and later)
"laravel/cashier": "~3.0" (For Stripe APIs up to and including 2015-02-16 version)

1.1.2 服務(wù)提供者

接下來(lái),在 app配置文件中注冊(cè)服務(wù)提供者Laravel\Cashier\CashierServiceProvider。

1.1.3 遷移

實(shí)現(xiàn) Cashier之前,我們需要添加額外的字段到數(shù)據(jù)庫(kù)。別擔(dān)心,你可以使用 Artisan命令 cashier:table來(lái)創(chuàng)建遷移以添加必要的字段。例如,要添加該字段到用戶表運(yùn)行如下命令:

php artisan cashier:table users

創(chuàng)建好遷移后,只需簡(jiǎn)單運(yùn)行 migrate命令。

1.1.4 設(shè)置模型

接下來(lái),添加 Billable trait 和相應(yīng)的日期調(diào)整器到模型定義:

use Laravel\Cashier\Billable;
use Laravel\Cashier\Contracts\Billable as BillableContract;

class User extends Model implements BillableContract{
    use Billable;
    protected $dates = ['trial_ends_at', 'subscription_ends_at'];
}

添加字段到模型的$dates 屬性使 Eloquent 返回 Carbon/Datetime 實(shí)例格式字段而不是原生字符串。

1.1.5 Stripe 鍵

最后,在配置文件 services.php 中設(shè)置 Stripe 鍵:

'stripe' => [
    'model'  => 'User',
    'secret' => env('STRIPE_API_SECRET'),
],

2、訂購(gòu)

2.1 創(chuàng)建訂購(gòu)

要?jiǎng)?chuàng)建一個(gè)訂購(gòu),首先獲取一個(gè)賬單模型的實(shí)例,通常是 App\User的實(shí)例。獲取到該模型實(shí)例之后,你可以使用 subscription方法來(lái)管理模型的訂購(gòu):

$user = User::find(1);
$user->subscription('monthly')->create($creditCardToken);

create 方法將會(huì)自動(dòng)創(chuàng)建 Stripe訂購(gòu),并使用 Stripe客戶 ID和其他相關(guān)單據(jù)信息更新數(shù)據(jù)庫(kù)。如果你在 Stripe中的計(jì)劃有一個(gè)試用配置,那么用戶記錄中的試用結(jié)束時(shí)間也會(huì)自動(dòng)設(shè)置。

如果你想要實(shí)現(xiàn)試用期,但是完全在 Laravel應(yīng)用中管理試用而不是將其定義在 Stripe中,你必須手動(dòng)設(shè)置試用結(jié)束時(shí)間:

$user->trial_ends_at = Carbon::now()->addDays(14);
$user->save();

2.1.1 額外的用戶詳情

如果你想要指定額外的客戶詳情,你可以將其作為第二個(gè)參數(shù)傳遞給 create方法:

$user->subscription('monthly')->create($creditCardToken, [
    'email' => $email, 
    'description' => 'Our First Customer'
]);

要了解更多 Stripe支持的字段,可以查看 Stripe關(guān)于客戶創(chuàng)建的文檔。

2.1.2 優(yōu)惠券

如果你想要在創(chuàng)建訂購(gòu)的時(shí)候使用優(yōu)惠券,可以使用 withCoupon方法:

$user->subscription('monthly')
     ->withCoupon('code')
     ->create($creditCardToken);

2.2 檢查訂購(gòu)狀態(tài)

用戶訂購(gòu)你的應(yīng)用后,你可以使用各種便利的方法來(lái)簡(jiǎn)單檢查訂購(gòu)狀態(tài)。首先,如果用戶有一個(gè)有效的訂購(gòu),則 subscribed方法返回 true ,即使訂購(gòu)現(xiàn)在出于試用期:

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

subscribed 方法還可以用于路由中間件,基于用戶訂購(gòu)狀態(tài)允許你對(duì)路由和控制器的訪問(wèn)進(jìn)行過(guò)濾:

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

    return $next($request);
}

如果你想要判斷一個(gè)用戶是否還在試用期,可以使用 onTrial方法,該方法在為還處于試用期的用戶顯示警告信息很有用:

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

onPlan 方法可用于判斷用戶是否基于 Stripe ID 訂購(gòu)了給定的計(jì)劃:

if ($user->onPlan('monthly')) {
    //
}

2.2.1 取消的訂購(gòu)狀態(tài)

要判斷用戶是否曾經(jīng)是有效的訂購(gòu)者,但現(xiàn)在取消了訂購(gòu),可以使用 cancelled 方法:

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

你還可以判斷用戶是否曾經(jīng)取消過(guò)訂購(gòu),但現(xiàn)在仍然在“寬限期”直到訂購(gòu)?fù)耆А@?,如果一個(gè)用戶在 3 月 5 號(hào)取消了一個(gè)實(shí)際有效期到 3 月 10 號(hào)的訂購(gòu),該用戶處于“寬限期”直到 3 月 10 號(hào)。注意 subscribed方法在此期間仍然返回 true。

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

everSubscribed 方法可以用于判斷用戶是否訂購(gòu)過(guò)應(yīng)用的計(jì)劃:

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

2.3 改變計(jì)劃

用戶訂購(gòu)應(yīng)用后,偶爾想要改變到新的訂購(gòu)計(jì)劃,要將用戶切換到新的訂購(gòu),使用 swap 方法。例如,我們可以輕松切換用戶到 premium 訂購(gòu):

$user = App\User::find(1);
$user->subscription('premium')->swap();

如果用戶在試用,試用期將會(huì)被維護(hù)。還有,如果訂購(gòu)存在數(shù)量,數(shù)量也可以被維護(hù)。當(dāng)交換訂購(gòu)計(jì)劃,還可以使用 prorate 方法來(lái)表明費(fèi)用是按比例的,此外,你可以使用 swapAndInvoice 方法立即為用戶計(jì)劃改變開(kāi)發(fā)票:

$user->subscription('premium')
            ->prorate()
            ->swapAndInvoice();

2.4 訂購(gòu)數(shù)量

有時(shí)候訂購(gòu)也會(huì)被數(shù)量影響,例如,你的應(yīng)用每個(gè)賬戶每月需要付費(fèi)$10,要簡(jiǎn)單增加或減少訂購(gòu)數(shù)量,使用 incrementdecrement 方法:

$user = User::find(1);

$user->subscription()->increment();
// 當(dāng)前訂購(gòu)數(shù)量+5...
$user->subscription()->increment(5);

$user->subscription()->decrement();
// 當(dāng)前訂購(gòu)數(shù)量-5...
$user->subscription()->decrement(5);

你也可以使用 updateQuantity 方法指定數(shù)量:

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

想要了解更多訂購(gòu)數(shù)量信息,查閱相關(guān)Stripe 文檔。

2.5 訂購(gòu)稅金

Cashier中,提供 tax_percent值發(fā)送給 Stripe很簡(jiǎn)單。要指定用戶支付訂購(gòu)的稅率,實(shí)現(xiàn)賬單模型的 getTaxPercent方法,并返回一個(gè)在 0 到 100 之間的數(shù)值,不要超過(guò)兩位小數(shù):

public function getTaxPercent() {
    return 20;
}

這將使你可以在模型基礎(chǔ)上使用稅率,對(duì)跨越不同國(guó)家的用戶很有用。

2.6 取消訂購(gòu)

要取消訂購(gòu),可以調(diào)用用戶訂購(gòu)上的 cancel方法:

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

當(dāng)訂購(gòu)被取消時(shí),Cashier將會(huì)自動(dòng)設(shè)置數(shù)據(jù)庫(kù)中的 subscription_ends_at字段。該字段用于了解 subscribed方法什么時(shí)候開(kāi)始返回 false。例如,如果客戶 3 月 1 號(hào)份取消訂購(gòu),但訂購(gòu)直到 3 月 5 號(hào)才會(huì)結(jié)束,那么subscribed `方法繼續(xù)返回 true 直到 3 月 5 號(hào)。

你可以使用 onGracePeriod方法判斷用戶是否已經(jīng)取消訂購(gòu)但仍然在“寬限期”:

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

2.7 恢復(fù)訂購(gòu)

如果用戶已經(jīng)取消訂購(gòu)但你想恢復(fù),使用 resume方法:

$user->subscription('monthly')->resume($creditCardToken);

如果用戶取消訂購(gòu)然后在訂購(gòu)失效前恢復(fù),將不會(huì)立即付款,相反,他們的訂購(gòu)會(huì)重新激活,他們將會(huì)在正常的付款周期進(jìn)行支付。

3、處理 Stripe

3.1 失敗的訂購(gòu)

如果客戶的信用卡失效怎么辦?不用擔(dān)心——Cashier 包含了 Webhook控制器,該控制器可以輕易的為你取消客戶訂購(gòu)。只需要設(shè)置下到該控制器的路由:

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

就這樣!失敗的支付將會(huì)被該控制器捕獲和處理。當(dāng) Stripe判斷訂購(gòu)失敗(正常情況下嘗試支付失敗三次后)時(shí)該控制器將會(huì)取消客戶的訂購(gòu)。不要忘了:你需要在 Stripe控制面板設(shè)置中配置 webhook URI。

由于 Stripe webhooks需要通過(guò) LaravelCSRF驗(yàn)證,確保將該 URI置于 VerifyCsrfToken中間件排除列表中:

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

3.2 其它 Webhooks

如果你有額外想要處理的 Stripe webhook事件,只需簡(jiǎn)單繼承 Webhook控制器, 你的方法名應(yīng)該和 Cashier期望的約定一致,尤其是方法應(yīng)該以“handle”開(kāi)頭并以駝峰命名法命名。例如,如果你想要處理 invoice.payment_succeeded webhook,你應(yīng)該添加 handleInvoicePaymentSucceeded方法到控制器:

<?php

namespace App\Http\Controller;

use Laravel\Cashier\WebhookController as BaseController;

class WebhookController extends BaseController{
    /**
     * 處理 stripe webhook.
     *
     * @param  array  $payload
     * @return Response
     */
    public function handleInvoicePaymentSucceeded($payload)
    {
        // 處理該事件
    }
}

4、一次性付款

如果你想要使用訂購(gòu)客戶的信用卡一次性結(jié)清賬單,可以使用單據(jù)模型實(shí)例上的 charge方法,該方法接收付款金額(應(yīng)用使用的貨幣的最小單位對(duì)應(yīng)的金額數(shù)值)作為參數(shù),例如,下面的例子要使用信用卡支付 100 美分,或 1 美元:

$user->charge(100);

charge 方法接收一個(gè)數(shù)組作為第二個(gè)參數(shù),允許你傳遞任何你想要傳遞的底層 Stripe 賬單創(chuàng)建參數(shù):

$user->charge(100, [
    'source' => $token,
    'receipt_email' => $user->email,]);

如果支付失敗 charge 方法將返回 false,這通常表明付款被拒絕:

if ( ! $user->charge(100)) {
    // The charge was denied...
}

如果支付成功,該方法將會(huì)返回一個(gè)完整的 Stripe響應(yīng)。

5、發(fā)票

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

$invoices = $user->invoices();

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

<table>
    @foreach ($invoices as $invoice)
        <tr>
            <td>{{ $invoice->dateString() }}</td>
            <td>{{ $invoice->dollars() }}</td>
            <td><a href="/user/invoice/{{ $invoice->id }}">Download</a></td>
        </tr>
    @endforeach
</table>

5.1 生成 PDF 發(fā)票

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

Route::get('user/invoice/{invoice}', function ($invoiceId) {
    return Auth::user()->downloadInvoice($invoiceId, [
        'vendor'  => 'Your Company',
        'product' => 'Your Product',
    ]);
});
上一篇:發(fā)行版本說(shuō)明下一篇:起步