bgultekin/cashier-fastspring 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

bgultekin/cashier-fastspring

Composer 安装命令:

composer require bgultekin/cashier-fastspring

包简介

Cashier Fastspring is a cashier-like laravel package which provides an interface to Fastspring subscription and payment services.

README 文档

README

Packagist Build Status Coverage Status Style CI Laravel 5 License

Table of contents

Introduction

Cashier Fastspring is a cashier-like laravel package which provides interface to Fastspring subscription and payment services. This package handles webhooks and provides a simple API for Fastspring. Before using this package, looking at Fastspring documentation is strongly recommended.

Installation

Add bgultekin/cashier-fastspring package to your dependencies.

composer require "bgultekin/cashier-fastspring"

After requiring package, add service provider of this package to providers in config/app.php.

'providers' => array(
    // ...
    Bgultekin\CashierFastspring\CashierServiceProvider::class,
)

Configuration

Migrations

Cashier Fastspring package comes with database migrations. After requiring the package, you can publish it with following command.

php artisan vendor:publish

After publishing them, you can find migration files in your database/migrations folder. Remember that you can modify them according to your needs.

Billable Model

Next, add the Billable trait to your model definition. This trait provides various methods to allow you to perform common billing tasks, such as creating and checking subscriptions, getting orders etc.

use Laravel\Cashier\Billable;

class User extends Authenticatable
{
    use Billable;
}

API Keys

You should add Fastspring configuration to config/services.php file.

'fastspring' => [
    'model' => App\User::class,
    'username' => env('FASTSPRING_USERNAME'),
    'password' => env('FASTSPRING_PASSWORD'),
    'store_id' => env('FASTSPRING_STORE_ID'),

    // strongly recommend to set hmac secret in webhook configuration
    // to prevent webhook spoofing
    'hmac_secret' => env('FASTSPRING_HMAC_SECRET')
],

Webhook Route

Fastspring can notify your application of a variety of events via webhooks. To handle webhooks, define a route and also set it in Fastspring settings.

Route::post(
    'fastspring/webhook',
    '\Bgultekin\CashierFastspring\Http\Controllers\WebhookController@handleWebhook'
)->name('fastspringWebhook');

Webhooks & CSRF Protection

Fastspring webhook requests need to bypass CSRF protection. That's why be sure to list your webhook URI as an exception in your VerifyCsrfToken middleware.

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

Creating Plans

This package does not cover creating plans at Fastspring side or storing created plans. You should create your subscription plans at Fastspring's Dashboard.

Quick Start

Cashier Fastspring comes with built-in listeners which you can find in src/Events for quickstart. These listeners help you to sync subscriptions and invoices with your database.

Remember that you can create and use your listeners and database structure according to your needs. In order to customize, you can check Usage.

In Cashier Fastspring, every webhook request fires related events. You can register listeners to webhook events in app/providers/EventServiceProvider.php. You can see more at Webhooks.

protected $listen = [
    // some others
    'Bgultekin\CashierFastspring\Events\SubscriptionCanceled' => [
        'Bgultekin\CashierFastspring\Listeners\SubscriptionStateChanged'
    ],
    'Bgultekin\CashierFastspring\Events\SubscriptionDeactivated' => [
        'Bgultekin\CashierFastspring\Listeners\SubscriptionDeactivated'
    ],
    'Bgultekin\CashierFastspring\Events\SubscriptionPaymentOverdue' => [
        'Bgultekin\CashierFastspring\Listeners\SubscriptionStateChanged'
    ],
    'Bgultekin\CashierFastspring\Events\OrderCompleted' => [
        'Bgultekin\CashierFastspring\Listeners\OrderCompleted'
    ],
    'Bgultekin\CashierFastspring\Events\SubscriptionActivated' => [
        'Bgultekin\CashierFastspring\Listeners\SubscriptionActivated'
    ],
    'Bgultekin\CashierFastspring\Events\SubscriptionChargeCompleted' => [
        'Bgultekin\CashierFastspring\Listeners\SubscriptionChargeCompleted'
    ]
];

You should create a session for subscription payment page. You can do it with newSubscription method as below.

// we create session and return it to frontend to care
$builder = Auth::user()->newSubscription('default', $selectedPlan);
$session = $builder->create();

You can provide session id $session->id to Fastspring's Popup Storefronts or Web Storefronts.

Note: newSubscription method does not create a subscription model. After a successful payment, you can use webhooks or browser script to inform your app and create related models.

Usage

Cashier Fastspring comes with ready-to-use Subscription, Subscription Period, Invoice models and webhook handler. You can find detailed explanation below. Remember that you can easily replace these models and logic with yours.

Subscriptions

Cashier Fastspring provides a local type of subscription which lets you to create subscriptions without interacting with Fastspring. This may help you to create plans without payment info required. If a subscription has no fastspring_id, it is typed as local. You can check type using type(), isLocal(), isFastspring() methods.

Creating Subscriptions

To create a subscription, you can use newSubscription method of the Billable model. After creating session, you can provide session id $session->id to Fastspring's Popup Storefronts or Web Storefronts.

