Laravel Cashier 提供语义化,流畅的接口和 Stripe 的订购管理服务集成。它几乎处理了所有让人退步三舍的订购管理相关逻辑。除了基本的订购管理,Cashier 还可以处理折价券,订购转换,管理订购“数量”、服务有效期限,甚至产生收据的 PDF。
首先,把 Cashier 扩展包加到 composer.json
:
"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)
然后,在 app
配置文件注册 Laravel\Cashier\CashierServiceProvider
。
使用 Cashier 前,我们需要增加几个字段到数据库。别担心,你可以使用 cashier:table
Artisan 命令,建立迁移文件来添加必要字段。例如,要增加字段到 users 数据表,使用 php artisan cashier:table users
。建立完迁移文件后,只要执行 migrate
命令即可。
然后,把 Billable
trait 和相关的日期字段参数加到模型里:
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'];
}
最后, 在 services.php
配置文件中设置你的 Stripe key:
'stripe' => [
'model' => 'User',
'secret' => env('STRIPE_API_SECRET'),
],
或者,也可以在初始化文件 (bootstrap) 或服务提供者中(如 AppServiceProvider
)加入 Stripe key:
User::setStripeKey('stripe-key');
当有了模型实例,你可以很简单的处理客户订购的 Stripe 里的方案:
$user = User::find(1);
$user->subscription('monthly')->create($creditCardToken);
如果你想在建立订购的时候使用折价券,可以使用 withCoupon
方法:
$user->subscription('monthly')
->withCoupon('code')
->create($creditCardToken);
subscription
方法会自动建立与 Stripe 的交易,以及将 Stripe customer ID 和其他相关帐款信息更新到数据库。如果你的方案有在 Stripe 配置试用期,试用到日期也会自动记录起来。
如果你的方案有试用期间,但是没有在 Stripe 里配置,你必须在处理订购后手动保存试用到日期。
$user->trial_ends_at = Carbon::now()->addDays(14);
$user->save();
如果你想自定义额外的顾客详细数据,你可以将数据数组作为 create
方法的第二个参数传入:
$user->subscription('monthly')->create($creditCardToken, [
'email' => $email, 'description' => 'Our First Customer'
]);
想知道更多 Stripe 支持的额外字段,可以查看 Stripe 的在线文档 建立客户。
如果你想使用一次性付款而不是信用卡订购方案,你可以使用 charge
方法:
$user->charge(100);
charge
方法接受一个用最低单位货币的数量参数。 比如,上面的例子中会付款 100 美分 或者 1.00 美元,而不是用户的信用卡。
charge
方法也接受一个数组作为第二个参数,允许你传入一些创建 Stripe 订购的选项:
$user->charge(100, [
'source' => $token,
'receipt_email' => $user->email,
]);
如果付款失败,charge
方法会返回 false
。一般来说,这意味着付款被拒绝:
if ( ! $user->charge(100))
{
// The charge was denied...
}
如果付款成功, 一个完整的 Stripe 响应会从这个方法返回。
如果你提供免信用卡试用服务,把 cardUpFront
属性设为 false
:
protected $cardUpFront = false;
建立帐号时,记得把试用到日期记录起来:
$user->trial_ends_at = Carbon::now()->addDays(14);
$user->save();
使用 swap
方法可以把用户转换到新的订购:
$user->subscription('premium')->swap();
如果用户还在试用期间,试用服务会跟之前一样可用。如果订单有“数量”,也会和之前一样。
有时候订购行为会跟“数量”有关。例如,你的应用程序可能会依照帐号的用户人数,每人每月收取 $10 元。你可以使用 increment
和 decrement
方法简单的调整订购数量:
$user = User::find(1);
$user->subscription()->increment();
// Add five to the subscription's current quantity...
$user->subscription()->increment(5);
$user->subscription()->decrement();
// Subtract five to the subscription's current quantity...
$user->subscription()->decrement(5);
With Cashier, it's easy to override the tax_percent
value sent to Stripe. To specify the tax percentage a user pays on a subscription, implement the getTaxPercent
method on your model, and return a numeric value between
0 and 100, with no more than 2 decimal places.
public function getTaxPercent()
{
return 20;
}
This enables you to apply a tax rate on a model-by-model basis, which may be helpful for a user base that spans multiple countries.
取消订购相当简单:
$user->subscription()->cancel();
当客户取消订购时,Cashier 会自动更新数据库的 subscription_ends_at
字段。这个字段会被用来判断 subscribed
方法是否该返回 false
。例如,如果顾客在三月一号取消订购,但是服务可以使用到三月五号为止,那么 subscribed
方法在三月五号前都会传回 true
。
如果你想要恢复客户之前取消的订购,使用 resume
方法:
$user->subscription('monthly')->resume($creditCardToken);
如果客户取消订购后,在服务过期前恢复,他们不用在当下付款。他们的服务会立刻重启,而付款则会遵循平常的流程。
要确认用户是否订购了你的应用,使用 subscribed
方法:
if ($user->subscribed())
{
//
}
subscribed
方法很适合用在 路由中间件:
public function handle($request, Closure $next)
{
if ($request->user() && ! $request->user()->subscribed())
{
return redirect('billing');
}
return $next($request);
}
你可以使用 onTrial
方法,确认用户是否还在试用期间:
if ($user->onTrial())
{
//
}
要确认用户是否曾经订购但是已经取消了服务,可以使用 cancelled
方法:
if ($user->cancelled())
{
//
}
你可能想确认用户是否已经取消订单,但是服务还没有到期。例如,如果用户在三月五号取消了订购,但是服务会到三月十号才过期。那么用户到三月十号前都是有效期间。注意, subscribed
方法在过期前都会返回 true
。
if ($user->onGracePeriod())
{
//
}
everSubscribed
方法可以用来确认用户是否订购过应用程序里的方案:
if ($user->everSubscribed())
{
//
}
onPlan
方法可以用方案 ID 来确认用户是否订购某方案:
if ($user->onPlan('monthly'))
{
//
}
如果顾客的信用卡过期了呢?无需担心,Cashier 包含了 Webhook 控制器,可以帮你简单的取消顾客的订单。只要在路由注册控制器:
Route::post('stripe/webhook', 'Laravel\Cashier\WebhookController@handleWebhook');
这样就成了!失败的交易会经由控制器捕捉并进行处理。控制器会进行至多三次再交易尝试,当 Stripe 认为三次都失败后才会取消顾客的订单。上面的 stripe/webhook
URI 只是一个例子,你必须使用配置在 Stripe 里的 URI 才行。
如果你想要处理额外的 Stripe webhook 事件,可以继承 Webhook 控制器。你的方法名称要对应到 Cashier 预期的名称,尤其是方法名称应该使用 handle
前缀,后面接着你想要处理的 Stripe webhook 。例如,如果你想要处理 invoice.payment_succeeded
webhook ,你应该增加一个 handleInvoicePaymentSucceeded
方法到控制器。
class WebhookController extends Laravel\Cashier\WebhookController {
public function handleInvoicePaymentSucceeded($payload)
{
// Handle The Event
}
}
注意: 除了更新你数据库里的订购信息以外, Webhook 控制器也会经由 Stripe API 取消你的订购。
你可以很简单的经由 invoices
方法拿到客户的收据数据数组:
$invoices = $user->invoices();
你可以使用这些辅助方法,列出收据的相关信息给客户看:
{{ $invoice->id }}
{{ $invoice->dateString() }}
{{ $invoice->dollars() }}
使用 downloadInvoice
方法产生收据的 PDF 下载。是的,它非常容易:
return $user->downloadInvoice($invoice->id, [
'vendor' => 'Your Company',
'product' => 'Your Product',
]);