Skip to Content

The three-way match, explained from a single invoice

August 11, 2026 by
HIKARIUS, Guillaume Klein

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.

4 200 €
Le fil rouge — la facture qui va nous suivre tout l’articleThe running example — the invoice that follows us through the article
Une PME commande 500 pièces à 8,00 € l’unité — prix ferme, négocié pour l’année. Les 500 pièces arrivent, conformes. Puis la facture tombe : 500 pièces à 8,40 €, soit 4 200 € au lieu de 4 000 €. Un écart de 200 €, discret. Répété sur toutes les lignes de ce fournisseur, il pèserait environ 24 000 € par mois. La question de l’article : votre organisation — et votre Odoo — repèrent-ils ces 200 € ?
A company orders 500 parts at €8.00 each — a firm price, negotiated for the year. All 500 parts arrive, compliant. Then the invoice lands: 500 parts at €8.40 — €4,200 instead of €4,000. A quiet €200 gap. Repeated across every line from this supplier, it would cost roughly €24,000 per month. The question of this article: would your organisation — and your Odoo — catch those €200?
Les fonctions décrites s’appuient sur la génération actuelle d’Odoo (17 à 19) ; tout paramétrage doit être revalidé sur la version cible. Certaines briques relèvent d’Odoo Enterprise (numérisation des factures, approbations de paiement), d’autres de modules communautaires (OCA).Features described are based on the current Odoo generation (17–19); every setting must be re-validated on the target version. Some building blocks require Odoo Enterprise (invoice digitisation, payment approvals), others come from community (OCA) modules.
Trois niveaux de lecture — arrêtez-vous quand vous avez ce qu’il vous fautThree reading levels — stop whenever you have what you need
Niveau 1 · ~7 minLevel 1 · ~7 min
ComprendreUnderstand
Pour tous. Les trois documents, ce qu’on vérifie, et pourquoi ça protège l’entreprise. Aucun prérequis.For everyone. The three documents, what gets checked, and why it protects the company. No prerequisites.
Niveau 2 · ~10 minLevel 2 · ~10 min
MaîtriserMaster
Pour la direction financière et l’équipe qui paie les factures : les écarts, les tolérances, et ce que ça écrit en comptabilité.For finance leadership and the team that pays the bills: discrepancies, tolerances, and what it all writes in the books.
Niveau 3 · ~10 minLevel 3 · ~10 min
Implémenter sur OdooImplement on Odoo
Pour qui conçoit le système : ce qu’Odoo fait vraiment, le piège du flux standard, et l’architecture qui corrige.For whoever designs the system: what Odoo really does, the trap in the standard flow, and the architecture that fixes it.
Niveau 1 · Chapitre 1Level 1 · Chapter 1

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.

Fil rougeOur invoice
500 pièces × 8,00 €500 parts × €8.004 000 €
Prix ferme du contrat annuelFirm price from the annual contract

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.

Fil rougeOur invoice
500 pièces reçues500 parts receivedconformecompliant
Comptées à l’arrivée, rien à signalerCounted on arrival, nothing to report

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.

Fil rougeOur invoice
500 pièces × 8,40 €500 parts × €8.404 200 €
+ 200 € par rapport au prix convenu+ €200 versus the agreed price
CommandéOrdered
Bon de commandePurchase order
500 × 8,00 €4 000 €
ReçuReceived
Bon de réceptionReceipt
500 pièces500 partsconformecompliant
RéclaméClaimed
Facture fournisseurVendor bill
500 × 8,40 €4 200 €
On compare les trois — avant de payerCompare all three — before paying
Question 1 — A-t-on reçu ce qu’on nous facture ? Oui : 500 = 500Question 1 — Did we receive what we’re billed for? Yes: 500 = 500 Question 2 — Est-ce au prix convenu ? Non : 8,40 € > 8,00 €Question 2 — At the agreed price? No: €8.40 > €8.00

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.

Niveau 1 · Chapitre 2Level 1 · Chapter 2

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:

