Skip to content

Laravel Cashier

介绍

Laravel Cashier 提供了一个对 Stripe 订阅计费服务的富有表现力的流畅接口。它处理了几乎所有你不想写的订阅计费样板代码。除了基本的订阅管理,Cashier 还可以处理优惠券、交换订阅、订阅“数量”、取消宽限期,甚至生成发票 PDF。

配置

Composer

首先,将 Cashier 包添加到你的 composer.json 文件中:

php
"laravel/cashier": "~5.0" (适用于 Stripe SDK ~2.0 2015-02-18 及以后的 Stripe API)
"laravel/cashier": "~4.0" (适用于 2015-02-18 及以后的 Stripe API)
"laravel/cashier": "~3.0" (适用于 2015-02-16 及以前的 Stripe API)

服务提供者

接下来,在你的 app 配置文件中注册 Laravel\Cashier\CashierServiceProvider

迁移

在使用 Cashier 之前,我们需要在数据库中添加几个列。别担心,你可以使用 cashier:table Artisan 命令创建一个迁移来添加必要的列。例如,要将列添加到用户表中,使用 php artisan cashier:table users。创建迁移后,只需运行 migrate 命令。

模型设置

接下来,将 Billable trait 和适当的日期变换器添加到你的模型定义中:

php
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'];

}

Stripe 密钥

最后,在你的 services.php 配置文件中设置你的 Stripe 密钥:

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

或者你可以将其存储在你的一个引导文件或服务提供者中,例如 AppServiceProvider

php
User::setStripeKey('stripe-key');

订阅计划

一旦你有了一个模型实例,你可以很容易地将该用户订阅到一个给定的 Stripe 计划:

php
$user = User::find(1);

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

如果你想在创建订阅时应用优惠券,可以使用 withCoupon 方法:

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

subscription 方法将自动创建 Stripe 订阅,并更新你的数据库中的 Stripe 客户 ID 和其他相关的计费信息。如果你的计划在 Stripe 中配置了试用期,试用结束日期也会自动设置在用户记录上。

如果你的计划有一个未在 Stripe 中配置的试用期,你必须在订阅后手动设置试用结束日期:

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

$user->save();

指定额外的用户详细信息

如果你想指定额外的客户详细信息,可以将它们作为 create 方法的第二个参数传递:

php
$user->subscription('monthly')->create($creditCardToken, [
	'email' => $email, 'description' => '我们的第一个客户'
]);

要了解 Stripe 支持的其他字段,请查看 Stripe 的客户创建文档

单次收费

如果你想对订阅客户的信用卡进行“一次性”收费,可以使用 charge 方法:

php
$user->charge(100);

charge 方法接受你想要收费的金额,以货币的最低单位表示。例如,上面的例子将对用户的信用卡收取 100 美分,即 $1.00。

charge 方法接受一个数组作为第二个参数,允许你将任何选项传递给底层的 Stripe 收费创建:

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

如果收费失败,charge 方法将返回 false。这通常表示收费被拒绝:

php
if ( ! $user->charge(100))
{
	// 收费被拒绝...
}

如果收费成功,方法将返回完整的 Stripe 响应。

无需预先提供信用卡

如果你的应用程序提供无需预先提供信用卡的免费试用期,请将模型上的 cardUpFront 属性设置为 false

php
protected $cardUpFront = false;

在账户创建时,务必在模型上设置试用结束日期:

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

$user->save();

更换订阅

要将用户更换到新的订阅,请使用 swap 方法:

php
$user->subscription('premium')->swap();

如果用户在试用期内,试用期将正常保持。此外,如果订阅存在“数量”,该数量也将保持。

订阅数量

有时订阅会受到“数量”的影响。例如,你的应用程序可能会对账户上的每个用户每月收取 $10。要轻松增加或减少订阅数量,请使用 incrementdecrement 方法:

php
$user = User::find(1);

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

// 在订阅的当前数量上增加五个...
$user->subscription()->increment(5);

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

