Hi, that a difficult problem. Have you ever building or fix that? You can either add a log as everyone would do. When you add a log you can easily track users as well as every user can also track himself. Just create a table in your database with 3-4 columns which will contain user_id(relationship with users table), what action did the user performed, when did he performed that action (date of spending a.k.a created_at) and then create helper function so you can easily add logs in your database within your code. For example: addLog( Auth::user()->id , 'Bought 15 domains' , Carbon::now() ); Hope that it useful with you, thanks and have a good day!
Handling users downgrading their subscription in Laravel Cashier
Hi everyone!
Hope you're well.
I'm hoping someone can share some insights into the best approach for a SaaS web application I'm building that uses Laravel Cashier (Stripe).
My web application is a system that has a free plan and several different paid plans offering additional features on each.
In my application, a user has the ability to add 50 domains to the free plan, they then have to upgrade to the first pro plan that offers 75, and if they want 100 domains, they upgrade to this account.
I have a users table and a domains table.
Let's say that I have 50 domains on my free account, I then decide to upgrade my account to the 100 domains (this is the second in the pro plans) plan and add 30 more domains to my account. My total is now 80 out of 100.
If I were to then downgrade my plan to the 75 plan, my account now contains 5 more than this plan allows and without any additional logic the user would be able to see these, so I'd like to disable them so that they can't be used until the user re-subscribes, they could only delete them.
My thinking is that I can simply figure out how many domains the user has got above the limit of a plan and then loop over them and then update a column called disabled_at with a date/time, but realised that this gets quite complicated because if the user added an odd number or was changing their plan often the calculations would need to be quite robust.
The logic of disabling domains for a user would run via a Job that's dispatched based on an event listener for Stripe when a subscription is updated/cancelled.
Maybe I'm overthinking this and there's a simpler way of doing it?
Here's my WIP code and I'm stuck at this point...
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\User;
use App\Models\Domain;
class ToggleSubscriptionFeatures implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* The domain instance.
*/
protected $customer_id = null;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($customer_id)
{
$this->customer_id = $customer_id;
}
/**
* Get plan limits
*/
protected function getPlanLimits($user)
{
$limits = [
'plan' => 'free',
'domains' => 50
];
try {
switch ($user->plan->slug) {
case 'monthly-75':
case 'yearly-75':
if ($user->subscribedToPrice($user->plan->stripe_id, 'default')) {
$limits['plan'] = 'pro';
$limits['domains'] = 75;
} else {
throw new \Exception("Not subscribed to this plan.");
}
break;
case 'monthly-100':
case 'yearly-100':
if ($user->subscribedToPrice($user->plan->stripe_id, 'default')) {
$limits['plan'] = 'pro';
$limits['domains'] = 100;
} else {
throw new \Exception("Not subscribed to this plan.");
}
break;
}
} catch (\Exception $e) { }
return $limits;
}
/**
* Get the user
*/
protected function getUser()
{
$user = User::where('stripe_id', $this->customer_id)->first();
return $user;
}
/**
* Get domains count for user
*/
protected function getDomainsCount($user_id)
{
return Domain::where('user_id', $user_id)->count();
}
/**
* Get domains for user
*/
protected function getDomains($user_id, $take)
{
return Domain::where('user_id', $user_id)
->orderBy('created_at', 'desc')
->take($take)
->get();
}
/**
* Calculate the number of records that we should disable
*/
protected function calculateAmountToDisable($records, $limit)
{
if ($records <= $limit) {
return 0;
}
// TODO: perform calculations here somehow??
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$user = $this->getUser();
// if user can't be found, do nothing
if (!$user) {
return;
}
// get limits
$limits = $this->getPlanLimits($user);
// disable domains
$domainsCount = $this->getDomainsCount($user->id);
// TODO: calculate here?
// $noOfDomainsToDisable = $this->calculateAmountToDisable($domainsCount, $limits['domains']);
// $domains = $this->getDomains($user->id, $noOfDomainsToDisable);
Log::debug("limits", [
'limits' => $limits,
'domainsCount' => $domainsCount,
'domainsLimit' => $limits['domains']
]);
}
}
Please or to participate in this conversation.