AI Budget Variance Commentary
Generate direction-aware budget-vs-actual narratives automatically on every budget, with or without an LLM provider.
Why this module
AI Budget Variance Commentary
Month-end narrative ready
One-paragraph commentary drops straight into the controller's monthly close pack without further editing, with a direction-aware headline and the largest movers already picked out.
Works out of the box
Deterministic template runs with no API keys, no network calls, and no configuration. Optionally enriched by a provider when one is registered at the company level.
Failure immunity
Missing or bad credentials never break the budget form. If an LLM call fails, the deterministic commentary is returned instead. Always delivers useful output.
Day in the life
FP&A analyst closes the December budget
Open the December budget record. The AI Commentary page shows a deterministic headline: 'Period total overran budget by 8.3% (1,200.00 vs 13,000.00). The top variance is Labour (6.2%), followed by Travel (4.1%), and Materials (3.8%).' If the company configured an AI provider (such as a hosted LLM service), the same snapshot produces a narrative paragraph instead: 'December spending exceeded budget primarily due to end-of-year labour costs and unexpected supplier pricing increases in materials. Labour was the dominant driver...'. Click Refresh AI commentary to regenerate if the budget lines changed since the last read.
Edge cases
The cases most modules quietly ignore.
In the shipped code today, each one a place where a cheaper module silently does the wrong thing.
A budget with no lines or all-zero lines returns a graceful placeholder: 'No budgeted or actual amounts for [Period]; nothing to comment on.'
A line with zero budget but non-zero actual is flagged as a full 100% overrun rather than masked as 0%, and included in the top movers.
The commentary determines direction from the total variance only (overran, underran, or matched); a mixed income and expense budget is summarised as one total variance, not split by account type.
Only the three largest absolute variances are listed. A 50-line budget highlights the top three, not all fifty.
If a provider is registered but the call fails, the deterministic template is returned silently. The form does not error or show a timeout; the user sees the deterministic backup.
The field is not stored; every read recomputes from current line amounts. Changing a budgeted amount updates the commentary on the next form load without manual refresh, unless the provider's cache is stale.
What is inside
Built to do the job, end to end.
- models/budget.py. EhBudget model inherits eh.budget.budget and adds eh_ai_variance_commentary computed field. Depends on line_ids, budgeted_amount, actual_amount, and account_id. Calls variance_commenter.comment() with a BudgetLineSnapshot list built from budget lines. Resolves is_income from account type and includes it in the BudgetLineSnapshot, though the current deterministic template derives direction from the total variance only. Includes action_eh_ai_refresh_commentary() for manual recompute.
- tools/variance_commenter.py (eh_account_ai_agent). Deterministic BudgetLineSnapshot dataclass and comment() function. Computes total variance and percentage, generates direction-aware headline (overran/underran/matched), lists top-N largest absolute variances. Handles empty snapshots with graceful placeholder. Calls provider.chat() if non-manual provider is registered; catches ProviderError to fall back to deterministic text.
- views/budget_views.xml. Inherits budget form view from eh_account_budget_pro. Adds AI Commentary page with eh_ai_variance_commentary readonly field and helper text explaining deterministic vs LLM modes. Includes Refresh AI commentary button in header to invalidate cached computed field.
- test_variance_commentary.py. Integration tests verify commentary is non-empty with period label, income flag is mapped from account type (revenue=True, expense=False), empty budget returns placeholder, and commentary recomputes on line_ids change. Tests call _eh_build_budget_snapshot() to inspect the snapshot list passed to the helper.
Honest about the edges
What this does not do, so nothing surprises you.
- Requires eh_account_budget_pro (provides eh.budget.budget model) and eh_account_ai_agent (provides variance_commenter tool and provider registry). Does not generate variance forecasts, anomaly detection, or trend analysis beyond deterministic template. Provider enrichment is opt-in at company level only (set eh_ai_provider_key on res.company); no per-budget or per-user provider choice.
- LLM augmentation calls providers as fallible best-effort; failures are caught silently and deterministic text returned. Analytic accounts and percentage-weighted actuals from eh_account_budget_pro are not exposed in commentary; field reads total variance only. Commentary is non-stored and recomputed on every read, so heavy-read budgets may trigger repeated provider calls.
- Does not support custom top-N movers; hardcoded to top 3 largest variances. Variance percentage is computed as (actual - budget) / budget * 100, so a zero-budget line shows 100% overrun; a zero-actual line shows negative 100% underrun. Multi-company budgets inherit the parent company's provider key; no subsidiary override per budget.
- Field text is plain text, not HTML; no formatting, links, or embedded charts in commentary. Period label sourced from budget.name only; empty or special-character names may render unclear in the period display. Provider calls run synchronously on field compute, so slow providers block the form load until timeout.
budget variance, budget actual commentary, close pack narrative, budget overrun, period variance, deterministic AI, Odoo budget analysis, cost overrun alert, revenue shortfall, month end close, budget reporting, variance analysis, accounting AI, Odoo 19 Community
Languages
Available in 19 languages
The interface ships translated out of the box. Switch language in Odoo and the fields, menus, and messages follow.
Please log in to comment on this module