'decimal:2', 'importo_pagato' => 'decimal:2', 'importo_residuo' => 'decimal:2', 'data_scadenza' => 'date', 'data_pagamento' => 'date', 'dettagli_pagamento' => 'array', 'numero_rata' => 'integer', // Compatibilità 'importo' => 'decimal:2' ]; protected $dates = [ 'data_scadenza', 'data_pagamento', 'created_at', 'updated_at', 'deleted_at' ]; /** * Boot method per generare automaticamente il codice rata */ protected static function boot() { parent::boot(); static::creating(function ($model) { if (empty($model->codice_rata)) { $model->codice_rata = self::generaCodiceRata(); } // Inizializza importo_residuo se non impostato if (is_null($model->importo_residuo)) { $model->importo_residuo = $model->importo_rata ?? $model->importo ?? 0; } }); } /** * Genera un codice univoco per la rata */ public static function generaCodiceRata() { do { $codice = 'RT' . strtoupper(Str::random(6)); } while (self::where('codice_rata', $codice)->exists()); return $codice; } /** * Relazione con PianoRateizzazione */ public function pianoRateizzazione() { return $this->belongsTo(PianoRateizzazione::class); } /** * Relazione con UnitaImmobiliare */ public function unitaImmobiliare() { return $this->belongsTo(UnitaImmobiliare::class); } /** * Relazione con AnagraficaCondominiale */ public function anagraficaCondominiale() { return $this->belongsTo(AnagraficaCondominiale::class); } /** * Relazione con User (registrato da) */ public function registratoDa() { return $this->belongsTo(User::class, 'registrato_da'); } // Relazioni di compatibilità con vecchia struttura /** * Relazione con Gestione (compatibilità) */ public function gestione() { return $this->belongsTo(Gestione::class, 'gestione_id', 'id_gestione'); } /** * Relazione con Soggetto (compatibilità) */ public function soggetto() { return $this->belongsTo(Soggetto::class, 'soggetto_id', 'id_soggetto'); } /** * Scope per stato */ public function scopeConStato($query, $stato) { return $query->where('stato', $stato); } /** * Scope per rate scadute */ public function scopeScadute($query) { return $query->where('data_scadenza', '<', now()->toDateString()) ->whereIn('stato', ['emessa']); } /** * Scope per rate in scadenza */ public function scopeInScadenza($query, $giorni = 30) { return $query->whereBetween('data_scadenza', [now()->toDateString(), now()->addDays($giorni)->toDateString()]) ->whereIn('stato', ['emessa']); } /** * Scope per rate pagate */ public function scopePagate($query) { return $query->where('stato', 'pagata'); } /** * Scope per rate emesse */ public function scopeEmesse($query) { return $query->where('stato', 'emessa'); } /** * Scope per piano rateizzazione */ public function scopePerPiano($query, $pianoId) { return $query->where('piano_rateizzazione_id', $pianoId); } /** * Scope per unità immobiliare */ public function scopePerUnita($query, $unitaId) { return $query->where('unita_immobiliare_id', $unitaId); } /** * Metodo per registrare pagamento completo */ public function registraPagamento($importo, $metodo = null, $riferimento = null, $note = null, $userId = null) { $importoPagamento = min($importo, $this->importo_residuo); $nuovoImportoPagato = $this->importo_pagato + $importoPagamento; $nuovoImportoResiduo = $this->importo_rata - $nuovoImportoPagato; $nuovoStato = $nuovoImportoResiduo <= 0 ? 'pagata' : 'parzialmente_pagata'; $this->update([ 'importo_pagato' => $nuovoImportoPagato, 'importo_residuo' => $nuovoImportoResiduo, 'stato' => $nuovoStato, 'data_pagamento' => now(), 'metodo_pagamento' => $metodo, 'riferimento_pagamento' => $riferimento, 'note_pagamento' => $note, 'registrato_da' => $userId ?? auth()->id() ]); return $this; } /** * Metodo per registrare pagamento parziale */ public function registraPagamentoParziale($importo, $metodo = null, $riferimento = null, $note = null, $userId = null) { return $this->registraPagamento($importo, $metodo, $riferimento, $note, $userId); } /** * Metodo per annullare la rata */ public function annulla($motivo = null) { $this->update([ 'stato' => 'annullata', 'note_pagamento' => $motivo ]); return $this; } /** * Metodo per verificare se è scaduta */ public function isScaduta() { return $this->data_scadenza < now()->toDateString() && in_array($this->stato, ['emessa']); } /** * Metodo per verificare se è in scadenza */ public function isInScadenza($giorni = 30) { $dataLimite = now()->addDays($giorni)->toDateString(); return $this->data_scadenza <= $dataLimite && $this->data_scadenza >= now()->toDateString() && in_array($this->stato, ['emessa']); } /** * Metodo per aggiornare automaticamente lo stato */ public function aggiornaStato() { if ($this->stato === 'emessa' && $this->isScaduta()) { $this->update(['stato' => 'scaduta']); } return $this; } /** * Verifica se può essere modificata */ public function puoEssereModificata() { return in_array($this->stato, ['emessa', 'scaduta']); } /** * Verifica se può essere eliminata */ public function puoEssereEliminata() { return in_array($this->stato, ['emessa', 'annullata']); } /** * Accessor per importo residuo calcolato */ public function getImportoResiduoCalcolatoAttribute() { return ($this->importo_rata ?? $this->importo ?? 0) - ($this->importo_pagato ?? 0); } /** * Accessor per stato formattato */ public function getStatoFormattatoAttribute() { return match ($this->stato) { 'emessa' => 'Emessa', 'pagata' => 'Pagata', 'parzialmente_pagata' => 'Parzialmente Pagata', 'scaduta' => 'Scaduta', 'annullata' => 'Annullata', default => ucfirst($this->stato) }; } /** * Accessor per metodo pagamento formattato */ public function getMetodoPagamentoFormattatoAttribute() { return match ($this->metodo_pagamento) { 'bonifico' => 'Bonifico Bancario', 'bollettino' => 'Bollettino Postale', 'contanti' => 'Contanti', 'assegno' => 'Assegno', 'pos' => 'POS/Carta', 'altro' => 'Altro', default => $this->metodo_pagamento ? ucfirst($this->metodo_pagamento) : 'Non Specificato' }; } /** * Accessor per giorni alla scadenza */ public function getGiorniAllaScadenzaAttribute() { return now()->diffInDays($this->data_scadenza, false); } /** * Accessor per percentuale pagata */ public function getPercentualePagataAttribute() { $importoTotale = $this->importo_rata ?? $this->importo ?? 0; if ($importoTotale == 0) { return 0; } return round((($this->importo_pagato ?? 0) / $importoTotale) * 100, 2); } /** * Accessor compatibilità con vecchia struttura */ public function getImportoResiduoAttribute() { // Se esiste la nuova colonna, usala if (isset($this->attributes['importo_residuo'])) { return $this->attributes['importo_residuo']; } // Altrimenti calcola return $this->getImportoResiduoCalcolatoAttribute(); } }