// 在订阅的当前数量上减少五个...
$user->subscription()->decrement(5);

订阅税

使用 Cashier,可以轻松覆盖发送到 Stripe 的 tax_percent 值。要指定用户在订阅上支付的税率,请在你的模型上实现 getTaxPercent 方法,并返回一个介于 0 和 100 之间的数值,最多保留两位小数。

php
public function getTaxPercent()
{
	return 20;
}

这使你可以在模型基础上应用税率,这对于跨多个国家的用户群可能很有帮助。

取消订阅

取消订阅就像散步一样简单:

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

当订阅被取消时,Cashier 将自动在你的数据库中设置 subscription_ends_at 列。此列用于知道何时 subscribed 方法应开始返回 false。例如,如果客户在 3 月 1 日取消订阅,但订阅计划在 3 月 5 日结束,subscribed 方法将继续返回 true 直到 3 月 5 日。

恢复订阅

如果用户已取消其订阅并希望恢复,请使用 resume 方法:

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

如果用户取消订阅并在订阅完全过期之前恢复该订阅,他们将不会立即被计费。他们的订阅将被重新激活,并将在原始计费周期中计费。

检查订阅状态

要验证用户是否订阅了你的应用程序,请使用 subscribed 方法:

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

subscribed 方法是一个很好的路由中间件候选者:

php
public function handle($request, Closure $next)
{
	if ($request->user() && ! $request->user()->subscribed())
	{
		return redirect('billing');
	}

	return $next($request);
}

你还可以使用 onTrial 方法确定用户是否仍在试用期内(如果适用):

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

要确定用户是否曾经是活跃订阅者,但已取消其订阅,可以使用 cancelled 方法:

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

你还可以确定用户是否已取消其订阅,但仍在其“宽限期”内,直到订阅完全过期。例如,如果用户在 3 月 5 日取消了计划在 3 月 10 日结束的订阅,用户将在 3 月 10 日之前处于“宽限期”。请注意,在此期间 subscribed 方法仍返回 true

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

everSubscribed 方法可用于确定用户是否曾经订阅过你的应用程序中的计划:

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

onPlan 方法可用于确定用户是否订阅了基于其 ID 的给定计划:

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

处理失败的订阅

如果客户的信用卡过期怎么办?不用担心 - Cashier 包含一个 Webhook 控制器,可以轻松地为你取消客户的订阅。只需将一个路由指向控制器:

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

就是这样!失败的付款将由控制器捕获并处理。当 Stripe 确定订阅失败时(通常在三次失败的付款尝试后),控制器将取消客户的订阅。此示例中的 stripe/webhook URI 仅供参考。你需要在 Stripe 设置中配置 URI。

处理其他 Stripe Webhooks

如果你有其他 Stripe webhook 事件想要处理,只需扩展 Webhook 控制器。你的方法名称应符合 Cashier 的预期约定,具体来说,方法应以 handle 和你想要处理的 Stripe webhook 的名称为前缀。例如,如果你想处理 invoice.payment_succeeded webhook,你应该在控制器中添加一个 handleInvoicePaymentSucceeded 方法。

php
class WebhookController extends Laravel\Cashier\WebhookController {

	public function handleInvoicePaymentSucceeded($payload)
	{
		// 处理事件
	}

}
lightbulb

除了更新数据库中的订阅信息外,Webhook 控制器还将通过 Stripe API 取消订阅。

发票

你可以使用 invoices 方法轻松检索用户发票的数组:

php
$invoices = $user->invoices();

在为客户列出发票时,你可以使用这些辅助方法来显示相关的发票信息:

php
{{ $invoice->id }}

{{ $invoice->dateString() }}

{{ $invoice->dollars() }}

使用 downloadInvoice 方法生成发票的 PDF 下载。是的,真的这么简单:

php
return $user->downloadInvoice($invoice->id, [
	'vendor'  => 'Your Company',
	'product' => 'Your Product',
]);