Parmi les nombreuses lignes que les notes de version d'Odoo 20 consacrent à la comptabilité, une phrase passe presque inaperçue. Odoo y annonce que les statuts de paiement « ont été renommés de "In Process" en "Paid" et de "Paid" en "Reconciled" afin de clarifier le flux »1. Sur l'écran, le changement paraît cosmétique. Dans la base de données, il déplace le sens d'un mot que vos rapports, vos automatisations et vos modules spécifiques utilisent depuis des années.
Nous avons comparé le code source des branches 19.0 et 20.0 du module account pour mesurer ce qui bouge réellement2. Le constat mérite qu'une PME qui prépare sa migration s'y arrête avant de lancer le moindre test.
Le même mot, deux réalités
Dans Odoo 19, un paiement (account.payment) traverse les états draft, in_process, paid, canceled et rejected. Un paiement enregistré mais pas encore retrouvé sur le relevé bancaire reste in_process. Il passe à paid lorsque le mouvement bancaire correspondant est rapproché, ou lorsque toutes les factures qu'il règle sont soldées.
Dans la branche 20.0, la liste devient draft, paid, reconciled, canceled et rejected. La clé technique in_process disparaît. La clé paid reste, mais elle désigne désormais l'étape intermédiaire, celle du paiement enregistré qui n'a pas encore été confronté à la banque. L'ancien sens de paid est repris par la nouvelle clé reconciled.
| Situation du paiement | Clé en 19.0 | Clé en 20.0 |
|---|---|---|
| Brouillon | draft | draft |
| Enregistré, pas encore vu en banque | in_process | paid |
| Rapproché avec la banque | paid | reconciled |
| Annulé ou rejeté | canceled / rejected | canceled / rejected |
Le statut de la facture elle-même ne suit pas ce mouvement. Le champ payment_state de account.move conserve dans les deux versions les valeurs not_paid, in_payment, paid, partial, reversed, blocked et invoicing_legacy2. Une facture paid reste donc une facture soldée, alors qu'un paiement paid n'est plus qu'un paiement déclaré. Deux objets voisins emploient le même mot pour deux niveaux de certitude différents, et c'est précisément là que les erreurs vont se loger.
Ce qui casse sans message d'erreur
Une clé qui disparaît fait planter le code qui la cherche, ce qui a au moins le mérite de se voir. Une clé qui change de sens ne déclenche aucune alerte. Un filtre [('state', '=', 'paid')] sur les paiements fonctionnera après la migration et renverra simplement d'autres enregistrements qu'avant.
Chez nos clients, ce filtre se retrouve à plusieurs endroits. Il alimente des tableaux de bord de trésorerie qui additionnent les encaissements « confirmés ». Il sert de déclencheur à des actions automatisées, par exemple pour libérer une commande ou notifier un commercial lorsque le client a payé. Il figure dans des exports vers un outil de BI ou de consolidation. Il apparaît enfin dans des modules spécifiques qui calculent des commissions sur les sommes réellement encaissées.
Après le passage en 20.0, tous ces usages compteront comme encaissé un paiement que personne n'a encore vu arriver sur le compte. Pour un virement, l'écart dure quelques jours. Pour un chèque, Odoo rappelle lui-même dans sa documentation qu'enregistrer un paiement par chèque « ne déplace pas de fonds »3 : un chèque remis puis rejeté aurait déjà déclenché la commission ou la livraison.
Le script de migration fourni par Odoo convertira très probablement les valeurs stockées, de sorte que les anciens paiements paid deviennent reconciled. Ce script ne réécrira pas en revanche vos domaines enregistrés dans des filtres favoris, vos actions serveur en Python, vos requêtes SQL externes ni le code de vos modules. Ces éléments restent à votre charge, et ce sont eux qui portent les règles de gestion.
La banque devient la seule source de vérité
Le renommage accompagne un durcissement plus profond. Les notes de version posent une règle nette : « toutes les écritures qui impactent les comptes bancaires doivent désormais provenir de transactions bancaires »1. Le code de la branche 20.0 en montre une traduction concrète.
Dans Odoo 19, un paiement dont le compte de liquidité n'était pas lettrable passait directement à l'état paid. C'est ce qui permettait une pratique répandue, que la documentation décrit encore : définir le compte bancaire principal comme compte d'attente sur le mode de paiement, pour qu'un règlement complet marque la facture comme payée sans passer par le rapprochement3. Dans la branche 20.0, cette condition a disparu du calcul d'état. De plus, la validation manuelle d'un paiement lié à un compte de type trésorerie lève l'erreur « Payments linked to an Asset Cash account cannot be reconciled »2.
Nous lisons ces deux changements comme la fin programmée du raccourci « compte bancaire en compte d'attente ». Odoo ne l'écrit pas en ces termes, et la page de documentation 20.0 sur les paiements contient toujours l'astuce correspondante au moment où nous écrivons3. Il faut donc tester ce cas sur une copie de votre base plutôt que de se fier à la documentation, qui n'a visiblement pas encore rattrapé le code.
Les autres ajustements vont dans le même sens. Le bouton manuel « Mark as Reconciled » quitte l'écran pour rejoindre le menu d'actions. La case « Allow Reconciliation » des comptes devient « Payment Reconciliation », et le lettrage manuel devient possible sur n'importe quel compte1. Des « Matching Rules » permettent de régler la tolérance de paiement et l'ordre de rapprochement automatique1. L'éditeur pousse clairement vers un rapprochement systématique avec la banque et décourage les contournements manuels.
Comment préparer la bascule
La bonne nouvelle tient dans la taille du chantier. Le périmètre est restreint et se laisse inventorier en une demi-journée pour une base de taille moyenne. Nous procédons en quatre temps.
- Recenser les usages de
account.payment.state. Il faut chercher dans le code des modules spécifiques, dans les actions serveur et les automatisations, dans les filtres favoris partagés et dans les requêtes des outils externes. Chaque occurrence depaiddoit être requalifiée : voulait-on dire « déclaré » ou « vu en banque » ? - Vérifier les modes de paiement. Pour chaque journal bancaire, contrôlez le compte d'attente configuré sur chaque mode de paiement. Si c'est le compte bancaire lui-même, prévoyez de basculer vers de vrais comptes d'attente avant la migration, ce qui suppose un flux de relevés bancaires fiable.
- Revoir les intitulés côté métier. Les équipes comptables lisaient « Payé » comme « l'argent est là ». En 20.0, cette information se lit dans « Reconciled ». Un rappel écrit d'une page évitera des semaines de malentendus avec le service recouvrement.
- Tester sur une base de recette. Rejouez un mois de paiements réels, puis comparez les totaux de vos tableaux de bord avant et après. Un écart signale presque toujours un filtre oublié.
Ce travail rejoint d'autres changements structurels de la version 20 en comptabilité, comme le remplacement des groupes de comptes par des comptes parents, que nous avons détaillé dans notre article sur le plan comptable. Mieux vaut traiter ces sujets ensemble dans un même lot de recette.
Notre lecture
Sur le fond, nous approuvons le choix d'Odoo. Distinguer un paiement déclaré d'un paiement constaté en banque correspond à la manière dont un expert-comptable raisonne, et le vocabulaire de la version 19 entretenait une confusion réelle. Réserver les écritures bancaires aux transactions bancaires renforce aussi la piste d'audit, ce qui comptera davantage à mesure que la facturation électronique et les agents IA multiplient les écritures générées automatiquement.
Nous regrettons en revanche la méthode. Réutiliser la clé technique paid avec un autre sens, plutôt que de créer deux clés nouvelles, transforme une clarification en piège silencieux pour tout ce qui a été construit autour d'Odoo. Une migration qui ne produit aucune erreur n'est pas forcément une migration réussie. Sur ce point précis, la recette doit porter sur les chiffres et pas seulement sur l'absence de plantage.
Sources
- Odoo 20 Release Notes : https://www.odoo.com/odoo-20-release-notes
- Code source Odoo 20.0, account_payment.py : https://github.com/odoo/odoo/blob/20.0/addons/account/models/account_payment.py
- Code source Odoo 19.0, account_payment.py : https://github.com/odoo/odoo/blob/19.0/addons/account/models/account_payment.py
- Documentation Odoo 20.0, Payments : https://www.odoo.com/documentation/20.0/applications/finance/accounting/payments.html
- Documentation Odoo 19.0, Payments : https://www.odoo.com/documentation/19.0/applications/finance/accounting/payments.html
Footnotes
-
Odoo, notes de version d'Odoo 20 (septembre 2026), section Accounting. Citations traduites de l'anglais par nos soins. ↩ ↩2 ↩3 ↩4
-
Constat effectué sur le fichier
addons/account/models/account_payment.pydes branches 19.0 et 20.0 du dépôt public odoo/odoo, consultées le 23 octobre 2026. Le code d'une branche peut encore évoluer par correctifs. ↩ ↩2 ↩3 -
Documentation officielle Odoo 20.0, page « Payments » de l'application Comptabilité, consultée le 23 octobre 2026. ↩ ↩2 ↩3