📋 AGGIUNTE PRINCIPALI: - Sistema contabile partita doppia con gestioni multiple - Documentazione implementazione completa - Models Laravel: GestioneContabile, MovimentoPartitaDoppia - Controller ContabilitaAvanzataController - Migration sistema contabile completo - Scripts automazione e trasferimento - Manuali utente e checklist implementazione 📊 FILES PRINCIPALI: - docs/10-IMPLEMENTAZIONE-CONTABILITA-PARTITA-DOPPIA-GESTIONI.md - SPECIFICHE-SISTEMA-CONTABILE-COMPLETO.md - netgescon-laravel/database/migrations/2025_07_20_100000_create_complete_accounting_system.php - netgescon-laravel/app/Models/GestioneContabile.php ✅ CHECKPOINT SICURO PER ROLLBACK
189 lines
4.7 KiB
PHP
189 lines
4.7 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
|
|
|
/**
|
|
* Gestione Contabile
|
|
* Rappresenta una gestione specifica all'interno di un esercizio contabile
|
|
*/
|
|
class GestioneContabile extends Model
|
|
{
|
|
use HasFactory, SoftDeletes;
|
|
|
|
protected $table = 'gestioni_contabili';
|
|
|
|
protected $fillable = [
|
|
'codice_gestione',
|
|
'stabile_id',
|
|
'esercizio_contabile_id',
|
|
'denominazione',
|
|
'descrizione',
|
|
'tipologia',
|
|
'stato',
|
|
'data_apertura',
|
|
'data_chiusura',
|
|
'budget_previsto',
|
|
'fondo_cassa_iniziale',
|
|
'regole_ripartizione',
|
|
'tabella_millesimale_id',
|
|
];
|
|
|
|
protected $casts = [
|
|
'data_apertura' => 'date',
|
|
'data_chiusura' => 'date',
|
|
'budget_previsto' => 'decimal:2',
|
|
'fondo_cassa_iniziale' => 'decimal:2',
|
|
'regole_ripartizione' => 'json',
|
|
];
|
|
|
|
protected static function boot()
|
|
{
|
|
parent::boot();
|
|
|
|
static::creating(function ($model) {
|
|
if (!$model->codice_gestione) {
|
|
$model->codice_gestione = static::generateCodiceGestione();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Genera un codice univoco per la gestione
|
|
*/
|
|
public static function generateCodiceGestione(): string
|
|
{
|
|
do {
|
|
$codice = 'GES' . sprintf('%05d', rand(10000, 99999));
|
|
} while (static::where('codice_gestione', $codice)->exists());
|
|
|
|
return $codice;
|
|
}
|
|
|
|
/**
|
|
* Relazioni
|
|
*/
|
|
public function stabile(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Stabile::class);
|
|
}
|
|
|
|
public function esercizioContabile(): BelongsTo
|
|
{
|
|
return $this->belongsTo(EsercizioContabile::class, 'esercizio_contabile_id');
|
|
}
|
|
|
|
public function tabellaMillesimale(): BelongsTo
|
|
{
|
|
return $this->belongsTo(TabellaMillesimale::class, 'tabella_millesimale_id');
|
|
}
|
|
|
|
public function movimenti(): HasMany
|
|
{
|
|
return $this->hasMany(MovimentoPartitaDoppia::class, 'gestione_contabile_id');
|
|
}
|
|
|
|
public function rate(): HasMany
|
|
{
|
|
return $this->hasMany(RataCondominiale::class, 'gestione_contabile_id');
|
|
}
|
|
|
|
/**
|
|
* Scopes
|
|
*/
|
|
public function scopeAttive($query)
|
|
{
|
|
return $query->where('stato', 'attiva');
|
|
}
|
|
|
|
public function scopeByTipologia($query, $tipologia)
|
|
{
|
|
return $query->where('tipologia', $tipologia);
|
|
}
|
|
|
|
/**
|
|
* Metodi di business logic
|
|
*/
|
|
public function calcolaTotaleMovimenti($tipo = null): float
|
|
{
|
|
$query = $this->movimenti()->where('stato_movimento', '!=', 'bozza');
|
|
|
|
if ($tipo) {
|
|
// Implementare logica per tipo entrata/uscita basata su dare/avere
|
|
}
|
|
|
|
return $query->sum('importo_netto');
|
|
}
|
|
|
|
public function calcolaSaldoContabile(): float
|
|
{
|
|
// Implementare calcolo saldo basato su partita doppia
|
|
$entrate = $this->movimenti()
|
|
->whereHas('righeContabili', function($q) {
|
|
$q->where('dare_avere', 'avere');
|
|
})
|
|
->sum('importo_netto');
|
|
|
|
$uscite = $this->movimenti()
|
|
->whereHas('righeContabili', function($q) {
|
|
$q->where('dare_avere', 'dare');
|
|
})
|
|
->sum('importo_netto');
|
|
|
|
return $entrate - $uscite;
|
|
}
|
|
|
|
public function getTotaleRateAttribute(): float
|
|
{
|
|
return $this->rate()->sum('importo_dovuto');
|
|
}
|
|
|
|
public function getTotaleIncassatoAttribute(): float
|
|
{
|
|
return $this->rate()->sum('importo_pagato');
|
|
}
|
|
|
|
public function getPercentualeIncassoAttribute(): float
|
|
{
|
|
$totale = $this->getTotaleRateAttribute();
|
|
if ($totale == 0) return 0;
|
|
|
|
return ($this->getTotaleIncassatoAttribute() / $totale) * 100;
|
|
}
|
|
|
|
/**
|
|
* Verifica se la gestione è chiudibile
|
|
*/
|
|
public function isChiudibile(): bool
|
|
{
|
|
// Verifica che tutti i movimenti siano confermati
|
|
$movimentiNonConfermati = $this->movimenti()
|
|
->whereIn('stato_movimento', ['bozza', 'da_verificare'])
|
|
->count();
|
|
|
|
return $movimentiNonConfermati === 0;
|
|
}
|
|
|
|
/**
|
|
* Chiude la gestione
|
|
*/
|
|
public function chiudiGestione(): bool
|
|
{
|
|
if (!$this->isChiudibile()) {
|
|
return false;
|
|
}
|
|
|
|
$this->update([
|
|
'stato' => 'chiusa',
|
|
'data_chiusura' => now(),
|
|
]);
|
|
|
|
return true;
|
|
}
|
|
}
|