controlla/conekta-cashier

Controlla Cashier 为 Laravel 提供了一个用于通过 Conketa 收费订阅的界面。

v1.0.6 2022-03-02 01:47 UTC

This package is auto-updated.

Last update: 2024-08-29 05:37:12 UTC


README

Build Status Total Downloads Latest Stable Version License

Conekta Cashier 是 Laravel Cashier 的 Conketa 版本 Laravel Cashier,用于 Conketa。

请注意,Laravel Cashier 的最新版本支持 Laravel 5+,如果您正在寻找 Laravel 4 的实现,请参阅 1.0 分支。

Conekta Cashier

简介

Conekta Cashier 提供了一个表达性、流畅的接口来访问 Conekta 的订阅计费服务。它处理了几乎所有您害怕编写的样板化订阅计费代码。除了基本的订阅管理外,Cashier 还可以处理优惠券、交换订阅、订阅 "数量"、取消宽限期,甚至生成发票 PDF。

安装

首先,使用 Composer 包管理器安装 Conekta 的 Cashier 包

composer require controlla/conekta-cashier

数据库迁移

Conekta 的服务提供者注册了自己的数据库迁移目录,因此在安装包后请务必迁移您的数据库。Cashier 迁移将在您的 users 表中添加几个列,并创建一个新的订阅表以存储所有客户的 subscriptions

php artisan migrate

如果您需要覆盖 Cashier 附加的迁移,您可以使用 vendor:publish Artisan 命令来发布它们

php artisan vendor:publish --tag="cashier-migrations"

如果您想完全阻止 Cashier 的迁移运行,您可以使用 Cashier 提供的 ignoreMigrations 方法。通常,此方法应在 AppServiceProviderregister 方法中调用

use Controlla\ConektaCashier\Cashier;

/**
* Register any application services.
*
* @return void
*/
public function register()
{
	Cashier::ignoreMigrations();
}

配置

可计费模型

在使用 Cashier 之前,请将 Billable 特性添加到您的可计费模型定义中。通常,这将是一个 App\Models\User 模型。此特性提供了各种方法,使您能够执行常见的计费任务,例如创建订阅、应用优惠券以及更新支付方式信息

use Controlla\ConektaCashier\Billable;

class User extends Authenticatable
{
	use Billable;
}

Cashier 假设您的计费模型将是 Laravel 附加的 App\Models\User 类。如果您希望更改此设置,您可以通过 useCustomerModel 方法指定不同的模型。此方法通常应在 AppServiceProvider 类的 boot 方法中调用

use App\Models\Cashier\User;
use Controlla\ConektaCashier\Cashier;

/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
		Cashier::useCustomerModel(User::class);
}

❗如果您使用的是 Laravel 提供的 App\Models\User 模型以外的其他模型,您需要发布并修改提供的 Cashier 迁移 以匹配您的替代模型的表

API 密钥

接下来,您应该在应用程序的 .env 文件中配置您的 Conekta API 密钥。您可以从 Conekta 控制面板中检索您的 Conekta API 密钥

CONEKTA_KEY=your-conekta-key
CONEKTA_SECRET=your-conekta-secret

货币配置

Cashier 的默认货币是墨西哥比索 (MXN)。您可以通过在应用程序的 .env 文件中设置 CASHIER_CURRENCY 环境变量来更改默认货币

CASHIER_CURRENCY=eur

除了配置 Cashier 的货币外,您还可以指定用于在发票上显示货币值时使用的区域设置。内部,Cashier 使用 PHP 的 NumberFormatter 类 设置货币区域设置

CASHIER_CURRENCY_LOCALE=nl_BE

客户

检索客户

您可以使用Cashier类的findBillable方法通过Conekta ID检索客户。此方法将返回可计费模型的实例。

use Controlla\ConektaCashier\Cashier;

$user = Cashier::findBillable($conektaId);

创建客户

有时,您可能希望在开始订阅之前创建一个Conekta客户。您可以使用createAsConektaCustomer方法完成此操作。

$conektaCustomer = $user->createAsConektaCustomer();

订阅计划

一旦您拥有一个模型实例,就可以轻松地将该用户订阅到给定的Conekta计划。

$user = User::find(1);

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

您还可以扩展订阅试用期。

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

$user->extendTrial(Carbon::now()->addMonth());

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

如果您的计划在Conekta中未配置试用期,您必须在订阅后手动设置试用期结束日期。

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

$user->save();

指定额外用户详情

如果您想指定额外的客户详情,您可以将它们作为第二个参数传递给create方法。