// we create session and return it to frontend to care
$builder = Auth::user()->newSubscription('default', $selectedPlan);
$session = $builder->create();

You can also provide coupon or quantity. As a hint, coupons also can be set on Fastspring's payment pages.

$builder = Auth::user()->newSubscription('default', $selectedPlan)
    ->withCoupon('free-ticket-to-Mars')
    ->quantity(1); // yeap no ticket for returning
$session = $builder->create();

If the Billable model is not created as Fastspring customer yet newSubscription model creates it automatically and saves fastspring_id. If you want to do this manually you can use createAsFastspringCustomer method.

$apiResponse = Auth::user()->createAsFastspringCustomer();

If details of a Billable model is updated, you can also update them at Fastspring side with updateAsFastspringCustomer method.

$apiResponse = Auth::user()->updateAsFastspringCustomer();

Checking Subscription Status

At Fastspring side, there are 5 states for subscriptions: active, overdue, canceled, deactivated, trial. The only state you should give up to serve your customer is deactivated state. Others are just informative states. Cashier Fastspring package keeps synchronized state of subscriptions with webhooks.

You can check if you should still serve to the Billable model by using subscribed method.

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

You can retrieve related subscription model by using subscription method and use methods of Subscription methods to check its status.

$subscription = $user->subscription('default');

// check if you should serve or not
$subscription->valid();

// check if its state is active
$subscription->active();

// check if its state is deactived
$subscription->deactivated();

// check if its state is overdue
$subscription->overdue();

// alias: onTrial(). check if its state is trial
$subscription->trial();

// alias: canceled(), onGracePeriod(). check if its state is canceled
$subscription->cancelled();

You can use the subscribedToPlan method to check if the user is subscribed to a given plan.

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

Changing Plans

You can change current plan of a Billable model by using swap method as below. Before using this, it is recommended to look at Prorating when Upgrading or Downgrading Subscription Plans.

$user = App\User::find(1);

$user->subscription('default')->swap('provider-plan-id', $prorate, $quantity, $coupons);

The swap method communicates with Fastspring and updates the subscription model according to response. If you plan to swap plan without prorating, plan doesn't change immediately. In that case, future plan and swap date are saved to swap_to and swap_at columns. End of the current subscription period, Fastspring sends you webhook request about subscription change. That's why if you think to use prorating, remember to set webhooks right.

Subscription Trials

You can handle trial days of your plans at Fastspring Dashboard.

Cancelling Subscriptions

To cancel a subscription, call the cancel method on the subscription model.

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

If you want to cancel a subscription immediately, you can use cancelNow method.

$user->subscription('default')->cancelNow();

Both methods update the subscription model according to response of Fastspring. The cancel method saves cancellation time to the swap_at column.

Resuming Subscriptions

To resume a subscription, you can use resume method on the subscription model. The user must be still on grace period. Otherwise, this method throws a LogicException.

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

This method updates the subscription model's state and set swap_to, swap_at columns null according to response.

Subscription Period

Cashier Fastspring package has also built-in subscription period model and related methods in order to help you to manage payment periods of subscription. This may help you to keep usage of particular resources of users between payment periods.

You can call activePeriodOrCreate method of Subscription model and retrieve current SubscriptionPeriod model which involves id, start_date, end_date information. If the current active period is not created yet, this method fetches it from Fastspring API and creates. If the subscription is a local subscription, it also creates a new period according to the last subscription period (if there is none, it assumes today is the start day of the subscription period).

$activePeriod = $user->subscription('default')->activePeriodOrCreate();

// if you don't want to create an active subscription period immediately when no exist
// you can use activePeriod method as below
// you can set a cron job for creation of new periods 
// or do it in your way
$activePeriod = $user->subscription('default')->activePeriod();

Updating Credit Cards

Fastspring does not provide any API to update credit card or any other payment information directly. You should redirect your customers to the their account management panel at Fastspring side. You can generate account management panel URL by using accountManagementURI method of the Billable model.

$redirectURI = $user->accountManagementURI();

Webhooks

Cashier Fastspring package provides an easy way to handle webhooks. It fires related events for each webhook request and provides request payload data as a parameter. It also handles message security if you set FASTSPRING_HMAC_SECRET. You can find sample listeners in src/Listeners folder.

Beside webhook specific events, there are also category and any events. For instance, if you want to listen all webhook requests, you can register your listener to Bgultekin\CashierFastspring\Events\Any event. Also, if you want to listen all subscription related webhook requests, you can use Bgultekin\CashierFastspring\Events\SubscriptionAny event.

You can see relation between package events and webhook requests at the table below.

