BFBambooForge Labs

Discount Approval on Sales Orders

Require manager approval when an order's margin falls below a floor or a line is priced below cost - a clean request, approve or refuse trail.

Buy on the Odoo Apps StoreOpen the live demoSales€104Community & Enterprise

Available for Odoo 16.0, Odoo 17.0, Odoo 18.0, Odoo 19.0. Technical name bambooforge_discount_approval.

Odoo 16.0Odoo 17.0Odoo 18.0Odoo 19.0
Full walkthrough on a live Odoo 19.0 database, with subtitles. It ends with what this app deliberately does not do.

Discount Approval on Sales Orders

Stop margin erosion from over-discounting. Set the maximum discount your salespeople can give on their own — anything above it must be approved by a sales manager before the order can be confirmed.

This page is the complete manual. Follow it top to bottom and you can install, set your threshold and run the workflow without contacting support.

Overview

  • You set a discount threshold (a percentage) per company.

  • When a quotation has a line discount above that threshold, it cannot be confirmed until a Sales Manager approves it.

  • Salespeople request approval; managers approve or refuse, with the whole decision logged on the order's chatter.

  • Lower the discount back under the threshold and the order confirms normally — no approval needed.

Requirements

  • Odoo 17.0 with Sales (sale_management). Installing this app pulls it in automatically.

No Enterprise modules and no external Python libraries are required.

Installation

  1. Copy bambooforge_discount_approval into your addons path.

  2. Update the apps list (Apps > Update Apps List).

  3. Search for Discount Approval and click Install.

Setting the threshold

Go to Settings > Sales > Pricing > Discount Approval and set Needs approval above to the maximum self-service discount (for example 15%). The threshold is per company.

The workflow

  1. A salesperson builds a quotation. If any line's discount exceeds the threshold, an Approval Pending state applies and confirming is blocked.

  2. The salesperson clicks Request Discount Approval — a to-do activity is raised for the team leader and the order shows To Approve.

  3. A Sales Manager opens the order and clicks Approve Discount (or Refuse Discount). Both are logged on the chatter.

  4. Once approved, the order confirms normally. If refused, it stays blocked until the discount is reduced or re-approved.

If the discount is lowered below the threshold at any point, the block clears automatically.

Frequently asked questions

Who can approve?

Any user in the Sales / Administrator (Sales Manager) group. Salespeople cannot approve their own discounts.

Does it look at the order's overall discount or each line?

It uses the highest line discount on the order, so a single deep-discounted line still triggers approval.

Can I set different thresholds per company?

Yes — the threshold is stored per company.

What if a manager builds the quotation?

A manager can approve and confirm in one go, since they hold the approval right.

Does it block other ways of confirming?

Confirmation is blocked wherever it runs, including the portal and back-office, because the check is on the confirm action itself.

Support

Questions or ideas: support@bambooforge.dev.

Troubleshooting

Order stuck at "To Approve" with no one to approve it

Cause

Requesting approval schedules a to-do activity for the sales team leader (team_id.user_id) or, failing that, the salesperson — but only a user in the Sales / Administrator group (sales_team.group_sale_manager) can actually approve. If the team has no leader, or the leader is not a Sales Manager, the activity lands on someone who cannot press Approve Discount.

Diagnosis

Open the order: the Approval Pending ribbon shows and Discount Approval reads To Approve. Check the activity assignee against the members of the Sales / Administrator group.

Resolution

Have any Sales Manager open the order and click Approve Discount (or Refuse Discount) — the buttons are visible only to that group. Optionally set the team's Team Leader to a Sales Manager so future requests route to the right person.

"Only a Sales Manager can approve or refuse a discount"

Cause

The Approve Discount / Refuse Discount buttons are visible only to the Sales / Administrator group, and both the action and the underlying write are guarded — a salesperson (or an RPC call) attempting to set the state to approved or refused is rejected with this error.

Diagnosis

Confirm the acting user's groups under Settings > Users. Salespeople hold Sales / User only.

Resolution

Grant the approver the Sales / Administrator group, or route the approval to an existing Sales Manager. This is by design: it prevents self-approval by a salesperson.

