netgescon-day0/app/Modules/Contabilita/Services/SituazioneInizialePrimaNotaService.php

195 lines
8.1 KiB
PHP

<?php
namespace App\Modules\Contabilita\Services;
use App\Models\GestioneContabile;
use App\Models\User;
use App\Modules\Contabilita\Models\Movimento;
use App\Modules\Contabilita\Models\Registrazione;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use RuntimeException;
class SituazioneInizialePrimaNotaService
{
/**
* Genera una registrazione di "bilancio di apertura" a partire dalle tabelle legacy importate.
*
* Logica volutamente minimale:
* - Debiti/Fondi: somma importo_euro da gescon_import.cre_deb_preced con c_d = 'D' (incluso=1)
* - Crediti: somma importo_euro da gescon_import.cre_deb_preced con c_d = 'C' (incluso=1)
* - Conguagli: somma cons_euro da gescon_import.dett_tab con cod_tab like 'CONG.%' (include negativi)
* - I conguagli vengono aggregati ai crediti verso condomini (se negativi riducono il credito complessivo)
* - Contropartita: conto speciale di apertura esercizio
*/
public function genera(
User $user,
int $stabileId,
GestioneContabile $gestione,
string $dataRegistrazione,
string $codStabileLegacy,
?string $legacyYear = null,
): Registrazione {
if (! Schema::hasColumn('contabilita_registrazioni', 'gestione_id')) {
throw new RuntimeException('Prima nota non supporta gestione_id. Eseguire le migrazioni.');
}
if (Schema::hasTable('contabilita_chiusure_gestione')) {
$chiusa = app(ChiusuraGestioneService::class)->isGestioneChiusa((int) $gestione->id);
if ($chiusa) {
throw new RuntimeException('Gestione chiusa: non è possibile generare nuove registrazioni.');
}
}
if (! Schema::connection('gescon_import')->hasTable('cre_deb_preced')) {
throw new RuntimeException('Tabella staging cre_deb_preced non presente. Importare prima dal MDB.');
}
if (! Schema::connection('gescon_import')->hasTable('dett_tab')) {
throw new RuntimeException('Tabella staging dett_tab non presente. Importare prima dal MDB.');
}
return DB::transaction(function () use ($user, $stabileId, $gestione, $dataRegistrazione, $codStabileLegacy, $legacyYear) {
$debiti = $this->sumCreDebPreced($codStabileLegacy, 'D', $legacyYear);
$crediti = $this->sumCreDebPreced($codStabileLegacy, 'C', $legacyYear);
$conguagli = $this->sumConguagli($codStabileLegacy, $legacyYear);
$creditiNetti = round($crediti + $conguagli, 2);
$debiti = round($debiti, 2);
$contoApertura = app(ChiusuraGestioneService::class)->resolveOrCreateConto(
(string) config('contabilita.conti_speciali.apertura_codice', ChiusuraGestioneService::CODICE_CONTO_APERTURA),
(string) config('contabilita.conti_speciali.apertura_descrizione', 'Conto apertura esercizio'),
(string) config('contabilita.conti_speciali.apertura_tipo', 'Patrimonio Netto'),
);
$contoCrediti = app(ChiusuraGestioneService::class)->resolveOrCreateConto(
(string) config('contabilita.conti_speciali.crediti_condomini_codice', '1100'),
(string) config('contabilita.conti_speciali.crediti_condomini_descrizione', 'Crediti verso condomini'),
(string) config('contabilita.conti_speciali.crediti_condomini_tipo', 'Attività'),
);
$contoDebiti = app(ChiusuraGestioneService::class)->resolveOrCreateConto(
(string) config('contabilita.conti_speciali.debiti_fornitori_codice', '2000'),
(string) config('contabilita.conti_speciali.debiti_fornitori_descrizione', 'Debiti verso fornitori'),
(string) config('contabilita.conti_speciali.debiti_fornitori_tipo', 'Passività'),
);
$regPayload = [
'stabile_id' => $stabileId,
'gestione_id' => Registrazione::resolveGestioneIdOrDefault((int) $gestione->id, $stabileId, $dataRegistrazione),
'data_registrazione' => $dataRegistrazione,
'descrizione' => 'Bilancio di apertura (situazione iniziale import)',
'created_by' => (int) $user->id,
'updated_by' => (int) $user->id,
];
if (Schema::hasColumn('contabilita_registrazioni', 'user_id')) {
$regPayload['user_id'] = (int) $user->id;
}
/** @var Registrazione $reg */
$reg = Registrazione::query()->create($regPayload);
$totDare = 0.0;
$totAvere = 0.0;
if (abs($creditiNetti) >= 0.005) {
if ($creditiNetti > 0) {
Movimento::query()->create([
'registrazione_id' => $reg->id,
'conto_id' => $contoCrediti->id,
'tipo' => 'dare',
'importo' => $creditiNetti,
]);
$totDare += $creditiNetti;
} else {
$imp = abs($creditiNetti);
Movimento::query()->create([
'registrazione_id' => $reg->id,
'conto_id' => $contoCrediti->id,
'tipo' => 'avere',
'importo' => $imp,
]);
$totAvere += $imp;
}
}
if (abs($debiti) >= 0.005) {
if ($debiti > 0) {
Movimento::query()->create([
'registrazione_id' => $reg->id,
'conto_id' => $contoDebiti->id,
'tipo' => 'avere',
'importo' => $debiti,
]);
$totAvere += $debiti;
} else {
$imp = abs($debiti);
Movimento::query()->create([
'registrazione_id' => $reg->id,
'conto_id' => $contoDebiti->id,
'tipo' => 'dare',
'importo' => $imp,
]);
$totDare += $imp;
}
}
$diff = round($totDare - $totAvere, 2);
if ($diff > 0) {
Movimento::query()->create([
'registrazione_id' => $reg->id,
'conto_id' => $contoApertura->id,
'tipo' => 'avere',
'importo' => $diff,
]);
} elseif ($diff < 0) {
Movimento::query()->create([
'registrazione_id' => $reg->id,
'conto_id' => $contoApertura->id,
'tipo' => 'dare',
'importo' => abs($diff),
]);
}
$reg->assertBilanciata();
return $reg;
});
}
private function sumCreDebPreced(string $codStabileLegacy, string $cd, ?string $legacyYear): float
{
$q = DB::connection('gescon_import')->table('cre_deb_preced')
->where('cod_stabile', $codStabileLegacy)
->whereRaw('UPPER(c_d) = ?', [strtoupper($cd)]);
if (Schema::connection('gescon_import')->hasColumn('cre_deb_preced', 'incluso')) {
$q->where('incluso', 1);
}
if ($legacyYear !== null && $legacyYear !== '' && Schema::connection('gescon_import')->hasColumn('cre_deb_preced', 'legacy_year')) {
$q->where('legacy_year', $legacyYear);
}
return (float) ($q->sum('importo_euro') ?: 0);
}
private function sumConguagli(string $codStabileLegacy, ?string $legacyYear): float
{
$q = DB::connection('gescon_import')->table('dett_tab')
->where('cod_tab', 'like', 'CONG.%');
if (Schema::connection('gescon_import')->hasColumn('dett_tab', 'cod_stabile')) {
$q->where('cod_stabile', $codStabileLegacy);
}
if ($legacyYear !== null && $legacyYear !== '' && Schema::connection('gescon_import')->hasColumn('dett_tab', 'legacy_year')) {
$q->where('legacy_year', $legacyYear);
}
return (float) ($q->sum('cons_euro') ?: 0);
}
}