Skip to content

Odoo Anglo-Saxon Costing: The Part Nobody Explains

2025-06-04 odooaccountingcosting

What the docs say

Odoo’s documentation will tell you that Anglo-Saxon costing posts the COGS entry at the time of delivery, not at the time of invoice. It posts the stock input account at receipt and clears it at billing.

That’s accurate. It’s also not the part that causes problems.

What actually breaks

1. The interim accounts don’t clear when you expect

When you receive goods, Odoo debits Stock Valuation and credits Stock Input (Interim). When you validate the vendor bill, it debits Stock Input (Interim) and credits Accounts Payable.

In theory these net to zero. In practice:

  • If the bill price differs from the PO price, the delta goes to a price difference account — not back to COGS
  • If the bill is in a different currency, exchange rate variance hits a separate account
  • If you cancel and re-validate receipts after billing, the interim account gets entries that no longer have a matching bill to clear them

The result: your Stock Input (Interim) account has a non-zero balance that nobody can explain six months later.

2. Average cost updates retroactively on backdate

If you backdate a vendor bill (or Odoo auto-dates it to the bill date instead of today), the average cost recalculation runs for that historical date. Stock moves that already posted at the old average cost don’t get updated. You end up with a cost discrepancy between what’s in the stock valuation account and what the product’s current average cost says.

Fix: always bill at today’s date unless you have a controlled cutoff process.

3. The “Done” column in stock moves is not what you think

New Odoo consultants look at the stock move’s product_uom_qty and think that’s the valued quantity. It’s the demand. The quantity_done is what was actually moved. The cost posting uses quantity_done, but reports often filter on product_uom_qty. This mismatch causes reconciliation headaches.

The journal entries you should actually see

Purchase flow (Anglo-Saxon):

Receipt validation:
DR Stock Valuation Account (product cost × qty)
CR Stock Input Account (Interim)
Vendor bill validation:
DR Stock Input Account (Interim)
CR Accounts Payable
Price difference (if bill price ≠ PO price):
DR/CR Price Difference Account
CR/DR Stock Input Account (Interim)

Sale flow:

Delivery validation:
DR COGS
CR Stock Valuation Account
Customer invoice:
DR Accounts Receivable
CR Revenue

Note: in Anglo-Saxon, the customer invoice does not touch COGS. That already happened at delivery. If you see COGS entries on your invoice journal, your costing method is set to Continental, not Anglo-Saxon.

How to audit your interim accounts

Run this in the Odoo shell to find uncleared interim entries:

from odoo import api, SUPERUSER_ID
from odoo.tools import date_utils
env = api.Environment(cr, SUPERUSER_ID, {})
# Find the stock input account (interim)
account = env['account.account'].search([('code', 'like', '3101')], limit=1)
lines = env['account.move.line'].search([
('account_id', '=', account.id),
('reconciled', '=', False),
('parent_state', '=', 'posted'),
])
for l in lines:
print(l.move_id.name, l.date, l.debit, l.credit, l.product_id.name)

Any unreconciled line here is a future accounting mystery. Fix them now.

The rule I follow

Set up a scheduled action to email the accounting team the balance of all interim accounts every Monday. If the balance is non-zero and aging > 30 days, something went wrong in the purchase flow. Catch it early.