Facturation électronique et SDI sur un e-commerce : comment ça marche, et un bug qui cassait le checkout

par Luca Cavallini Guides techniques
Facturation électronique et SDI sur un e-commerce : comment ça marche, et un bug qui cassait le checkout

Le symptôme

Un client finalise son paiement, clique sur le bouton final de la commande, et au lieu d'arriver sur la page de confirmation, le navigateur télécharge un fichier PDF. La page du checkout reste figée, comme si rien ne s'était passé. Vu depuis l'écran du client, la commande semble ne pas avoir abouti : il réessaie peut-être, ou abandonne. En réalité, la commande a été créée correctement : ce qui a cassé, c'est seulement l'étape finale, la redirection vers la confirmation, et c'est un module de facturation électronique qui la casse.

Comment la facturation électronique se branche vraiment sur le checkout

Sur PrestaShop, un module qui génère les factures et les transmet au Sistema di Interscambio (SDI) italien s'appuie sur deux points d'accroche standard, les hooks. Le premier est un hook sur le changement d'état de la commande (typiquement quand l'état passe à « paiement accepté ») : à ce moment-là, le module crée le document de facture, le numérote et, dans la configuration la plus complète, l'envoie aussi au service de facturation électronique qui le transmet au SDI. Le second est un hook que PrestaShop appelle chaque fois qu'il faut afficher ou générer le PDF de la facture d'une commande : displayPDFInvoice. Ce second hook est pensé pour un cas précis : un client ou un opérateur du back-office qui demande explicitement à télécharger la facture en PDF.

Le problème vient du fait que PrestaShop appelle le même hook displayPDFInvoice à un autre moment, moins évident : quand il génère automatiquement la facture PDF pendant le checkout, par exemple pour la joindre à l'e-mail de confirmation de commande. C'est le même hook, mais dans un contexte complètement différent : dans le premier cas, un client a cliqué sur « télécharger la facture » et attend un fichier ; dans le second, le système prépare seulement une pièce jointe dans un flux qui doit se poursuivre par une redirection vers la page de confirmation, pas par un téléchargement.

Où naît vraiment le conflit

Un module de facturation écrit sans distinguer les deux cas implémente displayPDFInvoice de la façon la plus directe possible : il récupère le PDF de la facture déjà générée (dans notre cas, téléchargé depuis le service de facturation distant), définit les en-têtes HTTP d'un téléchargement (Content-Disposition: attachment), le transmet avec readfile() et termine la requête avec exit(). C'est correct pour le cas « télécharger la facture ». C'est faux pour le cas « je génère seulement la pièce jointe de l'e-mail » : ce exit() interrompt la requête HTTP en cours, qui n'était pas du tout une requête de téléchargement ; c'était la requête finale du checkout, celle qui devait aller jusqu'à la redirection vers la confirmation de commande. Le résultat est exactement le symptôme décrit plus haut : le navigateur reçoit un fichier au lieu de la page qu'il attendait.

Le bug touche chaque commande pour laquelle la facture est générée automatiquement pendant le checkout, pas seulement des cas particuliers : c'est une question de moment où le hook est appelé, pas de produit acheté.

Comment le diagnostiquer

Le symptôme à lui seul (un téléchargement à la place de la redirection) désignait le module de facturation installé : dans le cas que nous avons suivi, FattureInCloud, l'intégration officielle avec le service de facturation électronique du même nom. Avec une commande passée pour vérification et la facturation automatique active, le comportement se reproduisait de façon fiable : paiement, validation de la commande, téléchargement du PDF à la place de la confirmation. En lisant la méthode hookDisplayPDFInvoice du module, on trouve exactement la séquence décrite plus haut, des en-têtes de téléchargement suivis de readfile() et exit(), sans aucune condition qui distingue d'où vient l'appel.

Comment le corriger, sans renoncer au vrai téléchargement

La solution n'est pas de supprimer la fonction de téléchargement (le client et le back-office doivent toujours pouvoir télécharger la facture quand ils la demandent vraiment) : c'est de faire en sorte que displayPDFInvoice se comporte différemment selon le contexte. Avant de transmettre le fichier et de sortir, le code vérifie si la requête en cours est vraiment une demande de téléchargement explicite, par exemple le contrôleur du back-office dédié au PDF, ou le contrôleur front-office qui ne sert qu'à cela, ou encore un paramètre d'action qui indique clairement « générer le PDF à télécharger ». Si aucune de ces conditions n'est vraie, le hook se contente de rendre la main à PrestaShop au lieu de transmettre et de sortir, et le checkout se poursuit normalement ; la facture est tout de même générée là où il le faut, simplement elle n'est pas transmise en téléchargement à ce moment de la requête.

C'est une petite correction, quelques vérifications sur ce que demande la requête en cours avant le exit(), mais elle dépend d'une modification d'un module tiers : si le module est mis à jour vers la version officielle, la correction doit être réappliquée, parce qu'une mise à jour écrase le fichier d'origine. Il vaut la peine d'en garder une trace dans un endroit visible, pas seulement dans le code modifié.

Comment le reconnaître sur votre boutique

  • Passez une commande de test avec la facturation automatique active et regardez ce qui se passe juste après le paiement : si le navigateur télécharge un fichier au lieu d'afficher la page de confirmation, la commande a probablement abouti quand même, mais un hook interrompt la réponse au mauvais moment.
  • Vérifiez si le module de facturation installé génère automatiquement le PDF pendant le checkout (par exemple pour le joindre à l'e-mail de confirmation) : si oui, vous êtes dans le cas où ce type de bug apparaît.
  • Dans le code du module, cherchez l'implémentation du hook displayPDFInvoice (ou son équivalent dans les modules plus anciens) et vérifiez s'il contient une combinaison d'en-têtes de téléchargement, de readfile() (ou similaire) et de exit()/die() sans aucune condition sur l'appelant.
  • Si vous mettez le module à jour, refaites la même commande de test : une mise à jour peut réintroduire silencieusement le problème si elle écrase une correction locale.

Une précision, pour être clair

Ce n'est pas un jugement sur la qualité générale d'un produit : c'est un mécanisme précis, le même hook appelé dans deux contextes différents sans les distinguer, qui peut arriver à n'importe quel module écrit en pensant uniquement au cas « téléchargement explicite » et pas au cas « génération automatique pendant le checkout ». Il vaut la peine de le vérifier avec n'importe quelle intégration de facturation électronique, pas seulement avec celle où nous l'avons trouvé. Nous ne vendons pas de module de facturation : cet article n'a pas de produit à proposer à la fin, seulement un mécanisme à connaître si vous en installez un.

Étiquettes : checkout fatturazione sdi

Laisser un commentaire

Les commentaires sont modérés avant publication.

← Blog

Chargement...
Retour en haut