$user->subscription('monthly')->create($creditCardToken, [
	'email' => $email, 'name' => 'Joe Doe'
]);

要了解更多关于Conekta支持的增加字段,请参阅Conekta关于客户创建的文档

单次收费

如果您想对已订阅客户的信用卡进行一次性收费,可以使用charge方法。

$user->charge(100);

charge方法接受您要收取的金额,金额以货币的最小分母为单位。例如,上面的例子将收取100美分,即1.00美元。

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

$user->charge(100, [
	'card' => $token,
]);

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

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

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

交换订阅

要切换用户到新的订阅,请使用swap方法。

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

如果用户处于试用期,试用期将按正常方式保持。此外,如果订阅存在“数量”,该数量也将保持不变。

取消订阅

取消订阅是一件轻而易举的事。

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

当订阅被取消时,Cashier会自动设置数据库中的subscription_ends_at列。该列用于确定何时subscribed方法应开始返回false。例如,如果客户在3月1日取消订阅,但订阅原计划在3月5日结束,则subscribed方法将继续在3月5日之前返回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())
{
	//
}

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

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

可以使用everSubscribed方法来确定用户是否曾经订阅过您的应用程序中的任何计划。

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

可以使用onPlan方法来确定用户是否根据其ID订阅了某个计划。

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

处理 Conkta Webhooks

Conekta可以通过webhook通知您的应用程序各种事件。默认情况下,Cashier服务提供者会自动注册指向Cashier webhook控制器的路由。此控制器将处理所有传入的webhook请求。

默认情况下,Conekta Cashier webhook控制器将自动处理因失败次数过多而取消的订阅(根据您的Conekta设置定义)、客户更新、客户删除、订阅更新和支付方式更改;然而,正如我们很快将发现的,您可以扩展此控制器以处理您喜欢的任何Conekta webhook事件。

为确保您的应用程序可以处理Conekta webhook,请确保在Conekta控制面板中配置webhook URL。默认情况下,Cashier的webhook控制器响应于/conekta/webhook URL路径。

为了方便,Cashier包含一个cashier:webhook Artisan命令。此命令将在Conekta中创建一个webhook,以监听Cashier所需的所有事件。

php artisan cashier:webhook

默认情况下,创建的webhook将指向由APP_URL环境变量和Cashier中包含的cashier.webhook路由定义的URL。如果您希望在调用命令时使用不同的URL,可以提供--url选项。

php artisan cashier:webhook --url "https://example.com/conekta/webhook"

定义Webhook事件处理器

Cashier自动处理因失败费用和其他常见Conekta webhook事件导致的订阅取消。但是,如果您想要处理其他webhook事件,您可以通过监听Cashier发出的以下事件来实现

  • Controlla\ConektaCashier\Events\WebhookReceived
  • Controlla\ConektaCashier\Events\WebhookHandled

这两个事件都包含Conekta webhook的完整有效载荷。例如,如果您希望处理charge.paid webhook,您可以注册一个监听器来处理此事件。

<?php

namespace App\Listeners;

use Controlla\ConektaCashier\Events\WebhookReceived;

class ConektaEventListener
{
	/**
	* Handle received Conekta webhooks.
	*
	* @param  \Controlla\ConektaCashier\Events\WebhookReceived  $event
	* @return void
	*/
	public function handle(WebhookReceived $event)
	{
		if ($event->payload['type'] === 'charge.paid') {
			// Handle the incoming event...
		}
	}
}

一旦定义了监听器,您可以在应用程序的EventServiceProvider中注册它。

<?php

namespace App\Providers;

use App\Listeners\ConektaEventListener;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Controlla\ConektaCashier\Events\WebhookReceived;

class EventServiceProvider extends ServiceProvider
{
	protected $listen = [
		WebhookReceived::class => [
			ConektaEventListener::class,
		],
	];
}

测试

在测试使用Cashier的应用程序时,您可能需要模拟对Conekta API的实际HTTP请求;然而,这需要您部分重新实现Cashier的行为。因此,我们建议允许您的测试击中实际Conekta API。虽然这较慢,但它提供了更多信心,表明您的应用程序按预期工作,任何慢速测试都可以放在它们自己的PHPUnit测试组中。

在测试时,请记住Cashier本身已经有一个很好的测试套件,因此您应该只关注测试您应用程序的订阅和支付流程,而不仅仅是Cashier的每个底层行为。

要开始,将您的Conekta密钥的测试版本添加到您的phpunit.xml文件中。

<env name="CONEKTA_SECRET" value="<your-key>"/>

现在,每当您在测试时与Cashier交互,它将向您的Conekta测试环境发送实际的API请求。