*/ use HasFactory; protected $fillable = [ 'name', 'stripe_price_id_monthly', 'stripe_price_id_annual', 'max_fuel_types', 'email_enabled', 'email_frequency', 'push_enabled', 'push_frequency', 'whatsapp_enabled', 'whatsapp_daily_limit', 'whatsapp_scheduled_updates', 'sms_enabled', 'sms_daily_limit', 'ai_predictions', 'price_threshold', 'score_alerts', 'active', ]; /** * Resolve the active plan for a user. * Falls back to the free plan when no active Cashier subscription exists. */ public static function resolveForUser(User $user): self { $cache = Cache::supportsTags() ? Cache::tags(['plans']) : Cache::store(); $planId = $cache->remember( "plan_for_user_{$user->id}", 3600, function () use ($user): ?int { $priceId = null; if (method_exists($user, 'subscriptions')) { $subscription = $user->subscriptions()->active()->first(); $priceId = $subscription?->stripe_price ?? null; } if ($priceId) { $plan = static::where(fn ($q) => $q ->where('stripe_price_id_monthly', $priceId) ->orWhere('stripe_price_id_annual', $priceId)) ->where('active', true) ->first(); if ($plan) { return $plan->id; } } return static::where('name', PlanTier::Free->value)->value('id'); } ); return static::findOrFail($planId); } /** * Resolve the active subscription cadence for a user. * Returns 'monthly' | 'annual', or null if the user has no paid subscription. */ public static function resolveCadenceForUser(User $user): ?string { if (! method_exists($user, 'subscriptions')) { return null; } $priceId = $user->subscriptions()->active()->value('stripe_price'); if ($priceId === null) { return null; } $plan = static::where('stripe_price_id_monthly', $priceId) ->orWhere('stripe_price_id_annual', $priceId) ->first(); if ($plan === null) { return null; } if ($plan->stripe_price_id_monthly === $priceId) { return 'monthly'; } if ($plan->stripe_price_id_annual === $priceId) { return 'annual'; } return null; } protected static function booted(): void { static::saved(function (): void { if (Cache::supportsTags()) { Cache::tags(['plans'])->flush(); } }); } protected function casts(): array { return [ 'max_fuel_types' => 'integer', 'email_enabled' => 'boolean', 'push_enabled' => 'boolean', 'whatsapp_enabled' => 'boolean', 'whatsapp_daily_limit' => 'integer', 'whatsapp_scheduled_updates' => 'integer', 'sms_enabled' => 'boolean', 'sms_daily_limit' => 'integer', 'ai_predictions' => 'boolean', 'price_threshold' => 'boolean', 'score_alerts' => 'boolean', 'active' => 'boolean', ]; } /** User-facing display label for this plan (e.g. basic → "Daily"). */ public function displayName(): string { $tier = PlanTier::tryFrom((string) $this->name) ?? PlanTier::Free; return $tier->label(); } }