argument('stabile_id'); if ($stabileId <= 0) { $this->error('stabile_id non valido'); return self::FAILURE; } $dry = (bool) $this->option('dry-run'); $fixMismatches = (bool) $this->option('fix-mismatches'); $stabile = Stabile::query()->select(['id', 'amministratore_id'])->find($stabileId); if (! $stabile) { $this->error('Stabile non trovato'); return self::FAILURE; } $adminId = (int) ($stabile->amministratore_id ?: 0); if ($adminId <= 0) { $this->error('Stabile senza amministratore_id'); return self::FAILURE; } $fattureQuery = FatturaFornitore::query() ->where('stabile_id', $stabileId) ->whereNotNull('fattura_elettronica_id'); if (! $fixMismatches) { $fattureQuery->whereNull('fornitore_id'); } $fatture = $fattureQuery ->orderBy('id') ->get(['id', 'fattura_elettronica_id', 'fornitore_id']); $this->info( $fixMismatches ? 'Fatture contabili da verificare: ' . $fatture->count() : 'Fatture contabili senza fornitore_id: ' . $fatture->count() ); $updated = 0; $skipped = 0; foreach ($fatture as $fattura) { $feId = (int) ($fattura->fattura_elettronica_id ?: 0); if ($feId <= 0) { $skipped++; continue; } $fe = FatturaElettronica::query()->find($feId); if (! $fe) { $skipped++; continue; } $piva = $this->normalizeId($fe->fornitore_piva); $cf = $this->normalizeId($fe->fornitore_cf); $fornitoreId = $this->matchFornitoreIdForAdmin($adminId, $piva, $cf); if (! $fornitoreId) { $skipped++; continue; } if ((int) ($fattura->fornitore_id ?: 0) === $fornitoreId) { $skipped++; continue; } $updated++; if ($dry) { $this->line("[dry-run] fattura_id={$fattura->id} -> fornitore_id={$fornitoreId}"); continue; } DB::transaction(function () use ($fattura, $fe, $fornitoreId): void { $fattura->fornitore_id = $fornitoreId; $fattura->save(); if ((int) ($fe->fornitore_id ?: 0) !== $fornitoreId) { $fe->fornitore_id = $fornitoreId; $fe->save(); } }); } $this->info('✅ Completato' . ($dry ? ' (dry-run)' : '')); $this->line(json_encode([ 'stabile_id' => $stabileId, 'amministratore_id' => $adminId, 'fix_mismatches' => $fixMismatches, 'updated' => $updated, 'skipped' => $skipped, ], JSON_UNESCAPED_UNICODE)); return self::SUCCESS; } private function normalizeId(?string $value): string { $value = strtoupper(trim((string) ($value ?? ''))); $value = str_replace(' ', '', $value); return $value; } private function matchFornitoreIdForAdmin(int $adminId, string $pivaNorm, string $cfNorm): ?int { $base = Fornitore::query()->where('amministratore_id', $adminId); if ($pivaNorm !== '' && $pivaNorm !== 'ND') { $match = (clone $base) ->whereRaw("REPLACE(UPPER(partita_iva), ' ', '') = ?", [$pivaNorm]) ->value('id'); if ($match) { return (int) $match; } if (str_starts_with($pivaNorm, 'IT') && strlen($pivaNorm) > 2) { $pivaNoIt = substr($pivaNorm, 2); $match = (clone $base) ->whereRaw("REPLACE(UPPER(partita_iva), ' ', '') = ?", [$pivaNoIt]) ->value('id'); if ($match) { return (int) $match; } } } if ($cfNorm !== '' && $cfNorm !== 'ND') { $match = (clone $base) ->whereRaw("REPLACE(UPPER(codice_fiscale), ' ', '') = ?", [$cfNorm]) ->value('id'); if ($match) { return (int) $match; } } return null; } }