# Design: Generatore PDF fattura di cortesia da XML FatturaPA

Data: 2026-07-21
Stato: approvato a voce, in attesa di revisione scritta

## Obiettivo

Pagina web su Vercel: si carica un file `.xml` di Fattura Elettronica italiana
(formato FPR12/FatturaPA, esempio in `template/IT01511230086_AAAAA.xml`) e si
scarica un PDF "fattura di cortesia" impaginato come `template/fattura.pdf`
(originale generato da FattureInCloud). Un XML in entrata, un PDF in uscita.
Nient'altro.

## Decisioni prese

| Tema | Decisione |
|---|---|
| Utenza | Solo Cinzia Loiacono (uso familiare). Dati non presenti nell'XML in un unico "profilo emittente" hardcoded, pensato per diventare un record per-utente se un domani si farà il multi-utente con login. |
| Generazione PDF | Lato server (API route su Vercel). |
| Libreria PDF | `@react-pdf/renderer` (componenti dichiarativi, layout flexbox, leggero su serverless). |
| Formati input | Solo `.xml`. Niente `.p7m` per ora. |
| Accesso | Pagina pubblica senza protezione. Login vera solo se/quando diventerà multi-utente. |
| Fedeltà | Massima fedeltà al template: font, colori, dimensioni e layout ricavati dal PDF originale (specifica sotto). |
| Privacy | La fattura caricata vive solo il tempo della richiesta; nessun salvataggio server-side. |

## Architettura

App Next.js (App Router, TypeScript) deployata su Vercel. Repo privata GitHub.

```
app/
  page.tsx              → UI: drag & drop / selettore file, pulsante "Genera PDF",
                          errori in italiano, download automatico del PDF
  api/genera-pdf/
    route.ts            → POST: riceve l'XML (multipart), orchestra parser →
                          mappatura → render PDF, risponde application/pdf
config/
  emittente.ts          → profilo emittente: titolo "Architetto", email
                          loiacono.cinzia@gmail.com, cell 0039 329 715 98 48,
                          testo fisso NOTE
lib/
  parser.ts             → XML → modello dati tipizzato `Fattura` (fast-xml-parser)
  mappe.ts              → tabelle di decodifica FatturaPA (vedi sotto)
  calcoli.ts            → totali, formattazione importi it-IT e date gg/mm/aaaa
components/
  FatturaPDF.tsx        → template @react-pdf/renderer che replica fattura.pdf
fonts/
  TrebuchetMS.ttf, TrebuchetMS-Bold.ttf, TrebuchetMS-Italic.ttf,
  TrebuchetMS-BoldItalic.ttf
                        → copiati da /System/Library/Fonts/Supplemental/ del Mac
                          di Paolo (uso privato; repo privata, nessuna
                          ridistribuzione pubblica)
test/
  fixtures/…            → XML di esempio come fixture
  *.test.ts             → Vitest su parser, mappe, calcoli + smoke test API
```

Flusso: `page.tsx` → `POST /api/genera-pdf` (FormData col file) → `parser.ts`
→ `calcoli.ts`/`mappe.ts` → `FatturaPDF.tsx` → buffer PDF → risposta con
`Content-Disposition: attachment; filename="Fattura_4_2026.pdf"`.

## Specifica tipografica (estratta dal PDF originale)

Pagina A4: 595,28 × 841,89 pt. Margini: sinistro 28,3 pt, destro fino a 566,9 pt
(≈ 28,3 pt), contenuto header da y≈30, piè di pagina a y≈814.

Font: **Trebuchet MS** per tutto il documento. L'originale incorporava solo la
face regular e simulava grassetto/corsivo; noi usiamo le face vere Bold/Italic
(resa uguale o migliore). Il DejaVu Serif Condensed dell'originale serviva solo
alla scritta laterale "Documento generato con FattureInCloud.it", che omettiamo.

Colori:

| Uso | Colore |
|---|---|
| Etichette/intestazioni (DESCRIZIONE, NOTE, FATTURA nr., totale grande…) | `#828282` |
| Testo contenuti | `#6a6a6a` |
| Bordi e righe di separazione | `#cecece` (0,75 pt tabella; 0,59 pt sezioni basse) |
| Sfondo righe alternate tabella (1ª, 3ª, …) | `#ededed` |

Dimensioni testo (pt):

