Documentation13 min de lecture

Remises, prix et tarifs : quinze modules pour tenir sa politique commerciale

Quinze modules OCA du dépôt `sale-workflow` rendent à Odoo 18 Community la souplesse tarifaire qui lui manque : `sale_fixed_discount` permet une remise **en montant fixe** et non plus en pourcentage seul, et `sale_discount_display_amount` affiche enfin le **montant** remisé, qu'Odoo calcule sans jamais le montrer. Les treize autres, du verrouillage du prix par règle de tarif à l'historique des prix pratiqués chez ce client.

Calculatrice utilisée au-dessus de documents chiffrés

La remise est le seul endroit d'un ERP où une négociation se matérialise. Elle se discute en euros, se décide en pourcentage, s'applique parfois à toute la commande, et finit souvent écrasée par un recalcul automatique.

Quinze modules communautaires couvrent ces cas. Trois types de remise, deux façons de protéger un prix, un historique, et une mécanique de tarifs nettement plus riche que le standard.

Résumé

Trois modules ajoutent des types de remise : en montant fixe (sale_fixed_discount), globale sur toute la commande et cumulable en cascade (sale_global_discount), ou globale répercutée sur le champ de remise de chaque ligne avec exclusions produit par produit (sale_order_general_discount). sale_discount_display_amount affiche le montant remisé et le total avant remise, sur la ligne et dans les totaux — ce qu'un client demande systématiquement.

Deux modules protègent un prix : sale_order_line_final_price verrouille prix unitaire et remise pour les non-responsables, sale_order_line_price_lock_by_pricelist verrouille le prix unitaire quand il vient d'une règle de tarif d'une portée donnée. Deux autres aident à le fixer : l'historique des prix pratiqués chez ce client, et deux boutons de recalcul des prix et des descriptions.

