find((int) $this->argument('amministratore_id')); if (! $amministratore instanceof Amministratore) { $this->error('Amministratore non trovato.'); return self::FAILURE; } $cf = $this->normalizeTaxId((string) $this->argument('codice_fiscale')); if ($cf === '') { $this->error('Codice fiscale / P.IVA non valido.'); return self::FAILURE; } $from = $this->parseYmd((string) $this->option('from')); $to = $this->parseYmd((string) $this->option('to')); if (! $from || ! $to) { $this->error('Specificare --from=YYYY-MM-DD e --to=YYYY-MM-DD'); return self::FAILURE; } if ($from > $to) { $this->error('Intervallo date non valido.'); return self::FAILURE; } $label = trim((string) $this->option('label')); if ($label === '') { $label = 'Archivio FE separato ' . $cf; } $stabile = $this->ensureDedicatedStabile($amministratore, $cf, $label); $periods = (string) $this->option('quarterly') === '1' ? $this->splitQuarterly($from, $to) : [[$from, $to]]; $rows = []; $hasErrors = false; foreach ($periods as [$dal, $al]) { $result = $service->downloadAndImport( $amministratore, $stabile, $dal, $al, (bool) ((int) $this->option('metadati') === 1), (int) $this->option('user_id'), [ 'force_update' => (int) $this->option('force_update') === 1, 'create_fornitore_if_missing' => (int) $this->option('create_fornitore_if_missing') === 1, 'importa_righe' => (string) $this->option('importa_righe'), 'no_skip' => (int) $this->option('force_update') === 1, ], ); $rows[] = [ 'periodo' => $dal->format('Y-m-d') . ' -> ' . $al->format('Y-m-d'), 'status' => (string) ($result['status'] ?? 'error'), 'imported' => (string) ((int) ($result['imported'] ?? 0)), 'duplicates' => (string) ((int) ($result['duplicates'] ?? 0)), 'errors' => (string) ((int) ($result['errors'] ?? 0)), 'files' => (string) ((int) ($result['files_total'] ?? 0)), 'message' => Str::limit((string) ($result['message'] ?? ''), 120, '...'), ]; if (($result['status'] ?? 'error') === 'error') { $hasErrors = true; } } $this->line('Contenitore separato: stabile #' . (int) $stabile->id . ' [' . (string) $stabile->codice_stabile . '] ' . (string) $stabile->denominazione); $this->table(['Periodo', 'Status', 'Importate', 'Duplicate', 'Errori', 'File', 'Messaggio'], $rows); return $hasErrors ? self::FAILURE : self::SUCCESS; } private function ensureDedicatedStabile(Amministratore $amministratore, string $cf, string $label): Stabile { $existing = Stabile::query() ->where('amministratore_id', (int) $amministratore->id) ->where('codice_fiscale', $cf) ->orderBy('id') ->first(); if ($existing instanceof Stabile) { $dirty = false; if (! filled($existing->denominazione)) { $existing->denominazione = $label; $dirty = true; } if (! filled($existing->cod_fisc_amministratore) && filled($amministratore->codice_fiscale_studio)) { $existing->cod_fisc_amministratore = (string) $amministratore->codice_fiscale_studio; $dirty = true; } if ($dirty) { $existing->save(); } return $existing; } return Stabile::query()->create([ 'amministratore_id' => (int) $amministratore->id, 'codice_stabile' => $this->nextDedicatedCode($amministratore, $cf), 'denominazione' => $label, 'codice_fiscale' => $cf, 'cod_fisc_amministratore' => (string) ($amministratore->codice_fiscale_studio ?? ''), 'indirizzo' => (string) ($amministratore->indirizzo_studio ?? 'Archivio separato FE'), 'cap' => (string) ($amministratore->cap_studio ?? '00000'), 'citta' => (string) ($amministratore->citta_studio ?? 'Roma'), 'provincia' => (string) ($amministratore->provincia_studio ?? 'RM'), 'attivo' => true, 'stato' => 'attivo', 'note' => 'Contenitore separato creato per import FE soggetto fiscale ' . $cf, 'amministratore_nome' => trim((string) (($amministratore->nome ?? '') . ' ' . ($amministratore->cognome ?? ''))), 'amministratore_email' => (string) ($amministratore->email_studio ?? ''), 'configurazione_avanzata' => ['scope' => 'fe_soggetto_separato'], ]); } private function nextDedicatedCode(Amministratore $amministratore, string $cf): string { $base = 'FE' . substr(preg_replace('/\D+/', '', $cf) ?: '000000', -6); $base = str_pad(substr($base, 0, 8), 8, '0'); $code = $base; $suffix = 1; while (Stabile::query()->where('codice_stabile', $code)->exists()) { $suffixText = str_pad((string) $suffix, 2, '0', STR_PAD_LEFT); $code = substr($base, 0, 6) . $suffixText; $suffix++; } return $code; } /** * @return array */ private function splitQuarterly(\DateTimeImmutable $from, \DateTimeImmutable $to): array { $periods = []; $cursor = $from; while ($cursor <= $to) { $quarter = intdiv(((int) $cursor->format('n')) - 1, 3) + 1; $quarterEndMonth = $quarter * 3; $quarterEnd = new \DateTimeImmutable($cursor->format('Y') . '-' . str_pad((string) $quarterEndMonth, 2, '0', STR_PAD_LEFT) . '-01'); $quarterEnd = $quarterEnd->modify('last day of this month'); if ($quarterEnd > $to) { $quarterEnd = $to; } $periods[] = [$cursor, $quarterEnd]; $cursor = $quarterEnd->modify('+1 day'); } return $periods; } private function parseYmd(string $value): ?\DateTimeImmutable { $value = trim($value); if ($value === '') { return null; } $date = \DateTimeImmutable::createFromFormat('Y-m-d', $value); return $date instanceof \DateTimeImmutable ? $date : null; } private function normalizeTaxId(string $value) : string { return strtoupper(trim(preg_replace('/\s+/', '', $value) ?? '')); } }