| Elemento | Corpo |
|---|---|
| Intestazione cedente (3 righe alto destra) | 8,25 (nome in bold) |
| "FATTURA nr. X/AAAA del gg/mm/aaaa" | 10,5 ("FATTURA", numero e data in bold) |
| Blocco P.IVA/CF/EMAIL + destinatario | 9 (etichette e nome destinatario bold) |
| Etichette colonne tabella (DESCRIZIONE, IMPORTO, % IVA) | 6 |
| Righe tabella e NOTE | 9 |
| Etichetta NOTE / DESTINATARIO | 6,75 |
| Etichette sezioni basse (MODALITÀ DI PAGAMENTO, SCADENZE, RIEPILOGO IVA, IMPONIBILE, IMPOSTE) | 5,34 |
| Contenuti sezioni basse (pagamento, scadenze, riepilogo, totali) | 6,53 (descrizioni riepilogo IVA in italic) |
| Totale documento grande | 17,81 (bold, `#828282`) |
| Piè di pagina | 7,5 |

Geometria di riferimento (coordinate dall'alto, pagina 1 dell'originale):

- Riga separatore sotto l'header: y≈127,9, larghezza piena.
- Tabella articoli: inizia y≈218,3; colonne: descrizione 28,3→482,2,
  importo 482,2→540,0, %IVA 540,0→566,9. Bordi `#cecece` 0,75 pt, righe
  con sfondo alternato `#ededed` a partire dalla prima.
- Blocco basso (ancorato verso il fondo pagina): riquadro da y≈589,1 a y≈776,6,
  divisore verticale a x≈284,5, riga orizzontale interna a y≈664,1.
  Quadranti: modalità di pagamento (alto sx), scadenze (alto dx),
  riepilogo IVA (basso sx, colonne IMPONIBILE ≈219→246 e IMPOSTE ≈255→275),
  totali (basso dx, allineati a destra).
- Piè di pagina: sx "Fattura nr. X/AAAA del gg/mm/aaaa - pag / tot",
  dx "«titolo nome» email / cell: …" su due righe, y≈809–827.

## Mappatura XML → PDF