Payer ce qu’on n’a jamais reçuPaying for what never arrived
Une commande livrée à moitié, facturée en entier. Sans comparaison avec la réception, rien ne s’y oppose.An order half delivered, billed in full. Without checking against the receipt, nothing stands in the way.
Payer plus cher que convenu — le plus sournoisPaying more than agreed — the sneakiest
Quelques centimes de plus par pièce ne se voient pas, se répètent sur chaque ligne et se cumulent sur l’année. C’est notre fil rouge — et l’angle mort d’Odoo (chapitre 6).A few extra cents per part go unseen, repeat on every line and add up over the year. That’s our running example — and Odoo’s blind spot (chapter 6).
Payer deux fois la même facturePaying the same invoice twice
La facture arrive par e-mail puis par courrier, ou un fournisseur relance une facture déjà réglée. Fréquent dans les organisations sans contrôle solide.The invoice arrives by e-mail, then by post; or a supplier chases an invoice already paid. Common wherever controls are weak.
La fausse factureThe fake invoice
Facture inventée ou gonflée. Le contrôle n’arrête pas toutes les fraudes, mais une facture sans commande ni réception derrière elle ne passe pas.Invented or inflated invoices. The control doesn’t stop every fraud, but an invoice with no order and no receipt behind it does not get through.
L’erreur de TVA ou de compteThe VAT or account error
Pas un surpaiement, mais une comptabilité faussée — et un risque en cas de contrôle fiscal.Not an overpayment, but distorted books — and a risk if the tax authorities come knocking.

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:

2
documents
Commande + facture. Pour les services et abonnements — rien de physique à compter.Order + invoice. For services and subscriptions — nothing physical to count.
3
documents — notre sujetdocuments — our topic
+ la réception. Pour les biens physiques, stockés ou consommés.+ the receipt. For physical goods, stocked or consumed.
4
documents
+ le contrôle qualité. Quand on ne doit payer que ce qui est accepté : pharma, agroalimentaire, industrie critique.+ quality control. When you should only pay for what passes inspection: pharma, food, critical industry.
+ contrat+ contract
le prix vit ailleursthe price lives elsewhere
Sous contrat annuel, le vrai prix est dans le contrat — la commande elle-même peut être fausse. On y revient au chapitre 3.Under an annual contract, the true price lives in the contract — the order itself can be wrong. More in chapter 3.
Fin du niveau 1 — vous pouvez vous arrêter iciEnd of level 1 — you can stop here
Avant de payer, on compare commande, réception et facture.Before paying, compare order, receipt and invoice.
Deux questions : a-t-on reçu ce qu’on nous facture, et au prix convenu ?Two questions: did we receive what we’re billed for, and at the agreed price?
Le risque le plus coûteux est le plus discret : le petit écart de prix répété.The costliest risk is the quietest: the small, repeated price gap.
La suite entre dans le métier : écarts, tolérances, comptabilité — puis Odoo.What follows gets into the craft: discrepancies, tolerances, accounting — then Odoo.
Niveau 2 · Chapitre 3Level 2 · Chapter 3

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”.

