0: usa (dare=conto_dare_id, avere=conto_avere_id) * - Se importo < 0: inverte automaticamente dare/avere (perché banca esce) */ public function generaRegistrazioneDaMovimento(User $user, MovimentoBanca $movimento): Registrazione { if (! Schema::hasTable('contabilita_registrazioni') || ! Schema::hasTable('contabilita_movimenti')) { throw new RuntimeException('Tabelle prima nota mancanti.'); } if ($movimento->registrazione_id) { $existing = Registrazione::query()->find((int) $movimento->registrazione_id); if ($existing) { return $existing; } } $stabileId = (int) ($movimento->stabile_id ?? 0); if ($stabileId <= 0) { throw new RuntimeException('Movimento banca senza stabile_id.'); } $gestioneId = (int) ($movimento->gestione_id ?? 0); if ($gestioneId <= 0) { throw new RuntimeException('Seleziona una gestione per questo movimento banca.'); } if (Schema::hasTable('contabilita_chiusure_gestione')) { $chiusa = app(ChiusuraGestioneService::class)->isGestioneChiusa($gestioneId); if ($chiusa) { throw new RuntimeException('Gestione chiusa: non è possibile generare nuove registrazioni.'); } } $causale = is_string($movimento->causale) ? trim((string) $movimento->causale) : ''; $chiave = $causale !== '' ? $causale : 'default'; $regola = RegolaPrimaNota::query() ->where('stabile_id', $stabileId) ->where('origine', 'banca') ->where('chiave', $chiave) ->where('attiva', true) ->first(); if (! $regola) { $regola = RegolaPrimaNota::query() ->where('stabile_id', $stabileId) ->where('origine', 'banca') ->where('chiave', 'default') ->where('attiva', true) ->first(); } if (! $regola || ! $regola->conto_dare_id || ! $regola->conto_avere_id) { throw new RuntimeException('Regola prima nota banca non configurata (origine=banca, chiave=' . $chiave . ' o default).'); } $importo = (float) ($movimento->importo ?? 0); if (abs($importo) < 0.005) { throw new RuntimeException('Importo movimento banca non valido.'); } $amount = round(abs($importo), 2); $descr = is_string($movimento->descrizione) ? trim((string) $movimento->descrizione) : ''; if ($descr === '') { $descr = 'Movimento banca'; } $data = $movimento->data ? $movimento->data->toDateString() : now()->toDateString(); return DB::transaction(function () use ($user, $movimento, $stabileId, $gestioneId, $regola, $data, $descr, $amount, $importo) { $swap = $importo < 0; $contoDare = (int) ($swap ? $regola->conto_avere_id : $regola->conto_dare_id); $contoAvere = (int) ($swap ? $regola->conto_dare_id : $regola->conto_avere_id); $prot = null; if ( Schema::hasColumn('contabilita_registrazioni', 'protocollo_completo') && Schema::hasTable('gestioni_contabili') ) { $g = GestioneContabile::query()->lockForUpdate()->find($gestioneId); if ($g) { $prot = $g->getNextProtocollo(); } } $regPayload = [ 'stabile_id' => $stabileId, 'gestione_id' => (Schema::hasColumn('contabilita_registrazioni', 'gestione_id') ? Registrazione::resolveGestioneIdOrDefault($gestioneId, $stabileId, $data) : null), 'data_registrazione' => $data, 'descrizione' => $descr, '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); if (is_array($prot) && ! empty($prot['completo'])) { $reg->fill([ 'protocollo_prefix' => $prot['prefix'] ?? null, 'protocollo_numero' => $prot['numero'] ?? null, 'protocollo_completo' => $prot['completo'] ?? null, ]); $reg->save(); } Movimento::query()->create([ 'registrazione_id' => (int) $reg->id, 'conto_id' => $contoDare, 'tipo' => 'dare', 'importo' => $amount, ]); Movimento::query()->create([ 'registrazione_id' => (int) $reg->id, 'conto_id' => $contoAvere, 'tipo' => 'avere', 'importo' => $amount, ]); $reg->assertBilanciata(); $movimento->registrazione_id = (int) $reg->id; $movimento->save(); return $reg; }); } }