option('dry-run'); $filterIds = collect((array) $this->option('fornitore-id')) ->map(fn($v) => (int) $v) ->filter(fn(int $v) => $v > 0) ->values() ->all(); $query = Fornitore::query(); if ($filterIds !== []) { $query->whereIn('id', $filterIds); } $fornitori = $query->get(); if ($fornitori->isEmpty()) { $this->warn('Nessun fornitore trovato per i filtri richiesti.'); return self::SUCCESS; } $created = 0; $updated = 0; $linked = 0; $skipped = 0; foreach ($fornitori as $fornitore) { $target = null; if ((int) ($fornitore->rubrica_id ?? 0) > 0) { $target = RubricaUniversale::query()->find((int) $fornitore->rubrica_id); } if (! $target) { $target = $this->findRubricaCandidate($fornitore); } $payload = [ 'tipo_contatto' => 'persona_giuridica', 'ragione_sociale' => $fornitore->ragione_sociale ?: trim(($fornitore->nome ?: '') . ' ' . ($fornitore->cognome ?: '')), 'nome' => $fornitore->nome, 'cognome' => $fornitore->cognome, 'partita_iva' => $fornitore->partita_iva, 'codice_fiscale' => $fornitore->codice_fiscale, 'indirizzo' => $fornitore->indirizzo, 'civico' => $fornitore->civico, 'cap' => $fornitore->cap, 'citta' => $fornitore->citta, 'provincia' => $fornitore->provincia, 'nazione' => $fornitore->nazione, 'email' => $fornitore->email, 'pec' => $fornitore->pec, 'telefono_ufficio' => $this->normalizePhone($fornitore->telefono), 'telefono_cellulare' => $this->normalizePhone($fornitore->cellulare), 'sito_web' => $fornitore->sito_web, 'note' => $fornitore->note, 'categoria' => 'fornitore', 'stato' => 'attivo', 'data_ultima_modifica' => now()->toDateString(), ]; if (! $target) { if ($dryRun) { $this->line("[DRY] Crea rubrica per fornitore #{$fornitore->id}"); } else { $target = RubricaUniversale::query()->create(array_merge($payload, [ 'data_inserimento' => now()->toDateString(), ])); $created++; } } else { $dirty = $this->isDirtyPayload($target, $payload); if (! $dirty) { $skipped++; } elseif ($dryRun) { $this->line("[DRY] Aggiorna rubrica #{$target->id} da fornitore #{$fornitore->id}"); } else { $target->fill($payload); $target->save(); $updated++; } } if (! $dryRun && $target && (int) ($fornitore->rubrica_id ?? 0) !== (int) $target->id) { $fornitore->rubrica_id = (int) $target->id; $fornitore->save(); $linked++; } } $this->info("Sync fornitori completato: creati {$created}, aggiornati {$updated}, collegati {$linked}, invariati {$skipped}." . ($dryRun ? ' (dry-run)' : '')); return self::SUCCESS; } private function findRubricaCandidate(Fornitore $fornitore): ?RubricaUniversale { $query = RubricaUniversale::query()->where('categoria', 'fornitore'); if (! empty($fornitore->partita_iva)) { $match = (clone $query)->where('partita_iva', $fornitore->partita_iva)->first(); if ($match) { return $match; } } if (! empty($fornitore->codice_fiscale)) { $match = (clone $query)->where('codice_fiscale', $fornitore->codice_fiscale)->first(); if ($match) { return $match; } } if (! empty($fornitore->email)) { $match = (clone $query)->where('email', $fornitore->email)->first(); if ($match) { return $match; } } if (! empty($fornitore->ragione_sociale)) { return (clone $query)->where('ragione_sociale', $fornitore->ragione_sociale)->first(); } return null; } private function normalizePhone(?string $phone): ?string { if (! is_string($phone) || trim($phone) === '') { return null; } return PhoneNumber::toE164Italy($phone); } private function isDirtyPayload(RubricaUniversale $rubrica, array $payload): bool { foreach ($payload as $key => $value) { if ((string) ($rubrica->{$key} ?? '') !== (string) ($value ?? '')) { return true; } } return false; } }