laravel-plans

Compute Tokens

Given a SaaS that has a monthly plan with free compute tokens every months. When a user has reached his limit, he is able to buy a one-time package of additional tokens. This additional tokens are available additional to the monthly limit. But always when there are monthly tokens, this will be used first. The additional tokens are only consumed, if the monthly limit is reached. The additional tokens are usable for one year after buying.

    $monthlyPlan = Plan::create([
        'slug' => 'monthly',
        'name' => [
            'en' => 'Monthly Plan',
        ],
        'billing_period' => 1,
        'billing_interval' => Interval::MONTH,
    ]);

    $additionalTokens = Plan::create([
        'slug' => 'additional_tokens',
        'name' => [
            'en' => 'Additional Tokens',
        ],
        'billing_period' => 1,
        'billing_interval' => Interval::YEAR,
    ]);
    $tokens = Feature::create([
        'slug' => 'tokens',
        'name' => [
            'en' => 'Tokens',
        ],
    ])

    $monthlyPlan->features()->attach($tokens, [
        'value' => 1000,
        'resettable_period' => 1,
        'resettable_interval' => Interval::MONTH,
    ]);

    $additionalTokens->features()->attach($tokens, [
        'value' => 10000,
    ]);

Now we have two plans, one for monthly tokens and one for additional tokens.

    $user->subscribe($monthlyPlan);
    
    $user->consumeFeature('tokens', $amountOfTokensToConsume);

From now on, the user will be able to consume 1000 tokens per month, and will get refilled the 1000 tokens every renewal. Unused tokens will not be aggregated. If you wish to also keep unused tokens, you have to care about that in your renewal solution. You cannot use the existing artisan command in that case - but you could extend it.

When the 1000 tokens are used and he needs more, he can subscribe to the additional plan. Keep in mind that all subscriptions are renewed automatically. So if you want to simulate a one time buy, just subscribe and cancel immediately after.

    $subscription = $user->subscribe($additionalTokens, uniqid());
    $subscription->cancel();
    
    // Continue consuming
    $user->consumeFeature('tokens', $amountOfTokensToConsume);

The second parameter of subscribe is needed to not overwrite the base-subscription with a new plan. Since onetime buys never shall be overwritten, you can simply use uniqid().

The immediate cancellation will ensure, that the additional plan is not renewed. Since the ordering of the plans happens automatically (second subscription is second in the list), it is ensured, that always the monthly tokens will be used first, when available.

If you have an additional buy first, and then a monthly buy, you have to ensure that your monthly plan is first in order.

    $user->subscribe($monthlyPlan, order: 1);
    
    // or
    $subscription = $user->subscribe($monthlyPlan);
    $subscription->moveToStart();

If you want the user to be able to consume the additional tokens forever, just simulate it by using a high billing period:

    $additionalTokens = Plan::create([
        'slug' => 'additional_tokens',
        'name' => [
            'en' => 'Additional Tokens',
        ],
        'billing_period' => 9999,
        'billing_interval' => Interval::YEAR,
    ]);

If somebody complains about unusable tokens after this time, just ignore it :-)