inventory.reorder-point
Reorder point: demand over the supplier lead time, rounded up to whole units, plus safety stock.
1.0.0 · published 2026-10-03 by charlie · Anterra
Pinned by 13 tests, run in TypeScript, Python and Rust.
What it does
The stock level at which to place a replenishment order:
reorder point = lead-time demand + safety stock lead-time demand = demand x leadTimeDays / demandPeriodDays, rounded up
For example
reorder_point(70, 7, 10, 20)→ 120 70 a week over a 10-day lead time, plus 20 safety stockreorder_point(1,000, 30, 7, 50)→ 284 1000 a month over 7 days is 233.33, rounded up to 234, plus 50reorder_point(2, 7, 2, 0)→ 1 a fraction under a half still rounds up: 2 a week over 2 days is 0.57, so 1
The function
The same function in TypeScript, Python and Rust, pinned by the same tests. Pick your language; the choice follows you around the registry.
def reorder_point(demand: int, demand_period_days: int, lead_time_days: int, safety_stock: int) -> int
| demand | int | units used in one demand period, e.g. 1000 a month |
| demand_period_days | int | days in that period: 1, 7, 30, 365; lets demand per day be fractional without floats |
| lead_time_days | int | days from placing an order to having the stock available |
| safety_stock | int | buffer in units, e.g. from inventory.safety-stock |
| returns | int | reorder when stock on hand plus on order falls to this many units |
Your code names it in one line, in the file that uses it
from fune.inventory.reorder_point import reorder_point # inventory.reorder-point@^1
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
from .math_round_div import round_div ← from math.round-div ^1.0.0 · built alongside by fune
def _whole_units(name: str, value: int) -> None:
if isinstance(value, bool) or not isinstance(value, int) or value < 0:
raise ValueError("%s must be a whole number, not negative, received %r" % (name, value))
def reorder_point(demand: int, demand_period_days: int, lead_time_days: int, safety_stock: int) -> int:
"""Lead-time demand, rounded up to whole units, plus safety stock.
Rounding up rather than to nearest: 233.33 units of lead-time demand needs
234 in hand, or the last third of a unit is a stock-out.
"""
_whole_units("demand", demand)
_whole_units("leadTimeDays", lead_time_days)
_whole_units("safetyStock", safety_stock)
if isinstance(demand_period_days, bool) or not isinstance(demand_period_days, int) or demand_period_days <= 0:
raise ValueError(
"demandPeriodDays must be a whole number of days, at least 1, received %r" % (demand_period_days,)
)
return round_div(demand * lead_time_days, demand_period_days, "up") + safety_stockInstall
fune build
With that line in your source, in a Python project (language python in fune.project), fune build resolves it and its 1 dependency, pins them in fune.lock, downloads only the Python package of each, and builds the code above into your project’s .fune/build, one readable file per capability with a header linking back here. Or pin a range in fune.project and build in one step:
fune add inventory.reorder-point
The manifest, vectors and README with only the Python implementation. Install it without the registry with fune add ./inventory.reorder-point-1.0.0-python.fune, or fetch it from a terminal with fune pull inventory.reorder-point@1.0.0:python.
The whole function, every language, is one file too: inventory.reorder-point-1.0.0.fune, 8,362 bytes, sha256 04b058af629a2ff2051b887513bb1b28d44cd180350dc6a5fb183a40448df0e0. It installs into a project of any language.
Customise it in your app
The seams this capability offers. Put a marker directly above a function of your own and fune build wires it into the built code; the package on the registry is not changed, the built file’s header lists it under CUSTOMISED, and fune hooks lists every hook in the project. How hooks work.
before — your function gets the arguments and returns them, changed or not, or throws to refuse the call.
# fune: before inventory.reorder-point
after — your function gets the result and the arguments, and returns the final result.
# fune: after inventory.reorder-point
replace — inside this capability’s code only, calls to a dependency go to your function, with the same signature. Other capabilities that use it are unaffected; write in * to replace it everywhere.
# fune: replace math.round-div in inventory.reorder-point
step — your function runs at a numbered point inside the function’s body, receives the in-scope values it names as parameters, and may return replacements. List the points with fune show inventory.reorder-point --steps.
# fune: step inventory.reorder-point after <n|label>
Tests
A version published now needs at least 8 tests for every function, and one that expects the error for each function that throws; the registry refuses it otherwise. fune verify --all runs each case in TypeScript, Python and Rust, and a project runs them again with fune verify. This page lists the cases; it does not run them. The exact JSON is vectors.json.
| Case | Arguments | Expected | |
|---|---|---|---|
| 70 a week over a 10-day lead time, plus 20 safety stock | 70, 7, 10, 20 | → | 120 |
| 1000 a month over 7 days is 233.33, rounded up to 234, plus 50 | 1,000, 30, 7, 50 | → | 284 |
| a fraction under a half still rounds up: 2 a week over 2 days is 0.57, so 1 | 2, 7, 2, 0 | → | 1 |
| an exact half rounds up: 15 per 2 days over 1 day is 7.5, so 8 | 15, 2, 1, 0 | → | 8 |
| a yearly figure: 3650 a year over 14 days is exactly 140 | 3,650, 365, 14, 0 | → | 140 |
| a daily rate: 10 a day over 5 days, no safety stock | 10, 1, 5, 0 | → | 50 |
| zero lead time leaves only the safety stock | 1,000, 30, 0, 25 | → | 25 |
| zero demand leaves only the safety stock | 0, 30, 14, 25 | → | 25 |
| a demand period of zero days is an error | 1,000, 0, 7, 0 | → | error: demandPeriodDays must be a whole number of days, at least 1 |
| negative demand is an error | -10, 7, 7, 0 | → | error: demand must be a whole number |
Show the other 3 tests
| Case | Arguments | Expected | |
|---|---|---|---|
| negative lead time is an error | 10, 7, -1, 0 | → | error: leadTimeDays must be a whole number |
| negative safety stock is an error | 10, 7, 7, -5 | → | error: safetyStock must be a whole number |
| a fractional lead time is an error: express it in the period's days | 10, 7, 2.5, 0 | → | error: leadTimeDays must be a whole number |
More from the author
Demand is given per period (units a week, a month, a year) with the period's length in days, so a daily rate of 33.3 units (1000 a month) needs no float: the division happens once, exactly, with `math.round-div`.
**Lead-time demand is rounded up**, never to nearest. 1000 a month over a 7-day lead time is 233.33 units; ordering at 233 plans to run out a third of a unit early. Safety stock is already whole units and is added unchanged.
Compare the result with stock on hand **plus stock already on order**, or an order placed yesterday triggers another today.
Zero lead time or zero demand leaves just the safety stock. Negative values and a demand period of zero days are errors.
Source: the standard textbook definition, e.g. APICS Dictionary ("order point") and Silver, Pyke and Thomas, *Inventory and Production Management in Supply Chains*, 4th ed., ch. 6.
Files
| Path | Bytes |
|---|---|
| README.md | 1,082 |
| impl/python.py | 1,066 |
| impl/rust.rs | 1,475 |
| impl/typescript.ts | 986 |
| vectors.json | 1,600 |