netgescon-master/app/Models/UnitaImmobiliare.php
Pikappa2 bb38044019 feat: Implementazione completa sistema ripartizione spese e gestione rate
 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
2025-07-08 17:42:01 +02:00

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;
}
}