Forecasting rolls up opportunities by period and category using configurable forecast types and conditions, visualized with ECharts.
This post is Part 21 of 28 in the Horilla CRM Technical Blog series.
What is sales forecasting in Horilla CRM?
Sales forecasting in Horilla CRM enables you to:
- Forecasttype and period configuration
- Condition-based inclusion rules
- Manager and rep forecast views
- Export via reports module
Calculation service
ForecastCalculator is the domain service that converts qualifying opportunities into forecast values. Views should delegate to it instead of embedding queryset filters, probability math, or target comparisons. This keeps interactive charts, scheduled updates, and signal-driven recalculation on the same definition.
from horilla_crm.forecast.methods import ForecastCalculator
calculator = ForecastCalculator(forecast_type)
forecast = calculator.calculate()
Use the application’s actual calculator entry point and arguments for the installed version; the snippet demonstrates the service boundary. The calculator can apply configured conditions, opportunity value fields, stage probabilities, forecast categories, and the relevant period before persisting or returning a Forecast. Business code should not use a dashboard total as a source of truth, because that total is presentation output of this calculation.
Opportunity-driven freshness
Opportunity lifecycle signals update forecasts. This relationship is crucial: the amount, stage probability, forecast category, close date, and source opportunity can each affect a forecast even though no forecast configuration changed. Signal handlers provide a central response when an opportunity is created, edited, or removed from eligibility.
Avoid using QuerySet.update() for forecast-relevant opportunity fields unless the corresponding recalculation is explicitly invoked. Bulk updates bypass normal save signals, leaving projection values stale. For imports, perform the import through supported services or schedule a targeted ForecastCalculator run for the affected forecast types and companies. Receivers should calculate only the scope that can have changed, not unconditionally rebuild every tenant’s forecasts after one opportunity edit.
Chart data and modal presentation
ECharts data is produced by get_forecast_chart_data. This function prepares the series and labels expected by the chart rather than making templates reverse-engineer forecast rows. ForecastChartsModalView supplies the modal UI that presents those data. Keep the JSON/data contract stable: charts need primitive labels and numeric series, while calculation objects may include model instances and money values unsuitable for direct serialization.
from horilla_crm.forecast.methods import get_forecast_chart_data
chart_data = get_forecast_chart_data(forecast_type=forecast_type)
Do not calculate forecast totals in browser JavaScript. JavaScript should render the series supplied by the server, because the server owns condition evaluation, tenant filtering, currency handling, and permissions. The modal view is also the right integration point for date range or forecast-type selection: it can validate input, calculate or retrieve the appropriate scope, and return the partial expected by HTMX/UI callers.
Targets and interpretation
A forecast target is not evidence that the projected amount reaches it. Compare the Forecast calculated amount to the matching ForecastTarget only after both are scoped to the same company, forecast type, and period. When adding a new chart, clearly label projected, target, and attainment series. Conflating these produces attractive but misleading dashboards.
Fiscal periods and category buckets
Forecast types usually map onto a fiscal calendar: monthly, quarterly, or custom periods defined by the company. The calculator must resolve the opportunity close date (or configured date field) into the correct period bucket before aggregation. Mixing fiscal and calendar months in the same type produces totals that look plausible in a chart but fail leadership reconciliation against the finance calendar.
Forecast categories (for example pipeline, best case, commit, and closed) are not interchangeable labels. Each category should reflect stage policy already used on opportunities. When you introduce a new category, update conditions and chart series together so managers do not compare a commit number from last quarter against a differently defined commit this quarter.
forecast = calculator.calculate(period_start=start, period_end=end)
Permissions, currency, and multi-company scope
Forecast rows inherit the same multi-tenant rules as opportunities. Always resolve forecasts through company-scoped managers, and never expose another company’s projection through a shared dashboard widget. Money amounts must respect company currency settings; if opportunities store MoneyField values, convert or display using the same helpers used elsewhere in CRM so a USD opportunity does not inflate an INR forecast chart.
Role and owner filters matter for rep-level forecasts. A manager view may roll up a team; a rep view should only include opportunities the user is allowed to see. Reusing the opportunity list permission path—or an explicit forecast permission—keeps the projection consistent with pipeline boards.
Operational guidance
Treat forecast type and condition edits as high-impact configuration. After changing conditions, run or schedule recalculation for the affected type instead of waiting for opportunistic opportunity saves. Document which opportunity fields feed each type so administrators do not accidentally point conditions at deprecated custom fields. For large tenants, prefer incremental recalculation by company and type over a nightly full rebuild unless you have measured that a full rebuild stays within an acceptable maintenance window.
Benefits of Forecasting in Horilla CRM
- Data-driven revenue planning
- Aligned with opportunity stages and probability
- Visual trends for leadership reviews
Forecasts consume opportunity data you already maintain — configure types and conditions to match your fiscal calendar.
Continue the series
Previous: Part 20 — How to Manage Campaigns in Horilla CRM with Members, Metrics, and Smart Insights
Next: Part 22 — The Horilla CRM Report Builder: Folders, Pivot Tables, and Exports
More posts are on the Horilla Blogs; share feedback on GitHub.