Axe quantitéQuantity axis
« On ne paie pas plus que ce qu’on a reçu »“Never pay for more than you received”
Facture : 500 piècesInvoice: 500 parts → comparé à →→ compared with → Réception : 500 piècesReceipt: 500 parts
Reçu 60 sur 100 ? La facture de 60 est légitime, le reste attendra d’être livré. Attention aussi aux unités : commander en cartons et être facturé à la pièce peut multiplier une erreur par 100.Received 60 of 100? An invoice for 60 is legitimate; the rest waits until delivered. Watch the units too: ordering in boxes and being billed per unit can multiply an error by 100.
Axe prixPrice axis
« On ne paie pas plus cher que convenu »“Never pay more than what was agreed”
Facture : 8,40 €Invoice: €8.40 → comparé à →→ compared with → Commande — ou contrat : 8,00 €Order — or contract: €8.00
L’axe le plus rentable et le plus négligé : une quantité manquante se voit (il manque des cartons), un prix trop haut ne se voit pas. Remise oubliée, frais de transport ajoutés, hausse non prévenue : tout passe par ici.The most profitable and most neglected axis: a missing quantity is visible (boxes are missing), an inflated price is not. Forgotten rebates, added freight charges, unannounced increases: it all comes through here.
Le piège du contrat annuelThe annual-contract trap
Notre PME a négocié 8,00 € dans un contrat annuel. Si quelqu’un crée un bon de commande à 8,40 € par erreur, puis que le fournisseur facture 8,40 € : la comparaison facture ↔ commande est parfaitement verte… et le surpaiement bien réel. Sur les achats sous contrat, il faut donc aussi vérifier la commande contre le contrat, en amont.Our company negotiated €8.00 in an annual contract. If someone mistakenly creates a purchase order at €8.40 and the supplier bills €8.40: the invoice ↔ order comparison is perfectly green… and the overpayment perfectly real. For contracted purchases, the order itself must also be checked against the contract, upstream.
Deux subtilités qui évitent de fausses alertesTwo subtleties that avoid false alarms
La devise : un achat en dollars se contrôle en dollars. 10 $ commandés, 10 $ facturés = aucun écart de prix, même si le taux de change a bougé entre-temps — cette différence-là est un écart de change, un autre sujet. La TVA : une facture sans TVA n’est pas forcément fausse — sur un achat auprès d’un fournisseur d’un autre pays de l’UE, c’est l’acheteur qui déclare la TVA lui-même. La bonne question n’est pas « y a-t-il de la TVA ? » mais « est-ce le régime attendu pour ce fournisseur et ce type d’achat ? »Currency: a purchase in dollars is checked in dollars. $10 ordered, $10 billed = no price gap, even if the exchange rate moved in between — that difference is a currency gain or loss, a separate topic. VAT: an invoice without VAT is not necessarily wrong — buying from a supplier in another EU country, the buyer self-assesses the VAT. The right question is not “is there VAT?” but “is this the expected regime for this supplier and this type of purchase?”
Niveau 2 · Chapitre 4Level 2 · Chapter 4

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:

Le cas : la hausse silencieuse de 1,8 %The case: the silent 1.8% increase
Un fournisseur augmente discrètement tous ses prix de 1,8 %, sans prévenir. Il facture 400 000 € par mois, en milliers de petites lignes. Quel réglage de tolérance repère la dérive ?A supplier quietly raises all its prices by 1.8%, without notice. It bills €400,000 a month, across thousands of small lines. Which tolerance setting catches the drift?
Tout passe. 86 400 € perdus sur l’année, invisibles.Everything gets through. €86,400 lost over the year, invisibly.

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.

Surpaiement cumulé sur 12 moisOverpayment accumulated over 12 months86 400 €
Toujours rien. Le seuil en euros ne suffit pas non plus.Still nothing. The euro threshold doesn’t help either.

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.

Écart par ligne : 9 € — seuil : 50 €Gap per line: €9 — threshold: €50accepté partoutaccepted everywhere
Détecté — pas en bloquant, en additionnant.Caught — not by blocking, by adding up.

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.

Écarts acceptés ce mois — fournisseur AAccepted gaps this month — supplier A7 200 € → alerte€7,200 → alert

Trois règles pour une tolérance bien conçueThree rules for a well-designed tolerance

