info('Renewal reminder notifications are disabled.'); return self::SUCCESS; } $days = (int) $this->option('days'); $dryRun = $this->option('dry-run'); if ($dryRun) { $this->warn('DRY RUN MODE - No emails will be sent'); } $this->info("Finding subscriptions renewing in {$days} days..."); // Find subscriptions renewing soon that haven't been reminded $subscriptions = Subscription::query() ->active() ->whereNull('cancelled_at') ->where('current_period_end', '>', now()) ->where('current_period_end', '<=', now()->addDays($days)) ->whereDoesntHave('metadata', function ($query) use ($days) { // Skip if already reminded for this period $query->where('last_renewal_reminder', '>=', now()->subDays($days)); }) ->with(['workspace', 'workspacePackage.package']) ->get(); if ($subscriptions->isEmpty()) { $this->info('No subscriptions require reminders.'); return self::SUCCESS; } $this->info("Found {$subscriptions->count()} subscriptions to remind."); $sent = 0; foreach ($subscriptions as $subscription) { $owner = $subscription->workspace?->owner(); if (! $owner) { $this->warn(" Skipping subscription {$subscription->id} - no workspace owner"); continue; } $package = $subscription->workspacePackage?->package; $billingCycle = $this->guessBillingCycle($subscription); $amount = $package?->getPrice($billingCycle) ?? 0; $this->line(" Sending reminder to {$owner->email} for subscription {$subscription->id}..."); if ($dryRun) { $sent++; continue; } try { $owner->notify(new UpcomingRenewal( $subscription, $amount, config('commerce.currency', 'GBP') )); // Record that we sent the reminder $subscription->update([ 'metadata' => array_merge($subscription->metadata ?? [], [ 'last_renewal_reminder' => now()->toISOString(), ]), ]); $sent++; $this->info(' ✓ Sent'); } catch (\Exception $e) { $this->error(" ✗ Failed: {$e->getMessage()}"); Log::error('Renewal reminder failed', [ 'subscription_id' => $subscription->id, 'error' => $e->getMessage(), ]); } } $this->newLine(); $this->info("Sent {$sent} renewal reminders."); return self::SUCCESS; } protected function guessBillingCycle(Subscription $subscription): string { $periodDays = $subscription->current_period_start ?->diffInDays($subscription->current_period_end); return ($periodDays ?? 30) > 32 ? 'yearly' : 'monthly'; } }