335 lines
13 KiB
PHP
335 lines
13 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\DB;
|
|
use App\Models\{
|
|
Stabile,
|
|
Gestione,
|
|
Fornitore,
|
|
VoceSpesa,
|
|
TabellaMillesimale,
|
|
MovimentoContabile,
|
|
TransazioneContabile,
|
|
RigaContabile,
|
|
PianoConti,
|
|
ProtocolloRegistrazione
|
|
};
|
|
|
|
/**
|
|
* ========================================
|
|
* CONTROLLER MASCHERA UNICA REGISTRAZIONE
|
|
* Sistema avanzato partita doppia NetGesCon
|
|
* ========================================
|
|
*/
|
|
class RegistrazioniController extends Controller
|
|
{
|
|
/**
|
|
* Mostra la maschera unica di registrazione
|
|
*/
|
|
public function create()
|
|
{
|
|
$amministratore_id = Auth::user()->amministratore->id_amministratore ?? null;
|
|
|
|
// Dati necessari per la maschera
|
|
$stabili = Stabile::where('amministratore_id', $amministratore_id)->attivi()->get();
|
|
$fornitori = Fornitore::where('amministratore_id', $amministratore_id)->get();
|
|
$vociSpesa = VoceSpesa::orderBy('codice')->get();
|
|
$conti = PianoConti::orderBy('codice_conto')->get();
|
|
|
|
// Template predefiniti per registrazioni comuni
|
|
$template = [
|
|
'fattura_fornitore' => [
|
|
'nome' => 'Fattura Fornitore',
|
|
'tipo_documento' => 'fattura_passiva',
|
|
'conti_automatici' => [
|
|
'dare' => ['6000' => 'Costi per servizi'],
|
|
'avere' => ['2000' => 'Debiti verso fornitori']
|
|
]
|
|
],
|
|
'bolletta_utenza' => [
|
|
'nome' => 'Bolletta Utenza',
|
|
'tipo_documento' => 'bolletta',
|
|
'conti_automatici' => [
|
|
'dare' => ['6100' => 'Spese per utenze'],
|
|
'avere' => ['2000' => 'Debiti verso fornitori']
|
|
]
|
|
],
|
|
'pagamento_bonifico' => [
|
|
'nome' => 'Pagamento Bonifico',
|
|
'tipo_documento' => 'bonifico',
|
|
'conti_automatici' => [
|
|
'dare' => ['2000' => 'Debiti verso fornitori'],
|
|
'avere' => ['1000' => 'Banca c/c']
|
|
]
|
|
],
|
|
'incasso_rata' => [
|
|
'nome' => 'Incasso Rata Condominiale',
|
|
'tipo_documento' => 'incasso',
|
|
'conti_automatici' => [
|
|
'dare' => ['1000' => 'Banca c/c'],
|
|
'avere' => ['3000' => 'Crediti verso condomini']
|
|
]
|
|
],
|
|
'ripartizione_spesa' => [
|
|
'nome' => 'Ripartizione Spesa',
|
|
'tipo_documento' => 'ripartizione',
|
|
'conti_automatici' => [
|
|
'dare' => ['3000' => 'Crediti verso condomini'],
|
|
'avere' => ['6000' => 'Costi per servizi']
|
|
]
|
|
]
|
|
];
|
|
|
|
return view('admin.registrazioni.create', compact(
|
|
'stabili', 'fornitori', 'vociSpesa', 'conti', 'template'
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Salva la registrazione con logica partita doppia
|
|
*/
|
|
public function store(Request $request)
|
|
{
|
|
$request->validate([
|
|
'stabile_id' => 'required|exists:stabili,id_stabile',
|
|
'gestione_id' => 'required|exists:gestioni,id_gestione',
|
|
'tipo_documento' => 'required|string',
|
|
'numero_documento' => 'required|string',
|
|
'data_documento' => 'required|date',
|
|
'data_registrazione' => 'required|date',
|
|
'fornitore_id' => 'nullable|exists:fornitori,id_fornitore',
|
|
'descrizione' => 'required|string',
|
|
'note' => 'nullable|string',
|
|
'importo_totale' => 'required|numeric|min:0.01',
|
|
'importo_iva' => 'nullable|numeric|min:0',
|
|
'ritenuta_acconto' => 'nullable|numeric|min:0',
|
|
'righe_contabili' => 'required|array|min:2',
|
|
'righe_contabili.*.conto_id' => 'required|exists:piano_conti,id',
|
|
'righe_contabili.*.tipo_riga' => 'required|in:dare,avere',
|
|
'righe_contabili.*.importo' => 'required|numeric|min:0.01',
|
|
'righe_contabili.*.descrizione' => 'nullable|string',
|
|
'ripartizioni' => 'nullable|array',
|
|
'ripartizioni.*.tabella_millesimale_id' => 'required_with:ripartizioni|exists:tabelle_millesimali,id',
|
|
'ripartizioni.*.voce_spesa_id' => 'required_with:ripartizioni|exists:voci_spesa,id'
|
|
]);
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
// Verifica quadratura dare/avere
|
|
$totaleDare = collect($request->righe_contabili)
|
|
->where('tipo_riga', 'dare')
|
|
->sum('importo');
|
|
|
|
$totaleAvere = collect($request->righe_contabili)
|
|
->where('tipo_riga', 'avere')
|
|
->sum('importo');
|
|
|
|
if (abs($totaleDare - $totaleAvere) > 0.01) {
|
|
throw new \Exception('La registrazione non è quadrata. Dare: €' . number_format($totaleDare, 2) . ' - Avere: €' . number_format($totaleAvere, 2));
|
|
}
|
|
|
|
// Genera protocolli
|
|
$protocolloGenerale = $this->generaProtocolloGenerale($request->stabile_id);
|
|
$protocolloGestione = $this->generaProtocolloGestione($request->stabile_id, $request->gestione_id);
|
|
|
|
// Crea transazione principale
|
|
$transazione = TransazioneContabile::create([
|
|
'stabile_id' => $request->stabile_id,
|
|
'gestione_id' => $request->gestione_id,
|
|
'fornitore_id' => $request->fornitore_id,
|
|
'protocollo_generale' => $protocolloGenerale,
|
|
'protocollo_gestione' => $protocolloGestione,
|
|
'tipo_documento' => $request->tipo_documento,
|
|
'numero_documento' => $request->numero_documento,
|
|
'data_documento' => $request->data_documento,
|
|
'data_registrazione' => $request->data_registrazione,
|
|
'descrizione' => $request->descrizione,
|
|
'note' => $request->note,
|
|
'importo_totale' => $request->importo_totale,
|
|
'importo_iva' => $request->importo_iva ?? 0,
|
|
'ritenuta_acconto' => $request->ritenuta_acconto ?? 0,
|
|
'stato' => 'confermata',
|
|
'quadrata' => true,
|
|
'utente_id' => Auth::id()
|
|
]);
|
|
|
|
// Crea righe contabili
|
|
foreach ($request->righe_contabili as $riga) {
|
|
RigaContabile::create([
|
|
'transazione_id' => $transazione->id,
|
|
'conto_id' => $riga['conto_id'],
|
|
'tipo_riga' => $riga['tipo_riga'],
|
|
'importo' => $riga['importo'],
|
|
'descrizione' => $riga['descrizione'] ?? null
|
|
]);
|
|
}
|
|
|
|
// Gestione ripartizioni automatiche se presenti
|
|
if ($request->has('ripartizioni') && count($request->ripartizioni) > 0) {
|
|
$this->processaRipartizioni($transazione, $request->ripartizioni);
|
|
}
|
|
|
|
// Aggiorna saldi real-time tramite trigger SQL
|
|
DB::statement('CALL sp_aggiorna_saldi_transazione(?)', [$transazione->id]);
|
|
|
|
// Registra nel protocollo
|
|
ProtocolloRegistrazione::create([
|
|
'stabile_id' => $request->stabile_id,
|
|
'gestione_id' => $request->gestione_id,
|
|
'transazione_id' => $transazione->id,
|
|
'protocollo_generale' => $protocolloGenerale,
|
|
'protocollo_gestione' => $protocolloGestione,
|
|
'data_registrazione' => $request->data_registrazione,
|
|
'tipo_protocollo' => 'contabile',
|
|
'utente_id' => Auth::id()
|
|
]);
|
|
|
|
DB::commit();
|
|
|
|
return redirect()
|
|
->route('admin.registrazioni.show', $transazione)
|
|
->with('success', 'Registrazione contabile salvata con successo. Protocollo: ' . $protocolloGenerale);
|
|
|
|
} catch (\Exception $e) {
|
|
DB::rollback();
|
|
return back()
|
|
->withInput()
|
|
->withErrors(['error' => 'Errore durante il salvataggio: ' . $e->getMessage()]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mostra una registrazione
|
|
*/
|
|
public function show(TransazioneContabile $transazione)
|
|
{
|
|
$transazione->load([
|
|
'stabile',
|
|
'gestione',
|
|
'fornitore',
|
|
'righe.conto',
|
|
'ripartizioni.tabellaMillesimale',
|
|
'ripartizioni.voceSpesa',
|
|
'documentiAllegati'
|
|
]);
|
|
|
|
return view('admin.registrazioni.show', compact('transazione'));
|
|
}
|
|
|
|
/**
|
|
* API: Ottieni template per tipo documento
|
|
*/
|
|
public function getTemplate($tipoDocumento)
|
|
{
|
|
$templates = [
|
|
'fattura_passiva' => [
|
|
'righe_suggerite' => [
|
|
['conto' => '6000', 'tipo' => 'dare', 'descrizione' => 'Costo per servizi'],
|
|
['conto' => '1250', 'tipo' => 'dare', 'descrizione' => 'IVA a credito'],
|
|
['conto' => '2000', 'tipo' => 'avere', 'descrizione' => 'Debito verso fornitore']
|
|
]
|
|
],
|
|
'bonifico' => [
|
|
'righe_suggerite' => [
|
|
['conto' => '2000', 'tipo' => 'dare', 'descrizione' => 'Estinzione debito'],
|
|
['conto' => '1000', 'tipo' => 'avere', 'descrizione' => 'Uscita da banca']
|
|
]
|
|
],
|
|
'incasso' => [
|
|
'righe_suggerite' => [
|
|
['conto' => '1000', 'tipo' => 'dare', 'descrizione' => 'Entrata in banca'],
|
|
['conto' => '3000', 'tipo' => 'avere', 'descrizione' => 'Estinzione credito']
|
|
]
|
|
]
|
|
];
|
|
|
|
return response()->json($templates[$tipoDocumento] ?? []);
|
|
}
|
|
|
|
/**
|
|
* API: Calcola ripartizione automatica
|
|
*/
|
|
public function calcolaRipartizione(Request $request)
|
|
{
|
|
$request->validate([
|
|
'importo' => 'required|numeric|min:0',
|
|
'tabella_millesimale_id' => 'required|exists:tabelle_millesimali,id',
|
|
'voce_spesa_id' => 'required|exists:voci_spesa,id'
|
|
]);
|
|
|
|
$tabella = TabellaMillesimale::with('quote')->find($request->tabella_millesimale_id);
|
|
$importo = $request->importo;
|
|
|
|
$ripartizioni = [];
|
|
$totaleQuote = $tabella->quote->sum('quota_millesimi');
|
|
|
|
foreach ($tabella->quote as $quota) {
|
|
$importoQuota = round(($importo * $quota->quota_millesimi) / $totaleQuote, 2);
|
|
|
|
$ripartizioni[] = [
|
|
'condomino_id' => $quota->condomino_id,
|
|
'quota_millesimi' => $quota->quota_millesimi,
|
|
'importo' => $importoQuota,
|
|
'condomino' => $quota->condomino->ragione_sociale ?? 'N/A'
|
|
];
|
|
}
|
|
|
|
return response()->json([
|
|
'ripartizioni' => $ripartizioni,
|
|
'totale_ripartito' => array_sum(array_column($ripartizioni, 'importo')),
|
|
'tabella_nome' => $tabella->nome
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Genera protocollo generale annuale
|
|
*/
|
|
private function generaProtocolloGenerale($stabileId)
|
|
{
|
|
$anno = now()->year;
|
|
|
|
$ultimoProtocollo = ProtocolloRegistrazione::where('stabile_id', $stabileId)
|
|
->where('tipo_protocollo', 'contabile')
|
|
->whereYear('data_registrazione', $anno)
|
|
->max('protocollo_generale');
|
|
|
|
$numeroProtocollo = $ultimoProtocollo ? (intval(substr($ultimoProtocollo, -4)) + 1) : 1;
|
|
|
|
return sprintf('%d-%04d', $anno, $numeroProtocollo);
|
|
}
|
|
|
|
/**
|
|
* Genera protocollo per gestione
|
|
*/
|
|
private function generaProtocolloGestione($stabileId, $gestioneId)
|
|
{
|
|
$anno = now()->year;
|
|
$gestione = Gestione::find($gestioneId);
|
|
|
|
$ultimoProtocollo = ProtocolloRegistrazione::where('stabile_id', $stabileId)
|
|
->where('gestione_id', $gestioneId)
|
|
->where('tipo_protocollo', 'contabile')
|
|
->whereYear('data_registrazione', $anno)
|
|
->max('protocollo_gestione');
|
|
|
|
$numeroProtocollo = $ultimoProtocollo ? (intval(substr($ultimoProtocollo, -4)) + 1) : 1;
|
|
|
|
return sprintf('%s-%d-%04d', strtoupper($gestione->tipo_gestione), $anno, $numeroProtocollo);
|
|
}
|
|
|
|
/**
|
|
* Processa ripartizioni automatiche
|
|
*/
|
|
private function processaRipartizioni($transazione, $ripartizioni)
|
|
{
|
|
foreach ($ripartizioni as $ripartizione) {
|
|
// Logica per creare ripartizioni automatiche
|
|
// Implementazione dettagliata delle ripartizioni condominiali
|
|
}
|
|
}
|
|
}
|