Asymétrique. Une facture moins chère que prévu n’est pas un risque : on peut l’accepter largement. Une facture plus chère doit bloquer bien plus tôt. Traiter les deux sens pareil est l’erreur la plus courante.Asymmetric. An invoice cheaper than expected is no risk: accept it generously. A more expensive one must block much sooner. Treating both directions the same is the most common mistake.
Par fournisseur et par catégorie. Un fournisseur sous contrat négocié mérite une tolérance de prix nulle. Du vrac pesé à la livraison mérite une tolérance de quantité souple — +4 % sur du vrac est normal, +4 % sur des pièces comptées est suspect.Per supplier and per category. A supplier under a negotiated contract deserves zero price tolerance. Bulk goods weighed at delivery deserve a loose quantity tolerance — +4% on bulk is normal, +4% on counted parts is suspicious.
Réglée par un tiers. Si l’acheteur règle lui-même la tolérance de son fournisseur, le contrôle est vidé de sa substance. Le paramétrage des tolérances est un rôle à part, validé par la direction financière.Set by a third party. If the buyer sets the tolerance for their own supplier, the control is hollowed out. Tolerance configuration is a separate role, approved by finance leadership.
Et le temps de déblocage est de l’argent. Beaucoup de fournisseurs accordent une remise pour paiement rapide (l’escompte, par exemple 2 % si payé sous 10 jours). Une facture coincée trois semaines dans une file d’anomalies fait mécaniquement perdre cette remise. Un contrôle qui bloque trop et résout lentement coûte de l’argent — l’équilibre entre contrôle et fluidité est le vrai critère de succès.And unblocking time is money. Many suppliers grant a discount for early payment (e.g. 2% if paid within 10 days). An invoice stuck three weeks in an exception queue mechanically loses that discount. A control that blocks too much and resolves too slowly costs money — the balance between control and flow is the real success criterion.
Niveau 2 · Chapitre 5Level 2 · Chapter 5

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.

Écriture à la réceptionEntry at receipt
DébitDebit
CréditCredit
StocksInventory
4 000,00
Compte d’attente (dette provisoire)Holding account (provisional debt)
4 000,00

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?

Écriture à la facturationEntry at invoicing
DébitDebit
CréditCredit
Compte d’attente (se solde)Holding account (cleared)
4 000,00
L’écart de 200 € — à répartir (étape 3)The €200 gap — to be allocated (step 3)
200,00
Fournisseur (dette réelle, hors TVA)Supplier (real debt, excl. VAT)
4 200,00

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.)

200 pièces encore en stock200 parts still in stock
200 × 0,40 € = 80 € → la valeur du stock est corrigée200 × €0.40 = €80 → inventory value corrected
300 pièces déjà vendues300 parts already sold
300 × 0,40 € = 120 € → en coût des ventes de la période300 × €0.40 = €120 → to cost of sales for the period
Un système qui ne sait pas faire cette répartition met tout au même endroit — et fausse soit la valeur du stock, soit le résultat. C’est un critère de choix d’ERP que personne ne teste en avant-vente.A system that cannot make this split puts everything in one place — and distorts either the inventory value or the P&L. It is an ERP selection criterion nobody tests before buying.

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:

Exemple de revue à la clôture — solde total : 186 000 €Example close-of-period review — total balance: €186,000
< 30 jours< 30 days
142 000 €normal, cycle courantnormal, current cycle
30–60 jours30–60 days
31 000 €à relancerchase suppliers
60–90 jours60–90 days
9 000 €anormal, à investiguerabnormal, investigate
> 90 jours> 90 days
4 000 €à solder, décision documentéewrite off, documented decision
Sans cette revue, ces 186 000 € restent une ligne de balance que personne ne regarde — jusqu’à ce qu’un auditeur pose la question.Without this review, those €186,000 remain a balance line nobody looks at — until an auditor asks the question.

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.

