'datetime', 'updated_at' => 'datetime', 'anno_costruzione' => 'integer', 'numero_piani' => 'integer', 'numero_unita' => 'integer', 'superficie_totale' => 'decimal:2', 'numero_ascensori' => 'integer', 'numero_garage' => 'integer', 'numero_rate_ordinarie' => 'integer', 'numero_rate_straordinarie' => 'integer', 'presenza_ascensore' => 'boolean', 'presenza_giardino' => 'boolean', 'presenza_piscina' => 'boolean', // Nuovi cast per campi avanzati 'struttura_fisica_json' => 'array', 'palazzine_data' => 'array', 'locali_servizio' => 'array', 'numero_palazzine' => 'integer', 'numero_scale_per_palazzina' => 'integer', 'piano_seminterrato' => 'boolean', 'piano_sottotetto' => 'boolean', 'cortile_giardino' => 'boolean', 'superficie_cortile' => 'decimal:2', 'riscaldamento_centralizzato' => 'boolean', 'acqua_centralizzata' => 'boolean', 'gas_centralizzato' => 'boolean', 'servizio_portineria' => 'boolean', 'videocitofono' => 'boolean', 'antenna_tv_centralizzata' => 'boolean', 'internet_condominiale' => 'boolean', 'fondo_riserva_minimo' => 'decimal:2', 'importo_rata_standard' => 'decimal:2', 'giorno_scadenza_rate' => 'integer', 'millesimi_generali_calcolati' => 'boolean', 'millesimi_riscaldamento_separati' => 'boolean', 'millesimi_acqua_separati' => 'boolean', 'millesimi_ascensore_separati' => 'boolean', 'configurazione_avanzata' => 'array', 'ultima_generazione_unita' => 'datetime', 'presenza_garage' => 'boolean', 'registro_anagrafe' => 'boolean', 'attivo' => 'boolean', 'mesi_rate_ordinarie' => 'array', 'mesi_rate_straordinarie' => 'array', // Nuovi cast per campi aggiunti 'palazzine_data' => 'array', 'locali_servizio' => 'array', 'data_nomina' => 'date', 'scadenza_mandato' => 'date', 'rendita_catastale' => 'decimal:2', 'superficie_catastale' => 'decimal:2', // Nuovi cast per i campi aggiunti 'palazzine_data' => 'array', 'locali_servizio' => 'array', 'rendita_catastale' => 'decimal:2', 'superficie_catastale' => 'decimal:2', 'data_nomina' => 'date', 'scadenza_mandato' => 'date' ]; /** * Relazione con Amministratore */ public function amministratore() { return $this->belongsTo(Amministratore::class, 'amministratore_id', 'id'); } /** * Relazione con UnitaImmobiliari */ public function unitaImmobiliari() { return $this->hasMany(UnitaImmobiliare::class, 'stabile_id', 'id'); } /** * Relazione con Tickets */ public function tickets() { return $this->hasMany(Ticket::class, 'stabile_id', 'id'); } /** * Relazione con RipartizioneSpese */ public function ripartizioniSpese() { return $this->hasMany(RipartizioneSpese::class); } /** * Relazione con PianoRateizzazione */ public function pianiRateizzazione() { return $this->hasMany(PianoRateizzazione::class); } /** * Relazione con ChiaviStabili */ public function chiavi() { return $this->hasMany(ChiaveStabile::class, 'stabile_id'); } /** * Relazione con FondiCondominiali */ public function fondi() { return $this->hasMany(FondoCondominiale::class, 'stabile_id'); } /** * Relazione con StrutturaFisicaDettaglio */ public function strutturaFisica() { return $this->hasMany(StrutturaFisicaDettaglio::class, 'stabile_id'); } /** * Relazione con le tabelle millesimali dinamiche */ public function tabelleMillesimali() { return $this->hasMany(TabellaMillesimale::class, 'stabile_id', 'id'); } /** * Relazione con i contatori */ public function contatori() { return $this->hasMany(Contatore::class, 'stabile_id', 'id'); } /** * Relazione con gli algoritmi di ripartizione */ public function algoritmiRipartizione() { return $this->hasMany(AlgoritmoRipartizione::class, 'stabile_id', 'id'); } /** * Contatori condominiali (non legati a unità specifiche) */ public function contatoriCondominiali() { return $this->hasMany(Contatore::class, 'stabile_id', 'id')->whereNull('unita_immobiliare_id'); } /** * Esercizi contabili dello stabile */ public function eserciziContabili() { return $this->hasMany(EsercizioContabile::class, 'stabile_id', 'id'); } /** * Esercizi contabili ordinari */ public function eserciziOrdinari() { return $this->eserciziContabili()->byTipologia('ordinaria')->ordinatiSequenzialmente(); } /** * Esercizi riscaldamento */ public function eserciziRiscaldamento() { return $this->eserciziContabili()->byTipologia('riscaldamento')->ordinatiSequenzialmente(); } /** * Esercizi straordinari */ public function eserciziStraordinari() { return $this->eserciziContabili()->byTipologia('straordinaria')->ordinatiSequenzialmente(); } /** * Tabelle millesimali attive */ public function tabelleMillesimaliAttive() { return $this->tabelleMillesimali()->attive(); } /** * Tabella millesimi di proprietà (principale) */ public function tabellaMillesimiProprieta() { return $this->hasOne(TabellaMillesimale::class, 'stabile_id', 'id') ->where('tipo_tabella', 'proprieta') ->where('attiva', true); } /** * Documenti dello stabile */ public function documenti() { return $this->hasMany(DocumentoStabile::class, 'stabile_id', 'id'); } /** * Documenti per categoria */ public function documentiPerCategoria($categoria = null) { $query = $this->documenti()->orderBy('created_at', 'desc'); if ($categoria) { $query->where('categoria', $categoria); } return $query; } /** * Documenti pubblici (visibili ai condomini) */ public function documentiPubblici() { return $this->documenti()->where('pubblico', true); } /** * Documenti in scadenza */ public function documentiInScadenza($giorni = 30) { return $this->documenti() ->whereNotNull('data_scadenza') ->where('data_scadenza', '<=', now()->addDays($giorni)) ->where('data_scadenza', '>=', now()); } /** * Costanti per frequenza rate */ public const FREQUENZE_RATE = [ 'mensile' => 'Mensile', 'bimestrale' => 'Bimestrale', 'trimestrale' => 'Trimestrale', 'quadrimestrale' => 'Quadrimestrale', 'semestrale' => 'Semestrale', 'annuale' => 'Annuale' ]; /** * Calcola il numero totale di unità immobiliari dalla struttura fisica */ public function calcolaTotaleUnita() { $totale = 0; for ($palazzina = 1; $palazzina <= $this->numero_palazzine; $palazzina++) { for ($scala = 1; $scala <= $this->numero_scale_per_palazzina; $scala++) { // Calcola piani totali (incluso seminterrato e sottotetto) $pianiTotali = $this->numero_piani; if ($this->piano_seminterrato) $pianiTotali++; if ($this->piano_sottotetto) $pianiTotali++; $totale += $pianiTotali * 2; // Assumiamo 2 unità per piano di default } } return $totale; } /** * Genera automaticamente la struttura fisica dettagliata */ public function generaStrutturaFisica() { $struttura = []; for ($palazzina = 1; $palazzina <= $this->numero_palazzine; $palazzina++) { $nomePalazzina = $this->numero_palazzine > 1 ? chr(64 + $palazzina) : '1'; for ($scala = 1; $scala <= $this->numero_scale_per_palazzina; $scala++) { $pianoMin = $this->piano_seminterrato ? -1 : 0; $pianoMax = $this->numero_piani; if ($this->piano_sottotetto) $pianoMax++; for ($piano = $pianoMin; $piano <= $pianoMax; $piano++) { $struttura[] = [ 'palazzina' => $nomePalazzina, 'scala' => (string)$scala, 'piano' => $piano, 'numero_interni' => 2, // Default 2 interni per piano 'presenza_ascensore' => $this->presenza_ascensore ]; } } } return $struttura; } /** * Accessor per nome completo stabile */ public function getNomeCompletoAttribute() { return $this->denominazione . ' - ' . $this->indirizzo . ', ' . $this->citta; } /** * Scope per stabili attivi */ public function scopeAttivi($query) { return $query->where('stato', 'attivo'); } /** * Verifica se lo stabile ha la struttura fisica configurata */ public function hasStrutturaFisicaConfigurata() { return !empty($this->struttura_fisica_json) || $this->strutturaFisica()->count() > 0; } /** * Accessor per il nome completo dell'indirizzo */ public function getIndirizzoCompletoAttribute() { return $this->indirizzo . ', ' . $this->cap . ' ' . $this->citta . ($this->provincia ? ' (' . $this->provincia . ')' : ''); } /** * Accessor per i dati catastali */ public function getDatiCatastaliAttribute() { return [ 'codice_comune' => $this->codice_catastale_comune, 'foglio' => $this->foglio, 'particella' => $this->particella, 'subalterno' => $this->subalterno, 'sezione' => $this->sezione ]; } /** * Accessor per i dati SDI */ public function getDatiSdiAttribute() { return [ 'codice_destinatario' => $this->codice_destinatario_sdi, 'pec_amministratore' => $this->pec_amministratore, 'pec_condominio' => $this->pec_condominio ]; } /** * Accessor per la configurazione rate ordinarie */ public function getConfigurazioneRateOrdinarieAttribute() { return [ 'numero_rate' => $this->numero_rate_ordinarie, 'mesi' => $this->mesi_rate_ordinarie ]; } /** * Accessor per la configurazione rate straordinarie */ public function getConfigurazioneRateStraordinarieAttribute() { return [ 'numero_rate' => $this->numero_rate_straordinarie, 'mesi' => $this->mesi_rate_straordinarie ]; } /** * Accessor per le caratteristiche dello stabile */ public function getCaratteristicheAttribute() { return [ 'anno_costruzione' => $this->anno_costruzione, 'numero_piani' => $this->numero_piani, 'numero_unita' => $this->numero_unita, 'superficie_totale' => $this->superficie_totale, 'tipo_riscaldamento' => $this->tipo_riscaldamento, 'tipo_acqua' => $this->tipo_acqua, 'presenza_ascensore' => $this->presenza_ascensore, 'numero_ascensori' => $this->numero_ascensori, 'presenza_giardino' => $this->presenza_giardino, 'presenza_piscina' => $this->presenza_piscina, 'presenza_garage' => $this->presenza_garage, 'numero_garage' => $this->numero_garage ]; } /** * Metodo per ottenere tutte le anagrafiche associate */ public function getAnagraficheAssociate() { return AnagraficaCondominiale::whereHas('dirittiReali.unitaImmobiliare', function ($query) { $query->where('stabile_id', $this->id); })->orWhereHas('contrattiLocazione.unitaImmobiliare', function ($query) { $query->where('stabile_id', $this->id); })->distinct()->get(); } /** * Metodo per ottenere i proprietari dello stabile */ public function getProprietari() { return AnagraficaCondominiale::whereHas('dirittiReali', function ($query) { $query->where('tipo_diritto', 'proprieta') ->whereNull('data_fine') ->whereHas('unitaImmobiliare', function ($q) { $q->where('stabile_id', $this->id); }); })->distinct()->get(); } /** * Metodo per ottenere gli inquilini dello stabile */ public function getInquilini() { return AnagraficaCondominiale::whereHas('contrattiLocazione', function ($query) { $query->where('stato', 'attivo') ->whereDate('data_inizio', '<=', now()) ->where(function ($q) { $q->whereNull('data_fine') ->orWhereDate('data_fine', '>=', now()); }) ->whereHas('unitaImmobiliare', function ($q) { $q->where('stabile_id', $this->id); }); })->distinct()->get(); } /** * Metodo per calcolare il totale millesimi */ public function getTotaleMillesimi($tipo = 'proprieta') { $campo = 'millesimi_' . $tipo; return $this->unitaImmobiliari()->where('attiva', true)->sum($campo); } /** * Metodo per verificare la coerenza dei millesimi */ public function verificaMillesimi($tipo = 'proprieta') { $totale = $this->getTotaleMillesimi($tipo); return abs($totale - 1000) < 0.001; // Tolleranza per errori di arrotondamento } /** * Metodo per ottenere le statistiche dello stabile */ public function getStatistiche() { $unita = $this->unitaImmobiliari()->where('attiva', true); return [ 'totale_unita' => $unita->count(), 'unita_in_locazione' => $unita->whereHas('contrattiLocazione', function ($query) { $query->where('stato', 'attivo') ->whereDate('data_inizio', '<=', now()) ->where(function ($q) { $q->whereNull('data_fine') ->orWhereDate('data_fine', '>=', now()); }); })->count(), 'superficie_totale' => $unita->sum('superficie_commerciale'), 'totale_millesimi_proprieta' => $this->getTotaleMillesimi('proprieta'), 'totale_proprietari' => $this->getProprietari()->count(), 'totale_inquilini' => $this->getInquilini()->count() ]; } }