Skip to main content
A is expected weekly demand for a part before sales orders exist. Planning nets projections against scheduled supply, explodes the part’s method into component demand, and suggests required jobs and purchase orders. You enter projections under Production → Demand Forecasts, one part at a time, as a 52-week grid. Each cell is the quantity you expect to consume that week. Save it, and the next run reads it.

What a projection is

A projection lives on the demandProjection table, keyed by item, location, and a weekly period — one row per part / location / week with a quantity. Weekly buckets are created on demand as the grid walks forward from today. Only make parts carry projections. The item picker on the form is fixed to type="Part" with replenishmentSystem="Make" (apps/erp/app/modules/production/ui/DemandProjection/DemandProjectionForm.tsx), so you project the things you build. Their purchased components inherit demand through the BOM explosion, not through their own projection.

How you enter one

The form is a drawer with a part, a location, and 52 numeric week cells grouped into four quarter tabs, plus a live bar-and-line chart of weekly and cumulative demand (apps/erp/app/modules/production/ui/DemandProjection/DemandProjectionForm.tsx). Week 1 starts at the current week; each cell is labelled with its calendar date. On save, the action pairs each week{i} value with the matching period id and upserts the rows (apps/erp/app/routes/x+/production+/demand-forecasts.$itemId.$locationId.tsx). A cell you set to zero is deleted rather than stored, so the grid stays sparse (upsertDemandProjections, products/supply-and-production-planning/src/forecast/native-forecast.server.ts). Editing a part reloads its existing rows back into the grid; deleting a part’s projections clears every future week for that item and location (apps/erp/app/routes/x+/production+/demand-forecasts.delete.$itemId.$locationId.tsx). The entry grid spans 52 weeks (WEEKS_TO_PROJECT = 52 in both demand-forecasts.new.tsx and demand-forecasts.$itemId.$locationId.tsx). The list view shows the next 48 (WEEKS_TO_PROJECT = 12 * 4, apps/erp/app/routes/x+/production+/demand-forecasts.tsx), pivoting the per-period rows back into week columns for scanning and labelling the first as “Present Week” (apps/erp/app/modules/production/ui/DemandProjection/DemandProjectionTable.tsx). Creating, editing, and deleting projections all require the production permission, and are available on the Business and Partner plans (the FORECAST feature, kernel/entitlements/src/plan.ts).

How planning consumes it

Planning runs on the Alforse backend (runMrp, products/supply-and-production-planning/src/planning-seam/index.ts), and it reads demandProjection directly as a demand source. But a projection does not simply add to demand: actual demand consumes the forecast. Each MRP run nets every open sales order line and job-material line against the projections for the same part and location — first in the order’s own week, then reaching backward and then forward a configurable number of weeks — and only the unconsumed remainder of the projection still drives demand. Ten forecast plus ten on order in the same week is ten of demand, not twenty; twelve on order against ten forecast is twelve. The reach is set company-wide on the Forecast Consumption card under Settings → Planning: Look back (weeks) and Look ahead (weeks); a new company starts at 0 and 0, so projections net within the same week until you widen the window. That window is what heals gaps — if you forecast 10 in one week and 0 the next, a sales order landing in the empty week consumes the neighboring forecast instead of double-counting. Leave both at 0 to net strictly within the same week. Each run persists what it consumed to demandProjection.consumedQuantity, so the planning screens, the item planning chart, and Inventory all read the same net number, and the edit form shows an “N consumed” note under each week that actual demand has claimed. Sales orders consume at their full open quantity — a Make to Order line already covered by its linked job still consumes the forecast that predicted it, even though the job, not the line, is what drives supply. An order dated before the current week is still demand, but it consumes no forecast; an order with no date counts as due now and does consume. Forecast in past weeks simply falls out of the horizon; it never lingers as phantom demand. That projection demand joins actual demand (open sales order lines and open job materials) in the gross-demand tally, and MRP explodes each make part’s method to push component demand down the BOM. The result is written to planningDemandForecast and to a planningDemandContribution lineage table that tags every unit with where it came from: "Sales Order", "Job Material", or "Demand Projection" (products/supply-and-production-planning/src/modules/planning-and-mrp/mrp-engine.ts). On a part’s planning page you can open the demand for any week and see exactly which projections, orders, and parent jobs make it up.

Fields

Projections are manual inputs. Alforse does not calculate them from history, seasonality, or a statistical model. Although the schema reserves forecastMethod and confidence, the Demand Forecast form does not write them. MRP provides the netting and BOM explosion.