| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Discuss (mail)
• Inventory (stock) • Purchase (purchase) • Invoicing (account) |
| Lines of code | 1166 |
| Technical Name |
grev_od_purchase_replenishment_adv |
| License | OPL-1 |
| Website | https://www.grevlin.com |
| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Discuss (mail)
• Inventory (stock) • Purchase (purchase) • Invoicing (account) |
| Lines of code | 1166 |
| Technical Name |
grev_od_purchase_replenishment_adv |
| License | OPL-1 |
| Website | https://www.grevlin.com |
🔄 Purchase Replenishment AdvancedDynamic safety stock, moving-average demand, risk scoring, MOQ enforcement, and bulk rule templates â extending Odoo’s native orderpoints without replacing them.
|
|
|
|
|
|
|
|
💬 Need Help?
|
|
Grevlin Global Corp Professional Odoo Solutions & Business Optimization |
Purchase Replenishment Advanced
Advanced replenishment planning for Odoo 19 — dynamic safety stock, moving-average demand, 4-level risk scoring, MOQ enforcement, and bulk rule templates that extend the native stock.warehouse.orderpoint without replacing it.
Compatible with both Odoo Community and Enterprise editions.
Overview
This module adds demand-aware intelligence on top of Odoo's built-in reorder point workflow. Every stock.warehouse.orderpoint gains:
- Computed average daily demand from stock.move done history
- Stock coverage in days (qty_on_hand ÷ avg daily demand)
- Dynamic safety stock via three selectable methods
- 4-level risk classification: Stockout / Low / Optimal / Overstock
- Minimum Order Quantity (MOQ) enforcement in the native _get_qty_to_order() chain
- A back-reference to a rule template that last stamped its settings
A separate model (grev.purchase.replenishment.rule) holds bulk-config templates that can stamp settings onto hundreds of orderpoints in a single action.
A reporting model (grev.purchase.replenishment.forecast) stores monthly forecast-vs-actual snapshots and computes MAPE-based accuracy scores.
An OWL dashboard (ir.actions.client tag replenishment_dashboard) surfaces the risk pipeline and a rolling forecast accuracy KPI.
Configuration
Installation
- Install the module from :menuselection:`Settings --> Apps`.
- All dependencies are standard Odoo modules: base, purchase, product, stock, purchase_stock, and mail. No additional installation is needed.
- Assign users to the appropriate security group (see below).
Note
The module integrates optionally with grev_od_purchase_budget_control. If that module is installed, the dashboard also shows budget-blocked order counts. If it is absent, the integration is silently skipped.
Security Groups
Three privilege tiers are provided under the Purchase Replenishment category:
| Group | Permissions |
|---|---|
| Replenishment User | Read-only: dashboard, orderpoints, rule templates, forecast accuracy records. |
| Replenishment Planner | Create and edit rule templates; sync templates to orderpoints; manage forecast records. Implies Replenishment User. |
| Replenishment Manager | Full CRUD including delete; run bulk-creation wizard. Implies Replenishment Planner. |
Setting Up Rule Templates
Rule templates are managed under :menuselection:`Replenishment --> Configuration --> Rule Templates`.
- Click :guilabel:`Create`.
- Set :guilabel:`Template Name`, :guilabel:`Warehouse`, and :guilabel:`Company`.
- Choose the scope: set either :guilabel:`Product` (single SKU) or :guilabel:`Product Category` (all storable products in that category). At least one of the two is required.
- Configure the safety stock and demand parameters (see below).
- Click :guilabel:`Save`, then :guilabel:`Sync to Orderpoints` to stamp the settings onto all matching orderpoints in the warehouse.
Important
Syncing overwrites the advanced fields on all matching orderpoints. It does not create new orderpoints — use :guilabel:`Create Missing Orderpoints` (wizard) for that.
Configuring Dynamic Safety Stock
Each orderpoint (and rule template) exposes three methods via :guilabel:`Safety Stock Method`:
| Method | Computed As |
|---|---|
| fixed | Constant grev_safety_stock_qty — suitable for low-velocity SKUs. |
| pct | avg_daily_demand × lead_days × (grev_safety_stock_pct / 100) — scales with velocity and lead time automatically. |
| coverage | avg_daily_demand × grev_safety_stock_days — holds N days of buffer. |
The result is stored in grev_dynamic_safety_stock (indexed). Push it to Odoo's product_min_qty by clicking :guilabel:`Sync Safety Stock` on the orderpoint form (non-fixed methods only).
Usage
Dashboard
Navigate to :menuselection:`Replenishment --> Dashboard` to open the OWL risk pipeline view.
The banner shows four clickable tiles — one per risk level — that filter the embedded native replenishment list below. The right panel displays:
- To Order — orderpoints with qty_to_order > 0
- Auto Trigger — orderpoints set to automatic replenishment
- Manual Trigger — orderpoints requiring manual action
- Forecast Accuracy — rolling average across the last 200 closed monthly periods
Click any tile to drill into the matching orderpoints. Click again to clear the filter and show all.
Understanding Risk Levels
The grev_risk_level field is recomputed on every save of the orderpoint:
| Level | Condition |
|---|---|
| stockout | qty_on_hand ≤ 0 or coverage_days < lead_days |
| low | coverage_days < lead_days + safety_days |
| overstock | qty_on_hand > product_max_qty (when product_max_qty > 0) |
| optimal | All other cases |
Using Rule Templates
- Go to :menuselection:`Replenishment --> Configuration --> Rule Templates`.
- Open or create a template. Configure safety stock method, demand lookback, and MOQ.
- Click :guilabel:`Sync to Orderpoints`. A notification reports how many orderpoints were updated.
- To create missing orderpoints for products that have no reorder rule yet, click :guilabel:`Create Missing Orderpoints` to open the bulk-creation wizard.
- To see which orderpoints are currently linked to a template, click :guilabel:`Synced Orderpoints` (smart button on the template form).
Tip
Use one template per product category per warehouse. Templates can be re-applied at any time — repeated syncs are idempotent.
Viewing Forecast Accuracy
Go to :menuselection:`Replenishment --> Reporting --> Forecast Accuracy`.
Each row represents one product × warehouse × month period. Closed periods (past period_end) display the forecast_accuracy percentage. Open periods show the forecasted qty until the cron closes them.
The monthly cron action_close_open_periods (ir.cron) closes all periods whose period_end < today by querying actual outbound done moves and writing actual_qty.
Technical Details
Models
| Model | Description |
|---|---|
| stock.warehouse.orderpoint (inherited) | Extended with grev_ prefixed fields for safety stock, demand metrics, risk level, MOQ, and rule template back-reference. |
| grev.purchase.replenishment.rule | Bulk-config rule template: scope (product/category + warehouse), safety stock settings, demand lookback, MOQ. Contains action_sync_to_orderpoints(). |
| grev.purchase.replenishment.forecast | Monthly forecast accuracy snapshot per orderpoint. Written by cron action_close_open_periods(). |
Key Fields — stock.warehouse.orderpoint
| Field | Description |
|---|---|
| grev_safety_stock_method | Selection: fixed / pct / coverage |
| grev_safety_stock_qty | Fixed safety stock quantity (method = fixed) |
| grev_safety_stock_pct | Safety stock percentage (method = pct, default 20 %) |
| grev_safety_stock_days | Safety stock days of coverage (method = coverage, default 7) |
| grev_demand_lookback_days | Historical window for demand average (default 90 days) |
| grev_dynamic_safety_stock | Computed safety stock qty (stored, indexed) |
| grev_avg_daily_demand | Average units consumed per day (stored, indexed) |
| grev_coverage_days | Estimated days of stock remaining (stored, indexed) |
| grev_min_order_qty | MOQ enforced by _get_qty_to_order() |
| grev_risk_level | Computed: stockout / low / optimal / overstock |
| grev_rule_template_id | Many2one to grev.purchase.replenishment.rule (set null on delete) |
Key Fields — grev.purchase.replenishment.rule
| Field | Description |
|---|---|
| name | Template name (unique per warehouse + company) |
| warehouse_id | Target warehouse |
| company_id | Company (multi-company isolation) |
| product_id | Single product scope (optional; takes priority over category) |
| product_category_id | Category scope — applies to all storable products in category |
| safety_stock_method | Same three-option selection as on the orderpoint |
| min_order_qty | MOQ to stamp onto matched orderpoints |
| last_sync_date | Datetime of last successful sync (read-only) |
| synced_orderpoint_count | Computed: count of orderpoints linked to this template |
Key Fields — grev.purchase.replenishment.forecast
| Field | Description |
|---|---|
| product_id | Product (required) |
| warehouse_id | Warehouse (required) |
| orderpoint_id | FK to originating orderpoint (nullable — survives orderpoint deletion) |
| period_start / period_end | Monthly period boundaries |
| forecasted_qty | Replenishment qty captured at period start |
| actual_qty | Actual outbound consumption written by cron after period closes |
| forecast_accuracy | max(0, (1 − |error| / forecasted) × 100) — MAPE-based, stored |
MOQ Override
_get_qty_to_order() is overridden on stock.warehouse.orderpoint:
def _get_qty_to_order(self, qty_in_progress_by_orderpoint=None): qty = super()._get_qty_to_order(...) if self.grev_min_order_qty and qty > 0.0: if qty < self.grev_min_order_qty: qty = self.grev_min_order_qty return qty
super() is always called first. MOQ only bumps up — it never forces an order for a product Odoo already considers adequately stocked. UoM rounding from _get_multiple_rounded_qty() still applies downstream.
Demand Computation
_compute_grev_demand_metrics() batches all orderpoints by (warehouse_id, demand_lookback_days) and issues one _read_group() query per batch against stock.move done records in outbound locations. This avoids N+1 queries when multiple orderpoints are recomputed together.
Scheduled Action
| Cron | Purpose |
|---|---|
| Replenishment Forecast — Close Open Periods | Monthly. Calls grev.purchase.replenishment.forecast.action_close_open_periods(). Closes all periods whose period_end < today by querying actual outbound consumption and computing forecast_accuracy. |
Integration Points
Optional upstream modules (graceful fallback if absent):
- grev_od_purchase_budget_control — dashboard surfaces budget-blocked order counts when this module is installed.
Downstream modules that may consume this data:
- grev_od_spend_analytics — replenishment spend analysis
- grev_od_purchase_ai_assistant — AI-assisted replenishment recommendations
Note
All cross-module lookups use try/except KeyError guards so the module operates correctly as a standalone installation without any other Grevlin modules.
See Also
- :doc:`../grev_od_purchase_budget_control/doc/index` — Budget Control for spend-limit-aware replenishment
- :doc:`../grev_od_spend_analytics/doc/index` — Spend Analytics for replenishment KPI reporting
- :doc:`../grev_od_purchase_ai_assistant/doc/index` — AI Assistant for predictive replenishment optimization
Odoo Proprietary License v1.0 This software and associated files (the "Software") may only be used (executed, modified, executed after modifications) if you have purchased a valid license from the authors, typically via Odoo Apps, or if you have received a written agreement from the authors of the Software (see the COPYRIGHT file). You may develop Odoo modules that use the Software as a library (typically by depending on it, importing it and using its resources), but without copying any source code or material from the Software. You may distribute those modules under the license of your choice, provided that this license is compatible with the terms of the Odoo Proprietary License (For example: LGPL, MIT, or proprietary licenses similar to this one). It is forbidden to publish, distribute, sublicense, or sell copies of the Software or modified copies of the Software. The above copyright notice and this permission notice must be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Please log in to comment on this module