awayr-sudo/yii2-cashier

从[yii2mod/cashier]派生,Yii2 Cashier提供对Stripe订阅计费服务的接口。

安装: 118

依赖: 0

建议者: 0

安全: 0

星标: 0

关注者: 0

分支: 23

开放性问题: 0

类型:yii2-extension

2.0.0 2018-03-22 19:24 UTC

This package is not auto-updated.

Last update: 2024-09-28 09:17:25 UTC


README

为Yii 2提供的Cashier扩展(由著名的Yii2 Cashier [yii2mod/cashier]移植)。实现了最新更新。


本扩展是Laravel的Cashier包的移植版,[href="https://laravel.net.cn/docs/5.4/billing" rel="nofollow noindex noopener external ugc"]

Latest Stable Version Total Downloads License Build Status

支持我们

您的业务依赖我们的贡献吗?在Patreon上联系我们并支持我们。所有承诺都将用于分配人力进行维护和新奇事物。

安装

安装此扩展的首选方式是通过composer

运行以下命令之一:

php composer.phar require --prefer-dist awayr-sudo/yii2-cashier "*"

"awayr-sudo/yii2-cashier": "*"

将以下内容添加到您的composer.json文件的require部分。

Stripe配置

本项目受Laravel的Cashier包的启发,并试图将其简洁性带到Yii框架中。

数据库迁移

在使用Cashier之前,我们还需要准备数据库。

$tableOptions = null;

if ($this->db->driverName === 'mysql') {
    $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
}

$this->createTable('subscriptions', [
    'id' => $this->primaryKey(),
    'user_id' => $this->integer()->notNull(),
    'name' => $this->string()->notNull(),
    'stripe_id' => $this->string()->notNull(),
    'stripe_plan' => $this->string()->notNull(),
    'quantity' => $this->integer()->notNull(),
    'trial_ends_at' => $this->timestamp()->null(),
    'ends_at' => $this->timestamp()->null(),
    'created_at' => $this->timestamp()->null(),
    'updated_at' => $this->timestamp()->null()
], $tableOptions);

$this->addColumn('users', 'stripe_id', $this->string());
$this->addColumn('users', 'card_brand', $this->string());
$this->addColumn('users', 'card_last_four', $this->string());
$this->addColumn('users', 'trial_ends_at', $this->timestamp()->null());

您也可以通过以下命令应用迁移:

php yii migrate --migrationPath=@vendor/yii2mod/yii2-cashier/migrations

模型设置

接下来,将Billable特性添加到您的User模型定义中

use awayr\cashier\Billable;

class User extends ActiveRecord implements IdentityInterface
{
    use Billable;
}

提供者密钥

接下来,您应该在配置文件中配置您的params部分

'params' => [
        .....
        'stripe' => [
            'apiKey' => 'Your Secret Api Key'
        ],
    ],

订阅

创建订阅

要创建订阅,首先检索您的billable模型实例,这通常是models\User的一个实例。检索到模型实例后,您可以使用newSubscription方法创建模型的订阅

$user = User::findOne(1);

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

传递给newSubscription方法的第一个参数是订阅的名称。如果您的应用程序只提供单个订阅,您可能将其称为main或primary。第二个参数是用户订阅的具体Stripe计划。此值应与Stripe中计划的标识符相匹配。

create方法将自动创建订阅,并将客户ID和其他相关计费信息更新到您的数据库中。

用户其他详细信息

如果您想指定额外的客户详细信息,可以在create方法的第二个参数中传递它们

$user->newSubscription('main', 'monthly')->create($creditCardToken, [
    'description' => 'Customer for test@example.com'
]);

要了解更多关于Stripe支持的其他字段的信息,请查看Stripe的客户创建文档

优惠券

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

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

检查订阅状态

一旦用户订阅了您的应用程序,您可以使用各种方便的方法轻松检查他们的订阅状态。首先,subscribed方法返回true,如果用户有一个活跃的订阅,即使订阅目前处于试用期内

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

如果您想确定用户是否仍在试用期内,可以使用onTrial方法。此方法可以用来向用户显示警告,告知他们仍在试用期内

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

subscribedToPlan方法可以用来确定用户是否基于给定的Stripe计划ID订阅了给定的计划。在此示例中,我们将确定用户的主订阅是否正在订阅月度计划

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

已取消订阅状态

为了确定用户是否曾经是活跃的订阅者,但现在已取消订阅,您可以使用已取消方法

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

您还可以确定用户是否已取消订阅,但仍在他们的“宽限期”内,直到订阅完全到期。例如,如果用户在3月5日取消了一个原定于3月10日到期的订阅,则用户在3月10日之前处于“宽限期”。请注意,在此期间,订阅方法仍然返回true。

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

更改计划

用户订阅您的应用程序后,他们有时可能想要更改到新的订阅计划。要切换用户到新的订阅,请使用交换方法。例如,我们可以轻松地将用户切换到高级订阅。

$user = User::findOne(1);

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

如果用户处于试用状态,试用期限将保持不变。此外,如果订阅中存在“数量”,则该数量也将保持不变。

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

如果您想要切换计划但跳过您要切换到的计划的试用期限,您可以使用skipTrial方法。

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

订阅数量

有时订阅会受到“数量”的影响。例如,您的应用程序可能对每个账户每月每个用户收取10美元的费用。要轻松增加或减少您的订阅数量,请使用incrementQuantity和decrementQuantity方法。

$user = User::findOne(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);

或者,您可以使用updateQuantity方法设置特定的数量。

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

有关订阅数量的更多信息,请参阅Stripe文档

订阅税费

