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) (($override['gestione_id'] ?? null) ?: ($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.'); } } $importo = (float) ($movimento->importo ?? 0); if (abs($importo) < 0.005) { throw new RuntimeException('Importo movimento banca non valido.'); } // Pagamento fornitore: tipicamente uscita (importo < 0). Accettiamo comunque il valore assoluto. $amount = round(abs($importo), 2); $contoFinanziarioId = (int) (($override['conto_finanziario_id'] ?? null) ?: 0); if ($contoFinanziarioId <= 0) { $contoFinanziarioId = (int) app(ContiFinanziariService::class) ->resolveContoFinanziarioDaMovimentoBanca($movimento) ->id; } $contoFinanziario = PianoConti::query()->find($contoFinanziarioId); if (! $contoFinanziario) { throw new RuntimeException('Conto finanziario non valido.'); } $fornitore = Fornitore::query()->find($fornitoreId); $fornitoreLabel = $fornitore && is_string($fornitore->ragione_sociale ?? null) ? trim((string) $fornitore->ragione_sociale) : null; $fornitoreCode = $fornitore && is_string($fornitore->codice_univoco ?? null) ? trim((string) $fornitore->codice_univoco) : null; $fattura = null; $fatturaId = (int) (($override['fattura_fornitore_id'] ?? null) ?: 0); if ($fatturaId > 0 && Schema::hasTable('contabilita_fatture_fornitori')) { $fattura = FatturaFornitore::query()->find($fatturaId); if (! $fattura) { throw new RuntimeException('Fattura fornitore non trovata.'); } if ((int) ($fattura->fornitore_id ?? 0) !== $fornitoreId) { throw new RuntimeException('La fattura selezionata non appartiene al fornitore indicato.'); } if ((int) ($fattura->gestione_id ?? 0) > 0 && $gestioneId <= 0) { $gestioneId = (int) $fattura->gestione_id; } } $contoDebitoFornitore = app(ContiSoggettiService::class)->resolveContoDebitoFornitore( $stabileId, $fornitoreId, $fornitoreLabel, $fornitoreCode ); $data = isset($override['data_registrazione']) && is_string($override['data_registrazione']) ? trim((string) $override['data_registrazione']) : null; $data = $data !== '' ? $data : null; $data = $data ?: ($movimento->data ? $movimento->data->toDateString() : now()->toDateString()); $descr = isset($override['descrizione']) && is_string($override['descrizione']) ? trim((string) $override['descrizione']) : ''; if ($descr === '') { $base = is_string($movimento->descrizione) ? trim((string) $movimento->descrizione) : ''; $descr = $base !== '' ? $base : 'Pagamento fornitore'; } return DB::transaction(function () use ($user, $movimento, $stabileId, $gestioneId, $data, $descr, $amount, $contoFinanziarioId, $contoDebitoFornitore, $fornitoreId, $fattura) { $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); // Dare: diminuisce il debito verso fornitore Movimento::query()->create([ 'registrazione_id' => (int) $reg->id, 'conto_id' => (int) $contoDebitoFornitore->id, 'tipo' => 'dare', 'importo' => $amount, ]); // Avere: diminuisce la banca/cassa Movimento::query()->create([ 'registrazione_id' => (int) $reg->id, 'conto_id' => $contoFinanziarioId, 'tipo' => 'avere', 'importo' => $amount, ]); $reg->assertBilanciata(); $movimento->registrazione_id = (int) $reg->id; $movimento->gestione_id = $gestioneId; if (Schema::hasColumn('contabilita_movimenti_banca', 'fornitore_id')) { $movimento->fornitore_id = $fornitoreId; } $movimento->save(); if ($fattura) { $fattura->data_pagamento = $fattura->data_pagamento ?: $data; $fattura->movimento_pagamento_id = (int) $movimento->id; $fattura->save(); $this->syncRegistroRitenutaDaPagamento($fattura, $gestioneId, $data); } return $reg; }); } private function syncRegistroRitenutaDaPagamento(FatturaFornitore $fattura, int $gestioneId, string $dataPagamento): void { if (! Schema::hasTable('registro_ritenute_acconto')) { return; } $ritenutaImporto = round((float) ($fattura->ritenuta_importo ?? 0), 4); $ritenutaAliquota = round((float) ($fattura->ritenuta_aliquota ?? 0), 2); if ($ritenutaImporto <= 0 || $ritenutaAliquota <= 0) { return; } $dataPagamentoCarbon = Carbon::parse($dataPagamento)->startOfDay(); $dataCompetenza = $fattura->data_documento?->copy() ?: $fattura->data_registrazione?->copy() ?: $dataPagamentoCarbon->copy(); $scadenzaVersamento = $dataPagamentoCarbon->copy()->addMonthNoOverflow()->day(16); $tenantId = ''; if (Schema::hasTable('gestioni_contabili')) { $gestione = \App\Models\GestioneContabile::query()->find($gestioneId); $tenantId = is_string($gestione?->tenant_id ?? null) ? trim((string) $gestione->tenant_id) : ''; } if ($tenantId === '') { $stabile = Stabile::query() ->with('amministratore:id,codice_amministratore') ->select(['id', 'amministratore_id']) ->find((int) $fattura->stabile_id); $tenantId = is_string($stabile?->amministratore?->codice_amministratore ?? null) ? trim((string) $stabile->amministratore->codice_amministratore) : ''; } $registro = RegistroRitenuteAcconto::query() ->where('gestione_id', $gestioneId) ->where(function ($query) use ($fattura, $dataCompetenza, $ritenutaImporto) { $query->where('fattura_id', (int) $fattura->id) ->orWhere(function ($sub) use ($fattura, $dataCompetenza, $ritenutaImporto) { $sub->where('fornitore_id', (int) $fattura->fornitore_id) ->whereDate('data_competenza', $dataCompetenza->toDateString()) ->where('importo_ritenuta', $ritenutaImporto); }); }) ->orderByDesc('id') ->first(); if (! $registro) { $registro = new RegistroRitenuteAcconto(); $registro->gestione_id = $gestioneId; $registro->numero_progressivo = ((int) (RegistroRitenuteAcconto::query() ->where('gestione_id', $gestioneId) ->lockForUpdate() ->max('numero_progressivo') ?? 0)) + 1; $registro->stato_versamento = 'da_versare'; $registro->fornitore_id = (int) $fattura->fornitore_id; $registro->fattura_id = (int) $fattura->id; } $registro->tenant_id = $tenantId !== '' ? $tenantId : 'stabile-' . (int) $fattura->stabile_id; $registro->data_competenza = $dataCompetenza->toDateString(); $registro->data_pagamento_fattura = $dataPagamentoCarbon->toDateString(); $registro->imponibile = round((float) ($fattura->imponibile ?? 0), 4); $registro->aliquota_ritenuta = $ritenutaAliquota; $registro->importo_ritenuta = $ritenutaImporto; $registro->codice_tributo = trim((string) ($fattura->ritenuta_codice_tributo ?? '')) ?: '1040'; $registro->tipo_ritenuta = trim((string) ($fattura->ritenuta_previdenziale_codice ?? '')) ?: 'professionale'; $registro->data_scadenza_versamento = $scadenzaVersamento->toDateString(); $registro->anno_dichiarazione = (int) $dataCompetenza->format('Y'); $registro->save(); } }