Comptabilité (Xero, QuickBooks)
Extension payante. Un règlement abouti pose un client et une facture dans Xero ou QuickBooks Online. Une facture par transaction, écrite en tâche de fond.
C’est le dernier maillon de la chaîne commerciale : le formulaire encaisse, la comptabilité enregistre. Le module fait cela, et rien d’autre — pas de rapprochement bancaire, pas d’avoir, pas de stock, pas de déclaration, pas de synchronisation en sens inverse, pas de modification d’une facture finalisée.
Deux choses le distinguent des vingt-sept modules qui le précèdent, et ce sont les deux premières sections.
Xero a un brouillon. QuickBooks n’en a pas.
C’est le fait qui décide de tout.
Chez Xero, une facture DRAFT ne crée aucune écriture et n’apparaît dans aucun
rapport. Un comptable la relit, la corrige, l’approuve. C’est exactement ce qu’on
entend par brouillon, et c’est ce que le plan demandait : « commencer par brouillon
plutôt que facture finale ».
Chez QuickBooks Online, l’API ne permet pas de créer une facture qui ne poste pas : une facture créée touche les livres immédiatement. Le seul objet non comptabilisé est le devis, qui est une proposition commerciale — en fabriquer un pour une commande déjà payée écrirait une contre-vérité dans la comptabilité de quelqu’un.
Cette différence n’est pas lissée. Le mode par défaut étant le brouillon, un formulaire relié à QuickBooks n’écrit rien tant que l’administrateur n’a pas explicitement choisi la facture comptabilisée. Trois écrans le disent : le panneau du formulaire, l’écran du module, et le rapprochement.
Le silence est volontaire. Il vaut mieux qu’un site qui poste des factures à l’insu de son propriétaire.
Et ce refus est inscrit
Une première version s’arrêtait avant même de créer la ligne de suivi : le site n’écrivait rien, et n’en gardait aucune trace. L’écran de rapprochement — dont tout l’objet est de montrer ce qui manque aux livres — ne montrait précisément pas ce cas-là.
La ligne est désormais posée, en échec, avec son motif. Un encaissement non facturé qui ne figure nulle part est la pire des deux erreurs possibles.
Rien n’est recalculé
Ni le prix, ni la remise, ni la taxe. Tout vient du récapitulatif enregistré avec la transaction, c’est-à-dire de ce qui a été affiché au client puis débité.
Un tarif, un taux ou un libellé peut changer après coup. Une facture composée depuis la configuration du formulaire montrerait alors autre chose que ce qui a été prélevé — et une facture qui ne correspond pas au prélèvement est une erreur comptable, pas un détail d’affichage.
Les montants restent en centimes entiers, comme dans le cœur des paiements, et ne sont divisés qu’au moment de composer la requête. Faire l’aller-retour à chaque étape aurait rouvert l’écart que le cœur ferme.
Si cela ne s’équilibre pas, rien n’est écrit
Lignes, moins la remise, plus la taxe si elle s’ajoute : le résultat doit retomber sur le montant encaissé, à deux centimes près — la tolérance d’un arrondi de taxe sur un sous-total remisé, pas celle d’une divergence de structure.
Au-delà, le module refuse. Un document qui ne s’équilibre pas laisse celui qui le relira sans aucun moyen de savoir lequel des deux chiffres croire.
La remise est une ligne, pas un prix rogné
Il aurait été plus court de retrancher la remise des prix unitaires : les lignes seraient retombées sur le total débité, et rien n’aurait eu l’air faux.
Ce serait une facture qui ment sur son contenu. Le client a commandé un article à son prix et obtenu une réduction ; des livres qui montrent l’article moins cher perdent la trace du geste commercial, et le code promotionnel avec lui.
Les deux services l’expriment différemment, et chacun reçoit le sien : une ligne de
montant négatif chez Xero, qui n’a pas de ligne de remise au niveau de la
facture ; une DiscountLineDetail en dernière position chez QuickBooks, qui en
a une, et dont le montant est positif — c’est le type qui dit qu’elle se retranche.
Ce point a coûté un défaut. Le contrôle d’équilibre d’origine comparait les lignes au total sans retrancher la remise : toute commande portant un code promotionnel repartait en « ne s’équilibre pas », sans rien écrire. Rien ne le trahissait, puisque les commandes sans remise passaient.
La taxe, et sa limite
Une commande sans taxe est annoncée comme telle : NoTax chez Xero,
NotApplicable chez QuickBooks. Sans cela, le service applique le taux par défaut
du compte de vente, et la facture réclame une taxe que le client n’a jamais payée.
Quand une taxe a été prélevée, le mode est transmis — prix taxe comprise ou hors taxe, se tromper ici décale le total de la taxe entière — mais le taux appliqué reste celui de la comptabilité : ce module n’impose pas le sien, parce qu’un taux de formulaire ne correspond à aucun code de taxe chez le fournisseur.
C’est la limite assumée, et une raison de plus pour que le brouillon soit le mode par défaut : un humain relit le chiffre avant qu’il n’entre dans les livres. Chez QuickBooks, où il n’y a pas de brouillon, c’est une raison de plus de n’activer la facture comptabilisée qu’en connaissance de cause.
Le paiement est acquis avant qu’on arrive ici
Une soumission dont le règlement ne convient pas est refusée avant tout enregistrement, par le garde du module de paiement. Ce module se raccroche donc à la soumission enregistrée, et contrôle seulement que la transaction attachée a bien abouti — une transaction peut passer en échec après coup, entre la planification et le passage du planificateur.
Il refuse aussi une soumission mise à la corbeille ou marquée indésirable : on ne facture pas ce qu’on vient de retirer de chez soi.
L’idempotence a deux étages
UNIQUE (transaction_id) empêche deux tâches croisées d’écrire deux fois, et la
prise de ligne — un UPDATE … WHERE state <> 'sent' avec un bail de quinze
minutes — empêche deux passages simultanés du planificateur.
La clé d’idempotence couvre le cas que la contrainte ne couvre pas : la requête
aboutit, et la réponse se perd en route. Elle est dérivée de la transaction, donc
stable d’une tentative à l’autre, et le service rend alors la première facture au
lieu d’en écrire une seconde. Xero la lit dans un en-tête Idempotency-Key,
QuickBooks dans un paramètre requestid : l’interface n’en demande qu’une, et
chaque fournisseur la place où son service l’attend.
C’est la garantie qui coûterait le plus cher à manquer. Un doublon de tableur se supprime ; un doublon de facture s’annule par une écriture inverse qu’il faut justifier, et se remarque à la clôture, longtemps après.
Les deux services n’honorent cependant une clé que pendant un temps fini. Un renvoi longtemps après la première tentative peut donc écrire une seconde facture, et l’écran le dit au moment de le proposer.
L’écran répond à la question d’un comptable
Pas « qu’est-ce qui est parti », mais « qu’est-ce qui a été encaissé et ne se trouve pas dans mes livres ». La jointure se fait sur la table des transactions, et non sur celle des documents : une ligne qui manquerait des deux côtés ne se verrait jamais.
Chaque motif de refus y est expliqué en français, parce que les trois plus fréquents
ne sont pas des pannes mais des refus volontaires du module : draft_unsupported,
does_not_balance, no_order_summary.
Le renvoi d’une facture n’existe que là, et pas dans le détail d’une soumission comme dans tous les autres modules. C’est un détour volontaire : rejouer une écriture comptable sans avoir d’abord regardé ce qui se trouve réellement dans la comptabilité, c’est accepter d’en poser une seconde.
Une transaction déjà facturée est d’ailleurs refusée au renvoi, et l’écran invite à ouvrir la facture plutôt qu’à en écrire une autre.
L’entreprise n’est pas devinée
realmId chez QuickBooks, identifiant de locataire chez Xero : sans lui, un jeton
valide ne sait pas dans quelle comptabilité écrire, et un jeton valide avec le
mauvais écrirait dans les livres d’une autre société.
Chez QuickBooks, il arrive avec le retour d’autorisation et nulle part ailleurs.
Chez Xero, il se demande à api.xero.com/connections juste après l’échange ; le
premier locataire est retenu, et l’écran montre le nom de l’entreprise — c’est ainsi
qu’on s’aperçoit de s’être relié à la mauvaise.
Une connexion sans entreprise n’est pas considérée comme prête, et le bouton « Éprouver la connexion » ne demande pas « êtes-vous là » mais « dans quels livres j’écris ».
Le client est désigné, pas deviné
Prendre « le premier champ qui ressemble à un nom » aurait facturé au nom d’un champ « Nom de votre entreprise » là où l’on voulait la personne, ou l’inverse.
Sans champ désigné, la facture porte le numéro de la soumission — Client #128 —
parce qu’une facture doit porter un client, et qu’un client nommé par ce qu’on sait
vraiment vaut mieux qu’un refus d’écrire pour un réglage qu’on a oublié.
Chez QuickBooks, le client est cherché avant d’être créé : sans cela, chaque commande de la même personne en créerait un nouveau, et le fichier clients doublerait tous les mois. Chez Xero, le contact est posé avec la facture, le service s’en chargeant lui-même.
Le journal ne porte aucun montant
Le journal des envois reçoit le code HTTP et le motif d’un refus. Ni les lignes, ni les totaux, ni le nom du client, ni l’identifiant de l’entreprise comptable : ce journal se consulte avec les soumissions, et le chiffre d’affaires d’un marchand ne s’y trouve pas.
Effacer une soumission n’annule pas la facture
La ligne de suivi s’en va avec la soumission. La facture, elle, reste dans la comptabilité du client.
Effacer une soumission est un acte d’effacement de données ; annuler une facture est un acte comptable qui se fait par une écriture inverse, et qui ne se décide pas depuis un écran de formulaires.
Ce qui n’est pas tenté, et ce qui est rejoué
Ne sont pas rejoués : un paiement qui n’a pas abouti, une soumission inactive, un récapitulatif absent ou qui ne s’équilibre pas, un brouillon demandé à un service qui n’en a pas, une autorisation périmée. Aucun de ces cas ne se répare en réessayant, et chacun porte son motif à l’écran.
Sont rejoués, trois fois, à une puis cinq puis trente minutes : une panne réseau, un
429, un 5xx.
Schéma
slf_accounting_documents : une ligne par transaction facturée, avec
UNIQUE (transaction_id), l’identifiant du document distant, l’état que le service
lui a donné, le motif du dernier problème et le nombre de tentatives.
Il n’y a pas de remise en attente automatique, contrairement aux autres modules : le renvoi passe par l’écran de rapprochement.
Les connexions vivent dans une option, indexées par fournisseur. Les jetons et le secret client y sont chiffrés ; l’identifiant client, celui de l’entreprise et son nom ne le sont pas — ce ne sont pas des secrets, et les lire en clair est exactement ce qu’on veut quand on cherche pourquoi des factures arrivent dans la mauvaise société.
Ce que la V1 ne fait pas
Pas d’avoir, pas de remboursement répercuté, pas de modification d’une facture déjà écrite, pas de paiement rattaché à la facture, pas de relance, pas de produit ni de compte de vente choisis par ligne, pas de sélection d’organisation quand une application en couvre plusieurs, pas de lecture depuis la comptabilité vers le site.
