API Fatture — Specifica Tecnica¶
Panoramica¶
API REST per la sincronizzazione di metadati delle fatture e per l'archiviazione/lettura degli allegati (PDF e XML elettronici) verso/da Areagate. La testata fattura risiede in ARPFATTU; gli allegati vengono archiviati su S3 e indicizzati in APCOGARIDX.
Endpoint disponibili¶
| Metodo | Path | Descrizione |
|---|---|---|
| GET | /v1/fattura |
Lettura fatture (paginazione) |
| GET | /v1/fattura/up |
Lettura fatture aggiornate a partire da un sync id |
| POST | /v1/fattura |
Inserimento/aggiornamento/cancellazione batch fatture (metadati) |
| GET | /v1/fattura/:codice_fattura/xml |
Scarica l'XML della fattura elettronica |
| POST | /v1/fattura/allegato |
Upload di un singolo allegato (PDF o XML) |
Nota: il POST
/allegatoe' implementato senza schema Fastify (multipart/form-data) e per questo motivo non risulta attualmente documentato in Swagger. Il contratto e' descritto nella sezione dedicata.
Schema output — GET¶
FatturaOutput¶
| Campo | Tipo | Campo DB / Join | Note |
|---|---|---|---|
codice_fattura |
string | trim(a_fat_fattura) |
Chiave completa fattura (max 20 char, puo' contenere /) |
codice_cliente |
string | trim(a_fat_anagrafica) |
Codice anagrafica interno (area) |
codice_host_cliente |
string | join ARPANAGR (rana_codice_host) |
Codice cliente nel sistema host esterno |
tipo |
string | trim(a_fat_tip) |
Tipo fattura (max 2 char) |
anno |
integer | a_fat_ann |
Anno fattura (4 cifre) |
numero |
integer | a_fat_num |
Numero fattura (max 7 cifre) |
data |
integer | a_fat_data (convertito in epoch ms) |
Data fattura in formato epoch ms |
imponibile |
number | a_fat_imponibile |
Imponibile |
iva |
number | a_fat_iva |
IVA |
totale |
number | a_fat_totale |
Totale |
cancellato |
boolean | a_fat_val = 'C' |
true se la fattura e' cancellata logicamente |
sync |
integer | a_fat_id_sincro |
ID di sincronizzazione |
Query string — GET /¶
| Parametro | Tipo | Obbligatorio | Note |
|---|---|---|---|
limit |
integer | NO | Max risultati (default/max: 1000) |
page |
integer | NO | Pagina (paginazione offset-based) |
Il GET / esclude le fatture cancellate (a_fat_val <> 'C').
Query string — GET /up¶
| Parametro | Tipo | Obbligatorio | Note |
|---|---|---|---|
sync |
integer | SI | ID sincronizzazione di partenza |
Il GET /up include anche le fatture cancellate (restituite con cancellato = true) e ordina per a_fat_id_sincro crescente.
Schema input — POST /v1/fattura¶
Il body e' un array di oggetti FatturaInput (max 1000 elementi).
FatturaInput¶
| Campo | Tipo | Obbligatorio | Note |
|---|---|---|---|
codice_fattura |
string | SI | Chiave univoca fattura (max 20 char) — usata per deduplicazione |
codice_host_cliente |
string | SI | Codice host cliente (max 16 char), risolto via raccordi clienti |
tipo |
string | NO | Tipo fattura (max 2 char, default "") |
anno |
integer | NO | Anno fattura (1-9999, default 1) |
numero |
integer | NO | Numero fattura (+/-7 cifre, default 0) |
data |
integer | NO | Data fattura in epoch ms (default 0 -> data 0001-01-01) |
imponibile |
number | NO | Imponibile (default 0) |
iva |
number | NO | IVA (default 0) |
totale |
number | NO | Totale (default 0) |
cancellato |
boolean | NO | Cancellazione logica (default false) |
Logica POST¶
- Deduplicazione payload: non sono ammessi
codice_fatturaduplicati nello stesso array (checkDuplicati). - Validazione: ogni
codice_host_clientedeve risolvere inARPANAGR. Se non risolvibile ->400 body/{i}/codice_host_cliente (...) mancante. - Categorie di operazioni calcolate confrontando payload con record esistente:
- Inserimento: record non esistente e non flaggato come cancellato
- Cancellazione: record esistente non cancellato + payload
cancellato=true - Modifica: record esistente con almeno un campo cambiato (cliente, tipo, anno, numero, data, imponibile, iva, totale). La modifica rimuove la flag di cancellazione (
a_fat_val = '') - Skip: record gia' cancellato e payload
cancellato=true; record non esistente e payloadcancellato=true
id_sincro: assegnato progressivamente dagetNextIdSincro(sql, id_azi, "ARPFATTU", n)per tutte le operazioni di scrittura in questa chiamata.
GET /v1/fattura/:codice_fattura/xml¶
Scarica l'XML della fattura elettronica. L'XML e' stato archiviato su S3 tramite il processo gestionale (sottoprogramma COGU06), in cbl/cogu06.cbl caso k-arcott-classe-fatture-clienti / k-arcott-classe-fatture-fornitori.
Path param¶
| Parametro | Note |
|---|---|
codice_fattura |
Stesso formato restituito da GET /v1/fattura (con slash). Il client URL-encoda gli slash come %2F. Fastify decodifica il parametro in trasparenza. |
Response body (200)¶
| Campo | Tipo | Note |
|---|---|---|
nome_originale |
string | Nome originale del file caricato (a_arx_nome_originale) |
nome_memorizzato |
string | Nome memorizzato su S3 (a_arx_nome_memorizzato) |
contenuto |
string | Contenuto XML codificato in base64 |
Logica¶
- Lookup in
ARPFATTU:trim(a_fat_fattura) = codice_fattura+a_fat_val <> 'C'. 404 se non trovata. -
Lookup in
APCOGARIDX:a_arx_doc_classe IN ('FC', 'FF')(include sia fatture clienti sia fornitori)replace(trim(a_arx_key_oggetto_gest), '/', '') = codice_fattura_senza_slash— il match normalizza gli slash su entrambi i lati perche' la chiave inAPCOGARIDXpuo' essere con slash (se archiviato dal POST/allegatodi questa API) o senza slash (se archiviato dal processo gestionaleswn013)a_arx_nome_memorizzato ILIKE '%.xml'a_arx_fl_canc <> 'C'
404 se XML non trovato. 3. Fetch credenziali AWS (
getAwsCredentials(db, id_azi)). 4. Download da S3, Bucket dalle credenziali, Keyfatture/{nome_memorizzato}. 5. Encodingcontenutoin base64.
POST /v1/fattura/allegato¶
Upload di un singolo file allegato a una fattura. Accetta sia PDF sia XML, a seconda del campo ext_file. Il file viene archiviato su S3 nella cartella fatture/ e registrato in APCOGARIDX.
Nota: questo endpoint e' implementato senza schema Fastify, quindi non appare in Swagger. La validazione dei campi avviene via
zodsulreq.fieldsdel multipart.
Request¶
- Content-Type:
multipart/form-data - Campi (tutti in form-data):
file: il file binario (PDF o XML) — limite 1 file per richiestacodice_host_cliente(string, SI): codice cliente nel sistema host esternocodice_fattura(string, SI): chiave fattura (max 20 char, puo' contenere/)data(integer, SI): data fattura in epoch msext_file(string, NO): estensione del file (default"pdf", es."xml"per upload XML)
Logica¶
- Verifica presenza del file (
req.file({ limits: { files: 1 } })). - Parse via
zoddei campi multipart. Errore ->400 Wrong data provided. - Validazione
codice_host_clientevia raccordi clienti (getRaccordiClienti). - Costruzione
nome_memorizzato = codice_fattura.replaceAll("/", ""). - Upload su S3:
- Bucket: da credenziali AWS dell'azienda
- Key:
fatture/{nome_memorizzato}.{ext_file} ContentType: dal multipartStorageClass: STANDARD_IA
- Insert in
APCOGARIDX:a_arx_progressivo: progressivo tramitenumericCodeGenerator(12, MAX(a_arx_progressivo))a_arx_doc_classe:"FC"(fisso — anche per fatture fornitori)a_arx_ana_tip/a_arx_ana_cod: derivati dacliente[0]/cliente.slice(1)(dal raccordo)a_arx_key_oggetto_gest:codice_fatturaoriginale (con slash)a_arx_prog_documento:1a_arx_data_esterno:datadal payloada_arx_nome_originale: filename originale del multiparta_arx_nome_memorizzato:{nome_memorizzato}.{ext_file}a_arx_id_sincro: dagetNextIdSincro(sql, id_azi, "APCOGARIDX", 1)
Response¶
- 200 OK:
{ "message": "OK" } - 400 Bad Request:
"No file provided"/"Wrong data provided"/ errori di validazione - 500 Internal Server Error: problemi di accesso credenziali S3
Tabelle sorgente¶
ARPFATTU — testata fatture¶
PK: (a_fat_azienda, a_fat_fattura). Il campo a_fat_fattura e' char(20) e contiene la chiave completa della fattura (puo' includere /).
| Campo | Tipo | Note |
|---|---|---|
a_fat_azienda |
char(6) | Codice azienda |
a_fat_fattura |
char(20) | Chiave completa fattura |
a_fat_tip |
char(2) | Tipo fattura |
a_fat_ann |
num(4) | Anno |
a_fat_num |
num(7) | Numero |
a_fat_data |
date | Data fattura |
a_fat_imponibile |
num(12,6) | Imponibile |
a_fat_iva |
num(12,6) | IVA |
a_fat_totale |
num(12,6) | Totale |
a_fat_anagrafica |
char(6) | Codice anagrafica (area) |
a_fat_val |
char(1) | 'C' se cancellato |
a_fat_id_sincro |
num(15) | ID sincronizzazione |
APCOGARIDX — indice archivio documentale¶
Usata per la registrazione degli allegati (sia PDF sia XML) e dei loro metadati.
| Campo | Note |
|---|---|
a_arx_doc_classe |
"FC" = Fatture clienti, "FF" = Fatture fornitori |
a_arx_key_oggetto_gest |
codice_fattura — puo' essere con slash (POST /allegato API) o senza slash (processo gestionale swn013) |
a_arx_nome_originale |
Filename originale |
a_arx_nome_memorizzato |
Filename memorizzato su S3 (con estensione). POST /allegato API: slash rimossi (es. CL20260000123.pdf). swn013 per XML: slash sostituiti con _ (es. CL_2026_0000123.xml) |
a_arx_fl_canc |
'C' se cancellato |
Storage S3¶
Le fatture vengono archiviate in una cartella piatta fatture/ (vedi cogu06.cbl:4718-4733):
Key = fatture/{a_arx_nome_memorizzato}
Il nome_memorizzato include l'estensione (.pdf o .xml) ed e' stato generato rimuovendo gli slash dal codice_fattura originale. Le credenziali del bucket vengono recuperate via getAwsCredentials(db, id_azi).
Limiti¶
| Vincolo | Valore |
|---|---|
| Max fatture per risposta GET | 1000 |
| Max fatture per body POST | 1000 |
| Max allegati per richiesta POST | 1 |
Max size codice_fattura |
20 char |
Max size codice_host_cliente |
16 char |
Note implementative¶
- Tutte le operazioni POST sono eseguite in una singola transazione (
db.begin) - Le date in output (
datainFatturaOutput) sono convertite daYYYY-MM-DDa epoch ms tramiteisoDateToInteger(memoizzato) - Le date in input (
datainFatturaInput) vengono convertite da epoch ms aYYYY-MM-DDtramiteintegerToDate(memoizzato); valore0->"0001-01-01" - I campi tecnici (
a_fat_di_*,a_fat_da_*) sono valorizzati automaticamente con data/ora odierne e costantiWS_OPE/WS_PROG