The Problem

Restaurants and commercial kitchens run on thin margins. Food cost — the single largest variable expense — can swing between 28% and 38% of revenue depending on wastage, portion control, and pilferage. Yet most kitchens reconcile their raw material consumption manually, at end-of-day or worse, at month-end.

A mid-sized restaurant chain approached Arsenal ITC with a specific pain point:

*”We know exactly what we sold from the POS. We know what we purchased from invoices. We know what’s physically on the shelf. But connecting these three numbers — sales → consumption → stock — takes 3 hours of manual spreadsheet work every single day. And by the time we find a variance, the food’s already gone.”*

They were running Odoo 17 Community Edition with the POS module. Purchases and inventory were in Odoo. The gap was the middle layer: automated consumption tracking triggered by sales, adjusted for real-world wastage.

This post covers the full architecture, data model, and key implementation decisions behind the module we built.

Architecture Overview

The module sits between three standard Odoo 17 Community modules: point_of_sale, mrp (for BOMs), and stock (for inventory and purchases).

Reverse BOM Consumption Engine - Odoo 17 Community Architecture

BOM Explosion Engine

The core computational logic: given a POS order line (product × quantity), traverse the BOM tree, accumulate raw material quantities, and apply wastage.

The Reconciliation View

The operational dashboard is built entirely with native Odoo tree views — no custom JavaScript widgetry needed in Odoo 17:

The decoration-danger/warning/success attributes give instant visual triage — kitchen managers can sort by variance and drill into the worst offenders first.

A wizard action triggers the daily computation:

Edge Cases Handled

Building this for a real restaurant surfaced several non-obvious problems:

1. Batch Cooking (Multiple BOMs per Product)

A single menu item can have multiple BOMs — one for a batch of 10 portions, another for a single portion. We handle this by preferring the BOM with the smallest product_qty that divides evenly into the sold quantity, falling back to proportional scaling.

2. Unit of Measure Inconsistencies

Recipe BOMs often mix UoMs: eggs in units, flour in grams, oil in liters. The explosion engine runs all conversions through Odoo’s uom.uom._compute_quantity() method rather than assuming consistent units.

3. POS Order Modifications

If a kitchen modifies an order post-submission (substitutions, extra portions), the consumption records for that order must be invalidated and recomputed. We use a pos.order write override that marks affected consumption records as draft:

4. Partial-Day Computations

A kitchen manager might want mid-shift consumption numbers (lunch vs. dinner). The wizard accepts a datetime range, not just a date, so the computation can be scoped to specific POS session windows.

Real Business Impact

After 3 months of production use:

The module paid for its development cost within 6 weeks — entirely through reduced food cost variance.

Why Odoo 17 Community?

We built this on Community Edition for a deliberate reason: the client didn’t need Enterprise MRP features (PLM, work center scheduling, MES). The Community edition’s BOM engine, stock module, and POS integration are feature-complete for kitchen-scale manufacturing. Adding a custom consumption layer was cleaner than fighting Enterprise features they’d never use.

Key Odoo 17 Community capabilities we relied on:

Native multi-level BOMsmrp.bom with bom_line_ids recursion works identically in Community

UoM conversion engineuom.uom._compute_quantity() is available in Community

Server actions + scheduled actions — cron-based auto-computation at end-of-shift

Studio-quality tree views with decorations — the reconciliation dashboard needs zero custom JS

Inheritance without monkey-patching — clean _inherit on pos.order with super() calls

Next Steps

We’re extending the module with:

1. ML-driven wastage prediction — using historical variance data to suggest wastage % adjustments per product category × season

2. Auto-PO generation — when physical stock drops below a computed reorder point, auto-generate a purchase order for the suggested quantity based on next-day sales forecast

3. Multi-kitchen consolidation — roll-up reconciliation across 5+ restaurant locations into a central procurement dashboard

If you’re building on Odoo Community and hitting manufacturing complexity — the framework can handle more than the marketing materials suggest. You just need to think in terms of clean data models and batched computation, not one-size-fits-all modules.

Have a similar challenge with Odoo Community? Reach out at arsenalitc.com — I’m happy to discuss architecture over a call.