136 lines
5.2 KiB
PHP
136 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\SubscribePlan;
|
|
use App\Models\User;
|
|
use App\Models\UserSubscriber;
|
|
use Illuminate\Console\Command;
|
|
|
|
class AddSubscriptionDays extends Command
|
|
{
|
|
protected $signature = 'subscriptions:add-days
|
|
{days=3 : Number of days to add}
|
|
{--all-users : Ensure every user gets days even if they have no subscription}
|
|
{--only-without-subscription : Process only users who do not have any subscription}
|
|
{--plan-id= : Subscribe plan id to use for users without a subscription}
|
|
{--include-expired : Also extend expired subscriptions}
|
|
{--chunk=1000 : Chunk size for processing}
|
|
{--dry-run : Show how many records would change without saving}';
|
|
|
|
protected $description = 'Add days to all user subscriptions';
|
|
|
|
public function handle(): int
|
|
{
|
|
$days = (int) $this->argument('days');
|
|
$chunkSize = max(1, (int) $this->option('chunk'));
|
|
$includeExpired = (bool) $this->option('include-expired');
|
|
$allUsers = (bool) $this->option('all-users');
|
|
$onlyWithoutSubscription = (bool) $this->option('only-without-subscription');
|
|
$dryRun = (bool) $this->option('dry-run');
|
|
|
|
if ($days <= 0) {
|
|
$this->error('Days must be a positive integer.');
|
|
return self::FAILURE;
|
|
}
|
|
|
|
if ($onlyWithoutSubscription && !$allUsers) {
|
|
$this->error('The --only-without-subscription option can only be used with --all-users.');
|
|
return self::FAILURE;
|
|
}
|
|
|
|
if ($allUsers) {
|
|
$planId = $this->option('plan-id');
|
|
if (!$planId) {
|
|
$this->error('When using --all-users you must provide --plan-id for users without a subscription.');
|
|
return self::FAILURE;
|
|
}
|
|
|
|
$plan = SubscribePlan::find($planId);
|
|
if (!$plan) {
|
|
$this->error('Subscribe plan not found for the given --plan-id.');
|
|
return self::FAILURE;
|
|
}
|
|
}
|
|
|
|
if ($allUsers) {
|
|
if ($onlyWithoutSubscription) {
|
|
$this->info("Granting {$days} day(s) only to users without a subscription." . ($dryRun ? ' (dry-run)' : ''));
|
|
} else {
|
|
$this->info("Granting {$days} day(s) to every user." . ($dryRun ? ' (dry-run)' : ''));
|
|
}
|
|
} else {
|
|
$scopeLabel = $includeExpired ? 'all' : 'active';
|
|
$this->info("Extending {$scopeLabel} subscriptions by {$days} day(s)." . ($dryRun ? ' (dry-run)' : ''));
|
|
}
|
|
|
|
$touched = 0;
|
|
if ($allUsers) {
|
|
$planId = (int) $this->option('plan-id');
|
|
$isFree = (bool) $plan->is_free;
|
|
|
|
User::query()->orderBy('id')->chunkById($chunkSize, function ($users) use (&$touched, $days, $dryRun, $planId, $isFree, $onlyWithoutSubscription) {
|
|
foreach ($users as $user) {
|
|
$latest = $user->userSubscribers()->orderByDesc('expired_at')->first();
|
|
|
|
if ($onlyWithoutSubscription && $latest) {
|
|
continue;
|
|
}
|
|
|
|
$touched++;
|
|
|
|
if ($dryRun) {
|
|
continue;
|
|
}
|
|
|
|
if ($latest) {
|
|
$baseDate = $latest->expired_at && $latest->expired_at->greaterThan(now())
|
|
? $latest->expired_at
|
|
: now();
|
|
$latest->expired_at = $baseDate->copy()->addDays($days);
|
|
$latest->save();
|
|
} else {
|
|
$user->userSubscribers()->create([
|
|
'subscribe_plan_id' => $planId,
|
|
'expired_at' => now()->addDays($days),
|
|
'is_free' => $isFree,
|
|
]);
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
$query = UserSubscriber::query();
|
|
if (!$includeExpired) {
|
|
$query->where('expired_at', '>', now());
|
|
}
|
|
|
|
$query->orderBy('id')->chunkById($chunkSize, function ($subscribers) use (&$touched, $days, $dryRun) {
|
|
foreach ($subscribers as $subscriber) {
|
|
$touched++;
|
|
if ($dryRun) {
|
|
continue;
|
|
}
|
|
|
|
if ($subscriber->expired_at === null) {
|
|
$subscriber->expired_at = now()->addDays($days);
|
|
} else {
|
|
$subscriber->expired_at = $subscriber->expired_at->copy()->addDays($days);
|
|
}
|
|
|
|
$subscriber->save();
|
|
}
|
|
});
|
|
}
|
|
|
|
if ($dryRun) {
|
|
$label = $allUsers ? 'user(s)' : 'subscription record(s)';
|
|
$this->info("{$touched} {$label} would be processed.");
|
|
} else {
|
|
$label = $allUsers ? 'user(s)' : 'subscription record(s)';
|
|
$this->info("{$touched} {$label} processed.");
|
|
}
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
}
|