Côté tarifs enfin : une règle de tarif par conditionnement, une catégorie de prix indépendante de la catégorie produit, le prix déterminé par la date de livraison plutôt que par la date de commande, l'affichage d'une majoration (et non seulement d'une remise), le choix de la méthode d'arrondi de TVA par client, et un cache de prix pour sortir un catalogue client complet sans relancer le moteur de calcul.

L'essentiel

  • Remise en euros sur la ligne, remise globale en cascade sur la commande, ou remise uniforme répercutée ligne à ligne avec exclusions.
  • Le montant de la remise affiché — sur la ligne et dans les totaux, en HT ou en TTC selon un paramètre.
  • Deux verrouillages de prix : par rôle, ou selon la portée de la règle de tarif qui a fixé le prix.
  • L'historique des prix pratiqués pour ce produit chez ce client, réappliquable en un clic.
  • Le prix calculé à la date de livraison plutôt qu'à la date de commande — décisif quand les tarifs changent au 1ᵉʳ janvier.
  • Un tarif par conditionnement : unité, carton, palette — le même article à trois prix.
  • Une catégorie de prix indépendante de la catégorie produit, pour des règles transversales.
  • Un cache de prix pour produire un catalogue client complet sans recalcul, avec file d'attente de traitement.

Ce que ces modules ajoutent à l'instance

ModuleCe qu'il apporteVersionDépend de
sale_fixed_discountRemise en montant fixe sur la ligne18.0.1.0.0account_invoice_fixed_discount
sale_global_discountRemises globales cumulables en cascade18.0.1.0.0account_global_discount
sale_order_general_discountRemise uniforme répercutée sur les lignes18.0.1.0.2sale
sale_discount_display_amountLe montant de la remise, enfin visible18.0.1.0.0sale_management
sale_order_line_final_pricePrix et remise verrouillés hors responsables18.0.1.0.2sale
sale_order_line_price_lock_by_pricelistPrix verrouillé selon la portée de la règle18.0.1.0.1sale
sale_order_line_price_historyHistorique des prix pour ce produit18.0.1.0.1sale
sale_order_price_recalculationRecalcul manuel des prix et descriptions18.0.1.0.0sale
sale_last_price_infoDernier prix pratiqué, accessible à la saisie18.0.1.0.0sale_management
sale_pricelist_packagingRègle de tarif par conditionnement18.0.1.0.0sale_management
product_price_categoryCatégorie de prix indépendante18.0.1.0.0sale_stock
sale_pricelist_from_commitment_datePrix calculé à la date de livraison18.0.1.0.0sale
sale_pricelist_display_surchargeAffichage des majorations18.0.1.0.0sale
sale_custom_roundingMéthode d'arrondi de TVA par client18.0.1.0.0account_invoice_custom_rounding
pricelist_cacheCache de prix pour catalogue client18.0.1.0.0product, queue_job, partner_pricelist_search

Un seul menu ajouté, par le dernier : Ventes ▸ Configuration ▸ Produits ▸ Pricelist Cache. Tous les autres enrichissent le devis, la ligne, la fiche produit ou la liste de prix.

Trois remises, trois logiques commerciales

ModuleOù s'applique la remisePour qui
sale_fixed_discountSur la ligne, en eurosLe commercial qui négocie « je vous fais 500 € »
sale_global_discountSur la commande entière, en cascadeLes remises financières successives — volume, puis fin d'année
sale_order_general_discountSur la commande, répercutée ligne à ligneLa remise uniforme avec exclusions produit

La différence entre les deux derniers est structurante. La remise globale reste une ligne de remise au niveau de la commande, transmise telle quelle à la facture ; la remise générale modifie le champ de remise de chaque ligne, donc change le prix net de chaque ligne.

Le choix se fait sur une question simple : votre client doit-il voir une remise par ligne, ou une remise en pied de document ? Un distributeur veut la première, un donneur d'ordre industriel souvent la seconde.

Le quatrième module du lot est celui qu'on finit toujours par installer. En standard, Odoo n'affiche que le taux de remise : jamais le montant. sale_discount_display_amount calcule et affiche ce montant, en HT ou en TTC selon un paramètre, sur chaque ligne et dans la zone des totaux, avec le total avant remise.

C'est exactement ce que le client demande au téléphone — « ça me fait combien de remise ? » — et ce qu'un vendeur calculait jusque-là à la main.

Protéger un prix négocié

Deux verrouillages, deux logiques, et ils se complètent plus qu'ils ne se concurrencent.

  • Par rôle : sale_order_line_final_price permet de poser un prix final et de verrouiller prix unitaire et remise pour les utilisateurs qui ne sont pas responsables des ventes. Le prix décidé par le responsable ne bouge plus.
  • Par origine du prix : sale_order_line_price_lock_by_pricelist verrouille le prix unitaire quand il provient d'une règle de tarif dont la portée — produit, variante, catégorie, tous produits — correspond à un niveau de verrouillage défini sur la liste de prix.

Le second est le plus fin, et le plus adapté aux entreprises qui ont une vraie politique tarifaire : un prix catalogue négocié au niveau d'un contrat client ne doit pas pouvoir être modifié à la main, tandis qu'un prix issu d'une règle générique peut rester ajustable.

Il complète utilement le verrouillage par la liste de prix côté achats, et les deux reposent sur le même principe : c'est l'origine du prix qui décide de sa modifiabilité, pas le rôle de celui qui regarde l'écran.

Et quand il faut au contraire recalculer

sale_order_price_recalculation ajoute deux boutons sur le devis : recalculer les prix selon la liste de prix courante, et réinitialiser les descriptions des lignes depuis la fiche produit.

Le cas d'usage est le devis ancien qu'on réactive : les tarifs ont changé, les libellés aussi, et tout reprendre à la main prend un quart d'heure. Deux boutons, et le devis est à jour — en assumant qu'il faut ensuite le relire.

Retrouver le bon prix : historique et dernier prix

Un vendeur au téléphone a une question récurrente : à quel prix lui avons-nous vendu ça la dernière fois ? Deux modules y répondent, avec deux niveaux de profondeur.

ModuleCe qu'il montreGeste
sale_order_line_price_historyL'historique des prix pratiqués pour le produit, chez ce client ou tous clients confondusRéappliquer un prix passé en un clic
sale_last_price_infoLe dernier prix pratiqué, accessible pendant la saisieInformation, sans ressaisie

Ce détail décide souvent de la cohérence tarifaire d'une entreprise. Sans historique accessible, chaque vendeur refait son prix — et le client finit par connaître l'écart entre deux commerciaux mieux que vous.

Le premier est le plus complet : il distingue l'historique chez ce client de l'historique général, ce qui est la bonne distinction pour une négociation.

Le symétrique existe côté achats, où il sert à ne pas payer plus cher que la dernière fois : voir la fiche des achats.

Des tarifs plus fins que le standard

Par conditionnement, par catégorie de prix

  • sale_pricelist_packaging permet des règles de tarif par conditionnement : le même article vendu à l'unité, au carton ou à la palette n'a pas le même prix unitaire. C'est la base du négoce, et c'est absent du standard.
  • product_price_category ajoute une catégorie de prix sur le produit, indépendante de la catégorie produit — qui, elle, porte la comptabilité et la logistique. On peut alors écrire des règles transversales sans tordre son arborescence comptable.

Le second résout un conflit classique : la catégorie produit sert déjà à la comptabilité analytique et au stock. Y greffer la logique tarifaire finit par produire une arborescence que plus personne ne comprend.

Quelle date fait le prix ?

sale_pricelist_from_commitment_date utilise la date d'engagement — la date de livraison — plutôt que la date de commande pour déterminer la règle de tarif applicable. Deux options permettent de rendre cette date plus visible, voire obligatoire, sur le formulaire.

Le cas se présente chaque 1ᵉʳ janvier : une commande prise en décembre pour une livraison en février doit-elle appliquer l'ancien tarif ou le nouveau ? La réponse dépend de vos conditions générales — et jusqu'ici, Odoo n'offrait qu'une seule réponse.

Majorations, arrondis et catalogue

  • sale_pricelist_display_surcharge affiche une majoration calculée par une règle de tarif. Par défaut, Odoo masque les « remises négatives » : le surcoût s'applique sans se voir, ce qui est le meilleur moyen de perdre la confiance du client.
  • sale_custom_rounding permet de choisir la méthode d'arrondi de TVA — par ligne ou globale — au niveau d'un contact ou d'une commande, plutôt que d'appliquer celle de la société. C'est une exigence de certains clients et de certains pays.
  • pricelist_cache précalcule le prix de chaque produit pour chaque tarif, afin de générer un catalogue client complet sans relancer le moteur de prix. Il s'appuie sur une file d'attente de traitement, donc sur une infrastructure de travaux de fond.

Le dernier n'est pas un module de confort : sur un catalogue de dizaines de milliers de références, produire la liste de prix d'un client est une opération qui met un serveur à genoux. Le cache la rend instantanée, au prix d'un mécanisme de rafraîchissement à surveiller.

Limites connues

  • Trois modules de remise qui se chevauchent : choisir selon ce que le client doit voir — remise par ligne ou en pied de document — et ne pas les empiler.
  • sale_fixed_discount et sale_global_discount dépendent de modules comptables correspondants : la remise doit exister sur la facture, pas seulement sur la commande.
  • Le verrouillage par règle de tarif suppose une politique tarifaire réelle : sans règles structurées, il n'a rien à verrouiller.
  • Le recalcul des prix écrase les ajustements manuels : c'est son rôle, et c'est à dire avant de donner le bouton.
  • pricelist_cache dépend d'une file de travaux de fond (queue_job) : c'est un composant d'infrastructure à exploiter, pas une case à cocher.
  • Le cache doit être rafraîchi : un prix modifié et un cache périmé produisent un catalogue faux, ce qui est pire que lent.

Identité technique

Les quinze modules viennent du dépôt OCA sale-workflow, branche 18.0, en licence AGPL-3 sauf sale_order_line_price_lock_by_pricelist (LGPL-3). Quatre dépendent d'un module comptable du dépôt account-invoicing — remise fixe, remise globale, arrondi personnalisé — parce que la remise doit vivre jusqu'à la facture.

Les autres familles de ce dépôt sont traitées dans la présentation des lignes et les dates et reliquats.

Questions fréquentes

Peut-on faire une remise en euros dans Odoo ?

Pas en standard : la remise d'une ligne est un pourcentage. sale_fixed_discount ajoute la remise en montant fixe, en s'appuyant sur le module comptable qui apporte déjà cette capacité aux factures — la remise doit en effet exister jusque sur la facture, pas seulement sur la commande.

Pourquoi Odoo n'affiche-t-il pas le montant de la remise ?

Parce qu'il n'affiche que le taux. sale_discount_display_amount calcule et affiche le montant remisé et le total avant remise, en HT ou en TTC selon un paramètre, sur chaque ligne et dans la zone des totaux. C'est la question que pose tout client au téléphone.

Comment empêcher un vendeur de modifier un prix négocié ?

Deux approches. sale_order_line_final_price verrouille prix et remise pour les utilisateurs non responsables des ventes. sale_order_line_price_lock_by_pricelist verrouille le prix selon l'origine : si le prix vient d'une règle de tarif dont la portée correspond au niveau de verrouillage de la liste de prix, il n'est plus modifiable à la main.

Quel tarif s'applique pour une commande prise avant un changement de prix ?

En standard, celui de la date de commande. sale_pricelist_from_commitment_date fait appliquer le tarif en vigueur à la date de livraison — ce qui change tout pour une commande de décembre livrée en février. Deux options rendent cette date plus visible, voire obligatoire sur le formulaire.

Peut-on vendre le même produit à des prix différents selon le conditionnement ?

Oui, avec sale_pricelist_packaging : les règles de tarif peuvent viser un conditionnement — unité, carton, palette. C'est la base du négoce et c'est absent du standard, où le prix est attaché au produit et à son unité de mesure.

Se faire accompagner

La politique tarifaire est le sujet où l'empilement de modules coûte le plus cher : trois types de remise installés en même temps produisent trois façons de faire la même chose, et des documents clients incohérents d'un vendeur à l'autre.

Nous commençons donc par écrire la politique — qui accorde quoi, jusqu'où, et ce que le client doit lire sur son devis — puis nous installons les deux ou trois modules qui la servent. Le reste n'a pas de raison d'exister sur votre instance. Voir les prestations d'Atalios Consulting, notre méthode ou demander un rappel.

Pour aller plus loin

En résumé

Trois formes de remise, deux verrouillages de prix, un historique client, et des tarifs enfin capables de distinguer un carton d'une palette ou une livraison de janvier d'une livraison de février. À choisir selon la politique commerciale écrite, pas selon la liste des modules disponibles. Parlons de votre politique tarifaire.

Documentation OCAVentesTarifs

Partager

Fiches connexes

Équipe au travail sur des ordinateurs portables autour d'une table
Le module OCA `account_invoice_en16931` (dépôt `fr-einvoicing`, version 18.0.1.0.0, licence AGPL-3) est le socle qui fabrique le fichier de facture électronique conforme à la norme européenne **EN 16931** : Factur-X (PDF/A-3 avec XML CII embarqué), XML UBL, XML CII ou PDF accompagné d'un UBL — et il ajoute des **contrôles bloquants à la validation** d'une facture client. Les quatre modules qui s'y greffent pour la France, et ce que le socle ne fait pas.
Lire la suite
Documentation OCA, Facturation électronique
Réunion d'approbation autour d'un document de travail
Relevé sur une instance Odoo 18 Community, le module OCA `base_tier_validation` (dépôt `server-ux`, version 18.0.3.5.1, licence AGPL-3) ajoute 1 modèle, 101 champs et 3 menus, mais ne s'active sur aucun document métier par lui-même : il lui faut un module d'implémentation. C'est le point qui surprend le plus — voici ce qu'il fait réellement, et comment le mettre en service.
Lire la suite
Documentation OCA, Odoo