325 lines
8.1 KiB
PHP
325 lines
8.1 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
|
|
|
class ContrattoLocazione extends Model
|
|
{
|
|
use HasFactory, SoftDeletes;
|
|
|
|
protected $table = 'contratti_locazione';
|
|
|
|
protected $fillable = [
|
|
'unita_immobiliare_id',
|
|
'locatore_id',
|
|
'conduttore_id',
|
|
'numero_contratto',
|
|
'data_contratto',
|
|
'data_inizio',
|
|
'data_fine',
|
|
'canone_mensile',
|
|
'deposito_cauzionale',
|
|
'tipo_contratto',
|
|
'regime_spese',
|
|
'configurazione_spese',
|
|
'stato',
|
|
'note'
|
|
];
|
|
|
|
protected $casts = [
|
|
'data_contratto' => 'date',
|
|
'data_inizio' => 'date',
|
|
'data_fine' => 'date',
|
|
'canone_mensile' => 'decimal:2',
|
|
'deposito_cauzionale' => 'decimal:2',
|
|
'configurazione_spese' => 'array'
|
|
];
|
|
|
|
/**
|
|
* Relazione con l'unità immobiliare
|
|
*/
|
|
public function unitaImmobiliare()
|
|
{
|
|
return $this->belongsTo(UnitaImmobiliare::class);
|
|
}
|
|
|
|
/**
|
|
* Relazione con l'anagrafica condominiale (conduttore/inquilino)
|
|
*/
|
|
public function conduttore()
|
|
{
|
|
return $this->belongsTo(AnagraficaCondominiale::class, 'conduttore_id');
|
|
}
|
|
|
|
/**
|
|
* Relazione con l'anagrafica condominiale (locatore)
|
|
*/
|
|
public function locatore()
|
|
{
|
|
return $this->belongsTo(AnagraficaCondominiale::class, 'locatore_id');
|
|
}
|
|
|
|
/**
|
|
* Alias per l'inquilino
|
|
*/
|
|
public function inquilino()
|
|
{
|
|
return $this->conduttore();
|
|
}
|
|
|
|
/**
|
|
* Alias legacy
|
|
*/
|
|
public function anagraficaCondominiale()
|
|
{
|
|
return $this->conduttore();
|
|
}
|
|
|
|
/**
|
|
* Scope per contratti attivi
|
|
*/
|
|
public function scopeAttivi($query)
|
|
{
|
|
return $query->where('stato', 'attivo');
|
|
}
|
|
|
|
/**
|
|
* Scope per contratti in corso
|
|
*/
|
|
public function scopeInCorso($query)
|
|
{
|
|
return $query->where('stato', 'attivo')
|
|
->whereDate('data_inizio', '<=', now())
|
|
->where(function ($q) {
|
|
$q->whereNull('data_fine')
|
|
->orWhereDate('data_fine', '>=', now());
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Scope per contratti scaduti
|
|
*/
|
|
public function scopeScaduti($query)
|
|
{
|
|
return $query->where('stato', 'attivo')
|
|
->whereNotNull('data_fine')
|
|
->whereDate('data_fine', '<', now());
|
|
}
|
|
|
|
/**
|
|
* Scope per contratti in scadenza
|
|
*/
|
|
public function scopeInScadenza($query, $giorni = 30)
|
|
{
|
|
return $query->where('stato', 'attivo')
|
|
->whereNotNull('data_fine')
|
|
->whereDate('data_fine', '>=', now())
|
|
->whereDate('data_fine', '<=', now()->addDays($giorni));
|
|
}
|
|
|
|
/**
|
|
* Scope per tipo di contratto
|
|
*/
|
|
public function scopeByTipoContratto($query, $tipo)
|
|
{
|
|
return $query->where('tipo_contratto', $tipo);
|
|
}
|
|
|
|
/**
|
|
* Scope per unità immobiliare
|
|
*/
|
|
public function scopeByUnitaImmobiliare($query, $unitaId)
|
|
{
|
|
return $query->where('unita_immobiliare_id', $unitaId);
|
|
}
|
|
|
|
/**
|
|
* Scope per inquilino
|
|
*/
|
|
public function scopeByInquilino($query, $anagraficaId)
|
|
{
|
|
return $query->where('anagrafica_condominiale_id', $anagraficaId);
|
|
}
|
|
|
|
/**
|
|
* Accessor per il tipo di contratto formattato
|
|
*/
|
|
public function getTipoContrattoFormattatoAttribute()
|
|
{
|
|
return match ($this->tipo_contratto) {
|
|
'libero_mercato' => 'Libero Mercato',
|
|
'concordato' => 'Concordato',
|
|
'transitorio' => 'Transitorio',
|
|
'studenti' => 'Studenti Universitari',
|
|
'commerciale' => 'Commerciale',
|
|
'uso_foresteria' => 'Uso Foresteria',
|
|
default => ucfirst(str_replace('_', ' ', $this->tipo_contratto))
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Accessor per lo stato formattato
|
|
*/
|
|
public function getStatoFormattatoAttribute()
|
|
{
|
|
return match ($this->stato) {
|
|
'attivo' => 'Attivo',
|
|
'scaduto' => 'Scaduto',
|
|
'risolto' => 'Risolto',
|
|
'disdetto' => 'Disdetto',
|
|
'sospeso' => 'Sospeso',
|
|
default => ucfirst($this->stato)
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Accessor per la modalità di pagamento formattata
|
|
*/
|
|
public function getModalitaPagamentoFormattataAttribute()
|
|
{
|
|
return match ($this->modalita_pagamento) {
|
|
'bonifico' => 'Bonifico Bancario',
|
|
'contanti' => 'Contanti',
|
|
'assegno' => 'Assegno',
|
|
'rid' => 'RID Bancario',
|
|
'carta_credito' => 'Carta di Credito',
|
|
default => ucfirst(str_replace('_', ' ', $this->modalita_pagamento))
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Accessor per il canone annuale
|
|
*/
|
|
public function getCanoneAnnualeAttribute()
|
|
{
|
|
return $this->canone_mensile * 12;
|
|
}
|
|
|
|
/**
|
|
* Accessor per i dati della registrazione
|
|
*/
|
|
public function getDatiRegistrazioneAttribute()
|
|
{
|
|
return [
|
|
'data' => $this->data_registrazione,
|
|
'numero' => $this->numero_registrazione,
|
|
'ufficio' => $this->ufficio_registrazione
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Metodo per verificare se il contratto è in corso
|
|
*/
|
|
public function isInCorso()
|
|
{
|
|
if ($this->stato !== 'attivo') {
|
|
return false;
|
|
}
|
|
|
|
$oggi = now()->toDateString();
|
|
|
|
if ($this->data_inizio > $oggi) {
|
|
return false; // Non ancora iniziato
|
|
}
|
|
|
|
if ($this->data_fine && $this->data_fine < $oggi) {
|
|
return false; // Già scaduto
|
|
}
|
|
|
|
return true; // In corso
|
|
}
|
|
|
|
/**
|
|
* Metodo per verificare se il contratto è scaduto
|
|
*/
|
|
public function isScaduto()
|
|
{
|
|
return $this->data_fine && $this->data_fine < now()->toDateString();
|
|
}
|
|
|
|
/**
|
|
* Metodo per verificare se il contratto è in scadenza
|
|
*/
|
|
public function isInScadenza($giorni = 30)
|
|
{
|
|
if (!$this->data_fine) {
|
|
return false;
|
|
}
|
|
|
|
$oggi = now();
|
|
return $this->data_fine >= $oggi->toDateString() &&
|
|
$this->data_fine <= $oggi->addDays($giorni)->toDateString();
|
|
}
|
|
|
|
/**
|
|
* Metodo per calcolare la durata del contratto
|
|
*/
|
|
public function getDurata()
|
|
{
|
|
if (!$this->data_fine) {
|
|
return null; // Durata indeterminata
|
|
}
|
|
|
|
return $this->data_inizio->diffInDays($this->data_fine);
|
|
}
|
|
|
|
/**
|
|
* Metodo per calcolare il canone con rivalutazione ISTAT
|
|
*/
|
|
public function getCanoneRivalutato($indice_attuale = null)
|
|
{
|
|
if (!$indice_attuale || !$this->indice_istat_base) {
|
|
return $this->canone_mensile;
|
|
}
|
|
|
|
$coefficiente_rivalutazione = $indice_attuale / $this->indice_istat_base;
|
|
return $this->canone_mensile * $coefficiente_rivalutazione;
|
|
}
|
|
|
|
/**
|
|
* Metodo per ottenere i giorni rimanenti
|
|
*/
|
|
public function getGiorniRimanenti()
|
|
{
|
|
if (!$this->data_fine) {
|
|
return null;
|
|
}
|
|
|
|
$oggi = now();
|
|
if ($this->data_fine < $oggi->toDateString()) {
|
|
return 0; // Scaduto
|
|
}
|
|
|
|
return $oggi->diffInDays($this->data_fine);
|
|
}
|
|
|
|
/**
|
|
* Metodo per calcolare l'imposta di registro annuale
|
|
*/
|
|
public function getImpostaRegistro()
|
|
{
|
|
if ($this->cedolare_secca) {
|
|
return 0; // Con cedolare secca non si paga l'imposta di registro
|
|
}
|
|
|
|
// Calcolo standard: 2% del canone annuale
|
|
return $this->canone_annuale * 0.02;
|
|
}
|
|
|
|
/**
|
|
* Metodo per calcolare la cedolare secca annuale
|
|
*/
|
|
public function getCedolareSecca()
|
|
{
|
|
if (!$this->cedolare_secca) {
|
|
return 0;
|
|
}
|
|
|
|
$aliquota = $this->aliquota_cedolare ?: 21; // Default 21%
|
|
return $this->canone_annuale * ($aliquota / 100);
|
|
}
|
|
}
|