Technical Lab · Synthetic demonstration
Forecast to inventory
The interactive demo lets you change the demand pattern and the model. This page holds those fixed and walks the decision from forecast to order.
Synthetic demonstration · Independent educational implementation. Same calculation as the interactive demo. Not a business result.
Turn a multi-week forecast and a coverage target into a quantity someone could order.
The forecast is not the decision. Stock already on hand, stock already coming, the lead time and the pack size all sit between the two.
Order-up-to level S = expected demand over (lead time + review) + safety stock
In a continuous-review policy the reorder point has the same shape, without the review interval. This demonstration uses the demo’s periodic-review level. The recommended order is the gap to S, rounded up to the pack size, and zero when stock already covers S.
Change the protection period
- Forecast
- 63.7, 66.7, 70.4 units per week
- Lead-time demand
- 200.8
- Safety stock
- 5.3
- Order-up-to level
- 206.2
- Inventory position
- 100 on hand and on order
- Recommended order
- 110
What happens to stock
The protection period is 3 weeks: lead time 2 plus a 1-week review. Expected demand over that period is 200.8. Safety stock, the gap between the 95% coverage target and that expectation, is 5.3. The order-up-to level is 206.2. Inventory position is 100. The gap is 106.2, which rounds up to an order of 110 in packs of 10. Expected stock goes negative in week 2, before the new order arrives. Ordering more today does not bring that delivery forward.
Open the interactive Forecast → Inventory demo to change the demand pattern, the model and the stock position.
Implementation
The decision itself is the demo module, not a second copy.
src/lib/forecast-inventory/decision.ts View source on GitHub: src/lib/forecast-inventory/decision.ts
const protectionPeriod = input.leadTime + REVIEW_WEEKS;
const weekly = model.pathMeans.slice(0, protectionPeriod);
const expectedDemand = weekly.reduce((sum, value) => sum + value, 0);
const target = model.targets[String(input.coverage)][protectionPeriod - 1];
const position = inventoryPosition(input.onHand, input.onOrder);
const requirement = Math.max(0, target - position);
const quantity = roundToPack(requirement);