Fatturazione elettronica e SDI su un e-commerce: come funziona, e un bug che rompeva il checkout

di Luca Cavallini Guide tecniche
Fatturazione elettronica e SDI su un e-commerce: come funziona, e un bug che rompeva il checkout

Il sintomo

Un cliente completa il pagamento, clicca il pulsante finale dell'ordine, e invece di arrivare alla pagina di conferma il browser scarica un file PDF. La pagina del checkout resta lì, come se niente fosse successo. Chi guarda dallo schermo del cliente pensa che l'ordine non sia andato a buon fine, magari riprova, magari abbandona. In realtà l'ordine è stato creato correttamente: quello che si è rotto è solo il passaggio finale, il redirect alla conferma, ed è un modulo di fatturazione elettronica a romperlo.

Come si aggancia davvero la fatturazione elettronica al checkout

Un modulo che genera fatture e le invia al Sistema di Interscambio si appoggia, su PrestaShop, a un paio di punti di aggancio standard, gli hook. Il primo è un hook sul cambio di stato dell'ordine (tipicamente quando lo stato diventa "pagamento accettato"): a quel punto il modulo crea il documento fattura, lo numera, e nella configurazione più completa lo invia anche al servizio di fatturazione elettronica per l'inoltro allo SDI. Il secondo è un hook che PrestaShop chiama ogni volta che serve mostrare o generare il PDF della fattura di un ordine: displayPDFInvoice. Questo secondo hook è pensato per un caso preciso, un cliente o un operatore di back office che chiede esplicitamente di scaricare la fattura in PDF.

Il problema nasce perché PrestaShop chiama lo stesso hook displayPDFInvoice anche in un momento diverso, meno ovvio: quando genera automaticamente la fattura PDF durante il checkout, per esempio per allegarla alla mail di conferma d'ordine. È lo stesso hook, ma un contesto completamente diverso: nel primo caso c'è un cliente che ha cliccato "scarica fattura" e si aspetta un file; nel secondo caso il sistema sta solo preparando un allegato in un flusso che deve proseguire con un redirect alla pagina di conferma, non con un download.

Dove nasce davvero il conflitto

Un modulo di fatturazione scritto senza distinguere i due casi implementa displayPDFInvoice nel modo più diretto possibile: recupera il PDF della fattura già generata (nel nostro caso, scaricata dal servizio di fatturazione remoto), imposta le intestazioni HTTP per un download (Content-Disposition: attachment), lo trasmette con readfile() e chiude la richiesta con exit(). Corretto per il caso "scarica la fattura". Sbagliato per il caso "sto solo generando l'allegato per la mail": quell'exit() interrompe la richiesta HTTP in corso, che però non era affatto una richiesta di download; era la richiesta finale del checkout, quella che doveva proseguire fino al redirect alla conferma d'ordine. Il risultato è esattamente il sintomo descritto sopra: il browser riceve un file al posto della pagina che si aspettava.

Il bug colpisce ogni ordine per cui la fattura viene generata automaticamente durante il checkout, non solo casi particolari: è una questione di quando l'hook viene chiamato, non di quale prodotto viene comprato.

Come si diagnostica

Il sintomo da solo (download al posto del redirect) puntava verso il modulo di fatturazione installato: nel caso che abbiamo seguito, FattureInCloud, l'integrazione ufficiale con il servizio di fatturazione elettronica omonimo. Con l'ordine fatto a scopo di verifica e la fatturazione automatica attiva, il comportamento si riproduceva in modo affidabile: pagamento, completamento ordine, download del PDF al posto della conferma. Leggendo il metodo hookDisplayPDFInvoice del modulo si trova esattamente la sequenza descritta sopra, intestazioni di download seguite da readfile() e exit(), senza nessuna condizione che distingua da dove arriva la chiamata.

Come si corregge, senza rinunciare al download vero

La soluzione non è togliere la funzione di download (il cliente e il back office devono comunque poter scaricare la fattura quando la chiedono davvero): è far sì che displayPDFInvoice si comporti diversamente a seconda del contesto. Prima di trasmettere il file ed uscire, il codice controlla se la richiesta corrente è davvero una richiesta di download esplicita, per esempio il controller di back office dedicato al PDF, o il controller front-end che serve solo quello scopo, oppure un parametro d'azione che indica chiaramente "genera il PDF da scaricare". Se nessuna di queste condizioni è vera, l'hook si limita a restituire il controllo a PrestaShop invece di trasmettere e uscire, lasciando che il checkout prosegua normalmente; la fattura viene comunque generata dove serve, solo non trasmessa come download in quel punto della richiesta.

È una correzione piccola, pochi controlli su cosa sta chiedendo la richiesta corrente prima dell'exit(), ma dipende da un aggiornamento del modulo di terze parti: se il modulo viene aggiornato alla versione ufficiale, la correzione va riapplicata, perché un aggiornamento sovrascrive il file originale. Vale la pena tenerne traccia da qualche parte visibile, non solo nel codice modificato.

Come riconoscerlo sul proprio negozio

  • Fate un ordine di prova con la fatturazione automatica attiva e guardate cosa succede subito dopo il pagamento: se il browser scarica un file invece di mostrare la pagina di conferma, l'ordine probabilmente è comunque andato a buon fine, ma un hook sta interrompendo la risposta al posto giusto.
  • Controllate se il modulo di fatturazione installato genera automaticamente il PDF durante il checkout (per esempio per allegarlo alla mail di conferma): se sì, è il caso in cui questo tipo di bug si presenta.
  • Nel codice del modulo, cercate l'implementazione dell'hook displayPDFInvoice (o equivalente per moduli più vecchi) e verificate se contiene una combinazione di intestazioni di download, readfile() (o simile) ed exit()/die() senza nessuna condizione su chi sta chiamando.
  • Se aggiornate il modulo, riprovate lo stesso ordine di prova: un aggiornamento può silenziosamente reintrodurre il problema se sovrascrive una correzione locale.

Una nota, per essere chiari

Questo non è un giudizio sulla qualità generale di nessun prodotto: è un meccanismo specifico, lo stesso hook chiamato in due contesti diversi senza distinguerli, che può capitare a qualunque modulo scritto pensando solo al caso "download esplicito" e non al caso "generazione automatica durante il checkout". Vale la pena controllarlo con qualunque integrazione di fatturazione elettronica, non solo con quella che abbiamo trovato noi. Non vendiamo un modulo di fatturazione: questo articolo non ha un prodotto da proporre in fondo, solo un meccanismo da conoscere se ne installate uno.

Lascia un commento

I commenti sono moderati prima della pubblicazione.

← Blog

Caricamento in corso ...
Torna all'inizio