Fin du niveau 2 — l’essentiel métierEnd of level 2 — the business essentials
La quantité se vérifie contre la réception, le prix contre ce qui a été convenu — commande ou contrat.Quantity is checked against the receipt, price against what was agreed — order or contract.
Les tolérances sont asymétriques, par fournisseur, réglées par un tiers — et la dérive lente ne se voit qu’au cumul.Tolerances are asymmetric, per supplier, set by a third party — and slow drift only shows in the aggregate.
Le rapprochement produit des écritures : compte d’attente à surveiller par ancienneté, écart de prix à répartir entre stock restant et pièces déjà vendues.Matching produces journal entries: a holding account to review by age, and a price gap to split between remaining stock and parts already sold.
Trois documents fabriqués par la même main concordent toujours : la séparation des rôles est le seul rempart contre la fraude interne.Three documents made by the same hand always match: role separation is the only rampart against internal fraud.
La suite s’adresse à qui met tout cela en place dans Odoo.What follows is for whoever builds all of this in Odoo.
Niveau 3 · Chapitre 6 — place à l’architecteLevel 3 · Chapter 6 — over to the architect

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:

Il signale, il ne bloque pasIt flags, it doesn’t block

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.

C’est un feu de signalisation, pas une barrière. Un contrôle qui n’empêche rien est une suggestion.It is a traffic light, not a gate. A control that prevents nothing is a suggestion.
Il ne regarde jamais le prixIt never looks at the price

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 contrôle natif est aveugle exactement là où le risque coûte le plus cher : l’axe prix.The native control is blind exactly where the risk costs most: the price axis.

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.

Niveau 3 · Chapitre 7 — le point le plus important de l’articleLevel 3 · Chapter 7 — the most important point of the article

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.

Parcours 1 — le flux standard d’OdooJourney 1 — Odoo’s standard flow

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.

Document papierPaper document
500 × 8,40 €4 200 €

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.

Facture à l’écranBill on screen
500 × 8,00 €4 000 €
Le prix réel n’a jamais été saisiThe real price was never entered

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.

Doit être payéShould Be Paid
Oui ✓Yes ✓
Dette enregistrée : 4 000 €Debt recorded: €4,000

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.

BilanOutcome
Écart détecté : non
Écart enregistré : non
Retrouvable a posteriori : non
Gap detected: no
Gap recorded: no
Traceable afterwards: no
Plus le flux est fluide — validation en un clic depuis la commande — plus le contrôle de prix est nul. Ce n’est pas un défaut de paramétrage : c’est la conception même du flux standard.The smoother the flow — one-click validation from the order — the weaker the price control. This is not a configuration flaw: it is the very design of the standard flow.
Parcours 2 — le flux corrigéJourney 2 — the corrected flow

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.

Facture capturéeCaptured bill
500 × 8,40 €4 200 €
Le prix réel est préservéThe real price is preserved

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.

Lien établiLink established
Ligne facture ↔ ligne commandeBill line ↔ order line
purchase_line_id

3 · 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.

Écart de prixPrice gap
+0,40 € / pièce · +5 %+€0.40 / part · +5%
Hors tolérance → blocageOut of tolerance → block

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.

BilanOutcome
Dette juste : oui, 4 200 €
Paiement : bloqué
Écart tracé : oui, +5 %
Debt right: yes, €4,200
Payment: blocked
Gap traced: yes, +5%
Sur l’ensemble des lignes du fournisseur, ce parcours évite environ 24 000 € de surpaiement par mois — que le parcours standard n’aurait ni vu, ni même laissé en trace.Across all of this supplier’s lines, this journey avoids roughly €24,000 of overpayment per month — which the standard flow would neither have seen nor even left a trace of.
Règle d’architecture nº1Architecture rule #1
La facture entre par la numérisation, jamais par « Créer la facture »The invoice enters through digitisation, never through “Create Bill”
La génération depuis la commande recopie le prix commandé et détruit la donnée de contrôle. Elle se réserve aux seuls cas légitimes (auto-facturation, acomptes) et se ferme par les droits d’accès partout ailleurs.Generating from the order copies the ordered price and destroys the control data. It is reserved for the few legitimate cases (self-billing, down payments) and closed off by access rights everywhere else.
Règle d’architecture nº2Architecture rule #2
On ne bloque pas la comptabilisation, on bloque le paiementDon’t block the posting — block the payment
Empêcher d’enregistrer une facture casse les imports, les avoirs et fausse les comptes de la période. Odoo sait bloquer le règlement au niveau de la ligne comptable — la dette est enregistrée, l’argent ne part pas. Cela règle aussi la facture arrivée avant la marchandise : comptabilisée à la bonne date, payée à la réception.Preventing a bill from being posted breaks imports and credit notes and distorts the period’s accounts. Odoo can block settlement at journal-line level — the debt is recorded, the money doesn’t leave. This also solves the invoice arriving before the goods: posted at the right date, paid on receipt.
Niveau 3 · Chapitre 8Level 3 · Chapter 8

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:

