Skip to Content
Q&A

Gross margin in Odoo: why you don't see it, and how to fix it

Invoices without products, bills without purchase orders and a cost price of zero: the four causes we see most, and four routes to reliable margin figures

Back to all Q&A
November 2, 2026 by
Gross margin in Odoo: why you don't see it, and how to fix it

In short: Odoo can show gross margin per quotation line, per order and per product. In practice many companies still only see revenue. The reason is almost never a missing report, but missing links in the data: invoices without products, vendor bills without purchase orders and products with a cost price of zero. In this article we explain what gross margin in Odoo is based on, the four causes we see most, and four routes to reliable margin figures.

"Where can I see my margin?" is one of the most common questions in our helpdesk. Recently a customer asked it about two companies at once: a Dutch entity whose invoices came in from Exact Online, and a Belgian entity that worked fully in Odoo. The assumption was that the Exact integration caused the problem. The analysis showed something else, and that is exactly why we wrote this article.

What is gross margin, and where does Odoo get it from?

Gross margin is the difference between what you sell something for and what it cost you, before overhead such as rent and salaries. As a formula: revenue minus cost of sales. As a percentage: that difference divided by revenue.

Odoo can calculate this at three levels:

  • Per quotation or order line. With the Margins option in the Sales settings, Odoo shows the margin per line and per order. The cost is taken from the cost price of the product.
  • Per product or product category, in the sales analysis, once the margin option is on.
  • Per company or period, in the profit and loss statement: revenue accounts against cost of sales accounts.

The first two levels depend entirely on two things: products on the lines and a correct cost price per product. The third level only needs correct general ledger accounts. That is the key to almost every margin question.

Four reasons why you do not see margin

1. Invoices come in without products

If invoices are imported from another package as bookings, each invoice has one or a few lines per general ledger account, with a description like "customer - invoice number". That is fine for the accounts, but Odoo does not know what was sold, so it cannot calculate margin per product. This was the situation in the Dutch entity: almost a hundred sales invoices and more than six hundred purchase lines, all without a product.

2. Vendor bills are booked without products and without purchase orders

The Belgian entity worked fully in Odoo. Almost all sales lines had a product. But on the purchase side only 9 of more than 1,600 bill lines had a product, and there were only a handful of purchase orders, none of which were linked to a sales order. Vendor bills were entered directly on a cost account. The purchase price never reached the product, so the cost price stayed empty.

3. The cost price on the product is zero

On the main products of that same entity the cost price was 0. Odoo then shows a margin of one hundred percent on every line. That looks great in a report, and it is useless. The cost price is either set manually (standard price), or updated from receipts if you use average cost or FIFO valuation. Neither happens if purchases bypass purchase orders and receipts.

4. A flow that stopped without anyone noticing

In the Dutch entity the import of sales orders from Exact had stopped weeks earlier because of a missing API permission. Invoices kept coming in, orders did not. So even the route via orders was blocked. We described this in seven lessons from a live Exact Online integration.

The conclusion for that customer: the missing margin had little to do with Exact. It was caused by how purchases were booked.

Four routes to reliable margin figures

Route 1: keep the cost price on products and switch on margins

The quickest step. Fill in the cost price of your main products, or let Odoo update it from receipts. Switch on the Margins option in Sales. From that moment you see an expected margin on every quotation and order, before you send it. This works immediately for orders entered in Odoo. It does not work for invoices imported as bookings.

Watch out: a manually maintained cost price is an estimate. If purchase prices change often, the margin on the order drifts away from reality. Then route 2 is better.

Route 2: purchase from the sales order

For products you buy specifically for a customer, use the routes Buy and Replenish on Order (MTO). Confirming the sales order then creates a purchase order at the supplier. The receipt updates stock and cost price, and the vendor bill is matched with the purchase order. The result: real margin per sales order, based on what you actually paid. This is the most reliable route, but it changes how your purchasing team works. Plan a short training and agree that bills without a purchase order are the exception.

Route 3: analytic accounting per order or project

Do you work with projects, or do sales stay partly outside Odoo? Then give each order or project an analytic account, and put that analytic account on the related revenue and cost lines, including vendor bills. In the analytic report you see revenue and costs per order or project side by side. That is less precise per product, but it works even if lines have no products.

Route 4: a margin dashboard at general ledger level

As a short-term solution, for example while route 2 is being introduced: a dashboard with revenue, cost of sales and gross margin per month and per company, straight from the accounts. In our analysis that gave an indicative gross margin of around half of revenue for the Dutch entity, excluding stock movements. That is not margin per order, but it gives management a reliable trend every month.

Which route fits you?

  • You sell from stock and enter orders in Odoo: route 1, possibly with average cost valuation.
  • You buy per customer order: route 2.
  • You work per project, or your invoices come from another package: route 3.
  • You need figures this month: route 4, while you work on one of the others.

Many companies combine routes. In our example the advice was: route 4 straight away for both companies, route 1 and 2 for the Belgian entity, and for the Dutch entity either bringing sales orders back from Exact or moving purchasing into Odoo.

Practical checks you can do today

  1. Open a few recent vendor bills. Is there a product on the lines, and is the bill linked to a purchase order?
  2. Filter your products on cost price equals 0. How many of your best sellers are in that list?
  3. Look at a recent sales order with the margin column on. Is the margin realistic?
  4. Check in your integrations whether all flows still run, not only the invoice flow.

Frequently asked questions

Where do I see gross margin in Odoo?

Switch on Margins in the Sales settings. You then see margin per line and per order on quotations and sales orders, and as a measure in the sales analysis. Per company or period you see it in the profit and loss statement.

Why does Odoo show a margin of 100 percent?

Usually because the cost price of the product is 0. Fill in the cost price, or let Odoo update it from receipts through average cost or FIFO valuation.

Can I see margin per order if my invoices come from Exact Online?

Not per product, because invoices from Exact arrive as bookings without products. Use analytic accounting per order or project, or let the sales and purchase process run in Odoo.

Does linking purchase orders to sales orders really help?

Yes. With the routes Buy and Replenish on Order, the purchase order is created from the sales order. Cost price and vendor bill then belong to that order, so you see real margin instead of an estimate.

Finally

Margin is not a report you switch on, but the result of good links between sales, purchasing and stock. Want help finding where the link breaks in your Odoo? Connecting another package such as Exact Online? We build integrations on Connecta and implement Odoo at a fixed price of €1,000 per app: AI builds, a consultant checks. Contact DAADit Group or take the free Business Scan.

Question not answered?

Our Odoo consultants are happy to think along with you. Book a no-obligation intro call.

Book an appointment
Importing Exact Online into Odoo: seven lessons from a live integration
Missing relations, invoice numbering, general ledger mapping, journals and API scopes: what we ran into, and how we solved it