netgescon-master/app/Models/UnitaImmobiliare.php
Pikappa2 f45845ba3c feat: Complete NetGesCon modernization - all core systems implemented
MAJOR IMPLEMENTATION COMPLETED:
 Modern database structure with Laravel best practices
 Complete Eloquent relationships (Amministratore→Stabili→Movements)
 8-character alphanumeric codes system (ADM, ANA, MOV, ALL prefixes)
 Multi-database architecture for administrators
 Complete property management (anagrafica_condominiale, diritti_reali, contratti)
 Distribution system for multi-server deployment
 Universal responsive UI with permission-based sidebar

NEW MODELS & MIGRATIONS:
- AnagraficaCondominiale: Complete person/entity management
- ContattoAnagrafica: Multi-contact system with usage flags
- DirittoReale: Property rights with quotas and percentages
- ContrattoLocazione: Rental contracts with landlord/tenant
- TipoUtilizzo: Property usage types (residential, commercial, etc.)
- Enhanced Stabile: Cadastral data, SDI, rate configuration
- Enhanced UnitaImmobiliare: Modern structure with backward compatibility

SERVICES & CONTROLLERS:
- DistributionService: Multi-server deployment and migration
- FileManagerController: Administrator folder management
- DistributionController: API for server-to-server communication
- MultiDatabaseService: Dynamic database connections

READY FOR PRODUCTION:
 Database schema: Complete and tested
 Models relationships: All working and verified
 Code generation: Automatic 8-char codes implemented
 Testing: Successful data creation confirmed
 Documentation: Complete internal technical docs

NEXT PHASE: Millésimal tables, expense categories, cost distribution engine
2025-07-08 16:24:03 +02:00

301 lines
7.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');
}
/**
* 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;
}
}