1
L’inversion du flux d’entréeInverting the entry flow
Capture obligatoire (numérisation, format électronique), qualité d’extraction du prix unitaire vérifiée, génération depuis la commande fermée par les droits. La brique la plus importante — et la moins coûteuse : c’est une décision de processus.Mandatory capture (digitisation, electronic formats), verified unit-price extraction quality, order-based generation closed off by access rights. The most important block — and the cheapest: it is a process decision.
2
Le contrôle et le blocage du paiementThe check and the payment block
Comparaison ligne à ligne quantité et prix, dans la devise du document, contre la bonne référence (commande ou contrat). Écart hors tolérance → blocage de règlement sur la ligne comptable, motif et montant affichés.Line-by-line comparison of quantity and price, in the document’s currency, against the right reference (order or contract). Out-of-tolerance gap → settlement block on the journal line, reason and amount displayed.
3
Le moteur de tolérancesThe tolerance engine
La grille du chapitre 4 : % et valeur absolue combinés, asymétrique, par fournisseur et catégorie, source de vérité du prix paramétrable. N’existe pas nativement — la « tolérance de réception » logistique d’Odoo ne couvre pas ce besoin. À construire ou à assembler (modules OCA à évaluer d’abord).The chapter 4 grid: % and absolute value combined, asymmetric, per supplier and category, configurable price source of truth. Does not exist natively — Odoo’s logistics “receipt tolerance” does not cover this need. To build or assemble (evaluate OCA modules first).
4
Le circuit des anomaliesThe exception workflow
Chaque blocage crée une tâche routée selon l’écart : prix → acheteur, quantité → entrepôt, doublon → comptabilité. Délai cible, escalade, dérogation approuvée selon le montant de l’écart, justification obligatoire et tracée.Every block creates a task routed by gap type: price → buyer, quantity → warehouse, duplicate → accounting. Target lead time, escalation, override approved according to the gap amount, mandatory traced justification.
5
Le volet comptableThe accounting side
Le rapport du compte d’attente par ancienneté (chapitre 5) — le livrable que l’audit demandera. Compte d’écart sur prix d’achat, règle de répartition stock/vendu, politique des frais annexes par type et par contrat.The aged holding-account report (chapter 5) — the deliverable auditors will ask for. Purchase price variance account, stock/sold allocation rule, ancillary cost policy by type and by contract.
6
Le tableau de bord analytiqueThe analytics dashboard
Ce qu’aucun blocage ligne à ligne ne voit : prix payé par fournisseur dans le temps, cumul des écarts acceptés, taux de dérogation par utilisateur, délai de résolution — corrélé aux escomptes capturés.What no line-by-line block ever sees: price paid per supplier over time, accepted-gap totals, override rate per user, resolution lead time — correlated with captured early-payment discounts.

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:

