'decimal:2', 'cookie_days' => 'integer', 'max_uses' => 'integer', 'uses_count' => 'integer', 'valid_from' => 'datetime', 'valid_until' => 'datetime', 'is_active' => 'boolean', 'metadata' => 'array', ]; // Relationships public function user(): BelongsTo { return $this->belongsTo(User::class); } // Validation /** * Check if code is currently valid for use. */ public function isValid(): bool { if (! $this->is_active) { return false; } if ($this->valid_from && $this->valid_from->isFuture()) { return false; } if ($this->valid_until && $this->valid_until->isPast()) { return false; } if ($this->max_uses && $this->uses_count >= $this->max_uses) { return false; } return true; } /** * Check if code has reached max uses. */ public function hasReachedMaxUses(): bool { if ($this->max_uses === null) { return false; } return $this->uses_count >= $this->max_uses; } // Getters /** * Get effective commission rate (own or default). */ public function getEffectiveCommissionRate(): float { return $this->commission_rate ?? ReferralCommission::DEFAULT_COMMISSION_RATE; } /** * Get effective cookie duration in days. */ public function getEffectiveCookieDays(): int { return $this->cookie_days ?? self::DEFAULT_COOKIE_DAYS; } // Actions /** * Increment usage count. */ public function incrementUsage(): void { $this->increment('uses_count'); } /** * Activate code. */ public function activate(): void { $this->update(['is_active' => true]); } /** * Deactivate code. */ public function deactivate(): void { $this->update(['is_active' => false]); } // Scopes public function scopeActive($query) { return $query->where('is_active', true); } public function scopeValid($query) { return $query->active() ->where(function ($q) { $q->whereNull('valid_from') ->orWhere('valid_from', '<=', now()); }) ->where(function ($q) { $q->whereNull('valid_until') ->orWhere('valid_until', '>=', now()); }) ->where(function ($q) { $q->whereNull('max_uses') ->orWhereRaw('uses_count < max_uses'); }); } public function scopeByCode($query, string $code) { return $query->where('code', $code); } public function scopeForUser($query, int $userId) { return $query->where('user_id', $userId); } public function scopeByType($query, string $type) { return $query->where('type', $type); } public function scopeCampaign($query) { return $query->where('type', self::TYPE_CAMPAIGN); } public function getActivitylogOptions(): LogOptions { return LogOptions::defaults() ->logOnly(['code', 'is_active', 'commission_rate', 'max_uses']) ->logOnlyDirty() ->dontSubmitEmptyLogs() ->setDescriptionForEvent(fn (string $eventName) => "Referral code {$eventName}"); } }