Introduction
Le champ Monétaire est l'un des types de champs les plus utiles et les plus souvent mal utilisés dans Odoo. Il ressemble à un nombre, se stocke comme un flottant, mais ne se comporte comme aucun des deux. Une fois que vous comprenez ce qui le rend différent, vous n'utiliserez plus jamais un simple Flottant pour une valeur financière.
Si vous avez déjà regardé le total d'une commande de vente, le montant d'une facture ou le prix d'un produit dans Odoo, vous avez déjà utilisé un champ Monétaire. Ils sont partout dans le modèle de données Odoo, et ils font discrètement beaucoup de travail autour du formatage des devises, du arrondi et de la précision.
Ce guide s'adresse aux développeurs Odoo, aux consultants et aux utilisateurs d'entreprise ayant une approche technique qui souhaitent comprendre comment le champ Monétaire fonctionne réellement. Que vous suiviez un tutoriel sur les champs Odoo, que vous construisiez un module personnalisé ou que vous essayiez simplement de comprendre pourquoi vos montants arrondissent différemment de ce que vous attendiez, c'est la référence dont vous avez besoin.
Qu'est-ce que le champ Monétaire dans Odoo
Le type fields.Monetary est l'un des types de champs principaux dans le cadre Odoo. Il est conçu spécifiquement pour stocker des valeurs exprimées en monnaie : prix, montants, totaux, budgets ou tout nombre représentant de l'argent.
Ce qui le distingue d'un Float ordinaire est la relation obligatoire avec une devise. Un champ Monétaire sait toujours avec quelle devise il travaille et utilise cette devise pour déterminer combien de décimales afficher et comment arrondir les valeurs stockées.
Comment il apparaît dans l'interface
Dans l'interface Odoo, un champ Monétaire affiche la valeur formatée selon la devise associée. Si la devise est l'Euro, vous voyez quelque chose comme € 1.234,50. Si c'est le Dollar américain, vous voyez $ 1.234,50. Le nombre de décimales suit la configuration de l'enregistrement de la devise.
Le champ est entièrement modifiable dans les vues de formulaire, s'affiche proprement dans les vues de liste et s'intègre naturellement dans les tableaux croisés et les rapports financiers. Les utilisateurs finaux n'ont pas à se soucier du formatage. Odoo s'en occupe de manière transparente.
Le type de données sous-jacent
Au niveau de la base de données, un champ Monétaire est stocké comme un float à double précision dans PostgreSQL. Les informations sur la devise ne sont pas stockées dans la même colonne. Elles proviennent d'un enregistrement lié res.currency, lié par un champ Many2one séparé sur le même modèle.
Cette séparation de la valeur et de la devise est intentionnelle. Elle garde les champs de la base de données Odoo propres et permet de changer la devise d'un enregistrement indépendamment de ses montants stockés.
Comment fonctionne le champ
Comprendre les mécanismes derrière le champ Monétaire vous aidera à l'utiliser correctement et à éviter les problèmes d'arrondi ou d'affichage qui sont étonnamment courants dans le développement personnalisé d'Odoo.
Le paramètre currency_field
Chaque champ Monétaire doit être associé à un champ Many2one pointant vers res.currency. Par défaut, Odoo recherche un champ nommé currency_id sur le même modèle. Vous pouvez remplacer cela avec le paramètre currency_field:
amount = fields.Monetary(string='Montant', currency_field='currency_id')
Si le champ de devise est manquant ou non défini sur un enregistrement donné, Odoo revient à la devise de l'entreprise. Cela évite les erreurs graves, mais dans un environnement multi-devises, cela produira un formatage incorrect. Déclarez toujours le champ de devise explicitement.
Arrondi et Précision
Une des principales différences entre Monétaire et Float est la façon dont l'arrondi fonctionne. Le modèle res.currency définit le nombre de décimales et le facteur d'arrondi pour chaque devise. Lorsque Odoo lit ou affiche une valeur Monétaire, il applique ces règles automatiquement.
Cela signifie qu'une valeur stockée comme 1.2349999 pour un champ EUR s'affichera comme 1.23, pas 1.235 ou 1.23499. Cela est critique pour les calculs de taxes, les totaux de factures et tout processus de réconciliation financière. Utiliser un Float simple dans ces contextes produira finalement des écarts d'arrondi difficiles à tracer.
Interaction avec l'ORM Odoo
Dans l'orm odoo, lire un champ Monétaire renvoie toujours un float Python. Le contexte de la devise provient du champ de devise associé sur le même enregistrement. Lors de calculs en Python impliquant des champs Monétaires, utilisez la méthode round() de la devise pour préserver la précision :
rounded_value = self.currency_id.round(self.amount)
Cela évite les erreurs d'accumulation de points flottants qui peuvent apparaître dans les totaux multi-lignes ou les calculs itératifs.
Champs Monétaires dans les Rapports QWeb
Dans les modèles de rapports QWeb, les champs Monétaires s'intègrent avec un widget dédié qui formate correctement la valeur dans les PDF et les rapports web :
<span t-esc="record.amount"
t-options='{"widget": "monetary", "display_currency": record.currency_id}'/>
Cela garantit le bon symbole de devise et le formatage décimal dans chaque document généré, quelle que soit la devise de l'enregistrement.
Cas d'utilisation en entreprise
Les champs monétaires sont utilisés dans tous les modules standards d'Odoo. Voici cinq exemples concrets qui illustrent où et pourquoi ils sont importants dans les flux de travail commerciaux réels.
1. Ventes : Prix des produits et totaux des commandes
Des champs comme price_unit, price_subtotal et amount_total sur les commandes de vente et les lignes de commande sont tous des champs monétaires. Ils respectent automatiquement la devise sélectionnée sur la commande client, qui peut différer de la devise opérationnelle de l'entreprise.
Lorsqu'un représentant commercial crée une commande en USD pour une entreprise qui opère en EUR, Odoo gère correctement l'affichage, l'arrondi et la conversion, car le champ monétaire fonctionne toujours dans le contexte de la devise de l'enregistrement, et non de la devise du système.
2. Comptabilité : Montants des factures et lignes de taxe
Dans le module de comptabilité, chaque colonne de montant sur une facture est un champ monétaire : amount_untaxed, amount_tax, amount_total. La devise définie sur la facture détermine l'arrondi de toutes ces valeurs.
Ce n'est pas un détail. Un arrondi incorrect sur les lignes de taxe crée des déséquilibres dans les écritures comptables qui sont difficiles à réconcilier. L'arrondi sensible à la devise du champ monétaire est ce qui empêche ces problèmes au niveau des données.
3. CRM : Revenus attendus sur les opportunités
Le champ expected_revenue sur une opportunité CRM est un champ monétaire. Les équipes de vente peuvent capturer les valeurs du pipeline dans la devise du prospect, tandis que les tableaux de bord et les rapports convertissent tout en devise de l'entreprise pour l'analyse du pipeline et les prévisions.
Cette configuration fonctionne parfaitement précisément parce que les champs monétaires transportent des informations de devise avec leur valeur numérique.
4. Achats : Prix des fournisseurs et commandes d'achat
Les commandes d'achat utilisent des champs monétaires pour les prix unitaires et les totaux, liés à la devise convenue avec le fournisseur. Une facture fournisseur en yen japonais est traitée de la même manière qu'une en euro. Le champ monétaire s'occupe de la précision et de l'affichage sans aucune manipulation manuelle de l'équipe des achats.
5. Champs personnalisés : Suivi du budget et des objectifs
Une demande de personnalisation très courante consiste à ajouter un montant de budget, un objectif de revenus ou un plafond de coûts à un projet, un département ou un modèle personnalisé. Dans tous ces cas, un champ Monétaire est le bon choix. Il s'intègre naturellement à la devise de l'entreprise, s'affiche correctement dans les formulaires et les listes, et se comporte de manière prévisible dans les rapports et les exports.
Utiliser un Float pour ce type de champ est techniquement possible mais entraîne des incohérences de formatage et des problèmes d'arrondi dès que des scénarios multi-devises se présentent.
Créer ou personnaliser le champ
Il existe deux principales façons d'ajouter un champ Monétaire à un modèle Odoo : via Odoo Studio pour une approche sans code, ou via un module Python personnalisé pour un contrôle total.
Utilisation d'Odoo Studio
Odoo Studio inclut un type Monétaire dans son panneau de création de champs. Lorsque vous utilisez les champs d'odoo studio pour ajouter un champ Monétaire à un modèle, Studio ajoute automatiquement un champ currency_id s'il n'existe pas déjà sur ce modèle. Cela couvre les cas d'utilisation les plus courants sans écrire de code.
Une chose à garder à l'esprit : les champs créés par Studio utilisent le préfixe x_ (par exemple, x_studio_budget). Si votre modèle a déjà un champ currency_id, le nouveau champ Monétaire l'utilisera. Sinon, Studio en créera un nouveau. Lorsque vous avez plusieurs champs Monétaires sur le même modèle avec potentiellement des devises différentes, ce champ de devise partagé mérite d'être examiné attentivement avant de passer en production.
Pour des scénarios simples, Studio est le moyen le plus rapide de créer des champs dans Odoo et fonctionne bien pour les utilisateurs commerciaux qui n'ont pas accès au développement.
Approche technique : Champs Python
Dans un module Odoo personnalisé, créer un champ Monétaire nécessite deux déclarations : le champ lui-même et le champ de devise associé. C'est le modèle standard dans le développement de champs Python Odoo :
from odoo import fields, models
class ProjectTask(models.Model):
_inherit = 'project.task'
x_budget = fields.Monetary(
string='Budget',
currency_field='x_budget_currency_id',
)
x_budget_currency_id = fields.Many2one(
comodel_name='res.currency',
string='Devise du Budget',
default=lambda self: self.env.company.currency_id,
)
Définir la devise de l'entreprise comme valeur par défaut est un choix pratique pour la plupart des champs internes. Cela empêche le champ de devise d'apparaître vide lorsque l'utilisateur ouvre un enregistrement pour la première fois, ce qui casserait le formatage du champ Monétaire.
Champs Monétaires Calculés
Les champs monétaires fonctionnent bien en tant que champs calculés dans Odoo. Si vous devez totaliser des montants de ligne ou appliquer une formule qui produit un résultat monétaire, voici le modèle standard :
x_total_budget = fields.Monetary(
string='Budget Total',
currency_field='currency_id',
compute='_compute_total_budget',
store=True,
)
@api.depends('x_line_ids.x_amount')
def _compute_total_budget(self):
for record in self:
record.x_total_budget = sum(record.x_line_ids.mapped('x_amount'))
L'attribut store=True est important si vous prévoyez de filtrer, trier ou agréger ce champ dans les vues en liste ou les rapports. Les champs calculés non stockés ne peuvent pas être utilisés dans les filtres de domaine ORM.
Ajouter un Champ Monétaire via l'API
Si vous devez créer des champs dans Odoo de manière programmatique via XML-RPC (par exemple, dans le cadre d'un script de configuration à distance), vous pouvez créer le champ Monétaire via ir.model.fields :
models.execute_kw(ODOO_DB, uid, ODOO_API_KEY,
'ir.model.fields', 'create',
[{
'name': 'x_budget',
'field_description': 'Budget',
'model_id': model_id,
'ttype': 'monetary',
'currency_field': 'currency_id',
'state': 'manual',
}]
)
Ceci fait partie de l'ensemble d'outils de personnalisation Odoo plus large disponible via l'API XML-RPC, qui est abordé plus en détail dans d'autres articles de cette collection de blogs.
Meilleures pratiques
Le champ Monétaire est simple à utiliser une fois que vous connaissez les modèles. Voici les pratiques qui garderont votre mise en œuvre propre et éviteront des problèmes à l'avenir.
1. Ne Jamais Utiliser Float pour les Valeurs Financières
C'est la règle la plus importante dans le développement Odoo en ce qui concerne l'argent. Si un champ représente un prix, un montant, un total, un budget ou tout nombre exprimé en devise, utilisez fields.Monetary. Un champ Float n'a pas de conscience de la devise et ne sera pas arrondi correctement entre différentes devises. Le champ Monétaire existe précisément pour résoudre ce problème.
2. Toujours Déclarer Explicitement le Champ de Devise
Ne comptez pas sur le retour à currency_id d'Odoo à moins que ce champ n'existe réellement dans votre modèle. Définissez explicitement le paramètre currency_field et déclarez toujours le Many2one correspondant à res.currency. Cela rend la relation claire et empêche un comportement de retour silencieux dans des environnements multi-devises.
3. Définir une Devise par Défaut
Pour les champs internes qui utiliseront presque toujours la devise de l'entreprise, définissez une valeur par défaut sur le champ de devise : default=lambda self: self.env.company.currency_id. Cela empêche le champ d'apparaître vide sur les nouveaux enregistrements, ce qui supprimerait le symbole de la devise et le formatage dans l'interface utilisateur.
4. Utilisez store=True sur les Champs Monétaires Calculés que Vous Prévoyez de Rechercher
Si vous définissez un champ Monétaire calculé et que vous vous attendez à ce que les utilisateurs ou les rapports filtrent ou trient par celui-ci, définissez store=True. Les champs calculés non stockés ne peuvent pas apparaître dans les domaines ORM ou les vues basées sur SQL. C'est une source courante de confusion lors de la création de tableaux de bord personnalisés dans Odoo.
5. Utilisez Currency Round() pour les Calculs Intermédiaires
Lorsque vous écrivez du code Python qui effectue plusieurs étapes arithmétiques sur des valeurs Monétaires, appliquez self.currency_id.round(value) à chaque étape significative plutôt qu'à la fin. Les erreurs de flottement s'accumulent sur plusieurs opérations, et appliquer un arrondi tôt empêche les écarts dans les totaux.
6. Soyez Intentional dans les Rapports Multi-Devises
Lors de l'agrégation de valeurs Monétaires à travers des enregistrements avec différentes devises, ne vous contentez pas de sommer les chiffres bruts. Convertissez d'abord toutes les valeurs en une devise commune en utilisant res.currency.compute(), ou rendez le rapport spécifique à la devise. Mélanger des devises dans une somme produit des chiffres qui sont techniquement corrects au niveau du champ mais financièrement dénués de sens.
Pièges courants
Même les développeurs Odoo expérimentés rencontrent des problèmes avec les champs Monétaires. Voici les erreurs les plus courantes et comment les éviter.
Piège 1 : Champ de Devise Manquant
Le problème le plus fréquent lors de l'ajout d'un champ Monétaire est d'oublier de créer le champ Many2one de devise associé. Si currency_id n'existe pas dans le modèle, Odoo reviendra silencieusement à la devise de l'entreprise dans certains contextes et lèvera une erreur dans d'autres. Créez toujours le champ de devise en même temps que le champ Monétaire, même si vous ne vous attendez jamais à ce que les utilisateurs le changent.
Piège 2 : Deux champs Monétaires partageant un champ de devise avec des devises prévues différentes
Si vous avez deux champs Monétaires sur le même modèle qui sont censés contenir des valeurs dans des devises différentes (par exemple, un prix client en EUR et un coût fournisseur en USD), ils ne peuvent pas partager en toute sécurité un seul champ currency_id. Chacun a besoin de sa propre référence de devise. Ne pas faire cela signifie qu'un paramètre de devise remplace les deux champs, ce qui produira des données incorrectes et un comportement d'interface utilisateur déroutant.
Piège 3 : Discrepances d'arrondi lors de l'agrégation entre devises
Additionner des valeurs de champs Monétaires à travers des enregistrements avec des devises différentes produira des totaux qui semblent incorrects, car vous additionnez des montants en EUR à des montants en USD comme s'ils étaient la même unité. C'est une source courante d'erreurs de reporting dans les entreprises qui opèrent en plusieurs devises. Normalisez toujours à une seule devise avant d'agréger.
Piège 4 : Comparaisons à virgule flottante dans les recherches ORM
Rechercher un champ Monétaire avec une vérification d'égalité exacte (par exemple, chercher des enregistrements où amount = 10.0) peut manquer des enregistrements en raison de la façon dont les flottants sont stockés dans la base de données. Utilisez >= et <= avec une petite tolérance, ou appliquez un arrondi de devise avant de comparer des valeurs dans la logique Python. C'est un problème général d'odoo orm avec des champs basés sur des flottants, pas spécifique à Monétaire, mais cela compte davantage quand de l'argent est impliqué.
Piège 5 : Ignorer l'arrondi de devise lors de l'importation de données
Lors de l'importation d'enregistrements via CSV ou XML-RPC qui incluent des valeurs de champs Monétaires, les nombres importés sont stockés tels que fournis sans arrondi automatique. Si vos données sources ont plus de décimales que la devise cible ne le permet, la valeur stockée sera techniquement correcte mais s'affichera différemment de ce qui est attendu, et peut provoquer de petites divergences dans les totaux. Appliquez un arrondi de devise dans vos scripts d'importation ou étapes de préparation des données avant d'envoyer des valeurs à Odoo.
Conclusion
Le champ Monétaire est l'un de ces types de champs Odoo qui semble simple en surface mais qui comporte beaucoup de comportements importants en dessous. Sa relation étroite avec l'enregistrement de devise est ce qui le rend fiable pour les données financières : arrondi correct, formatage cohérent et affichage conscient de la devise à travers toute l'interface Odoo et le moteur de rapport.
L'utiliser correctement, ce qui signifie toujours l'associer à un champ de devise explicite et ne jamais substituer un Float pour des valeurs financières, vous évitera toute une catégorie de bogues subtils qui sont notoirement difficiles à traquer en production. Le modèle de données odoo est construit autour de ce type de champ pour une bonne raison.
Que vous suiviez un guide de développeur odoo, personnalisiez un module standard ou construisiez quelque chose de nouveau à partir de zéro, bien configurer vos champs Monétaires est l'une des décisions fondamentales qui façonne la manière dont votre implémentation Odoo gère l'argent de manière fiable.
Besoin d'aide pour votre mise en œuvre Odoo ?
Chez Dasolo, nous aidons les entreprises à mettre en œuvre, personnaliser et optimiser Odoo à toutes les échelles et configurations. Que vous ayez besoin d'un modèle de données propre, d'une stratégie de champ personnalisée, d'un support multi-devises ou d'un déploiement complet d'Odoo, notre équipe a la profondeur technique et fonctionnelle pour bien faire les choses.
Si vous avez des questions sur les champs monétaires ou tout autre aspect de votre mise en œuvre d'Odoo, nous sommes heureux de vous aider. Contactez-nous et parlons de ce que vous êtes en train de construire.