使用Cashier,轻松提供发送给Stripe的tax_percent值。要指定用户在订阅上支付的税费百分比,请在您的可收费模型上实现taxPercentage方法,并返回一个介于0和100之间的小数值,最多两位小数。

public function taxPercentage() {
    return 20;
}

这使您能够根据模型应用税率,这可能有助于跨越多个国家的用户基础。

取消订阅

要取消订阅,只需在用户的订阅上调用cancel方法。

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

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

您可以使用onGracePeriod方法确定用户是否已取消订阅但仍在他们的“宽限期”内。

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

恢复订阅

如果用户已取消订阅并且您希望恢复它,请使用resume方法。用户必须仍在他们的宽限期才能恢复订阅。

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

如果用户取消订阅然后在此订阅完全到期之前恢复该订阅,他们不会立即收费。相反,他们的订阅将被重新激活,他们将在原始账单周期内被收费。

订阅试用

预先收取信用卡

如果您想在收集客户支付方式信息的同时为客户提供试用期限,您应该在创建订阅时使用trialDays方法。

$user = User::findOne(1);

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

此方法将在数据库中的订阅记录上设置试用期限结束日期,并指示Stripe在此日期之后不开始向客户收费。

如果客户在试用结束日期前未取消订阅,那么试用期一结束,他们就会被立即收费,因此您应该通知用户他们的试用期结束日期。您可以使用用户实例的onTrial方法,或者订阅实例的onTrial方法来确定用户是否处于试用期。以下两个示例在目的上基本相同

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

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

无需预先提供信用卡

如果您想在收集用户支付方式信息之前提供试用期,您只需将用户记录中的trialEndAt列设置为所需的试用期结束日期即可。例如,这通常在用户注册期间完成

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

收银员将此类试用称为“通用试用”,因为它与任何现有订阅无关。如果当前日期未超过trialEndAt的值,则User实例上的onTrial方法将返回true

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

如果您想确切知道用户是否处于“通用”试用期并且尚未创建实际订阅,则可以使用onGenericTrial方法

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

一旦您准备好为用户创建实际订阅,您可以像往常一样使用newSubscription方法

$user = User::findOne(1);

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

处理Stripe Webhooks

失败的订阅

只需将WebhookController添加到您的配置文件中的controllerMap即可

'controllerMap' => [
        //Stripe webhook
        'webhook' => 'awayr\cashier\controllers\WebhookController',
    ],

就是这样!失败支付将被捕获并由控制器处理。当Stripe确定订阅失败时(通常在三次失败支付尝试后),控制器将取消客户的订阅。别忘了:您需要在Stripe控制面板设置中配置webhook URI,例如:yoursite.com/webhook/handle-webhook

单次收费

简单收费

当使用Stripe时,charge方法接受您希望以应用程序使用的货币的最小单位计费的数量。

如果您想对已订阅客户的信用卡进行一次性的收费,您可以在账单模型实例上使用charge方法。

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

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

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

如果收费失败,charge方法将抛出异常。如果收费成功,方法将返回完整的Stripe响应

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

带有发票的收费

有时您可能需要一次性收费,同时也需要生成收费的发票,以便您可以向客户提供PDF收据。invoiceFor方法可以做到这一点。例如,让我们为客户的“一次性费用”开一张5.00美元的发票

// Stripe Accepts Charges In Cents...

$user->invoiceFor('One Time Fee', 500);

发票将立即对用户的信用卡收费。invoiceFor方法也接受一个数组作为第三个参数,允许您将任何选项传递给底层的Stripe收费创建

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

如果第一次收费失败,invoiceFor方法将创建一个Stripe发票,该发票将重试失败的账单尝试。如果您不希望发票重试失败的收费,您需要在第一次失败收费后使用Stripe API关闭它们

发票

您可以使用invoices方法轻松检索账单模型的发票数组

$invoices = $user->invoices();

当列出客户的发票时,您可以使用发票的辅助方法显示相关的发票信息。例如,您可能希望在一个GridView中列出每个发票,使用户可以轻松下载它们

$dataProvider = new \yii\data\ArrayDataProvider([
            'allModels' => $invoices,
            'pagination' => [
                'pageSize' => 10,
            ],
        ]);

 echo yii\grid\GridView::widget([
        'dataProvider' => $dataProvider,
        'columns' => [
            [
                'label' => 'Invoice Date',
                'value' => function ($model) {
                    return $model->date()->toFormattedDateString();
                }
            ],
            [
                'label' => 'Total',
                'value' => function ($model) {
                    return $model->total();
                }
            ],
            [
                'header' => 'Action',
                'class' => 'yii\grid\ActionColumn',
                'template' => '{download}',
                'buttons' => [
                    'download' => function ($url, $model, $key) {
                        $options = [
                            'title' => Yii::t('yii', 'Download Invoice'),
                            'data-pjax' => '0',
                        ];
                        $url = ['download-invoice', 'invoiceId' => $model->id];
                        return \yii\helpers\Html::a('<span class="glyphicon glyphicon-download"></span>', $url, $options);
                    }
                ],
            ],
        ],
 ]);

生成发票PDF

在您的控制器中创建download-invoice操作,例如

public function actionDownloadInvoice($invoiceId)
{
    return $user->downloadInvoice($invoiceId, [
        'vendor' => 'Your Company',
        'product' => 'Your Product',
    ]);
}

退款

退款对象允许您对之前已创建但尚未退款的费用进行退款。资金将退还至原始收费的信用卡或借记卡。您最初被收取的费用也将退还。

// Create Invoice
$invoice = $user->invoiceFor('Invoice Description', 1000);

// Create the refund
$refund = $user->refund($invoice->charge);

var_dump($refund->amount); // 1000