Cosa fa questo modulo
Modulo «Importer CSV con preview e mapping»: wizard riusabile per importare dati tabulari (CSV/Excel/TSV/ODS) da file caricato dall'utente verso qualunque entità del dominio (Cliente/Lead/Prodotto/Servizio/Stanza/Veicolo/Ordine/Fattura/Patient/Iscritto corso/Contatto newsletter/Movimento contabile) in modo configurabile e safe. Architettura wizard multi-step (Livewire o Vue): **Step 1 Upload** drag&drop area con validazione mime (`text/csv`/`application/vnd.ms-excel`/`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`/`text/tab-separated-values`/`application/vnd.oasis.opendocument.spreadsheet`) + size max configurabile (default 50MB), salvataggio temporaneo storage `imports/{uuid}/source.{ext}`, hash SHA-256 per dedup re-upload identico (skip parse + reuse mapping precedente opt.); **Step 2 Detect & Configure** auto-detect via `league/csv` o `box/spout` o `phpoffice/phpspreadsheet`: delimitatore (`,`/`;`/`\t`/`|` via sniffer su prime 10 righe count consistenza), encoding (UTF-8/ISO-8859-1/Windows-1252 via `mb_detect_encoding` + BOM detection auto-strip), enclosure (`"`/`'`), escape char, header row index (default 1, configurabile se prime righe sono metadata), sheet picker per Excel multi-sheet, range cell opt. (es. `A1:F1000` per skip totali/footer); UI mostra preview prime 20 righe in tabella scrollabile con header riconosciuto evidenziato + tipo dato inferito per colonna (string/int/decimal/date/email/url/bool/enum) + count righe totali stimato. **Step 3 Mapping colonne** drag&drop o select-based assegnazione colonna sorgente → campo modello destinazione, con suggerimenti automatici via fuzzy match (Levenshtein/Jaro-Winkler) tra header CSV e nome attributo modello (es. `nome_cliente`→`name`, `e-mail`→`email`, `telefono`→`phone`, `città`→`city`, `Codice Fiscale`→`tax_code`) + dizionario sinonimi multilingua IT/EN/DE/FR/ES configurabile (`first_name`↔`nome`↔`vorname`↔`prénom`↔`nombre`), badge confidenza match (verde >0.9, giallo 0.6-0.9, grigio <0.6 = chiedi conferma), opzione «ignora colonna» per dati non rilevanti, opzione «valore costante» (es. tutti i record importati hanno `source=csv_import_2026_05`), opzione «concatena colonne» (es. `nome`+` `+`cognome`→`full_name`), opzione «trasforma» (uppercase/lowercase/trim/replace regex/format date custom/parse decimal IT `1.234,56`→`1234.56`/normalizza phone E.164/sanitize HTML/strip emoji), required-field check (errore se field DB notNull senza mapping o senza default). Mapping salvabile come **preset** riusabile (nome + scope: utente/team/azienda/globale) → re-import successivi stessa fonte = mapping pre-compilato, versioning preset (cambia schema sorgente → diff mostrato). **Step 4 Validation & Dry-run** scan completo file con engine validation Laravel: regole per campo (`required`/`email`/`unique:table,col`/`exists:table,col`/`numeric`/`date_format:Y-m-d`/`in:val1,val2`/`regex:...`/`max:255`/custom rule callback), report errori riga-per-riga con: numero riga, colonna, valore originale, regola fallita, messaggio human-readable IT/EN; suggerimento fix automatico opzionale («14 righe hanno data formato `dd/mm/yyyy` invece di `yyyy-mm-dd` — applica conversione?»); summary cards: «1234 righe valide», «56 errori bloccanti», «12 warning non-bloccanti», «8 duplicati interni (stessa email)», «3 esistenti in DB (skip o update?)»; tabella errori paginata filtrabile/scaricabile (XLSX con highlight celle problematiche o CSV con colonna `_errors` appended); modalità dry-run = nessuna scrittura DB, solo report; toggle utente «proseguire ignorando le righe in errore» (skip-on-error) vs «abortire se anche solo una riga fallisce» (all-or-nothing transactional). **Step 5 Commit & Execute** scelta modalità: `insert_only` (errore su duplicato chiave), `upsert` (insert nuovi + update esistenti by unique key configurabile, es. `email`/`codice_fiscale`/`partita_iva`/`codice_articolo`), `update_only` (skip nuovi, aggiorna solo matching), `replace` (truncate+insert, con conferma esplicita testuale «SCRIVI REPLACE»); selezione chiave dedup (single o composta es. `email`+`telefono`); processing: file piccolo (<1000 righe) sincrono con progress bar JS via SSE/WebSocket, file grandi queue async chunked (default 500 righe per job, configurabile), job `ProcessImportChunk` con retry 3x su deadlock/timeout, transazione per chunk (rollback chunk-only su errore, non tutto l'import), foreign-key resolution lazy (es. CSV ha `customer_email` → lookup `Customer::where(email)->id` con cache in-memory per ridurre query, opt. auto-create entità correlata se mancante con flag `create_missing_references=true`); avanzamento utente: barra progressiva `12345/56789 righe (22%)`, ETA, throughput righe/sec, pulsante «pausa»/«cancella» (job interrompibile, rollback pulito); notifica completamento via Toast + email + push (#8312) opz. **Post-import**: report finale scaricabile (PDF/XLSX) con: timestamp start/end, durata, utente, file sorgente, mapping usato, righe processate/inserite/aggiornate/skipped/errored, log errori, link audit (#8330); record `Import` persistente in DB con stato (`pending`/`validating`/`running`/`completed`/`failed`/`cancelled`) consultabile in admin → lista import storica filtrabile per modello/utente/data; rollback completo opt. via `Import::rollback($id)` (cancella tutte righe inserite + restore valori pre-update da snapshot in `import_changes` table — costoso storage, abilitabile per import critici). Casi d'uso workspace: **Holiday Self Drive** (import storico veicoli da Excel concessionario + clienti legacy da CRM precedente + bookings storici da gestionale vecchio per migrazione iniziale), **Gestionale Casarile** (import prenotazioni storiche da Excel reception + listino prezzi stagionali + ospiti fidelity), **Klabhouse** (import iscritti corsi da Excel segreteria + insegnanti + listino prezzi pacchetti), **Gestionale Altramusica** (import allievi+lezioni storiche da Excel docenti, fatture pregresse PA, calendario eventi), **TMK/LB advisory** (import contratti clienti + scadenze + practice management da Excel commercialista), **mscarichi** (import interventi storici da Excel cartaceo + clienti zona Maps), **the-body-code/realpilates** (import pazienti+sedute da gestionale precedente con consenso GDPR), **prontointervento** (import squadre+turni storici + clienti contratto), **Footility marketing** (import lead newsletter da export Mailchimp/Brevo → modulo #8314, import contatti CSV da rubrica Google/iCloud), **e-commerce/catalogo** (#8317 import prodotti da listino fornitore CSV settimanale con upsert by SKU + update prezzi/giacenze), **fatturazione** (import movimenti bancari home banking CSV CBI per riconciliazione automatica con fatture #8322). Casi limite/edge: file UTF-8 con BOM → strip auto, encoding misto (alcune righe ISO-8859-1) → fallback char-by-char con warning, delimitatore `;` (standard IT Excel) vs `,` (standard US) → auto-detect, decimal IT `1.234,56` vs US `1,234.56` → conversione configurabile per locale, date formato ambiguo `02/03/2026` (DMY o MDY?) → forzare scelta utente o euristica su valori 13+, celle Excel con formula `=SUM(A1:A10)` → valore calcolato cached, righe vuote intermezzo → skip auto, riga con # colonne diverso da header → error «schema mismatch riga 1234», caratteri di controllo (\x00, \r mid-line) → sanitize, valori troppo lunghi vs colonna DB varchar(255) → truncate con warning o error configurabile, foreign-key reference non trovato → skip o create_missing o error, duplicato chiave unique → upsert/skip/error config, file 500MB 5M righe → chunk read streaming senza loadare tutto in RAM (`SplFileObject` line-by-line o `box/spout` reader), Excel zip-bomb (xlsx malicious) → limite worksheet/celle, SQL injection da valore CSV → eloquent parameter binding always, header mancante (CSV senza first-row label) → modalità «no header» con `col_1`/`col_2`/.../`col_N` auto-name, BOM Mac line ending `\r` only → normalize `\r\n`, virgola dentro campo quotato `"Rossi, Mario"` → enclosure rispettato, newline dentro campo (multi-line value) → gestione enclosure con `\n` interno, file ODS LibreOffice → phpoffice/phpspreadsheet o pandoc, Excel old `.xls` BIFF → phpoffice/phpspreadsheet, file corrotto → parse error + suggerimento «riapri in Excel e salva come CSV UTF-8», file con sola riga header → import vuoto con warning, mapping con campo readonly (es. `id` auto-increment) → blocca, mapping con field encrypted (`tax_code` con cast `encrypted`) → encrypt al insert, mapping enum value non valido → suggerisci enum vicini fuzzy, race condition import parallelo stessa entità → lock pessimistic per chunk o queue serializzata, retry job idempotente (check riga già inserita prima di re-insert) via `import_id`+`row_number` unique. Estensioni roadmap: AI auto-mapping intelligente (LLM analizza header + sample 5 righe → suggerisce mapping completo + transformazioni necessarie, riduce tempo setup da 5min a 30sec, via #8261 chatbot-rag o OpenAI), AI data cleansing (auto-fix typo nome città «Milnao»→«Milano», auto-normalize address tramite Google Geocoding/Nominatim, auto-validate VAT via VIES), schedule import ricorrente (cron settimanale fetch SFTP/HTTP da fornitore → auto-import upsert), import incrementale (timestamp last_import → solo righe newer), reverse mapping export (definito mapping CSV→DB, usa stesso mapping per DB→CSV export #8328), import da Google Sheets/Airtable/Notion API (oltre file), Webhook trigger post-import (notifica sistemi terzi via #8324), template CSV scaricabile pre-import (utente scarica esempio con header corretti + 2 righe sample + commenti tipo dato), validazione cross-row (es. somma colonna importo = totale a piè di lista), supporto multi-file zip (es. ZIP con 10 CSV mensili → tutti importati con tag periodo auto), versioning import (rerun stesso file con mapping aggiornato → diff verso prima esecuzione), import wizard riusabile come componente embed in altri moduli (es. #8317 catalogo «importa listino» triggera wizard pre-configurato modello Prodotto). Differenze e relazioni: **#8327 CRUD generico anagrafiche datatable** ogni risorsa con datatable espone bottone «Importa CSV» che apre wizard pre-configurato sul modello corrente, **#8328 export-excel-pdf** è il duale (export DB→file), mapping/template condivisibili tra import e export, **#8330 audit-log-azioni-utente** logga ogni import con righe affette + utente + dry-run/commit, **#8326 area-cliente-riservata** consente cliente di caricare proprio CSV per self-service (es. lista contatti azienda B2B), **#8317 catalogo-prodotti** import listino settimanale fornitore, **#8104 lead-form** import bulk lead da fiera/evento (CSV export tablet), **#8314 newsletter-signup** import contatti rubrica esistente in lista mailing, **#8322 fatturazione** import movimenti bancari riconciliazione, **#8312 notifiche-push** notifica completamento import a utente, **#8261 chatbot-rag** può ingest CSV come fonte (vedi però #8261 spec specifica), **#8316 booking-call** non rilevante, **#8324 webhooks** trigger post-import. Costo nuovo modulo (greenfield): 0.25g install dipendenze (`league/csv` o `box/spout` o `phpoffice/phpspreadsheet`) + migrazione tabelle `imports`/`import_rows`/`import_presets`/`import_changes` (rollback), 0.5g step Upload drag&drop + validazione + storage temporaneo + dedup hash, 0.5g step Detect (delimitatore/encoding/header auto-detect + preview tabella + tipo inferito), 1g step Mapping UI drag&drop + fuzzy suggest + dizionario sinonimi + trasformazioni (lowercase/trim/regex/date parse/decimal locale/concat/constant/ignore), 0.5g preset save/load + versioning, 0.75g step Validation engine (regole Laravel + custom rule + summary cards + report errori paginato + download XLSX errori), 0.5g step Commit modalità (insert/upsert/update/replace + dedup key composta + foreign-key resolution lazy + create_missing), 0.75g processing queue chunked + progress SSE/WebSocket + pausa/cancella + transazione chunk + retry job idempotente, 0.5g report finale PDF/XLSX + storia import admin + rollback opt., 0.5g componente Livewire/Vue wizard multi-step state + back/next + persist intermediate, 0.5g comandi artisan `import:retry`/`import:rollback`/`import:cleanup-orphans` (file temporanei >7gg), 0.5g API REST `POST /api/imports` + `GET /api/imports/{id}/status` + webhook on-complete, 0.5g integration audit log #8330 + permessi (Spatie Permission scope import per ruolo), 0.5g testing E2E (upload CSV/XLSX/ODS happy path, encoding misto, delimitatore detection, mapping fuzzy, dry-run/commit, rollback, chunk fail/retry, file 100k righe perf). Costo riuso nuovo cliente (modulo pronto): 0.25g registrazione modello target su wizard (definizione campi mappabili + regole validation + chiave dedup), 0.25g preset mapping default per fonte tipica cliente, 0.25g dizionario sinonimi custom cliente (es. campi vocabolario settore), 0.25g test happy path import file reale cliente, 0.25g eventuali trasformazioni custom (es. normalizzazione codice fiscale italiano regex, partita IVA VIES). Dipendenze: Laravel 10/11, `league/csv` ^9 (lightweight CSV reader/writer streaming) o `box/spout` ^3 (Excel/CSV/ODS streaming low-memory) o `phpoffice/phpspreadsheet` ^2 (Excel completo ma RAM intensive, sconsigliato file grandi), `laravel/horizon` o queue worker per job async chunked, `livewire/livewire` ^3 o Vue 3 + Alpine.js per UI wizard, opt. `pusher-php-server`/`laravel-websockets`/SSE per progress real-time, opt. `maatwebsite/excel` ^3 alternativa wrapper Laravel-friendly (basa su PhpSpreadsheet), opt. `intervention/validation` per regex IT (CF/PIVA/CAP), opt. integration #8330 audit log, opt. integration #8261 AI auto-mapping, opt. integration #8328 export per template scaricabile, opt. `spatie/laravel-permission` per scope import per ruolo.
Esempi d'uso