Inviare pezzi
Una sola strada d'ingresso: il file. Ogni regola qui sotto vale per ciascun pezzo che contiene.
POST /api/v1/integration/pieces/import
Inviate un .csv, .xlsx o .zip come multipart form data, in un campo chiamato file:
curl -H "X-API-Key: mgi_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-F "file=@esempio.zip" \
https://vostro-server/api/v1/integration/pieces/import
Il nome del campo conta: qualsiasi cosa diversa da file arriva come nulla e l'importazione fallisce. Anche l'estensione — il server decide cosa fare dal nome che inviate, quindi uno ZIP chiamato dati.txt viene rifiutato.
{
"fileFormat": "ZIP (CSV)",
"totals": { "read": 3, "created": 1, "ignored": 1, "rejected": 1 },
"items": [
{ "barcode": "ABC-001", "outcome": "CREATED" },
{ "barcode": "ABC-002", "outcome": "IGNORED", "reason": "Codice a Barre già esistente" },
{ "barcode": "ABC-003", "outcome": "REJECTED", "reason": "Indicare almeno un servizio in ServicosAplicaveis (es.: [CORTE_MONO],[TEMPERA]) — senza servizio non esiste un ciclo di produzione." }
],
"warnings": [],
"createdGlassTypes": [],
"createdCustomers": []
}
I campi che forse sorprendono
fileFormat dice cosa il server ha letto davvero — ZIP (CSV) significa che dentro il vostro ZIP ha trovato un CSV. Utile quando il pacchetto è costruito male.
warnings non sono fatali. Un'immagine o una sagoma citata nel foglio e assente dal pacchetto, per esempio: il pezzo è entrato, l'allegato no.
createdGlassTypes e createdCustomers elencano ciò che il sistema ha creato da solo a partire dal vostro file. Una tipologia o un cliente che non esiste ancora viene creato durante l'importazione — e riceverne l'elenco è ciò che impedisce all'anagrafica di crescere a vostra insaputa. Se in due settimane diverse compaiono qui GLASS A e GLASS A, qualcuno sta scrivendo in modo diverso all'origine.
I tre esiti
| Esito | Cosa significa | Cosa fare |
|---|---|---|
CREATED | Il pezzo è stato creato, con il suo ciclo di lavorazione | Niente |
IGNORED | Quel codice a barre esisteva già | Niente. È il risultato atteso di un reinvio |
REJECTED | Non è entrato, e reason dice perché | Correggere il dato e reinviare solo i rifiutati |
outcome arriva sempre come testo, mai come numero. È garantito e coperto da test — un enum serializzato come numero vi costringerebbe a memorizzare un ordine che potrebbe cambiare in silenzio.
reason è valorizzato su IGNORED e REJECTED, e nullo su CREATED, dove non c'è nulla da spiegare.
reason torna nella vostra lingua. Inviate un header Accept-Language — it, en, es-ES o pt-BR — e il testo del rifiuto arriva tradotto. Senza l'header ricevete il portoghese. Quel testo è fatto per essere letto da una persona: non basateci mai una condizione del codice, perché la formulazione può essere riscritta e la traduzione corretta. Basatevi su outcome, che non cambia.
Il file non è atomico
Ogni pezzo ha una transazione propria. Un file con 100 pezzi e 3 righe sbagliate ne salva 97 e ne rifiuta 3. Non esiste rollback del lotto.
È per questo che la risposta è voce per voce. Due conseguenze da tenere presenti nel vostro codice:
- Reinviare l'intero file dopo la correzione è sicuro — i 97 tornano come
IGNORED - Ma sapere quali 3 hanno fallito vi evita di doverlo fare
Ripetere è sicuro
Il codice a barre è vostro, e garantiamo di non duplicarlo.
Se una richiesta va in timeout e non sapete se è arrivata, rimandatela. Il caso peggiore è IGNORED. Non c'è un passo di riconciliazione, non c'è una chiave di idempotenza da gestire, e non esiste una finestra in cui un reinvio crea un gemello.
Cosa non è un rifiuto
Un rifiuto è una risposta di business, non un guasto del server. Arriva con 200, non con 500.
Questa distinzione conta per la vostra logica di ripetizione: 5xx significa riprovare più tardi, il contenuto non è mai stato il problema. REJECTED significa che il contenuto è il problema, e ripeterlo invariato fallirà sempre allo stesso modo.