Le niveau de contrôle par catégorie d’achat — 2, 3 ou 4 documents, contrat ou non.The control level per purchase category — 2, 3 or 4 documents, contract or not.
La référence du prix par catégorie — bon de commande ou contrat-cadre.The price reference per category — purchase order or framework contract.
La grille de tolérances — axes, seuils, asymétrie, par fournisseur et catégorie.The tolerance grid — axes, thresholds, asymmetry, per supplier and category.
La matrice des approbations et dérogations — qui force, jusqu’où, et qui règle les tolérances (ni l’acheteur, ni l’équipe facturation).The approval and override matrix — who overrides, up to what, and who sets the tolerances (neither the buyer nor the billing team).
La politique comptable des écarts — méthode de valorisation, comptes dédiés, règle de répartition stock/vendu, frais annexes.The accounting policy for gaps — valuation method, dedicated accounts, stock/sold allocation rule, ancillary costs.
Le critère de succès n’est pas « tout bloquer ». Un dispositif mature vise à la fois un taux élevé de factures traitées sans intervention humaine (> 80 % sur les catégories concernées) et un contrôle réel. Les deux ne s’opposent que si la capture est médiocre ou les tolérances mal réglées. Avant de développer : évaluer les modules communautaires OCA (dépôt 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.
En résumé — ce qu’il faut retenir de la facture à 4 200 €In summary — what to remember from the €4,200 invoice
Le three-way match, c’est deux questions avant de payer : a-t-on reçu, et au prix convenu ?The three-way match is two questions before paying: did we receive it, and at the agreed price?
Le « 3-way matching » natif d’Odoo contrôle la quantité, pas le prix — et il signale sans bloquer.Odoo’s native “3-way matching” checks quantity, not price — and it flags without blocking.
Le flux standard efface l’écart de prix : la facture doit entrer par la numérisation, jamais par « Créer la facture ».The standard flow erases the price gap: the invoice must enter through digitisation, never through “Create Bill”.
On ne bloque pas la comptabilisation, on bloque le paiement — Odoo sait le faire nativement, au niveau de la ligne.Don’t block the posting — block the payment. Odoo can do it natively, at line level.
La dérive lente ne se voit qu’au cumul — le tableau de bord fait partie du contrôle, pas du reporting.Slow drift only shows in the aggregate — the dashboard is part of the control, not of reporting.
Le socle natif est riche ; ce qui manque — contrôle du prix, tolérances, circuit d’anomalies — est précisément ce qui fait la valeur du contrôle. C’est un projet de conception, pas une case à cocher.The native foundation is rich; what’s missing — price control, tolerances, exception workflow — is precisely what gives the control its value. It is a design project, not a checkbox.
AnnexeAppendix

Le jargon, traduit une fois pour toutesThe jargon, translated once and for all

Three-way matchRapprochement de la commande, de la réception et de la facture avant paiement.Matching the order, the receipt and the invoice before payment.
AP / comptabilité fournisseursAP / accounts payableL’équipe qui reçoit, vérifie et paie les factures des fournisseurs.The team that receives, checks and pays supplier invoices.
GR/IR · compte d’interceptionGR/IR · stock interim accountLe « compte d’attente » entre réception et facture. Son solde = valeur reçue non encore facturée.The “holding account” between receipt and invoice. Its balance = value received not yet invoiced.
ToléranceToleranceLe seuil d’écart en dessous duquel une facture est acceptée sans intervention.The gap threshold below which an invoice is accepted without intervention.
Capture / OCRCapture / OCRLa numérisation de la facture reçue, qui fait entrer dans le système les montants réellement réclamés.Digitising the incoming invoice, so the amounts actually claimed enter the system.
TouchlessPart des factures traitées de bout en bout sans intervention humaine.Share of invoices processed end to end without human intervention.
EscompteEarly payment discountRemise accordée par le fournisseur pour un paiement rapide — perdue si la facture reste bloquée.A discount granted by the supplier for fast payment — lost if the invoice stays blocked.
Landed costFrais annexes (transport, douane) incorporés au coût du stock plutôt que passés en charge.Ancillary costs (freight, customs) rolled into inventory cost rather than expensed.
FNPAccrued liabilities (FNP)« Factures non parvenues » : marchandise reçue, facture pas encore arrivée à la clôture.Goods received, invoice not yet arrived at closing time.
Achat maverickMaverick buyingAchat effectué hors processus, sans commande — la facture arrive sans rien à quoi la comparer.A purchase made outside the process, with no order — the invoice arrives with nothing to compare it against.