619 lines
19 KiB
PHP
Executable File
619 lines
19 KiB
PHP
Executable File
<?php
|
|
namespace App\Models;
|
|
|
|
use App\Models\RubricaUniversale;
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
|
use Illuminate\Support\Carbon;
|
|
|
|
class Stabile extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $table = 'stabili';
|
|
// Primary key di default ('id')
|
|
|
|
protected $fillable = [
|
|
'amministratore_id',
|
|
'codice_stabile',
|
|
'denominazione',
|
|
'codice_fiscale',
|
|
'cod_fisc_amministratore',
|
|
'indirizzo',
|
|
'citta',
|
|
'cap',
|
|
'provincia',
|
|
'note',
|
|
'old_id',
|
|
'stato',
|
|
// Dati catastali
|
|
'codice_comune_catasto',
|
|
'foglio',
|
|
'foglio_catasto',
|
|
'particella',
|
|
'particella_catasto',
|
|
'mappale',
|
|
'subalterno',
|
|
'sezione',
|
|
'categoria',
|
|
'categoria_catastale',
|
|
'classe',
|
|
'consistenza',
|
|
'rendita_catastale',
|
|
'superficie_catastale',
|
|
// Dati amministrativi e fiscali aggiuntivi
|
|
'codice_destinatario_sdi',
|
|
'pec_amministratore',
|
|
'pec_condominio',
|
|
'configurazione_default_unita',
|
|
'modalita_rateizzazione',
|
|
'inizio_esercizio',
|
|
'fine_esercizio',
|
|
// Dati bancari principali
|
|
'iban_principale',
|
|
'banca_principale',
|
|
'filiale',
|
|
'iban_secondario',
|
|
'banca_secondaria',
|
|
'filiale_secondaria',
|
|
// Info amministratore e mandato
|
|
'amministratore_nome',
|
|
'amministratore_email',
|
|
'data_nomina',
|
|
'scadenza_mandato',
|
|
// Configurazioni strutturali e caratteristiche
|
|
'struttura_fisica_json',
|
|
'numero_palazzine',
|
|
'numero_scale_per_palazzina',
|
|
'numero_piani',
|
|
'piano_seminterrato',
|
|
'piano_sottotetto',
|
|
'presenza_ascensore',
|
|
'cortile_giardino',
|
|
'superficie_cortile',
|
|
'riscaldamento_centralizzato',
|
|
'acqua_centralizzata',
|
|
'gas_centralizzato',
|
|
'servizio_portineria',
|
|
'orari_portineria',
|
|
'videocitofono',
|
|
'antenna_tv_centralizzata',
|
|
'internet_condominiale',
|
|
'palazzine_data',
|
|
'locali_servizio',
|
|
// Configurazioni economiche e rate
|
|
'fondo_riserva_minimo',
|
|
'importo_rata_standard',
|
|
'frequenza_rate',
|
|
'giorno_scadenza_rate',
|
|
'iban_condominio',
|
|
'numero_rate_ordinarie',
|
|
'mesi_rate_ordinarie',
|
|
'numero_rate_straordinarie',
|
|
'mesi_rate_straordinarie',
|
|
'configurazione_avanzata',
|
|
'ultima_generazione_unita',
|
|
'rate_ordinarie_mesi',
|
|
'rate_riscaldamento_mesi',
|
|
'descrizione_rate',
|
|
// Indicatori vari
|
|
'millesimi_generali_calcolati',
|
|
'millesimi_riscaldamento_separati',
|
|
'millesimi_acqua_separati',
|
|
'millesimi_ascensore_separati',
|
|
// Altri campi legacy
|
|
'anno_costruzione',
|
|
'numero_unita',
|
|
'superficie_totale',
|
|
'tipo_riscaldamento',
|
|
'tipo_acqua',
|
|
'numero_ascensori',
|
|
'presenza_giardino',
|
|
'presenza_piscina',
|
|
'presenza_garage',
|
|
'numero_garage',
|
|
'codice_interno',
|
|
'registro_anagrafe',
|
|
'documenti_path',
|
|
'attivo',
|
|
'rubrica_id',
|
|
];
|
|
|
|
protected $casts = [
|
|
'created_at' => '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',
|
|
'presenza_garage' => 'boolean',
|
|
'registro_anagrafe' => 'boolean',
|
|
'attivo' => 'boolean',
|
|
'mesi_rate_ordinarie' => 'array',
|
|
'mesi_rate_straordinarie' => 'array',
|
|
'configurazione_default_unita' => 'array',
|
|
'struttura_fisica_json' => 'array',
|
|
'palazzine_data' => 'array',
|
|
'locali_servizio' => 'array',
|
|
'configurazione_avanzata' => 'array',
|
|
'rate_ordinarie_mesi' => 'array',
|
|
'rate_riscaldamento_mesi' => 'array',
|
|
'rendita_catastale' => 'decimal:2',
|
|
'superficie_catastale' => 'decimal:2',
|
|
'fondo_riserva_minimo' => 'decimal:2',
|
|
'importo_rata_standard' => 'decimal:2',
|
|
'inizio_esercizio' => 'date',
|
|
'fine_esercizio' => 'date',
|
|
'data_nomina' => 'date',
|
|
'scadenza_mandato' => 'date',
|
|
'ultima_generazione_unita' => 'datetime',
|
|
];
|
|
|
|
public function hasOperationalHeating(): bool
|
|
{
|
|
if ((bool) ($this->riscaldamento_centralizzato ?? false)) {
|
|
return true;
|
|
}
|
|
|
|
if ((bool) ($this->millesimi_riscaldamento_separati ?? false)) {
|
|
return true;
|
|
}
|
|
|
|
$rateRiscaldamento = $this->rate_riscaldamento_mesi ?? [];
|
|
if (is_string($rateRiscaldamento)) {
|
|
$rateRiscaldamento = json_decode($rateRiscaldamento, true);
|
|
}
|
|
|
|
if (is_array($rateRiscaldamento) && $rateRiscaldamento !== []) {
|
|
return true;
|
|
}
|
|
|
|
return (bool) data_get($this->getOperationalConfiguration(), 'mostra_riscaldamento', false);
|
|
}
|
|
|
|
public function getOperationalConfiguration(): array
|
|
{
|
|
return is_array($this->configurazione_avanzata ?? null) ? $this->configurazione_avanzata : [];
|
|
}
|
|
|
|
public function getTakeoverDate(): ?Carbon
|
|
{
|
|
$raw = data_get($this->getOperationalConfiguration(), 'amministrazione.presa_in_carico_dal');
|
|
|
|
if (is_string($raw) && trim($raw) !== '') {
|
|
try {
|
|
return Carbon::parse($raw);
|
|
} catch (\Throwable) {
|
|
// ignore invalid stored values
|
|
}
|
|
}
|
|
|
|
return $this->data_nomina instanceof Carbon ? $this->data_nomina : null;
|
|
}
|
|
|
|
public function isOperationalYearVisible(?int $year): bool
|
|
{
|
|
if (! is_int($year) || $year <= 0) {
|
|
return true;
|
|
}
|
|
|
|
$takeoverDate = $this->getTakeoverDate();
|
|
if (! $takeoverDate) {
|
|
return true;
|
|
}
|
|
|
|
return $year >= (int) $takeoverDate->year;
|
|
}
|
|
|
|
public function getNominaVerbaleDocumentoId(): ?int
|
|
{
|
|
$id = data_get($this->getOperationalConfiguration(), 'amministrazione.verbale_nomina_documento_id');
|
|
|
|
return is_numeric($id) && (int) $id > 0 ? (int) $id : null;
|
|
}
|
|
|
|
/**
|
|
* Relazione con Amministratore
|
|
*/
|
|
public function amministratore()
|
|
{
|
|
return $this->belongsTo(Amministratore::class, 'amministratore_id', 'id');
|
|
}
|
|
|
|
public function amministratoreTransfers(): HasMany
|
|
{
|
|
return $this->hasMany(StabileAmministratoreTransfer::class, 'stabile_id', 'id');
|
|
}
|
|
|
|
public function latestAmministratoreTransfer(): HasOne
|
|
{
|
|
return $this->hasOne(StabileAmministratoreTransfer::class, 'stabile_id', 'id')->latestOfMany();
|
|
}
|
|
|
|
/**
|
|
* Rubrica universale collegata (opzionale)
|
|
*/
|
|
public function rubrica()
|
|
{
|
|
return $this->belongsTo(RubricaUniversale::class, 'rubrica_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');
|
|
}
|
|
|
|
public function insurancePolicies()
|
|
{
|
|
return $this->hasMany(InsurancePolicy::class, 'stabile_id', 'id')
|
|
->orderByDesc('renewal_at')
|
|
->orderByDesc('expires_at')
|
|
->orderByDesc('id');
|
|
}
|
|
|
|
/**
|
|
* Relazione con RipartizioneSpese
|
|
*/
|
|
public function ripartizioniSpese()
|
|
{
|
|
return $this->hasMany(RipartizioneSpese::class);
|
|
}
|
|
|
|
/**
|
|
* Relazione con VociSpesa
|
|
*/
|
|
public function vociSpesa()
|
|
{
|
|
return $this->hasMany(VoceSpesa::class, 'stabile_id', 'id')->orderBy('ordinamento')->orderBy('descrizione');
|
|
}
|
|
|
|
/**
|
|
* Relazione con TabelleMillesimali
|
|
*/
|
|
public function tabelleMillesimali()
|
|
{
|
|
return $this->hasMany(TabellaMillesimale::class, 'stabile_id', 'id')->orderBy('ordinamento')->orderBy('nome_tabella');
|
|
}
|
|
|
|
/**
|
|
* Relazione con Gestioni Contabili (per CRUD nella vista dello stabile)
|
|
*/
|
|
public function gestioniContabili()
|
|
{
|
|
return $this->hasMany(GestioneContabile::class, 'stabile_id', 'id')
|
|
->orderByDesc('anno_gestione')
|
|
->orderBy('tipo_gestione')
|
|
->orderBy('numero_straordinaria');
|
|
}
|
|
|
|
/**
|
|
* Relazione con Contratti Hub
|
|
*/
|
|
public function contrattiHub()
|
|
{
|
|
return $this->hasMany(StabileContratto::class, 'stabile_id', 'id')
|
|
->orderByDesc('decorrenza_dal')
|
|
->orderByDesc('id');
|
|
}
|
|
|
|
/**
|
|
* Relazione con PianoRateizzazione
|
|
*/
|
|
public function pianiRateizzazione()
|
|
{
|
|
return $this->hasMany(PianoRateizzazione::class);
|
|
}
|
|
|
|
/**
|
|
* Scope per stabili attivi
|
|
*/
|
|
public function scopeAttivi($query)
|
|
{
|
|
return $query->where('attivo', true);
|
|
}
|
|
|
|
/**
|
|
* Scope per stabili per amministratore
|
|
*/
|
|
public function scopeByAmministratore($query, $amministratoreId)
|
|
{
|
|
return $query->where('amministratore_id', $amministratoreId);
|
|
}
|
|
|
|
/**
|
|
* 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()
|
|
{
|
|
$codiceComune = $this->codice_comune_catasto ?? $this->codice_catastale_comune;
|
|
|
|
$foglio = $this->foglio ?? $this->foglio_catasto;
|
|
|
|
$particella = $this->particella ?? $this->particella_catasto ?? $this->mappale;
|
|
|
|
$categoria = $this->categoria_catastale ?? $this->categoria;
|
|
|
|
return [
|
|
'codice_comune' => $codiceComune,
|
|
'foglio' => $foglio,
|
|
'particella' => $particella,
|
|
'subalterno' => $this->subalterno,
|
|
'sezione' => $this->sezione,
|
|
'categoria' => $categoria,
|
|
'classe' => $this->classe,
|
|
'consistenza' => $this->consistenza,
|
|
'rendita' => $this->rendita_catastale,
|
|
'superficie' => $this->superficie_catastale,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 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(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Relazione con dati bancari
|
|
*/
|
|
public function datiBancari()
|
|
{
|
|
return $this->hasMany(DatiBancari::class, 'stabile_id');
|
|
}
|
|
|
|
/**
|
|
* Relazione con documenti collegati
|
|
*/
|
|
public function documentiCollegati()
|
|
{
|
|
return $this->hasMany(DocumentoCollegato::class, 'stabile_id');
|
|
}
|
|
|
|
/**
|
|
* Relazione con Palazzine
|
|
*/
|
|
public function palazzine()
|
|
{
|
|
return $this->hasMany(Palazzina::class, 'stabile_id');
|
|
}
|
|
|
|
/**
|
|
* Relazione con Palazzine attive
|
|
*/
|
|
public function palazzineAttive()
|
|
{
|
|
return $this->palazzine()->where('attiva', true);
|
|
}
|
|
|
|
/**
|
|
* Relazione con Gestioni Condominiali
|
|
*/
|
|
public function gestioniCondominiali()
|
|
{
|
|
return $this->hasMany(\App\Models\GestioneCondominiale::class, 'stabile_id');
|
|
}
|
|
|
|
/**
|
|
* Relazione con Gestioni Condominiali attive
|
|
*/
|
|
public function gestioniAttive()
|
|
{
|
|
return $this->gestioniCondominiali()->where('stato', 'ATTIVA');
|
|
}
|
|
|
|
/**
|
|
* Sincronizza o crea il contatto dello stabile nella Rubrica Universale.
|
|
*/
|
|
public function syncRubricaContatto(): RubricaUniversale
|
|
{
|
|
$rubrica = $this->rubrica;
|
|
|
|
$data = [
|
|
'amministratore_id' => $this->amministratore_id,
|
|
'codice_univoco' => substr('ST-' . $this->codice_stabile, 0, 8),
|
|
'categoria' => 'condomino', // Usiamo condomino o altra categoria gestita
|
|
'tipo_contatto' => 'persona_giuridica',
|
|
'ragione_sociale' => $this->denominazione,
|
|
'cognome' => null,
|
|
'nome' => null,
|
|
'codice_fiscale' => $this->codice_fiscale,
|
|
'indirizzo' => $this->indirizzo,
|
|
'citta' => $this->citta,
|
|
'cap' => $this->cap,
|
|
'provincia' => $this->provincia,
|
|
'stato' => 'attivo',
|
|
];
|
|
|
|
if (! $rubrica && ! empty($data['codice_univoco'])) {
|
|
$existing = RubricaUniversale::where('codice_univoco', $data['codice_univoco'])->first();
|
|
if ($existing) {
|
|
$rubrica = $existing;
|
|
$this->update(['rubrica_id' => $rubrica->id]);
|
|
}
|
|
}
|
|
|
|
if ($rubrica) {
|
|
$rubrica->update($data);
|
|
} else {
|
|
$rubrica = RubricaUniversale::create($data);
|
|
$this->update(['rubrica_id' => $rubrica->id]);
|
|
}
|
|
|
|
return $rubrica;
|
|
}
|
|
|
|
/**
|
|
* Collaboratori assegnati allo stabile (tramite pivot)
|
|
*/
|
|
public function collaboratori()
|
|
{
|
|
return $this->belongsToMany(User::class, 'collaboratore_stabile', 'stabile_id', 'user_id')
|
|
->withPivot(['ruolo', 'permessi'])
|
|
->withTimestamps();
|
|
}
|
|
}
|