Avant de payer un fournisseur, une entreprise prudente vérifie trois papiers : ce qu’elle a commandé, ce qu’elle a reçu, et ce qu’on lui facture. C’est tout le three-way match — « rapprochement à trois documents » en français. La règle tient en une phrase ; ses conséquences remplissent cet article. Nous allons suivre une seule facture, pas à pas, du bon de commande jusqu’au paiement.
Before paying a supplier, a careful company checks three documents: what it ordered, what it received, and what it is being billed. That is the whole three-way match. The rule fits in one sentence; its consequences fill this article. We will follow a single invoice, step by step, from purchase order to payment.
Trois documents, deux questionsThree documents, two questions
Quand une entreprise achète, trois papiers se succèdent. Chacun raconte une partie de l’histoire — et aucun ne suffit seul. Cliquez sur les étapes pour suivre notre facture fil rouge.When a company buys, three documents follow one another. Each tells part of the story — and none is enough on its own. Click through the steps to follow our running invoice.
1 · Le bon de commande — « ce qu’on a promis d’acheter »1 · The purchase order — “what we promised to buy”
L’entreprise passe commande : la référence, la quantité et surtout le prix convenu. C’est le document de l’engagement — la promesse écrite des deux côtés.The company places the order: the reference, the quantity and above all the agreed price. It is the document of commitment — the written promise on both sides.
2 · Le bon de réception — « ce qui est vraiment arrivé »2 · The receipt — “what actually arrived”
À la livraison, quelqu’un compte ce qui entre dans l’entrepôt et le note. C’est le document du réel : pas ce qui était prévu, ce qui est arrivé.At delivery, someone counts what enters the warehouse and writes it down. It is the document of reality: not what was planned — what arrived.
3 · La facture — « ce que le fournisseur réclame »3 · The invoice — “what the supplier claims”
Le fournisseur envoie sa demande de paiement. C’est le document de la réclamation — et rien ne garantit qu’elle corresponde aux deux premiers.The supplier sends its payment request. It is the document of the claim — and nothing guarantees it matches the first two.
Tout le three-way match se ramène à ces deux questions. La quantité : on ne paie pas plus que ce qu’on a reçu. Le prix : on ne paie pas plus cher que ce qui a été convenu. Notre facture fil rouge passe la première question et échoue à la seconde — c’est exactement le cas que beaucoup de systèmes laissent passer, on verra pourquoi au niveau 3.The whole three-way match boils down to these two questions. Quantity: never pay for more than you received. Price: never pay more than what was agreed. Our running invoice passes the first question and fails the second — exactly the case many systems let through, as we’ll see at level 3.
Ce que la vérification empêcheWhat the check prevents
Personne n’installe ce contrôle pour le plaisir de comparer des papiers. On l’installe contre cinq façons bien réelles de perdre de l’argent :Nobody sets up this control for the joy of comparing paperwork. It exists to stop five very real ways of losing money:
Faut-il toujours trois documents ?Do you always need three documents?
Non — et c’est une vraie décision, pas un réglage par défaut. Un abonnement logiciel n’a pas de livraison à compter : exiger une réception bloquerait tout. À l’inverse, des marchandises stockées méritent les trois documents. Le bon niveau dépend de ce qu’on achète :No — and it is a real decision, not a default setting. A software subscription has no delivery to count: requiring a receipt would block everything. Stocked goods, on the other hand, deserve all three documents. The right level depends on what you buy:
Chaque question a sa référenceEach question has its own reference
Le point que presque tout le monde simplifie à tort : les deux questions ne se vérifient pas contre le même document. La quantité facturée se compare à ce qui a été reçu. Le prix facturé se compare à ce qui a été convenu — et « convenu » ne veut pas toujours dire « le bon de commande ».The point almost everyone wrongly simplifies: the two questions are not checked against the same document. The billed quantity is compared with what was received. The billed price is compared with what was agreed — and “agreed” does not always mean “the purchase order”.
Les tolérances — jusqu’où fermer les yeuxTolerances — how far to look away
Bloquer chaque facture au moindre centime d’écart noierait l’équipe sous les alertes — et un contrôle qui alerte trop finit ignoré. On définit donc une tolérance : en dessous d’un seuil, l’écart est accepté automatiquement. C’est le réglage le plus important du dispositif, et le plus souvent raté. Testez trois réglages sur un cas réel :Blocking every invoice over a single cent would drown the team in alerts — and a control that cries wolf ends up ignored. So we define a tolerance: below a threshold, the gap is accepted automatically. It is the most important setting of the whole system, and the most often botched. Try three settings on a real case:
1,8 % est sous le seuil de 3 % : chaque ligne est validée automatiquement, « dans la tolérance ». Le surpaiement fait 7 200 € par mois — et personne ne voit rien, puisque chaque ligne, prise seule, est acceptable.1.8% sits below the 3% threshold: every line is approved automatically, “within tolerance”. The overpayment is €7,200 a month — and nobody sees a thing, since each line, taken alone, is acceptable.
Sur une ligne moyenne de 500 €, 1,8 % font 9 € — très en dessous des 50 €. Chaque ligne passe encore. Un seuil bien conçu combine d’ailleurs les deux (« moins de 2 % et moins de 200 € »)… mais aucun seuil par ligne, si malin soit-il, n’attrapera une dérive diffuse.On an average €500 line, 1.8% is €9 — far below €50. Every line still passes. A well-designed threshold combines both (“under 2% and under €200”)… but no per-line threshold, however clever, will catch a diffuse drift.
Chaque ligne reste acceptée, mais le tableau de bord additionne les écarts acceptés par fournisseur : 7 200 € ce mois-ci chez ce fournisseur. L’alerte vient du cumul, pas de la ligne. C’est la leçon du chapitre : la dérive lente ne se voit qu’au cumul.Each line remains accepted, but the dashboard adds up the accepted gaps per supplier: €7,200 this month for this supplier. The alert comes from the total, not from any line. That is the chapter’s lesson: slow drift only shows in the aggregate.
Trois règles pour une tolérance bien conçueThree rules for a well-designed tolerance
Ce que ça écrit en comptabilitéWhat it writes in the books
Le rapprochement ne se termine pas par « on paie / on ne paie pas » : il produit des écritures comptables. Entre le jour où la marchandise arrive et le jour où la facture arrive, il se passe quelque chose en comptabilité — suivons notre facture fil rouge, étape par étape.The match does not end with “pay / don’t pay”: it produces journal entries. Between the day the goods arrive and the day the invoice arrives, something happens in the books — let’s follow our running invoice, step by step.
Jour 1 — la marchandise arrive, pas la factureDay 1 — the goods arrive, the invoice doesn’t
Le stock entre pour sa valeur convenue (500 × 8,00 €). En face, on ne connaît pas encore la dette exacte : elle va dans un compte d’attente — une « dette provisoire » envers le fournisseur. Les grands systèmes l’appellent GR/IR, Odoo « compte d’interception de stock » : même idée.Inventory comes in at its agreed value (500 × €8.00). On the other side, the exact debt isn’t known yet: it goes to a holding account — a “provisional debt” to the supplier. Big systems call it GR/IR; Odoo calls it the “stock interim account”: same idea.
Jour 18 — la facture arrive : 4 200 €Day 18 — the invoice arrives: €4,200
Le compte d’attente se vide, la dette devient réelle envers le fournisseur — au montant facturé. Reste une question : où mettre les 200 € d’écart ?The holding account empties, and the debt to the supplier becomes real — at the billed amount. One question remains: where do the €200 go?
Les 200 € — stock ou charge ? Ça dépend de ce qui resteThe €200 — inventory or expense? Depends on what’s left
Si l’entreprise valorise son stock au coût réellement payé, l’écart corrige la valeur… des pièces encore en stock seulement. Entre-temps, 300 pièces ont déjà été vendues : leur part de l’écart part en coût des ventes. (En « coût standard », autre méthode, tout l’écart irait dans un compte dédié d’écart sur prix d’achat.)If the company values its inventory at the cost actually paid, the gap corrects the value… of the parts still in stock only. Meanwhile, 300 parts have already been sold: their share of the gap goes to cost of sales. (Under “standard cost”, another method, the whole gap would go to a dedicated purchase price variance account.)
Le compte d’attente, thermomètre du processusThe holding account, the process’s thermometer
Le solde de ce compte d’attente a une signification très concrète : c’est la valeur de tout ce qu’on a reçu et que personne ne nous a encore facturé. À chaque clôture, on le passe en revue par ancienneté — un solde qui vieillit sans explication est le symptôme d’un processus malade :The balance of this holding account means something very concrete: it is the value of everything received that nobody has invoiced us for yet. At every close, review it by age — a balance ageing without explanation is the symptom of a sick process:
Le contrôle qui ne se code pas : séparer les rôlesThe control you can’t code: separating roles
Un dernier garde-fou, avant Odoo. Imaginez qu’une même personne crée un fournisseur, émette la commande, enregistre une réception fictive, saisisse la facture et l’approuve : les trois documents concordent parfaitement — ils ont été fabriqués par la même main. Aucun rapprochement ne détecte cette fraude ; seule la séparation des rôles la rend impossible. Créer le fournisseur (et son IBAN), commander, réceptionner, saisir la facture, approuver le paiement, l’exécuter — et régler les tolérances : sept rôles, des personnes distinctes. Le dernier est le plus souvent oublié.One last safeguard before Odoo. Imagine one person creating a supplier, issuing the order, recording a fictitious receipt, entering the invoice and approving it: all three documents match perfectly — they were made by the same hand. No matching detects this fraud; only role separation makes it impossible. Creating the supplier (and its bank details), ordering, receiving, entering the invoice, approving payment, executing it — and setting tolerances: seven roles, distinct people. The last one is the most often forgotten.
Ce qu’Odoo appelle « 3-way matching »What Odoo calls “3-way matching”
Odoo propose une option nommée 3-way matching dans les paramètres Achats. Une fois activée, chaque facture porte un champ « Doit être payé » qui compare la quantité facturée à la quantité reçue. Deux limites, énormes, à connaître avant de cocher la case :Odoo offers an option called 3-way matching in the Purchase settings. Once enabled, every bill carries a “Should Be Paid” field comparing billed quantity with received quantity. Two huge limits to know before ticking the box:
Le champ prend la valeur Oui, Non ou Exception — et c’est tout. Aucun message d’erreur, aucune barrière : un utilisateur peut voir « Exception » et enregistrer le paiement sans obstacle. La documentation d’Odoo l’assume : le système remarque l’écart, il ne l’empêche pas.The field shows Yes, No or Exception — and that’s it. No error message, no barrier: a user can see “Exception” and register the payment unhindered. Odoo’s documentation owns it: the system notices the discrepancy, it does not prevent it.
Le calcul porte uniquement sur la quantité. 100 pièces commandées à 10 €, reçues, facturées 100 pièces à 15 € : quantité conforme, champ à « Oui », surpaiement de 50 % sans le moindre signalement.The calculation covers quantity only. 100 parts ordered at €10, received, billed as 100 parts at €15: quantity compliant, field says “Yes”, a 50% overpayment without the slightest flag.
Le socle natif est pourtant plus riche qu’on ne le ditYet the native foundation is richer than people say
Soyons justes : Odoo relie proprement les trois documents ligne à ligne (champ purchase_line_id), gère les livraisons partielles, empêche de facturer sans aucune réception, possède le compte d’attente du chapitre 5, sait incorporer les frais de transport au coût du stock (landed costs), gère les contrats d’achat annuels, numérise les factures reçues (Enterprise) — et dispose d’un blocage de paiement au niveau de la ligne comptable, méconnu et décisif pour la suite. Ce qui manque n’est pas le socle : c’est la couche de contrôle actif au-dessus.To be fair: Odoo links the three documents line by line (the purchase_line_id field), handles partial deliveries, prevents billing with no receipt at all, has the chapter 5 holding account, can roll freight into inventory cost (landed costs), manages annual purchase agreements, digitises incoming invoices (Enterprise) — and has a payment block at journal-line level, little known and decisive for what follows. What’s missing isn’t the foundation: it’s the active control layer on top.
Le piège : l’écart qui disparaîtThe trap: the gap that disappears
Qu’Odoo ne contrôle pas le prix est déjà gênant. Ce qui suit l’est davantage : dans son flux le plus naturel, Odoo fait disparaître l’écart de prix. Déroulez les deux parcours avec notre facture fil rouge — le parcours standard, puis le parcours corrigé.That Odoo doesn’t check the price is already troubling. What follows is worse: in its most natural flow, Odoo makes the price gap disappear. Walk through both journeys with our running invoice — the standard flow, then the corrected one.
1 · La facture papier arrive : 500 × 8,40 €1 · The paper invoice arrives: 500 × €8.40
Le fournisseur réclame 4 200 €. Le comptable ouvre le bon de commande dans Odoo pour créer la facture correspondante — le geste le plus naturel du monde.The supplier claims €4,200. The accountant opens the purchase order in Odoo to create the matching bill — the most natural gesture in the world.
2 · Clic sur « Créer la facture » — Odoo pré-remplit2 · Click “Create Bill” — Odoo pre-fills
Odoo recopie les quantités reçues… et le prix du bon de commande : 8,00 €. Pas 8,40 €. La facture à l’écran ne correspond déjà plus au document papier.Odoo copies the received quantities… and the purchase-order price: €8.00. Not €8.40. The bill on screen already no longer matches the paper document.
3 · Validation en un clic — tout est vert3 · One-click validation — everything is green
Quantité facturée = quantité reçue : le champ « Doit être payé » affiche Oui. La facture est comptabilisée à 4 000 €. Aucune alerte — il n’y a, dans le système, littéralement aucun écart.Billed quantity = received quantity: the “Should Be Paid” field shows Yes. The bill is posted at €4,000. No alert — in the system there is literally no discrepancy.
4 · L’écart n’a jamais existé — et le paiement part à 4 200 €4 · The gap never existed — and the payment goes out at €4,200
Le prix réel de 8,40 € n’a jamais été enregistré : aucun audit ne pourra retrouver l’écart, la donnée a été détruite à la saisie. Le règlement, lui, part au montant du papier : 4 200 €. Les 200 € de différence ressurgiront des semaines plus tard, au rapprochement bancaire, sans cause identifiable.The real €8.40 price was never recorded: no audit will ever find the gap — the data was destroyed at entry. The payment, though, goes out at the paper amount: €4,200. The €200 difference resurfaces weeks later, at bank reconciliation, with no identifiable cause.
Écart enregistré : non
Retrouvable a posteriori : nonGap detected: no
Gap recorded: no
Traceable afterwards: no
1 · La facture entre par la numérisation1 · The invoice enters through digitisation
Le document du fournisseur est numérisé (ou reçu en format électronique) : 500 × 8,40 €. Le prix réellement réclamé entre dans le système tel quel — c’est toute la différence. On ne crée jamais la facture depuis le bon de commande.The supplier’s document is digitised (or received electronically): 500 × €8.40. The price actually claimed enters the system as is — that is the whole difference. The bill is never created from the purchase order.
2 · Rattachement à la commande2 · Linked to the order
La facture capturée est reliée au bon de commande, ligne à ligne. Ce lien est le prérequis absolu : sans lui, aucune comparaison automatique n’est possible, quel que soit le développement réalisé.The captured bill is linked to the purchase order, line by line. This link is the absolute prerequisite: without it, no automatic comparison is possible, whatever gets developed.
purchase_line_id3 · Le contrôle compare — et trouve l’écart3 · The control compares — and finds the gap
Quantité : 500 = 500, conforme. Prix : 8,40 € contre 8,00 € convenus au contrat — écart de +5 %, tolérance nulle sur ce fournisseur. L’écart existe, il est mesuré, il est tracé.Quantity: 500 = 500, compliant. Price: €8.40 versus €8.00 agreed in the contract — a +5% gap, zero tolerance on this supplier. The gap exists, it is measured, it is traced.
4 · Comptabilisée, mais pas payable4 · Posted, but not payable
La facture est enregistrée en comptabilité à 4 200 € — la dette est vraie, les comptes sont justes. Mais un blocage de paiement est posé sur la ligne : aucun règlement ne peut partir. Une tâche est assignée à l’acheteur ; le blocage ne se lève que par résolution ou dérogation justifiée et tracée.The bill is posted in the books at €4,200 — the debt is true, the accounts are right. But a payment block is set on the line: no payment can go out. A task is assigned to the buyer; the block is only lifted by resolution or by a justified, traced override.
Paiement : bloqué
Écart tracé : oui, +5 %Debt right: yes, €4,200
Payment: blocked
Gap traced: yes, +5%
L’architecture cible, en six briquesThe target architecture, in six building blocks
Concevoir un vrai three-way match sur Odoo n’est pas cocher une case : c’est inverser le flux d’entrée de la facture, puis construire une couche de contrôle sur le socle natif. Six briques, dans l’ordre :Designing a real three-way match on Odoo is not ticking a box: it means inverting the invoice entry flow, then building a control layer on the native foundation. Six blocks, in order:
Avant tout paramétrage : cinq décisions à faire signerBefore any configuration: five decisions to get signed
Sans ces cinq documents validés par la direction financière, tout paramétrage est arbitraire et ne tiendra pas l’audit :Without these five documents approved by finance leadership, any configuration is arbitrary and will not survive an audit:
purchase-workflow) sur la version cible, et tester le tout en recette : écart de prix bloqué mais comptabilisé, achat en devise sans faux écart, facture en transit, dérogation tracée.The success criterion is not “block everything”. A mature setup aims for both a high share of invoices processed without human intervention (> 80% in the relevant categories) and real control. The two only conflict when capture quality is poor or tolerances badly set. Before developing: evaluate the community OCA modules (the purchase-workflow repository) on the target version, and test everything in UAT: a price gap blocked but posted, a foreign-currency purchase with no false gap, an invoice in transit, a traced override.Le jargon, traduit une fois pour toutesThe jargon, translated once and for all
Avant de payer un fournisseur, une entreprise prudente vérifie trois papiers : ce qu’elle a commandé, ce qu’elle a reçu, et ce qu’on lui facture. C’est tout le three-way match — « rapprochement à trois documents » en français. La règle tient en une phrase ; ses conséquences remplissent cet article. Nous allons suivre une seule facture, pas à pas, du bon de commande jusqu’au paiement.
Before paying a supplier, a careful company checks three documents: what it ordered, what it received, and what it is being billed. That is the whole three-way match. The rule fits in one sentence; its consequences fill this article. We will follow a single invoice, step by step, from purchase order to payment.
Trois documents, deux questionsThree documents, two questions
Quand une entreprise achète, trois papiers se succèdent. Chacun raconte une partie de l’histoire — et aucun ne suffit seul. Cliquez sur les étapes pour suivre notre facture fil rouge.When a company buys, three documents follow one another. Each tells part of the story — and none is enough on its own. Click through the steps to follow our running invoice.
1 · Le bon de commande — « ce qu’on a promis d’acheter »1 · The purchase order — “what we promised to buy”
L’entreprise passe commande : la référence, la quantité et surtout le prix convenu. C’est le document de l’engagement — la promesse écrite des deux côtés.The company places the order: the reference, the quantity and above all the agreed price. It is the document of commitment — the written promise on both sides.
2 · Le bon de réception — « ce qui est vraiment arrivé »2 · The receipt — “what actually arrived”
À la livraison, quelqu’un compte ce qui entre dans l’entrepôt et le note. C’est le document du réel : pas ce qui était prévu, ce qui est arrivé.At delivery, someone counts what enters the warehouse and writes it down. It is the document of reality: not what was planned — what arrived.
3 · La facture — « ce que le fournisseur réclame »3 · The invoice — “what the supplier claims”
Le fournisseur envoie sa demande de paiement. C’est le document de la réclamation — et rien ne garantit qu’elle corresponde aux deux premiers.The supplier sends its payment request. It is the document of the claim — and nothing guarantees it matches the first two.
Tout le three-way match se ramène à ces deux questions. La quantité : on ne paie pas plus que ce qu’on a reçu. Le prix : on ne paie pas plus cher que ce qui a été convenu. Notre facture fil rouge passe la première question et échoue à la seconde — c’est exactement le cas que beaucoup de systèmes laissent passer, on verra pourquoi au niveau 3.The whole three-way match boils down to these two questions. Quantity: never pay for more than you received. Price: never pay more than what was agreed. Our running invoice passes the first question and fails the second — exactly the case many systems let through, as we’ll see at level 3.
Ce que la vérification empêcheWhat the check prevents
Personne n’installe ce contrôle pour le plaisir de comparer des papiers. On l’installe contre cinq façons bien réelles de perdre de l’argent :Nobody sets up this control for the joy of comparing paperwork. It exists to stop five very real ways of losing money:
Faut-il toujours trois documents ?Do you always need three documents?
Non — et c’est une vraie décision, pas un réglage par défaut. Un abonnement logiciel n’a pas de livraison à compter : exiger une réception bloquerait tout. À l’inverse, des marchandises stockées méritent les trois documents. Le bon niveau dépend de ce qu’on achète :No — and it is a real decision, not a default setting. A software subscription has no delivery to count: requiring a receipt would block everything. Stocked goods, on the other hand, deserve all three documents. The right level depends on what you buy:
Chaque question a sa référenceEach question has its own reference
Le point que presque tout le monde simplifie à tort : les deux questions ne se vérifient pas contre le même document. La quantité facturée se compare à ce qui a été reçu. Le prix facturé se compare à ce qui a été convenu — et « convenu » ne veut pas toujours dire « le bon de commande ».The point almost everyone wrongly simplifies: the two questions are not checked against the same document. The billed quantity is compared with what was received. The billed price is compared with what was agreed — and “agreed” does not always mean “the purchase order”.
Les tolérances — jusqu’où fermer les yeuxTolerances — how far to look away
Bloquer chaque facture au moindre centime d’écart noierait l’équipe sous les alertes — et un contrôle qui alerte trop finit ignoré. On définit donc une tolérance : en dessous d’un seuil, l’écart est accepté automatiquement. C’est le réglage le plus important du dispositif, et le plus souvent raté. Testez trois réglages sur un cas réel :Blocking every invoice over a single cent would drown the team in alerts — and a control that cries wolf ends up ignored. So we define a tolerance: below a threshold, the gap is accepted automatically. It is the most important setting of the whole system, and the most often botched. Try three settings on a real case:
1,8 % est sous le seuil de 3 % : chaque ligne est validée automatiquement, « dans la tolérance ». Le surpaiement fait 7 200 € par mois — et personne ne voit rien, puisque chaque ligne, prise seule, est acceptable.1.8% sits below the 3% threshold: every line is approved automatically, “within tolerance”. The overpayment is €7,200 a month — and nobody sees a thing, since each line, taken alone, is acceptable.
Sur une ligne moyenne de 500 €, 1,8 % font 9 € — très en dessous des 50 €. Chaque ligne passe encore. Un seuil bien conçu combine d’ailleurs les deux (« moins de 2 % et moins de 200 € »)… mais aucun seuil par ligne, si malin soit-il, n’attrapera une dérive diffuse.On an average €500 line, 1.8% is €9 — far below €50. Every line still passes. A well-designed threshold combines both (“under 2% and under €200”)… but no per-line threshold, however clever, will catch a diffuse drift.
Chaque ligne reste acceptée, mais le tableau de bord additionne les écarts acceptés par fournisseur : 7 200 € ce mois-ci chez ce fournisseur. L’alerte vient du cumul, pas de la ligne. C’est la leçon du chapitre : la dérive lente ne se voit qu’au cumul.Each line remains accepted, but the dashboard adds up the accepted gaps per supplier: €7,200 this month for this supplier. The alert comes from the total, not from any line. That is the chapter’s lesson: slow drift only shows in the aggregate.
Trois règles pour une tolérance bien conçueThree rules for a well-designed tolerance
Ce que ça écrit en comptabilitéWhat it writes in the books
Le rapprochement ne se termine pas par « on paie / on ne paie pas » : il produit des écritures comptables. Entre le jour où la marchandise arrive et le jour où la facture arrive, il se passe quelque chose en comptabilité — suivons notre facture fil rouge, étape par étape.The match does not end with “pay / don’t pay”: it produces journal entries. Between the day the goods arrive and the day the invoice arrives, something happens in the books — let’s follow our running invoice, step by step.
Jour 1 — la marchandise arrive, pas la factureDay 1 — the goods arrive, the invoice doesn’t
Le stock entre pour sa valeur convenue (500 × 8,00 €). En face, on ne connaît pas encore la dette exacte : elle va dans un compte d’attente — une « dette provisoire » envers le fournisseur. Les grands systèmes l’appellent GR/IR, Odoo « compte d’interception de stock » : même idée.Inventory comes in at its agreed value (500 × €8.00). On the other side, the exact debt isn’t known yet: it goes to a holding account — a “provisional debt” to the supplier. Big systems call it GR/IR; Odoo calls it the “stock interim account”: same idea.
Jour 18 — la facture arrive : 4 200 €Day 18 — the invoice arrives: €4,200
Le compte d’attente se vide, la dette devient réelle envers le fournisseur — au montant facturé. Reste une question : où mettre les 200 € d’écart ?The holding account empties, and the debt to the supplier becomes real — at the billed amount. One question remains: where do the €200 go?
Les 200 € — stock ou charge ? Ça dépend de ce qui resteThe €200 — inventory or expense? Depends on what’s left
Si l’entreprise valorise son stock au coût réellement payé, l’écart corrige la valeur… des pièces encore en stock seulement. Entre-temps, 300 pièces ont déjà été vendues : leur part de l’écart part en coût des ventes. (En « coût standard », autre méthode, tout l’écart irait dans un compte dédié d’écart sur prix d’achat.)If the company values its inventory at the cost actually paid, the gap corrects the value… of the parts still in stock only. Meanwhile, 300 parts have already been sold: their share of the gap goes to cost of sales. (Under “standard cost”, another method, the whole gap would go to a dedicated purchase price variance account.)
Le compte d’attente, thermomètre du processusThe holding account, the process’s thermometer
Le solde de ce compte d’attente a une signification très concrète : c’est la valeur de tout ce qu’on a reçu et que personne ne nous a encore facturé. À chaque clôture, on le passe en revue par ancienneté — un solde qui vieillit sans explication est le symptôme d’un processus malade :The balance of this holding account means something very concrete: it is the value of everything received that nobody has invoiced us for yet. At every close, review it by age — a balance ageing without explanation is the symptom of a sick process:
Le contrôle qui ne se code pas : séparer les rôlesThe control you can’t code: separating roles
Un dernier garde-fou, avant Odoo. Imaginez qu’une même personne crée un fournisseur, émette la commande, enregistre une réception fictive, saisisse la facture et l’approuve : les trois documents concordent parfaitement — ils ont été fabriqués par la même main. Aucun rapprochement ne détecte cette fraude ; seule la séparation des rôles la rend impossible. Créer le fournisseur (et son IBAN), commander, réceptionner, saisir la facture, approuver le paiement, l’exécuter — et régler les tolérances : sept rôles, des personnes distinctes. Le dernier est le plus souvent oublié.One last safeguard before Odoo. Imagine one person creating a supplier, issuing the order, recording a fictitious receipt, entering the invoice and approving it: all three documents match perfectly — they were made by the same hand. No matching detects this fraud; only role separation makes it impossible. Creating the supplier (and its bank details), ordering, receiving, entering the invoice, approving payment, executing it — and setting tolerances: seven roles, distinct people. The last one is the most often forgotten.
Ce qu’Odoo appelle « 3-way matching »What Odoo calls “3-way matching”
Odoo propose une option nommée 3-way matching dans les paramètres Achats. Une fois activée, chaque facture porte un champ « Doit être payé » qui compare la quantité facturée à la quantité reçue. Deux limites, énormes, à connaître avant de cocher la case :Odoo offers an option called 3-way matching in the Purchase settings. Once enabled, every bill carries a “Should Be Paid” field comparing billed quantity with received quantity. Two huge limits to know before ticking the box:
Le champ prend la valeur Oui, Non ou Exception — et c’est tout. Aucun message d’erreur, aucune barrière : un utilisateur peut voir « Exception » et enregistrer le paiement sans obstacle. La documentation d’Odoo l’assume : le système remarque l’écart, il ne l’empêche pas.The field shows Yes, No or Exception — and that’s it. No error message, no barrier: a user can see “Exception” and register the payment unhindered. Odoo’s documentation owns it: the system notices the discrepancy, it does not prevent it.
Le calcul porte uniquement sur la quantité. 100 pièces commandées à 10 €, reçues, facturées 100 pièces à 15 € : quantité conforme, champ à « Oui », surpaiement de 50 % sans le moindre signalement.The calculation covers quantity only. 100 parts ordered at €10, received, billed as 100 parts at €15: quantity compliant, field says “Yes”, a 50% overpayment without the slightest flag.
Le socle natif est pourtant plus riche qu’on ne le ditYet the native foundation is richer than people say
Soyons justes : Odoo relie proprement les trois documents ligne à ligne (champ purchase_line_id), gère les livraisons partielles, empêche de facturer sans aucune réception, possède le compte d’attente du chapitre 5, sait incorporer les frais de transport au coût du stock (landed costs), gère les contrats d’achat annuels, numérise les factures reçues (Enterprise) — et dispose d’un blocage de paiement au niveau de la ligne comptable, méconnu et décisif pour la suite. Ce qui manque n’est pas le socle : c’est la couche de contrôle actif au-dessus.To be fair: Odoo links the three documents line by line (the purchase_line_id field), handles partial deliveries, prevents billing with no receipt at all, has the chapter 5 holding account, can roll freight into inventory cost (landed costs), manages annual purchase agreements, digitises incoming invoices (Enterprise) — and has a payment block at journal-line level, little known and decisive for what follows. What’s missing isn’t the foundation: it’s the active control layer on top.
Le piège : l’écart qui disparaîtThe trap: the gap that disappears
Qu’Odoo ne contrôle pas le prix est déjà gênant. Ce qui suit l’est davantage : dans son flux le plus naturel, Odoo fait disparaître l’écart de prix. Déroulez les deux parcours avec notre facture fil rouge — le parcours standard, puis le parcours corrigé.That Odoo doesn’t check the price is already troubling. What follows is worse: in its most natural flow, Odoo makes the price gap disappear. Walk through both journeys with our running invoice — the standard flow, then the corrected one.
1 · La facture papier arrive : 500 × 8,40 €1 · The paper invoice arrives: 500 × €8.40
Le fournisseur réclame 4 200 €. Le comptable ouvre le bon de commande dans Odoo pour créer la facture correspondante — le geste le plus naturel du monde.The supplier claims €4,200. The accountant opens the purchase order in Odoo to create the matching bill — the most natural gesture in the world.
2 · Clic sur « Créer la facture » — Odoo pré-remplit2 · Click “Create Bill” — Odoo pre-fills
Odoo recopie les quantités reçues… et le prix du bon de commande : 8,00 €. Pas 8,40 €. La facture à l’écran ne correspond déjà plus au document papier.Odoo copies the received quantities… and the purchase-order price: €8.00. Not €8.40. The bill on screen already no longer matches the paper document.
3 · Validation en un clic — tout est vert3 · One-click validation — everything is green
Quantité facturée = quantité reçue : le champ « Doit être payé » affiche Oui. La facture est comptabilisée à 4 000 €. Aucune alerte — il n’y a, dans le système, littéralement aucun écart.Billed quantity = received quantity: the “Should Be Paid” field shows Yes. The bill is posted at €4,000. No alert — in the system there is literally no discrepancy.
4 · L’écart n’a jamais existé — et le paiement part à 4 200 €4 · The gap never existed — and the payment goes out at €4,200
Le prix réel de 8,40 € n’a jamais été enregistré : aucun audit ne pourra retrouver l’écart, la donnée a été détruite à la saisie. Le règlement, lui, part au montant du papier : 4 200 €. Les 200 € de différence ressurgiront des semaines plus tard, au rapprochement bancaire, sans cause identifiable.The real €8.40 price was never recorded: no audit will ever find the gap — the data was destroyed at entry. The payment, though, goes out at the paper amount: €4,200. The €200 difference resurfaces weeks later, at bank reconciliation, with no identifiable cause.
Écart enregistré : non
Retrouvable a posteriori : nonGap detected: no
Gap recorded: no
Traceable afterwards: no
1 · La facture entre par la numérisation1 · The invoice enters through digitisation
Le document du fournisseur est numérisé (ou reçu en format électronique) : 500 × 8,40 €. Le prix réellement réclamé entre dans le système tel quel — c’est toute la différence. On ne crée jamais la facture depuis le bon de commande.The supplier’s document is digitised (or received electronically): 500 × €8.40. The price actually claimed enters the system as is — that is the whole difference. The bill is never created from the purchase order.
2 · Rattachement à la commande2 · Linked to the order
La facture capturée est reliée au bon de commande, ligne à ligne. Ce lien est le prérequis absolu : sans lui, aucune comparaison automatique n’est possible, quel que soit le développement réalisé.The captured bill is linked to the purchase order, line by line. This link is the absolute prerequisite: without it, no automatic comparison is possible, whatever gets developed.
purchase_line_id3 · Le contrôle compare — et trouve l’écart3 · The control compares — and finds the gap
Quantité : 500 = 500, conforme. Prix : 8,40 € contre 8,00 € convenus au contrat — écart de +5 %, tolérance nulle sur ce fournisseur. L’écart existe, il est mesuré, il est tracé.Quantity: 500 = 500, compliant. Price: €8.40 versus €8.00 agreed in the contract — a +5% gap, zero tolerance on this supplier. The gap exists, it is measured, it is traced.
4 · Comptabilisée, mais pas payable4 · Posted, but not payable
La facture est enregistrée en comptabilité à 4 200 € — la dette est vraie, les comptes sont justes. Mais un blocage de paiement est posé sur la ligne : aucun règlement ne peut partir. Une tâche est assignée à l’acheteur ; le blocage ne se lève que par résolution ou dérogation justifiée et tracée.The bill is posted in the books at €4,200 — the debt is true, the accounts are right. But a payment block is set on the line: no payment can go out. A task is assigned to the buyer; the block is only lifted by resolution or by a justified, traced override.
Paiement : bloqué
Écart tracé : oui, +5 %Debt right: yes, €4,200
Payment: blocked
Gap traced: yes, +5%
L’architecture cible, en six briquesThe target architecture, in six building blocks
Concevoir un vrai three-way match sur Odoo n’est pas cocher une case : c’est inverser le flux d’entrée de la facture, puis construire une couche de contrôle sur le socle natif. Six briques, dans l’ordre :Designing a real three-way match on Odoo is not ticking a box: it means inverting the invoice entry flow, then building a control layer on the native foundation. Six blocks, in order:
Avant tout paramétrage : cinq décisions à faire signerBefore any configuration: five decisions to get signed
Sans ces cinq documents validés par la direction financière, tout paramétrage est arbitraire et ne tiendra pas l’audit :Without these five documents approved by finance leadership, any configuration is arbitrary and will not survive an audit:
purchase-workflow) sur la version cible, et tester le tout en recette : écart de prix bloqué mais comptabilisé, achat en devise sans faux écart, facture en transit, dérogation tracée.The success criterion is not “block everything”. A mature setup aims for both a high share of invoices processed without human intervention (> 80% in the relevant categories) and real control. The two only conflict when capture quality is poor or tolerances badly set. Before developing: evaluate the community OCA modules (the purchase-workflow repository) on the target version, and test everything in UAT: a price gap blocked but posted, a foreign-currency purchase with no false gap, an invoice in transit, a traced override.