'date', 'returned_at' => 'date', 'counted_in_campaign' => 'boolean', ]; } // ─── Relationships ───────────────────────────────────────── public function territorio() { return $this->belongsTo(Territorio::class, 'territorio_id')->withTrashed(); } public function proclamatore() { return $this->belongsTo(Proclamatore::class, 'proclamatore_id')->withTrashed(); } public function annoTeocratico() { return $this->belongsTo(AnnoTeocratico::class, 'anno_teocratico_id'); } public function campagna() { return $this->belongsTo(Campagna::class, 'campaign_id'); } public function creatoDa() { return $this->belongsTo(User::class, 'created_by'); } public function rientratoDa() { return $this->belongsTo(User::class, 'returned_by'); } // ─── Computed ─────────────────────────────────────────────── /** * Number of days between assignment and return (or today if still open). */ public function getGiorniAttribute(): int { $end = $this->returned_at ?? now(); return Carbon::parse($this->assigned_at)->diffInDays($end); } public function getIsApertaAttribute(): bool { return is_null($this->returned_at); } // ─── Scopes ───────────────────────────────────────────────── public function scopeAperte($query) { return $query->whereNull('returned_at'); } public function scopeChiuse($query) { return $query->whereNotNull('returned_at'); } public function scopePerAnnoTeocratico($query, $annoId) { return $query->where('anno_teocratico_id', $annoId); } // ─── Business Logic ───────────────────────────────────────── /** * Check if a campaign prompt should be shown when returning this assignment. * Returns the matching campaign or null. */ public function campagnaApplicabile(?\Carbon\Carbon $returnDate = null): ?Campagna { $returnDate = $returnDate ?? now(); return Campagna::where('start_date', '<=', $returnDate) ->where('end_date', '>=', $this->assigned_at) ->first(); } }