'decimal:2', 'trial_limit_value' => 'decimal:2', 'is_enabled' => 'boolean', 'applies_during_trial' => 'boolean', 'metadata' => 'array', ]; /** * Limit types */ const LIMIT_MONTHLY = 'monthly'; const LIMIT_DAILY = 'daily'; const LIMIT_TOTAL = 'total'; /** * Get the plan that owns this feature limit */ public function plan(): BelongsTo { return $this->belongsTo(Plan::class); } /** * Get the feature that this limit applies to */ public function planFeature(): BelongsTo { return $this->belongsTo(PlanFeature::class); } /** * Scope: Enabled limits */ public function scopeEnabled($query) { return $query->where('is_enabled', true); } /** * Scope: By limit type */ public function scopeByType($query, string $type) { return $query->where('limit_type', $type); } /** * Check if feature is enabled for this plan */ public function isEnabled(): bool { return $this->is_enabled; } /** * Get the effective limit value (considering trial status) */ public function getEffectiveLimit(bool $isOnTrial = false): ?float { if ($isOnTrial && $this->applies_during_trial && $this->trial_limit_value !== null) { return (float) $this->trial_limit_value; } return $this->limit_value ? (float) $this->limit_value : null; } /** * Check if user can use this feature within limits */ public function canUseFeature(float $currentUsage = 0, bool $isOnTrial = false): bool { if (! $this->isEnabled()) { return false; } $limit = $this->getEffectiveLimit($isOnTrial); // If limit is null, feature is unlimited if ($limit === null) { return true; } return $currentUsage < $limit; } /** * Get remaining usage allowance */ public function getRemainingUsage(float $currentUsage = 0, bool $isOnTrial = false): float { $limit = $this->getEffectiveLimit($isOnTrial); if ($limit === null) { return INF; } return max(0, $limit - $currentUsage); } /** * Get percentage of limit used */ public function getUsagePercentage(float $currentUsage = 0, bool $isOnTrial = false): float { $limit = $this->getEffectiveLimit($isOnTrial); if ($limit === null || $limit == 0) { return 0; } return min(100, ($currentUsage / $limit) * 100); } }