217 lines
5.5 KiB
PHP
217 lines
5.5 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
|
|
class FondoCondominiale extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $table = 'fondi_condominiali';
|
|
|
|
protected $fillable = [
|
|
'stabile_id',
|
|
'tipo_fondo',
|
|
'denominazione',
|
|
'descrizione',
|
|
'saldo_attuale',
|
|
'saldo_minimo',
|
|
'percentuale_accantonamento',
|
|
'attivo'
|
|
];
|
|
|
|
protected $casts = [
|
|
'saldo_attuale' => 'decimal:2',
|
|
'saldo_minimo' => 'decimal:2',
|
|
'percentuale_accantonamento' => 'decimal:2',
|
|
'attivo' => 'boolean',
|
|
'created_at' => 'datetime',
|
|
'updated_at' => 'datetime'
|
|
];
|
|
|
|
/**
|
|
* Tipi fondo disponibili
|
|
*/
|
|
public const TIPI_FONDO = [
|
|
'ordinario' => 'Fondo Ordinario',
|
|
'riserva' => 'Fondo di Riserva',
|
|
'ascensore' => 'Fondo Ascensore',
|
|
'riscaldamento' => 'Fondo Riscaldamento',
|
|
'facciata_tetto' => 'Fondo Facciata/Tetto',
|
|
'verde_giardini' => 'Fondo Verde/Giardini',
|
|
'sicurezza' => 'Fondo Sicurezza/Videosorveglianza',
|
|
'innovazione' => 'Fondo Innovazione Tecnologica',
|
|
'investimenti' => 'Fondo Investimenti Spazi Comuni',
|
|
'personalizzato' => 'Fondo Personalizzato'
|
|
];
|
|
|
|
/**
|
|
* Priorità fondi (per ordinamento)
|
|
*/
|
|
public const PRIORITA_FONDI = [
|
|
'ordinario' => 1,
|
|
'riserva' => 2,
|
|
'ascensore' => 3,
|
|
'riscaldamento' => 4,
|
|
'facciata_tetto' => 5,
|
|
'verde_giardini' => 6,
|
|
'sicurezza' => 7,
|
|
'innovazione' => 8,
|
|
'investimenti' => 9,
|
|
'personalizzato' => 10
|
|
];
|
|
|
|
/**
|
|
* Relazione con Stabile
|
|
*/
|
|
public function stabile()
|
|
{
|
|
return $this->belongsTo(Stabile::class, 'stabile_id');
|
|
}
|
|
|
|
/**
|
|
* Relazione con MovimentiContabili
|
|
*/
|
|
public function movimenti()
|
|
{
|
|
return $this->hasMany(MovimentoContabile::class, 'fondo_id');
|
|
}
|
|
|
|
/**
|
|
* Accessor per tipo fondo descrizione
|
|
*/
|
|
public function getTipoFondoDescrizioneAttribute()
|
|
{
|
|
return self::TIPI_FONDO[$this->tipo_fondo] ?? $this->tipo_fondo;
|
|
}
|
|
|
|
/**
|
|
* Accessor per priorità ordinamento
|
|
*/
|
|
public function getPrioritaAttribute()
|
|
{
|
|
return self::PRIORITA_FONDI[$this->tipo_fondo] ?? 999;
|
|
}
|
|
|
|
/**
|
|
* Accessor per badge class tipo fondo
|
|
*/
|
|
public function getTipoFondoBadgeClassAttribute()
|
|
{
|
|
return match($this->tipo_fondo) {
|
|
'ordinario' => 'bg-primary',
|
|
'riserva' => 'bg-success',
|
|
'ascensore', 'riscaldamento', 'facciata_tetto' => 'bg-warning',
|
|
'verde_giardini', 'sicurezza' => 'bg-info',
|
|
'innovazione', 'investimenti' => 'bg-purple',
|
|
'personalizzato' => 'bg-secondary',
|
|
default => 'bg-secondary'
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Accessor per stato saldo (critico, normale, ottimale)
|
|
*/
|
|
public function getStatoSaldoAttribute()
|
|
{
|
|
if ($this->saldo_attuale < $this->saldo_minimo) {
|
|
return 'critico';
|
|
} elseif ($this->saldo_attuale < ($this->saldo_minimo * 1.5)) {
|
|
return 'normale';
|
|
} else {
|
|
return 'ottimale';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Accessor per stato saldo badge class
|
|
*/
|
|
public function getStatoSaldoBadgeClassAttribute()
|
|
{
|
|
return match($this->stato_saldo) {
|
|
'critico' => 'bg-danger',
|
|
'normale' => 'bg-warning',
|
|
'ottimale' => 'bg-success',
|
|
default => 'bg-secondary'
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Scope per fondi attivi
|
|
*/
|
|
public function scopeAttivi($query)
|
|
{
|
|
return $query->where('attivo', true);
|
|
}
|
|
|
|
/**
|
|
* Scope per tipo fondo
|
|
*/
|
|
public function scopePerTipo($query, $tipo)
|
|
{
|
|
return $query->where('tipo_fondo', $tipo);
|
|
}
|
|
|
|
/**
|
|
* Scope ordinati per priorità
|
|
*/
|
|
public function scopeOrdinatiPerPriorita($query)
|
|
{
|
|
return $query->orderByRaw("FIELD(tipo_fondo, 'ordinario', 'riserva', 'ascensore', 'riscaldamento', 'facciata_tetto', 'verde_giardini', 'sicurezza', 'innovazione', 'investimenti', 'personalizzato')");
|
|
}
|
|
|
|
/**
|
|
* Calcola l'accantonamento necessario per raggiungere il saldo minimo
|
|
*/
|
|
public function calcolaAccantonamentoNecessario()
|
|
{
|
|
$differenza = $this->saldo_minimo - $this->saldo_attuale;
|
|
return max(0, $differenza);
|
|
}
|
|
|
|
/**
|
|
* Aggiorna il saldo del fondo
|
|
*/
|
|
public function aggiornaSaldo($importo, $descrizione = null)
|
|
{
|
|
$this->saldo_attuale += $importo;
|
|
$this->save();
|
|
|
|
// Registra il movimento se richiesto
|
|
if ($descrizione) {
|
|
$this->movimenti()->create([
|
|
'descrizione' => $descrizione,
|
|
'importo' => $importo,
|
|
'data_movimento' => now()
|
|
]);
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Verifica se il fondo è sotto la soglia minima
|
|
*/
|
|
public function isSaldoCritico()
|
|
{
|
|
return $this->saldo_attuale < $this->saldo_minimo;
|
|
}
|
|
|
|
/**
|
|
* Boot method per eventi model
|
|
*/
|
|
protected static function boot()
|
|
{
|
|
parent::boot();
|
|
|
|
static::creating(function ($fondo) {
|
|
// Se non specificata, genera denominazione automatica
|
|
if (empty($fondo->denominazione)) {
|
|
$fondo->denominazione = self::TIPI_FONDO[$fondo->tipo_fondo] ?? 'Fondo Personalizzato';
|
|
}
|
|
});
|
|
}
|
|
}
|