Vertical SaaS · Inventory

Inventory Replenishment Automation

How automated replenishment actually works in an ERP-connected inventory system: reorder points, safety stock, lead-time variability, and why fully automatic purchase orders need a human review step somewhere.

John Kihiu12 min read

"Automate replenishment" usually means one specific thing in practice: stop having a person eyeball a stock report every Monday and decide what to reorder, and instead let the system generate purchase order suggestions from reorder points and lead times. The mechanics are simple arithmetic. The hard part is getting the inputs — lead time, demand variability, safety stock — accurate enough that the suggestions are trustworthy, because an automated system that reorders wrong is worse than a manual one, since nobody is double-checking it.

Reorder point is the core formula, safety stock is where it gets real

The textbook reorder point formula is (average daily demand × lead time in days) + safety stock. The average daily demand and lead time are the easy parts to get from historical data. Safety stock is where most implementations are either too naive (a flat buffer like "2 weeks of stock" for every SKU) or too complex (a full service-level-based statistical model on day one). A reasonable middle ground is safety stock scaled to each SKU's actual demand variability and lead-time variability, not a single number applied uniformly across a catalog with wildly different velocity items.

SQL · REORDER POINT WITH VARIABILITY-SCALED SAFETY STOCK
WITH demand_stats AS (
  SELECT
    sku_id,
    AVG(daily_qty)    AS avg_daily_demand,
    STDDEV(daily_qty) AS demand_stddev
  FROM daily_sales_by_sku
  WHERE sale_date >= CURRENT_DATE - INTERVAL '90 days'
  GROUP BY sku_id
)
SELECT
  s.sku_id,
  s.avg_daily_demand,
  l.avg_lead_time_days,
  -- z = 1.65 targets ~95% service level
  ROUND(1.65 * s.demand_stddev * SQRT(l.avg_lead_time_days), 0) AS safety_stock,
  ROUND(s.avg_daily_demand * l.avg_lead_time_days
        + 1.65 * s.demand_stddev * SQRT(l.avg_lead_time_days), 0) AS reorder_point
FROM demand_stats s
JOIN supplier_lead_times l USING (sku_id);
Lead time is a distribution, not a constant

Suppliers rarely deliver in exactly N days every time. Track actual received-date minus PO-date per supplier per SKU over time, and use that distribution's mean and variance in the reorder point formula — a supplier with a longer but more consistent lead time needs less safety stock than a shorter but wildly inconsistent one, even if their averages look similar.

Generating suggestions vs. auto-approving purchase orders

There's a meaningful line between "the system flags what needs reordering" and "the system creates and submits the purchase order without a human looking at it." The former is close to risk-free automation — worst case, a buyer ignores a bad suggestion. The latter removes the safety net: a bad supplier lead-time assumption, a demand spike from a one-time bulk order skewing the average, or a discontinued SKU that's still in the reorder logic can all generate a purchase order for the wrong quantity, from the wrong supplier, that nobody catches until the invoice arrives.

Where a human review step still belongs

Full automation is usually safe for low-value, high-velocity, single-supplier SKUs where the cost of an occasional bad order is trivial. It's usually not safe for high-value items, multi-supplier SKUs where the choice of supplier matters, or anything with irregular demand (seasonal items, one-off project materials). A practical middle ground most systems land on: auto-generate the suggested PO for every SKU that hits its reorder point, but require explicit approval above a dollar threshold or for SKUs flagged as high-variance, and let the rest go through automatically.

Watch for demand spikes bleeding into the average

A single large one-off order — a customer buying a year's worth of stock at once — can distort a 90-day rolling average enough to trigger over-ordering for months afterward. Either exclude statistical outliers from the demand calculation or cap the influence of any single day's demand before it feeds into the reorder point.

Tying replenishment back to the ERP

In practice this logic doesn't live in isolation — it reads current on-hand quantity, open purchase orders, and open sales orders from the ERP system's inventory and purchasing modules, and it writes back either a suggested PO or a submitted one. The integration point that actually causes problems isn't the math, it's timing: if the replenishment job runs against a stale inventory snapshot (a nightly ETL copy, say, rather than live data), it can suggest reordering stock that already has a PO in flight, or miss a stockout that happened after the snapshot was taken. Reading current, not cached, on-hand and open-PO quantities at generation time avoids most of this class of bug.

Wrapping up

Automated replenishment is a reorder-point calculation with two inputs that are easy to get wrong: lead-time variability and demand variability. Get those from real historical data instead of flat assumptions, keep a human review step for high-value or high-variance items, and make sure the job reads live inventory and open-PO state rather than a stale snapshot. The math is the easy 20%; the input quality and the review threshold are the 80% that determines whether people trust the system's suggestions.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.