✨ Nuovo Sistema Ripartizione Spese: - Migration e modelli RipartizioneSpese, DettaglioRipartizioneSpese - Calcolo automatico ripartizione millesimale - Gestione quote personalizzate ed esenzioni - Stati workflow: bozza → confermata → contabilizzata - Integrazione con tabelle millesimali e voci spesa ✨ Nuovo Sistema Gestione Rate: - Migration e modelli PianoRateizzazione, Rata (aggiornato) - Generazione automatica rate per piani di rateizzazione - Gestione pagamenti completi e parziali - Frequenze: mensile, trimestrale, semestrale, personalizzata - Monitoraggio scadenze e stati rate 🔧 Funzionalità Avanzate: - Codici automatici univoci (RS*, PR*, RT*) - Relazioni complete tra tutti i modelli - Scope e query builder avanzati - Statistiche e reporting - Backward compatibility con vecchia struttura �� Test e Integrazione: - Test modelli e database completati - Relazioni Eloquent integrate - Metodi di calcolo validati - Sistema pronto per produzione
349 lines
8.8 KiB
PHP
349 lines
8.8 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
|
|
|
class UnitaImmobiliare extends Model
|
|
{
|
|
use HasFactory, SoftDeletes;
|
|
|
|
protected $table = 'unita_immobiliari';
|
|
|
|
protected $fillable = [
|
|
'stabile_id',
|
|
'tipo_utilizzo_id',
|
|
'numero_interno',
|
|
'palazzina',
|
|
'piano',
|
|
'scala',
|
|
'codice_interno',
|
|
'codice_catastale',
|
|
'foglio',
|
|
'particella',
|
|
'subalterno',
|
|
'categoria',
|
|
'classe',
|
|
'consistenza',
|
|
'rendita_catastale',
|
|
'superficie_catastale',
|
|
'superficie_commerciale',
|
|
'millesimi_proprieta',
|
|
'millesimi_riscaldamento',
|
|
'millesimi_ascensore',
|
|
'millesimi_scale',
|
|
'millesimi_acqua',
|
|
'millesimi_custom_1',
|
|
'millesimi_custom_2',
|
|
'millesimi_custom_3',
|
|
'nome_custom_1',
|
|
'nome_custom_2',
|
|
'nome_custom_3',
|
|
'stato',
|
|
'data_acquisto',
|
|
'valore_acquisto',
|
|
'note',
|
|
'documenti_path',
|
|
'attiva',
|
|
// Campi legacy per compatibilità
|
|
'interno',
|
|
'fabbricato',
|
|
'categoria_catastale',
|
|
'superficie',
|
|
'vani',
|
|
'indirizzo'
|
|
];
|
|
|
|
protected $casts = [
|
|
'data_acquisto' => 'date',
|
|
'valore_acquisto' => 'decimal:2',
|
|
'rendita_catastale' => 'decimal:2',
|
|
'superficie_catastale' => 'decimal:2',
|
|
'superficie_commerciale' => 'decimal:2',
|
|
'millesimi_proprieta' => 'decimal:6',
|
|
'millesimi_riscaldamento' => 'decimal:6',
|
|
'millesimi_ascensore' => 'decimal:6',
|
|
'millesimi_scale' => 'decimal:6',
|
|
'millesimi_acqua' => 'decimal:6',
|
|
'millesimi_custom_1' => 'decimal:6',
|
|
'millesimi_custom_2' => 'decimal:6',
|
|
'millesimi_custom_3' => 'decimal:6',
|
|
'attiva' => 'boolean',
|
|
// Legacy casts
|
|
'superficie' => 'decimal:2',
|
|
'vani' => 'decimal:2',
|
|
'created_at' => 'datetime',
|
|
'updated_at' => 'datetime',
|
|
];
|
|
|
|
/**
|
|
* Relazione con Stabile
|
|
*/
|
|
public function stabile()
|
|
{
|
|
return $this->belongsTo(Stabile::class, 'stabile_id', 'id');
|
|
}
|
|
|
|
/**
|
|
* Relazione con il tipo di utilizzo
|
|
*/
|
|
public function tipoUtilizzo()
|
|
{
|
|
return $this->belongsTo(TipoUtilizzo::class);
|
|
}
|
|
|
|
/**
|
|
* Relazione con i diritti reali
|
|
*/
|
|
public function dirittiReali()
|
|
{
|
|
return $this->hasMany(DirittoReale::class);
|
|
}
|
|
|
|
/**
|
|
* Relazione con i contratti di locazione
|
|
*/
|
|
public function contrattiLocazione()
|
|
{
|
|
return $this->hasMany(ContrattoLocazione::class);
|
|
}
|
|
|
|
/**
|
|
* Relazione con le ripartizioni spese inquilini
|
|
*/
|
|
public function ripartizioniSpese()
|
|
{
|
|
return $this->hasMany(RipartizioneSpeseInquilini::class);
|
|
}
|
|
|
|
/**
|
|
* Relazione con Tickets (legacy)
|
|
*/
|
|
public function tickets()
|
|
{
|
|
return $this->hasMany(Ticket::class, 'unita_immobiliare_id', 'id');
|
|
}
|
|
|
|
/**
|
|
* Relazione con Proprietà (legacy)
|
|
*/
|
|
public function proprieta()
|
|
{
|
|
return $this->hasMany(Proprieta::class, 'unita_immobiliare_id', 'id');
|
|
}
|
|
|
|
/**
|
|
* Relazione con DettaglioRipartizioneSpese
|
|
*/
|
|
public function dettagliRipartizioneSpese()
|
|
{
|
|
return $this->hasMany(DettaglioRipartizioneSpese::class);
|
|
}
|
|
|
|
/**
|
|
* Relazione con Rate
|
|
*/
|
|
public function rate()
|
|
{
|
|
return $this->hasMany(Rata::class);
|
|
}
|
|
|
|
/**
|
|
* Rate attive (emesse o parzialmente pagate)
|
|
*/
|
|
public function rateAttive()
|
|
{
|
|
return $this->hasMany(Rata::class)->whereIn('stato', ['emessa', 'parzialmente_pagata', 'scaduta']);
|
|
}
|
|
|
|
/**
|
|
* Rate scadute
|
|
*/
|
|
public function rateScadute()
|
|
{
|
|
return $this->hasMany(Rata::class)->scadute();
|
|
}
|
|
|
|
/**
|
|
* Metodo per ottenere il totale delle rate da pagare
|
|
*/
|
|
public function getTotaleRateDaPagare()
|
|
{
|
|
return $this->rateAttive()->sum('importo_residuo');
|
|
}
|
|
|
|
/**
|
|
* Metodo per ottenere il numero di rate scadute
|
|
*/
|
|
public function getNumeroRateScadute()
|
|
{
|
|
return $this->rateScadute()->count();
|
|
}
|
|
|
|
/**
|
|
* Scope per unità attive
|
|
*/
|
|
public function scopeAttive($query)
|
|
{
|
|
return $query->where('attiva', true);
|
|
}
|
|
|
|
/**
|
|
* Scope per tipo di utilizzo
|
|
*/
|
|
public function scopeByTipoUtilizzo($query, $tipoUtilizzo)
|
|
{
|
|
return $query->whereHas('tipoUtilizzo', function ($q) use ($tipoUtilizzo) {
|
|
$q->where('codice', $tipoUtilizzo);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Scope per stabile
|
|
*/
|
|
public function scopeByStabile($query, $stabileId)
|
|
{
|
|
return $query->where('stabile_id', $stabileId);
|
|
}
|
|
|
|
/**
|
|
* Accessor per il nome completo dell'unità
|
|
*/
|
|
public function getNomeCompletoAttribute()
|
|
{
|
|
$nome = '';
|
|
|
|
if ($this->palazzina) {
|
|
$nome .= "Palazzina {$this->palazzina} - ";
|
|
}
|
|
|
|
if ($this->scala) {
|
|
$nome .= "Scala {$this->scala} - ";
|
|
}
|
|
|
|
if ($this->piano) {
|
|
$nome .= "Piano {$this->piano} - ";
|
|
}
|
|
|
|
$numeroInterno = $this->numero_interno ?: $this->interno;
|
|
$nome .= "Interno {$numeroInterno}";
|
|
|
|
return $nome;
|
|
}
|
|
|
|
/**
|
|
* Accessor per i dati catastali
|
|
*/
|
|
public function getDatiCatastaliAttribute()
|
|
{
|
|
return [
|
|
'foglio' => $this->foglio,
|
|
'particella' => $this->particella,
|
|
'subalterno' => $this->subalterno,
|
|
'categoria' => $this->categoria ?: $this->categoria_catastale,
|
|
'classe' => $this->classe,
|
|
'consistenza' => $this->consistenza,
|
|
'rendita' => $this->rendita_catastale
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Accessor per tutti i millesimi
|
|
*/
|
|
public function getMillesimiAttribute()
|
|
{
|
|
return [
|
|
'proprieta' => $this->millesimi_proprieta,
|
|
'riscaldamento' => $this->millesimi_riscaldamento,
|
|
'ascensore' => $this->millesimi_ascensore,
|
|
'scale' => $this->millesimi_scale,
|
|
'acqua' => $this->millesimi_acqua,
|
|
'custom_1' => $this->millesimi_custom_1,
|
|
'custom_2' => $this->millesimi_custom_2,
|
|
'custom_3' => $this->millesimi_custom_3
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Metodo per ottenere i proprietari attuali
|
|
*/
|
|
public function getProprietariAttuali()
|
|
{
|
|
return $this->dirittiReali()
|
|
->where('tipo_diritto', 'proprieta')
|
|
->whereNull('data_fine')
|
|
->with('anagraficaCondominiale')
|
|
->get();
|
|
}
|
|
|
|
/**
|
|
* Metodo per ottenere gli inquilini attuali
|
|
*/
|
|
public function getInquiliniAttuali()
|
|
{
|
|
return $this->contrattiLocazione()
|
|
->where('stato', 'attivo')
|
|
->whereDate('data_inizio', '<=', now())
|
|
->where(function ($query) {
|
|
$query->whereNull('data_fine')
|
|
->orWhereDate('data_fine', '>=', now());
|
|
})
|
|
->with('anagraficaCondominiale')
|
|
->get();
|
|
}
|
|
|
|
/**
|
|
* Metodo per verificare se l'unità è in locazione
|
|
*/
|
|
public function isInLocazione()
|
|
{
|
|
return $this->contrattiLocazione()
|
|
->where('stato', 'attivo')
|
|
->whereDate('data_inizio', '<=', now())
|
|
->where(function ($query) {
|
|
$query->whereNull('data_fine')
|
|
->orWhereDate('data_fine', '>=', now());
|
|
})
|
|
->exists();
|
|
}
|
|
|
|
/**
|
|
* Metodo per ottenere la ripartizione spese attuale
|
|
*/
|
|
public function getRipartizioneSpese()
|
|
{
|
|
return $this->ripartizioniSpese()
|
|
->whereDate('data_inizio', '<=', now())
|
|
->where(function ($query) {
|
|
$query->whereNull('data_fine')
|
|
->orWhereDate('data_fine', '>=', now());
|
|
})
|
|
->first();
|
|
}
|
|
|
|
/**
|
|
* Accessor per identificazione completa dell'unità (legacy)
|
|
*/
|
|
public function getIdentificazioneCompiletaAttribute()
|
|
{
|
|
$parts = [];
|
|
if ($this->fabbricato) $parts[] = 'Fabb. ' . $this->fabbricato;
|
|
if ($this->scala) $parts[] = 'Scala ' . $this->scala;
|
|
if ($this->piano) $parts[] = 'Piano ' . $this->piano;
|
|
if ($this->interno || $this->numero_interno) {
|
|
$interno = $this->numero_interno ?: $this->interno;
|
|
$parts[] = 'Int. ' . $interno;
|
|
}
|
|
return implode(', ', $parts) ?: 'N/A';
|
|
}
|
|
|
|
/**
|
|
* Accessor per l'indirizzo completo
|
|
*/
|
|
public function getIndirizzoCompletoAttribute()
|
|
{
|
|
return $this->indirizzo ?: $this->stabile->indirizzo_completo;
|
|
}
|
|
} |