- Corretti errori di foreign key nelle migrazioni - Rimosso userSetting() non definito e aggiunto helpers.php - Aggiornati modelli PianoRateizzazione e Rata con relazioni corrette - Aggiornato DATA_ARCHITECTURE.md con nuovi modelli per ripartizione spese - Corrette dipendenze tra tabelle nelle migrazioni
382 lines
9.6 KiB
PHP
382 lines
9.6 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
|
use Illuminate\Support\Str;
|
|
|
|
/**
|
|
* Class Rata
|
|
*
|
|
* Gestisce le rate singole dei piani di rateizzazione
|
|
*
|
|
* @package App\Models
|
|
*/
|
|
class Rata extends Model
|
|
{
|
|
use HasFactory, SoftDeletes;
|
|
|
|
protected $table = 'rate';
|
|
|
|
protected $fillable = [
|
|
'codice_rata',
|
|
'piano_rateizzazione_id',
|
|
'unita_immobiliare_id',
|
|
'anagrafica_condominiale_id',
|
|
'numero_rata',
|
|
'descrizione',
|
|
'importo_rata',
|
|
'data_scadenza',
|
|
'stato',
|
|
'importo_pagato',
|
|
'importo_residuo',
|
|
'data_pagamento',
|
|
'note_pagamento',
|
|
'dettagli_pagamento',
|
|
'metodo_pagamento',
|
|
'riferimento_pagamento',
|
|
'registrato_da',
|
|
// Compatibilità con vecchia struttura
|
|
'gestione_id',
|
|
'soggetto_id',
|
|
'importo',
|
|
'tipo_rata',
|
|
'note'
|
|
];
|
|
|
|
protected $casts = [
|
|
'importo_rata' => '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 RipartizioneSpese
|
|
*/
|
|
public function ripartizione()
|
|
{
|
|
return $this->belongsTo(RipartizioneSpese::class, 'ripartizione_spese_id');
|
|
}
|
|
|
|
/**
|
|
* 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();
|
|
}
|
|
} |