Confirmation blocked: "needs sales-manager approval"

Cause

action_confirm refuses to confirm while approval_required is set and the order is not yet approved. This fires on every confirm path (back office and portal), listing the trigger in the Approval Reason.

Resolution

Either reduce what triggered it (bring the top line discount back under the threshold, or lift the margin), or click Request Discount Approval and have a Sales Manager approve. Reducing the discount below the threshold clears the block automatically.

Discount is over the limit but no approval is requested

Cause

Approval keys off the highest single line discount versus the per-company Discount Approval Threshold. An order-level discount spread across lines, a threshold set too high, or a threshold of 0 (which approves everything above 0%) can all leave approval_required unset.

Diagnosis

In developer mode inspect max_line_discount, discount_approval_threshold and approval_required on the order. Verify the threshold under Settings > Sales > Pricing for the order's company.

Resolution

Set the threshold on the correct company (it is per company) and apply discounts on the lines so max_line_discount reflects them.

Margin floor or below-cost check never triggers

Cause

Gross margin is computed from each product's cost (standard price) in the company currency. When no line carries a cost, the order is treated as full (100%) margin and gives no signal, so neither the Minimum Gross Margin floor nor Block Below-Cost Lines can fire. A Minimum Gross Margin left at 0 also disables the floor check entirely.

Diagnosis

Check bf_margin_percent and bf_below_cost on the order, and confirm the products have a non-zero Cost. Confirm Minimum Gross Margin and Block Below-Cost Lines are set for the company.

Resolution

Maintain product costs, set the margin floor above 0, and enable Block Below-Cost Lines if below-cost deals should require approval.

Approval clears itself after the order is edited

Cause

Changing the order lines revisits the decision: if the edit removes the trigger, the state falls back to No Approval Needed; if an already-approved order still needs approval, it drops back to To Approve so it is reviewed again.

Resolution

This is intended — margin and discount are re-evaluated on every line change. Re-request and re-approve after material edits.

Upgrading & version compatibility

This build targets Odoo 18.0. Each Odoo major series (17.0, 18.0, 19.0) has its own dedicated build of this module — always install the build that matches your Odoo version. Mixing a build with a different Odoo series is not supported.

Patch upgrades (same series, e.g. 18.0.1.0.0 → later)

  1. Back up your database and filestore first.

  2. Replace the module folder with the newer build.

  3. Restart Odoo with the module updated:

    ./odoo-bin -c your.conf -u bambooforge_discount_approval -d your_db
  4. Odoo applies any schema/data changes automatically. Your existing records and configuration are preserved.

Cross-version migration (e.g. Odoo 17 → 18)

Upgrading Odoo itself is a database migration handled by Odoo's standard upgrade tooling. When you migrate the database to the next Odoo series, install the matching build of this module for that series. Data created by this module carries over with the database migration.

Uninstallation

You can remove this module at any time from Apps → (this module) → Uninstall, or from the command line. Uninstalling is clean and reversible by reinstalling — but note what is and is not deleted.

What is removed

  • The fields, views and analysis definitions this module added.

  • The menus, actions, views and reports this module installed.

What is preserved

  • Your standard Odoo data (partners, products, sales, invoices, inventory moves) is not deleted — this module only reads and annotates it; the underlying records stay.

  • Attachments and chatter messages on standard records are kept.

As always, take a database backup before uninstalling in production.

Changelog

18.0.1.0.0

Current release for Odoo 18.0. This build includes:

  • Require manager approval when an order's gross margin falls below a configurable floor or a line is priced below cost.

  • On top of your existing discount-percentage threshold. Stop margin erosion, with a clean request-approve-refuse workflow and a guard against self-approval.

Feature additions and fixes ship as new builds on the Odoo Apps store; this page and the module's version reflect the current published release. Always keep the build matched to your Odoo series (see Upgrading & version compatibility).

Screens

Order approved - bambooforge_discount_approval
Order approved
Order pending - bambooforge_discount_approval
Order pending
Settings - bambooforge_discount_approval
Settings