Webhook Request Fired Cashier Fastspring Events
account.created Bgultekin\CashierFastspring\Events\AccountCreated, Bgultekin\CashierFastspring\Events\AccountAny, Bgultekin\CashierFastspring\Events\Any
fulfillment.failed Bgultekin\CashierFastspring\Events\FulfillmentFailed, Bgultekin\CashierFastspring\Events\FulfillmentAny, Bgultekin\CashierFastspring\Events\Any
mailingListEntry.removed Bgultekin\CashierFastspring\Events\MailingListEntryRemoved, Bgultekin\CashierFastspring\Events\MailingListEntryAny, Bgultekin\CashierFastspring\Events\Any
mailingListEntry.updated Bgultekin\CashierFastspring\Events\MailingListEntryUpdated, Bgultekin\CashierFastspring\Events\MailingListEntryAny, Bgultekin\CashierFastspring\Events\Any
order.approval.pending Bgultekin\CashierFastspring\Events\OrderApprovalPending, Bgultekin\CashierFastspring\Events\OrderAny, Bgultekin\CashierFastspring\Events\Any
order.canceled Bgultekin\CashierFastspring\Events\OrderCanceled, Bgultekin\CashierFastspring\Events\OrderAny, Bgultekin\CashierFastspring\Events\Any
order.payment.pending Bgultekin\CashierFastspring\Events\OrderPaymentPending, Bgultekin\CashierFastspring\Events\OrderAny, Bgultekin\CashierFastspring\Events\Any
order.completed Bgultekin\CashierFastspring\Events\OrderCompleted, Bgultekin\CashierFastspring\Events\OrderAny, Bgultekin\CashierFastspring\Events\Any
order.failed Bgultekin\CashierFastspring\Events\OrderFailed, Bgultekin\CashierFastspring\Events\OrderAny, Bgultekin\CashierFastspring\Events\Any
payoutEntry.created Bgultekin\CashierFastspring\Events\PayoutEntryCreated, Bgultekin\CashierFastspring\Events\PayoutEntryAny, Bgultekin\CashierFastspring\Events\Any
return.created Bgultekin\CashierFastspring\Events\ReturnCreated, Bgultekin\CashierFastspring\Events\ReturnAny, Bgultekin\CashierFastspring\Events\Any
subscription.activated Bgultekin\CashierFastspring\Events\SubscriptionActivated, Bgultekin\CashierFastspring\Events\SubscriptionAny, Bgultekin\CashierFastspring\Events\Any
subscription.canceled Bgultekin\CashierFastspring\Events\SubscriptionCanceled, Bgultekin\CashierFastspring\Events\SubscriptionAny, Bgultekin\CashierFastspring\Events\Any
subscription.charge.completed Bgultekin\CashierFastspring\Events\SubscriptionChargeCompleted, Bgultekin\CashierFastspring\Events\SubscriptionAny, Bgultekin\CashierFastspring\Events\Any
subscription.charge.failed Bgultekin\CashierFastspring\Events\SubscriptionChargeFailed, Bgultekin\CashierFastspring\Events\SubscriptionAny, Bgultekin\CashierFastspring\Events\Any
subscription.deactivated Bgultekin\CashierFastspring\Events\SubscriptionDeactivated, Bgultekin\CashierFastspring\Events\SubscriptionAny, Bgultekin\CashierFastspring\Events\Any
subscription.payment.overdue Bgultekin\CashierFastspring\Events\SubscriptionPaymentOverdue, Bgultekin\CashierFastspring\Events\SubscriptionAny, Bgultekin\CashierFastspring\Events\Any
subscription.payment.reminder Bgultekin\CashierFastspring\Events\SubscriptionPaymentReminder, Bgultekin\CashierFastspring\Events\SubscriptionAny, Bgultekin\CashierFastspring\Events\Any
subscription.trial.reminder Bgultekin\CashierFastspring\Events\SubscriptionTrialReminder, Bgultekin\CashierFastspring\Events\SubscriptionAny, Bgultekin\CashierFastspring\Events\Any
subscription.updated Bgultekin\CashierFastspring\Events\SubscriptionUpdated, Bgultekin\CashierFastspring\Events\SubscriptionAny, Bgultekin\CashierFastspring\Events\Any

To listen an event, you can register listeners in app/providers/EventServiceProvider.php.

protected $listen = [
    // some others
    'Bgultekin\CashierFastspring\Events\SubscriptionCanceled' => [
        'Your\Lovely\Listener'
    ]
];

Single Charges

Not implemented yet. If you need it you can contribute to the package. Please check Contributing.

Invoices

In Fastspring, invoices are generated by Fastspring. You don't need to generate official or unofficial invoices. If you are using default webhook listeners, your invoices will be sync to your database. You can get invoices URL with the Invoice model or over the Billable trait.

Contributing

Thank you for considering contributing to the Cashier Fastspring. You can read the contribution guide lines here. You can also check issues to improve this package.

Credits

Cashier Fastspring package is developed by Bilal Gultekin over Taylor Otwell's Cashier package. You can see all contributors here.

License

Cashier Fastspring is open-sourced software licensed under the MIT license.

bgultekin/cashier-fastspring 适用场景与选型建议

bgultekin/cashier-fastspring 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 216 次下载、GitHub Stars 达 19, 最近一次更新时间为 2018 年 07 月 20 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「laravel」 「billing」 「cashier」 「fastspring」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 bgultekin/cashier-fastspring 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 bgultekin/cashier-fastspring 我们能提供哪些服务?
定制开发 / 二次开发

基于 bgultekin/cashier-fastspring 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 216
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 19
  • 点击次数: 19
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 19
  • Watchers: 4
  • Forks: 24
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2018-07-20