'date', 'data_fine' => 'date', 'data_limite_bilancio' => 'date', 'data_approvazione' => 'date', 'chiusa_contabilita' => 'boolean', 'approvato_assemblea' => 'boolean', 'anno' => 'integer', 'ordine_sequenza' => 'integer', ]; protected $dates = [ 'data_inizio', 'data_fine', 'data_limite_bilancio', 'data_approvazione', 'deleted_at', ]; // === RELATIONSHIPS === /** * Stabile di appartenenza */ public function stabile(): BelongsTo { return $this->belongsTo(Stabile::class); } /** * Esercizio precedente */ public function esercizio_precedente(): BelongsTo { return $this->belongsTo(EsercizioContabile::class, 'esercizio_precedente_id'); } /** * Esercizio successivo */ public function esercizio_successivo() { return $this->hasOne(EsercizioContabile::class, 'esercizio_precedente_id'); } /** * Assemblea di approvazione */ public function assemblea(): BelongsTo { return $this->belongsTo(Assemblea::class); } /** * Movimenti contabili dell'esercizio */ public function movimenti(): HasMany { return $this->hasMany(MovimentoContabile::class, 'esercizio_id'); } /** * Bilanci dell'esercizio */ public function bilanci(): HasMany { return $this->hasMany(Bilancio::class, 'esercizio_id'); } // === ACCESSORS === /** * Nome completo dell'esercizio */ public function getNomeCompletoAttribute(): string { $tipologia = ucfirst($this->tipologia); $nome = "{$tipologia} {$this->anno}"; if ($this->tipologia === 'straordinaria' && $this->descrizione_straordinaria) { $nome .= " - " . $this->descrizione_straordinaria; } return $nome; } /** * Verifica se l'esercizio è aperto */ public function getIsApertoAttribute(): bool { return $this->stato === 'aperto'; } /** * Verifica se l'esercizio è chiuso */ public function getIsChiusoAttribute(): bool { return $this->stato === 'chiuso'; } /** * Verifica se l'esercizio è consolidato */ public function getIsConsolidatoAttribute(): bool { return $this->stato === 'consolidato'; } /** * Colore badge per la tipologia */ public function getColoreBadgeAttribute(): string { return match($this->tipologia) { 'ordinaria' => 'primary', 'riscaldamento' => 'warning', 'straordinaria' => 'danger', default => 'secondary' }; } /** * Icona per la tipologia */ public function getIconaAttribute(): string { return match($this->tipologia) { 'ordinaria' => 'fas fa-calendar-alt', 'riscaldamento' => 'fas fa-fire', 'straordinaria' => 'fas fa-exclamation-triangle', default => 'fas fa-book' }; } // === SCOPES === /** * Scope per filtrare per tipologia */ public function scopeByTipologia($query, string $tipologia) { return $query->where('tipologia', $tipologia); } /** * Scope per esercizi aperti */ public function scopeAperti($query) { return $query->where('stato', 'aperto'); } /** * Scope per esercizi chiusi */ public function scopeChiusi($query) { return $query->where('stato', 'chiuso'); } /** * Scope per esercizi di uno stabile */ public function scopeByStabile($query, int $stabileId) { return $query->where('stabile_id', $stabileId); } /** * Scope per esercizi per anno */ public function scopeByAnno($query, int $anno) { return $query->where('anno', $anno); } /** * Scope per ordinamento sequenziale */ public function scopeOrdinatiSequenzialmente($query) { return $query->orderBy('tipologia', 'asc') ->orderBy('ordine_sequenza', 'asc') ->orderBy('anno', 'asc'); } // === METHODS === /** * Verifica se l'esercizio può essere modificato */ public function puoEssereModificato(): bool { return $this->stato === 'aperto' && !$this->chiusa_contabilita; } /** * Verifica se l'esercizio può essere chiuso */ public function puoEssereChiuso(): bool { return $this->stato === 'aperto' && !$this->chiusa_contabilita; } /** * Chiude l'esercizio */ public function chiudi(): bool { if (!$this->puoEssereChiuso()) { return false; } $this->stato = 'chiuso'; $this->chiusa_contabilita = true; return $this->save(); } /** * Consolida l'esercizio */ public function consolida(): bool { if ($this->stato !== 'chiuso') { return false; } $this->stato = 'consolidato'; return $this->save(); } /** * Ottieni il prossimo numero di sequenza per una tipologia */ public static function getNextSequenza(int $stabileId, string $tipologia): int { return static::where('stabile_id', $stabileId) ->where('tipologia', $tipologia) ->max('ordine_sequenza') + 1; } /** * Crea esercizio successivo */ public function creaEsercizioSuccessivo(array $attributes = []): ?EsercizioContabile { $defaults = [ 'stabile_id' => $this->stabile_id, 'tipologia' => $this->tipologia, 'anno' => $this->anno + 1, 'ordine_sequenza' => $this->ordine_sequenza + 1, 'esercizio_precedente_id' => $this->id, ]; return static::create(array_merge($defaults, $attributes)); } }