jojostx/larasubs

Flexible plans and subscription management system for Laravel, with the required tools to run your SAAS like services efficiently

v0.1.5 2023-01-12 05:51 UTC

This package is auto-updated.

Last update: 2024-05-04 14:05:58 UTC


README

Banner

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

About

This package provides a straightforward interface to handle subscriptions and features consumption.

Considerations

  • Payments are out of scope for this package.
  • You may want to extend some of the core models, in case you need to override the logic behind some helper methods like renew(), cancel() etc. E.g.: when cancelling a subscription you may want to also cancel the recurring payment attached.

Installation

You can install the package via composer:

composer require jojostx/larasubs

Publish resources (config and migrations files):

php artisan vendor:publish --provider="Jojostx\Larasubs\LarasubsServiceProvider" --tag=larasubs-config

php artisan vendor:publish --provider="Jojostx\Larasubs\LarasubsServiceProvider" --tag=larasubs-migrations

Usage

To start using it, you just have to add the Jojostx\Larasubs\Models\Concerns\HasSubscriptions trait to your User model (or any model you want to have subscriptions):

<?php
namespace App\Models;

use Jojostx\Larasubs\Models\Concerns\HasSubscriptions;

class User
{
    use HasSubscriptions;
}

And that's it!

Setting Plans Up

First things first, you have to define the plans you'll offer. In the example below, we are creating two plans.

<?php
namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Jojostx\Larasubs\Enums\IntervalType;
use Jojostx\Larasubs\Models\Models\Plan;

class PlanSeeder extends Seeder
{
    public function run()
    {
        $silver = Plan::create([
            'name'                    => 'silver',
            'description'             => 'Plan for medium businesses',
            'active'                  => true,
            'price'                   => 100000, // price in the lowest currency value (kobo)
            'currency'                => 'NGN',
            'interval'                => 6,
            'interval_type'           => IntervalType::YEAR,
            'trial_interval'          => 1,
            'trial_interval_type'     => IntervalType::MONTH,
            'grace_interval'          => 1,
            'grace_interval_type'     => IntervalType::MONTH,
            'sort_order' => 1,
        ]);

        $gold = Plan::create([
            'name'                    => 'gold',
            'description'             => 'Plan for large businesses',
            'active'                  => true,
            'price'                   => 10000000, // price in the lowest currency value (kobo)
            'currency'                => 'NGN',
            'interval'                => 6,
            'interval_type'           => IntervalType::YEAR,
            'trial_interval'          => 1,
            'trial_interval_type'     => IntervalType::MONTH,
            'grace_interval'          => 1,
            'grace_interval_type'     => IntervalType::MONTH
        ]);
    }
}

Everything here is quite simple, but it is worth to emphasize: by receiving the interval options above, the two plans are defined as yearly with a 1 month trial period and grace period.

Trial Period

You can define a trial period for each plan, so your users will can access a plan on trial before the subscription starts:

Grace Period

You can define a grace period for each plan, so your users will not loose access to their features immediately when the subscription ends.

Setting Up Features

Next, you may define the features your plan will offer. In the example below, we are creating two features. In the example below, we are creating two features: one to handle how much minutes each user can spend with deploys and if they can use subdomains.

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Jojostx\Larasubs\Enums\IntervalType;
use Jojostx\Larasubs\Models\Models\Feature;

class FeatureSeeder extends Seeder
{
    public function run()
    {
        $deployMinutes = Feature::create([
            'name'             => 'deploy-minutes',
            'consumable'       => true,
            'interval'      => 1,
            'interval_type' => IntervalType::DAY,
        ]);

        $customDomain = Feature::create([
            'name'       => 'custom-domain',
            'description' => 'Ability to create and use subdomains',
            'consumable' => false,
            'active' => true,
            'interval'      => 1,
            'interval_type' => IntervalType::DAY,
        ]);
    }
}

Associating Plans with Features

As each feature can belong to multiple plans (and they can have multiple features), you have to associate them:

use Jojostx\Larasubs\Models\Feature;

// ...

$deployMinutes = Feature::where('name', 'deploy-minutes')->first();
$subdomains    = Feature::where('name', 'subdomains')->first();

$silver->features()->attach($deployMinutes, ['units' => 15]);

$gold->features()->attach($deployMinutes, ['units' => 25]);
$gold->features()->attach($subdomains);

It is necessary to pass a value to units when associating a consumable feature with a plan.

In the example above, we are giving 15 minutes of deploy time to silver users and 25 to gold users. We are also allowing gold users to use subdomains.

Subscribing

Now that you have a set of plans with their own features, it is time to subscribe users to them. Registering subscriptions is quite simple:

<?php

namespace App\Listeners;

use App\Events\PaymentApproved;

class SubscribeUser
{
    public function handle(PaymentApproved $event)
    {
        $subscriber = $event->user;
        $plan       = $event->plan;
        $subscriptionName  = $user->name . strval(time()); // should be unique

        $subscriber->subscribeTo(
            $plan,
            $subscriptionName
        );
    }
}

In the example above, we are simulating an application that subscribes its users when their payments are approved. It is easy to see that the method subscribeTo requires only two arguments:

  • the plan the user is subscribing to.
  • the unique name for the subscription.

There are other options you can pass to it to handle particular cases that we're gonna cover below.

By default, the subscribeTo method calculates the expiration considering the plan's 'Interval' options, so you don't have to worry about it.

Testing

composer test

Security Policy

If you discover any security related issues, please send an email instead of using the issue tracker.

Support

The following support channels are available at your fingertips:

License

This software is released under The MIT License (MIT).

(c) 2022 Jojostx, Some rights reserved.