| Sezione PDF | Origine dati |
|---|---|
| Intestazione alto dx: "Architetto Cinzia Loiacono" / indirizzo / "P.iva … - C.F. …" | Titolo dal profilo + `CedentePrestatore/DatiAnagrafici/Anagrafica` (Nome+Cognome, oppure Denominazione se presente); `Sede` (Indirizzo, NumeroCivico, CAP, Comune, Provincia); `IdFiscaleIVA/IdCodice`, `CodiceFiscale` |
| "FATTURA nr. 4/2026 del 20/07/2026" | Etichetta da `TipoDocumento` (mappa TD → testo), `Numero`, anno e data da `Data` |
| Blocco sx: P.IVA / CF / EMAIL | `CessionarioCommittente/DatiAnagrafici`: `IdFiscaleIVA/IdCodice`, `CodiceFiscale`; EMAIL: `DatiTrasmissione/PECDestinatario` se presente, altrimenti la riga si omette (nell'XML di esempio non esiste) |
| Blocco DESTINATARIO | `Anagrafica/Denominazione` (o Nome+Cognome), `Sede`: "INDIRIZZO, CIVICO" / "CAP COMUNE (PROV)" |
| Tabella articoli | Una riga per `DettaglioLinee`: `Descrizione`, `PrezzoTotale`, `AliquotaIVA` (intero, senza %). Riga aggiuntiva "Marca da bollo / importo / 0" se `DatiBollo` presente (`ImportoBollo`) |
| NOTE | Testo fisso dal profilo: "Documento privo di valenza fiscale ai sensi dell'art. 21 Dpr 633/72. L'originale è disponibile all'indirizzo telematico da Lei fornito oppure nella Sua area riservata dell'Agenzia delle Entrate." |
| MODALITÀ DI PAGAMENTO | `ModalitaPagamento` decodificata (MP05 → "Bonifico Bancario"), "IBAN: …" se presente, `Beneficiario` |
| SCADENZE | Per ogni `DettaglioPagamento`: data (`DataScadenzaPagamento` se presente, altrimenti `DataRiferimentoTerminiPagamento`, altrimenti `Data` documento) + `ImportoPagamento` → "gg/mm/aaaa: € X" |
| RIEPILOGO IVA | Una riga per `DatiRiepilogo`: "«aliquota»% - «descrizione natura»", `ImponibileImporto`, `Imposta`. Riga aggiuntiva "0% - Escluso Art.15 / importo bollo / € 0,00" se `DatiBollo` presente |
| Totali (basso dx) | Vedi "Calcoli" |
| Totale grande | `ImportoTotaleDocumento` |
| Piè di pagina | Numero/data documento + numero pagina (react-pdf `render` callback); contatti dal profilo |

## Tabelle di decodifica (`lib/mappe.ts`)

Si includono i codici FatturaPA d'uso comune, con fallback al codice grezzo se
non mappato:

- **TipoDocumento**: TD01 Fattura, TD02 Acconto/anticipo su fattura, TD03,
  TD04 Nota di credito, TD05 Nota di debito, TD06 Parcella, TD24, TD25, TD26…
  (etichetta documento: "FATTURA" per TD01, ecc.)
- **ModalitaPagamento**: MP01 Contanti, MP02 Assegno, MP05 Bonifico Bancario,
  MP08 Carta di pagamento, MP12 RIBA, MP19 SEPA DD… (set completo MP01–MP23)
- **TipoCassa**: TC04 → "Cassa di previdenza e assistenza per gli ingegneri e
  architetti (INARCASSA)" + le altre casse TC01–TC22
- **Natura**: N1 Escluse ex art. 15, N2.1, N2.2 "Operazione non soggetta a IVA",
  N3.x, N4, N6.x… Caso speciale: se `RegimeFiscale` = RF19 e natura N2.2, la
  descrizione del riepilogo diventa la dicitura forfettario dell'originale:
  "Operazione non soggetta a IVA ai sensi dell'art. 1, commi 54-89, Legge
  n. 190/2014 e succ. modifiche/integrazioni"

## Calcoli (`lib/calcoli.ts`)

Con l'XML di esempio, per verifica:

- **Totale onorario** = Σ `PrezzoTotale` delle linee = € 6.900,00
- **Riga cassa** = etichetta da `TipoCassa` + `AlCassa`% → `ImportoContributoCassa` = € 276,00 (riga presente solo se `DatiCassaPrevidenziale` esiste)
- **Imponibile** = Σ `ImponibileImporto` dei riepiloghi = € 7.176,00
- **Non imponibile** = `ImportoBollo` = € 2,00 (riga presente solo se bollo)
- **Marca da bollo** = `ImportoBollo` = € 2,00
- **Totale documento** = `ImportoTotaleDocumento` = € 7.178,00

Formattazione: importi `Intl.NumberFormat('it-IT')` con simbolo € anteposto
("€ 6.900,00"); date `gg/mm/aaaa`. I valori monetari si trattano come stringhe
decimali → numeri con arrotondamento a 2 decimali solo in presentazione; le
somme si fanno in centesimi per evitare errori di virgola mobile.

## Gestione errori

- File mancante, non XML, XML malformato o senza `FatturaElettronica` →
  HTTP 400 con messaggio in italiano, mostrato nella pagina senza ricaricarla.
  Esempi: "Il file non sembra una Fattura Elettronica (manca il nodo
  FatturaElettronica)".
- Encoding: si legge il file come UTF-8 (l'XML di esempio contiene già mojibake
  a monte, es. "unitÃ": non è compito nostro correggerlo; si riproduce fedele).
- Campi opzionali assenti (bollo, cassa, pagamento, email) → la riga/sezione si
  omette, il layout non si rompe.
- Più `FatturaElettronicaBody` nello stesso file → si genera un unico PDF con
  le fatture in sequenza, ognuna da pagina nuova.
- Molte righe di dettaglio → la tabella prosegue su più pagine; il blocco basso
  (pagamento/riepilogo/totali) sta ancorato al fondo dell'ultima pagina; il piè
  di pagina numera "X / Y" su ogni pagina.

## Test

- **Vitest** su `parser.ts`, `mappe.ts`, `calcoli.ts` usando l'XML di esempio
  come fixture: valori estratti attesi (numero 4, data 2026-07-20, totali come
  sopra, IBAN, natura, cassa…).
- Smoke test dell'API: risposta 200, `Content-Type: application/pdf`, buffer
  che inizia con `%PDF`.
- Verifica visiva finale a occhio contro `template/fattura.pdf` (confronto
  affiancato), con revisione paragrafo per paragrafo insieme a Paolo.

## Fuori scope (futuro possibile)

- Login e profili multi-utente con dati salvati (il profilo emittente è già
  isolato per questo).
- Supporto `.xml.p7m` firmati.
- Anteprima/modifica dei dati prima della generazione.
