'decimal:2', 'features' => 'array', 'limits' => 'array', 'is_active' => 'boolean', 'is_featured' => 'boolean', 'is_free' => 'boolean', 'trial_days' => 'integer', 'sort_order' => 'integer', ]; // ==================== RELATIONSHIPS ==================== public function subscriptions(): HasMany { return $this->hasMany(Subscription::class); } // ==================== SCOPES ==================== public function scopeActive($query) { return $query->where('is_active', true); } public function scopeOrdered($query) { return $query->orderBy('sort_order')->orderBy('price'); } public function scopeFree($query) { return $query->where('billing_period', 'free'); } public function scopePaid($query) { return $query->where('billing_period', '!=', 'free'); } // ==================== ACCESSORS ==================== public function getIsFreeAttribute(): bool { return $this->billing_period === 'free' || $this->price == 0; } public function getHasTrialAttribute(): bool { return $this->trial_days > 0; } public function getFormattedPriceAttribute(): string { if ($this->is_free) { return 'Gratis'; } $symbols = [ 'EUR' => '€', 'USD' => '$', 'BRL' => 'R$', ]; $symbol = $symbols[$this->currency] ?? $this->currency; $period = match ($this->billing_period) { 'monthly' => '/mes', 'annual' => '/año', 'lifetime' => ' (único)', default => '', }; return $symbol . number_format($this->price, 2, ',', '.') . $period; } public function getMonthlyPriceAttribute(): float { if ($this->billing_period === 'annual') { return round($this->price / 12, 2); } return $this->price; } public function getSavingsPercentAttribute(): ?int { if ($this->billing_period !== 'annual') { return null; } // Find monthly equivalent $monthlyPlan = static::where('billing_period', 'monthly') ->where('is_active', true) ->where('price', '>', 0) ->first(); if (!$monthlyPlan) { return null; } $annualEquivalent = $monthlyPlan->price * 12; $savings = (($annualEquivalent - $this->price) / $annualEquivalent) * 100; return (int) round($savings); } // ==================== METHODS ==================== public function hasFeature(string $feature): bool { return in_array($feature, $this->features ?? []); } public function getLimit(string $key, $default = null) { return $this->limits[$key] ?? $default; } /** * Get the default free plan */ public static function getFreePlan(): ?self { return static::where('slug', 'free')->first(); } /** * Get plans for pricing page */ public static function getForPricing(): \Illuminate\Database\Eloquent\Collection { return static::active()->ordered()->get(); } }