# Plan Subscription Schedule
Want to change a subscription but not right now? Schedule it at the end of the period? With this extension you can schedule your subscription plan changes.
# What it does
- Plan Subscription is scheduled to change to another plan at a certain date in the future.
- In this schedule you specify date and which service will be executed before the change.
- You can also set a timeout and tries for the job.
- A job is added in your app schedule
- When the time comes, job batches all pending schedules and dispatches it.
- Job will execute your defined service before plan change, if it succeeds, change will be done. If it fails, schedule will be flagged as failed.
# Usage
# Create schedule
You can schedule a change in your user subscription like this:
$date = Carbon::now()->add(15, 'day');
$user->subscription('main')->toPlan($this->testPlanPro)->onDate($date)->setSchedule();
You can set other options like:
service()
: References service name in config file.timeout()
: Timeout for the job that will launch the service.tries()
: Number of tries job will be attempted
$date = Carbon::now()->add(15, 'day');
$user->subscription('main')->toPlan($this->testPlanPro)->onDate($date)->service('default')->tries(2)->timeout(200)->setSchedule();
# Schedules per subscription
You can set a limit of schedules per subscription in your config.
You can check if subscription has reached its limit on your subscription object
with $subscription->reachedScheduleLimit()
.
You can also dynamically ignore the schedule limit with ignoreLimit(true|false)
(defaults to true
):
$user->subscription('main')->toPlan($this->testPlanPro)->onDate($date)->ignoreLimit()->setSchedule();
# Scopes
These are the scopes you can apply to your PlanSubscriptionSchedule
model.
notProcessed()
returns all unprocessed schedules (not having success or failure) in the past and in the future.
# Pending
pending()
returns a list of schedules that have not been processed and are due to be processed. To define an ending
date, use Carbon
date as parameter to show pending until specified date. Default returns pending until now.
# Services
By default, the config file includes a default
service for processing your plan change. This service it's a good
starting point to see how it works. The default service is an empty service that will not perform any action or stop the
plan change.
# How to make a service?
In the example DefaultScheduleService
you can see the minimum requirements of a service.
Your own service has to implement interface PlanSubscriptionScheduleService
and also use IsScheduleService
trait. __construct
accepts one parameter, the PlanSubscriptionSchedule
Eloquent object of the subscription schedule.
The outcome to later change plan or not is defined by success
property. By default is false
, so your successful
process has to set it to true
. Any exception will stop the process.
<?php
namespace Bpuig\SubbySchedule\Services;
use Bpuig\SubbySchedule\Contracts\PlanSubscriptionScheduleService;
use Bpuig\SubbySchedule\Traits\IsScheduleService;
class DefaultScheduleService implements PlanSubscriptionScheduleService
{
use IsScheduleService;
/**
* DefaultScheduleService constructor.
* Save current Plan Subscription Schedule
* @param $planSubscriptionSchedule
*/
public function __construct($planSubscriptionSchedule)
{
$this->planSubscriptionSchedule = $planSubscriptionSchedule;
}
/**
* Execute the strategy
*
* Since this is kind of a dummy process, set success to true
*/
public function execute()
{
$this->success = true;
$this->clearUsage = true;
}
}
# Jobs
To process the schedules you need to include the SubscriptionScheduleQueuerJob
in your app schedule.
I recommend setting it without overlapping, since package allows to schedule multiple plan changes for the same
subscription. In app/Console/Kernel.php
:
protected function schedule(Schedule $schedule)
{
...
$schedule->job(new SubscriptionScheduleQueuerJob)->everyFiveMinutes()->withoutOverlapping();
}
This job will make a batch of jobs for pending subscription changes.
I recommend running first this job with a date parameter and then chain your regular subscription renewal job with said
date parameter as end to avoid collision since a subscription can have same ends_at
and scheduled_at
dates. This
order of events would prevent renewals before schedules, since after schedule is processed ends_at
would have changed
to next period.
← Models