Dynamic Pricing & AI Sales Forecast
Rule-based dynamic pricing engine combined with an AI-powered 30/60/90-day revenue forecaster, customer churn detection, and a live OWL dashboard — all inside Odoo 19.
The Problem
Manual pricing is costing you money — every day
Most Odoo stores set prices once and forget them. That means you're selling fast-moving stock too cheap, sitting on dead inventory at full price, and watching Gold customers get the same deal as a first-time buyer.
Stock goes to zero at the wrong price
When stock drops below 5 units, you should be charging more — not the same price as when you had 200 in the warehouse. Every unit sold cheap is margin left on the table.
Dead inventory drains cash
Overstock sitting in the warehouse for 90 days? Without automatic price reductions, it stays there. A 10% auto-discount moves product faster than a manual campaign you'll never remember to run.
No visibility into next month's revenue
Your sales manager is guessing next quarter's target. There is no data-backed forecast — just spreadsheets and gut feel. Budget decisions get made on hope, not numbers.
Customers churn silently
A customer who bought every month for a year suddenly goes quiet. Nobody notices until the annual revenue review. By then it's too late to win them back.
The Solution
This module automates every one of those problems
Set your rules once. Every night, the pricing engine scans your catalogue, adjusts prices based on live stock and demand, logs every change with a full audit trail, and emails nothing — it just works. In the morning you open the dashboard and see exactly what changed and why.
What changes after you install this module
| Situation | Without this module | With this module |
|---|---|---|
| Stock drops to 3 units | Price stays the same — sold at a loss of margin | Stock-Low rule fires automatically, price rises 10–20% |
| 200 units sit unsold for 60 days | Takes up warehouse space, no action taken | Overstock rule kicks in, price drops to move inventory |
| Gold customer places a quote | Gets the same public price as everyone else | Customer-Tier rule gives them a 5% loyalty discount |
| End-of-season products | Manager manually runs a sale — if remembered | Time-based rule activates on date range, no action needed |
| Planning next quarter budget | Spreadsheet guess based on last year's numbers | 30/60/90-day AI forecast ready every Monday morning |
| Key customer goes quiet | Noticed at year-end review when it's too late | Customer Health flags them as At-Risk within days |
| Cost of goods increases 5% | Selling below margin until someone updates prices | Margin-Protect rule ensures prices stay above your floor |
What's inside
Everything you need to price smarter
One module, four interconnected engines — working automatically every night so you wake up to optimised prices and fresh forecasts.
Dynamic Pricing Engine
Apply priority-ordered pricing rules across your entire product catalogue every night. Each rule can raise, lower, or formula-adjust prices based on live stock levels, demand rates, customer tiers, seasons, or margin floors.
- 6 rule types
- Min / max price guards
- Full audit history log
- Formula expressions
AI Sales Forecasting
Uses Ridge Regression (scikit-learn) trained on 365 days of historical order data to predict revenue for the next 30, 60, and 90 days. Graceful fallback to rolling average when scikit-learn is not installed.
- 30 / 60 / 90-day horizons
- Lag-7 & lag-30 features
- Accuracy tracking vs actuals
- Confidence scoring
Customer Health Scoring
Automatically scores every customer 0–100 based on recency, order frequency, and payment behaviour. Flags at-risk and churned customers so sales teams can act before revenue is lost.
- Recency score (40%)
- Frequency score (30%)
- Payment score (30%)
- Healthy / At-Risk / Churned
Manual Pricing Wizard
Trigger the pricing engine on-demand for any subset of products. Dry-run mode shows exactly which prices would change before a single record is written — perfect for testing new rules safely.
- Dry-run preview
- Product subset filter
- HTML result table
- History logged as "manual"
Live OWL Dashboard
A fully reactive OWL 2 dashboard showing real-time KPIs, forecast progress bars, customer health distribution, and the last 10 price changes — all in one screen.
- 6 live KPI tiles
- Revenue forecast bars
- Health stacked bar
- Recent changes table
Automated Scheduling
Three pre-configured scheduled actions run in the background: pricing runs nightly, forecasts regenerate weekly, and health scores refresh daily — zero manual intervention needed.
- Nightly pricing cron
- Weekly forecast cron
- Daily health cron
- Batch-safe commits
Pricing Engine
Six intelligent rule types
Rules are applied in priority order (lower number = first). Each rule evaluates conditions at runtime against live Odoo data and applies a percentage, fixed-amount, or custom Python formula adjustment.
Raises price when stock falls below a threshold. Ideal for high-demand products running low.
Discounts slow-moving items when stock exceeds a threshold. Clear warehouse space automatically.
Different prices for Gold, Silver, Bronze and New customers. Stored directly on the partner record.
Active only between date_from and date_to. Perfect for seasonal promotions or end-of-month pushes.
Triggers when the daily order rate exceeds a configurable multiplier threshold.
Ensures the price never drops below a minimum margin percentage over product cost.
Formula-based adjustment example
AI Engine
How the sales forecast works
Collect 365 days of order data
An efficient SQL aggregation query groups sale.order lines by day, computing total revenue and order count per day — no large recordsets loaded into memory.
Feature engineering
Five time-based features are derived per day: day of week, month, day of year, 7-day lag, and 30-day lag. These capture seasonality and recent momentum.
Train Ridge Regression
A regularised linear model (Ridge, α=1.0) is fitted on standardised features using StandardScaler. Ridge is chosen for its robustness on small datasets without overfitting.
Predict 30 / 60 / 90 days
Three forecast records are created for each run, summing daily predictions. As actuals are filled in, accuracy percentage is computed automatically.
Accuracy tracking
Each forecast record stores both predicted and actual revenue. Once the horizon period ends and actuals are entered, the accuracy score is computed automatically:
error = abs(predicted - actual) / actual
accuracy_pct = max(0, (1 - error) * 100)
Fallback mode
If scikit-learn or pandas are not installed, the engine automatically falls back to a 30-day rolling average with 50% confidence score. The module installs and runs without ML dependencies — they are optional enhancements.
Churn Prevention
Customer Health Scoring
Every customer with customer_rank > 0 gets a health score from 0–100 computed nightly. Three risk levels drive colour-coded badges in the list view and dashboard.
Score components & weights
OWL 2 Dashboard
Everything at a glance
The dashboard loads instantly, requires no page refresh, and every tile navigates directly to the related list view.
Revenue Forecast vs Actuals
Customer Health Distribution
Under the hood
How every calculation works
No black boxes. Here is exactly what runs, in what order, and how each number is computed — from your historical orders to the price on your product form.
Pricing Engine — nightly cron flow
dynamic.pricing.rule records where
active = True, sorted by priority ascending
(lower number = applied first).
product.template where
sale_ok = True and active = True.
Processed in batches of 100 to avoid memory spikes.
cost = standard_priceprice = lst_pricestock = qty_availabledemand_rate = 0.0 (default)
lst_price is updated and a
dynamic.pricing.history record is created
with before/after prices and the triggering rule.
Rule match conditions (how each rule type decides to fire)
| Rule Type | Fires when… | Price adjustment formula |
|---|---|---|
| Stock Low | qty_available < stock_threshold |
price × (1 + value / 100) — e.g. +10% |
| Overstock | qty_available > stock_threshold |
price × (1 + value / 100) — e.g. −15% |
| Customer Tier | partner.customer_tier == rule.customer_tier |
Percentage or fixed amount adjustment |
| Time Based | date_from ≤ today ≤ date_to |
Any adjustment type |
| Demand Surge | demand_rate ≥ rule.demand_multiplier |
Injected externally — default 0, no match |
| Margin Protect | lst_price < standard_price × (1 + value/100) |
Raises price to the minimum margin floor |
| Formula | Always matches when scope matches | Python expression: min(cost*2, max(cost*1.15, price)) |
min_price and max_price.
After the adjustment formula runs, the result is clamped:
final = max(min_price, min(max_price, computed)).
Set 0 to disable the guard.
Forecast Engine — weekly cron flow
Step-by-step data pipeline
-
SQL aggregation — one query fetches daily
revenueandordersfor the last 365 days fromsale_order_linejoined tosale_order(state IN sale/done, filtered by company). -
Feature engineering — from each date record,
5 features are extracted:
day_of_week,month,day_of_year,lag_7(7-day trailing avg revenue),lag_30(30-day trailing avg revenue). - StandardScaler — all 5 features are z-score normalised (mean=0, std=1) before training so no single feature dominates due to scale differences.
-
Ridge Regression (
alpha=1.0) — trained on the scaled features. Ridge adds L2 regularisation to prevent overfitting on short or sparse data. Requires ≥ 30 days of data to train; falls back to rolling average otherwise. - Prediction loop — for each future day (1 → horizon_days), the same 5 features are computed from the target date using the last known lag_7 and lag_30 values. Each day's prediction is summed to produce total predicted revenue.
-
Forecast records created — one
sales.forecastrecord per horizon (30/60/90 days) is written with predicted_revenue, predicted_orders, and a confidence_score of 75% (ML path) or 50% (fallback path).
Fallback behaviour
The engine automatically falls back to a 30-day rolling average:
avg_daily_revenue × horizon_days.
The confidence score is set to 50% to signal lower accuracy.
Install scikit-learn + numpy + pandas
to unlock the ML path.
Ridge Regression requires at least 30 days of historical sale orders. On a fresh database, the cron exits early without error and falls back automatically as data accumulates.
Feature importance (conceptual)
| Feature | What it captures |
|---|---|
lag_7 | Recent short-term trend (week-over-week pattern) |
lag_30 | Medium-term baseline (monthly seasonality) |
day_of_week | Weekend / weekday revenue dip |
month | Annual seasonal cycles (Q4 spike, summer dip) |
day_of_year | Fine-grained intra-year position |
Customer Health Engine — daily cron flow
Scoring formula
What each component measures
| Signal | Weight | Logic | Boundary |
|---|---|---|---|
| Recency | 40% | Counts days since last confirmed sale order. 0 days = 100, 180 days = 0. | No order ever → 999 days → score 0 |
| Frequency | 30% | Orders per month (total_orders ÷ months since first order). 10+ orders/month = 100. | New customer with 1 order → ~10 score |
| Payment | 30% | Starts at 100. Each overdue unpaid invoice deducts 20 points. | 5+ overdue invoices → score 0 |
env.cr.commit() after each batch. On a database with
10,000 customers, this prevents a single long transaction from
timing out or locking tables.
Complete data flow at a glance
| Data Source (Odoo) | → | Engine | → | Output Written To | Schedule |
|---|---|---|---|---|---|
product.template (stock + cost) |
PricingEngine | product.lst_price + dynamic.pricing.history |
Nightly 2 AM | ||
sale_order_line (365-day history) |
ForecastEngine (Ridge) | sales.forecast (30/60/90d records) |
Weekly Monday | ||
sale.order + account.move |
HealthEngine | customer.health (score + risk_level) |
Nightly daily | ||
| All three tables above | OWL Dashboard | Live JSON → KPIs, forecast bars, health chart | On page load |
UI Tour
Every screen, documented
Dashboard — live KPI tiles, forecast bars, health distribution, recent price changes table
| Priority | Name | Rule Type | Adjustment | Value | All Products | Active |
|---|---|---|---|---|---|---|
| 5 | Margin Protection Floor | Minimum Margin | Percentage | 20% | Active | |
| 10 | Low Stock Surge | Stock Below | Percentage | +15% | Active | |
| 15 | Gold Customer Discount | Customer Tier | Percentage | -10% | Active | |
| 20 | Summer Sale | Time Based | Percentage | -20% | Archived |
Pricing Rules list — sortable, filterable by rule type, archived rules greyed out
Rule form — conditional fields show/hide based on rule type
| Date | Product | Before | After | % |
|---|---|---|---|---|
| Jan 15 | Widget A | € 45.00 | € 51.75 | +15% |
| Jan 15 | Gadget Pro | € 120.00 | € 138.00 | +15% |
| Jan 14 | Bulk Pack | € 89.00 | € 66.75 | -25% |
| Jan 14 | Cable Set | € 12.00 | € 10.80 | -10% |
Price Change History — full read-only audit trail
| Name | Date | Horizon | Predicted Revenue | Confidence | Actual Revenue | Accuracy | State |
|---|---|---|---|---|---|---|---|
| Forecast 2024-01-15 | 30d | All | 2024-01-15 | 30 | € 84,200 | 75% | € 79,100 | 94% | Realized |
| Forecast 2024-01-15 | 60d | All | 2024-01-15 | 60 | € 162,400 | 75% | — | — | Active |
| Forecast 2024-01-15 | 90d | All | 2024-01-15 | 90 | € 239,800 | 75% | — | — | Active |
Sales Forecasts list — colour-coded by state, graph and pivot tabs available
Forecast form — status bar workflow, accuracy auto-computed
Graph view — built-in Odoo bar chart, switchable measures
| Customer | Score | Risk | Last Order | Days Since | Orders | Revenue |
|---|---|---|---|---|---|---|
| Acme Corp | 88 |
Healthy | 2024-01-12 | 3 | 47 | € 128,400 |
| Beta Ltd | 54 |
At Risk | 2023-11-28 | 48 | 12 | € 34,800 |
| Old Client Inc | 22 |
Churned | 2023-07-04 | 195 | 5 | € 8,200 |
Customer Health list — rows colour-coded by risk level, progress bar score widget
Health form — score components breakdown, one-click recompute
Customer Tier field on the standard Contacts form — drives tier-based pricing rules
| Product | Old Price | New Price | Rules Applied |
|---|---|---|---|
| Widget A | € 45.00 | € 51.75 | Low Stock Surge |
| Gadget Pro | € 120.00 | € 138.00 | Low Stock Surge |
| Bulk Pack | € 89.00 | € 66.75 | Overstock Clearance |
| … 44 more rows … | |||
Pricing Wizard — dry-run preview before committing any price change
Technical
Specifications
Module details
| Odoo Version | 19.0 |
| Module Name | dynamic_pricing_forecast |
| Author | Veloxio |
| License | OPL-1 |
| Price | € 99 (launch) · lifetime · one-time |
| Category | Sales / Sales |
Dependencies
| Odoo Modules | sale_management crm stock purchase account |
| Python (optional) | numpy pandas scikit-learn |
| Frontend | OWL 2, Bootstrap 5 |
| Database | PostgreSQL (standard Odoo) |
Models overview
| Model | Description | Key Fields |
|---|---|---|
dynamic.pricing.rule | Pricing rule definitions | rule_type, adjustment_type, adjustment_value, priority |
dynamic.pricing.history | Audit log of every price change | product_id, price_before, price_after, change_pct, triggered_by |
sales.forecast | AI forecast records per horizon | horizon_days, predicted_revenue, actual_revenue, accuracy_pct |
customer.health | Per-customer health scores | score, risk_level, recency_score, payment_score |
apply.pricing.wizard | Manual pricing trigger (TransientModel) | product_ids, dry_run, result_html |
Getting started
Installation & Configuration
Installation steps
Copy the module
Place dynamic_pricing_forecast/ inside your Odoo addons directory.
Install Python dependencies (optional)
Enables Ridge Regression forecasting. Skip to use rolling-average fallback.
Install via Odoo Apps menu
Settings → Apps → Update Apps List → search "Dynamic Pricing" → Install.
Navigate to AI Pricing
A new AI Pricing top-level menu appears. Start with Configuration → Pricing Rules to create your first rule.
Quick configuration guide
Support
Frequently Asked Questions
Does this module modify the standard Odoo price list?
No. The module writes directly to product.template.lst_price and logs every change in its own history model. It does not touch product.pricelist or any standard Odoo pricelist configuration.
What if I don't have scikit-learn installed?
The module installs and runs completely without it. The forecast engine falls back to a 30-day rolling average automatically. You will see model: rolling_average and confidence: 50% on forecast records.
Can I restrict which users can change pricing rules?
Yes. Sales Managers have full CRUD on all models. Sales Users have read-only access to pricing rules and history. The Apply Pricing Wizard is accessible to both groups.
How many products can the nightly cron handle?
The cron processes products in batches of 100 and commits each batch independently. It can handle tens of thousands of products without memory issues or transaction timeout errors.
Is upgrade safe (v1 → v2)?
Yes. Run odoo-bin -u dynamic_pricing_forecast after replacing the module files. No manual SQL migration is needed for the v1.0.0 release.
Simple Pricing
One price. Everything included.
No subscription. No per-user fees. One purchase, use forever.
- All 6 pricing rule types
- AI sales forecasting (30/60/90d)
- Customer health scoring
- OWL live dashboard
- Manual pricing wizard
- Free updates for this major version
- Odoo App Store support channel
Why this is a better deal
| Feature | Generic Modules | This Module |
|---|---|---|
| Dynamic Pricing Engine | ||
| AI / ML Forecasting | ||
| Customer Churn Detection | ||
| OWL Live Dashboard | ||
| Dry-run Wizard | ||
| Formula-based Rules | Basic | Full Python |
| Scheduled Automation | Manual | 3 Crons |
| Typical Price | € 79 – 179 | € 99 (launch) |
History
Changelog
v 1.0.0
customer_tier field added to res.partner
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