AWRA OpsHub Search

The Store That Empties Once a Year: Reorder Points, Dead Stock & Expiry

Reorder points assume stock is consumed steadily and replaced continuously. An input store buys once, sells for six weeks and then holds whatever is left for eleven months. Three alerts now watch that store, one of them shipped this month — and one number you type by hand decides whether any of them help.

Agribusiness & Cooperatives Washingtone Aura 14 min read

Almost every inventory feature ever built assumes a shop. Stock goes out at a rate, the rate is roughly stable, you watch a level and you top it up. An agricultural input store breaks all three assumptions at once: it buys a season's worth in one purchase, sells most of it in six weeks around the rains, and then sits on the remainder until the next long rains — by which time some of it has expired and all of it has cost you money to hold.

That is not a reason to avoid stock control. It is a reason to be precise about which of its parts help you and which will quietly mislead you, because a reorder point set for a shop is actively wrong in a store that buys once.

3
automatic stock alerts, all of them daily or faster
90
days idle before the dead-stock alert fires, by default
30/60/90
expiry horizons, with the value at risk in each
0
of them that read your demand forecast

The three alerts, and what each one actually watches

Start here, because these are the parts that do work without you thinking about them daily. All three run without anybody opening a page, which is the whole point — a report about stock that is not moving is a report nobody opens, precisely because nothing is happening.

Alert When it fires What it is blind to
Low stock The moment an item crosses to or below its reorder point, on any decrease path — plus a daily digest at 08:30 Whether you actually intend to reorder. In a store that buys once a season, crossing the line in week five is expected
Batch expiry Daily, for any batch expiring within 90 days, bucketed 30/60/90 with the value at risk — and only where stock is still on hand Batches with no expiry date typed. It cannot alert on a date nobody entered
Dead stock Daily, once an item has had no movement for the configured number of days — 90 by default, and 0 turns it off Whether the stillness is a problem. Out of season, most of your store is legitimately still

The low-stock alert is edge-triggered rather than scanned, which matters more than it sounds: it fires on the transaction that crosses the line, once, rather than nagging every hour while the level stays low. The dead-stock alert is the opposite by necessity — dead stock is defined by the absence of a movement, so there is no moment to hook and it has to be a scan. It stamps the item when it alerts and clears that stamp the next time the item moves, so a resurrected item that goes quiet again is alerted afresh.

The expiry alert has a switch, and until this batch you could not reach it

Expiry alerts were gated by an on/off setting and a cadence that existed in code and appeared on no screen — so the alert sent daily and there was no way to slow it to weekly or turn it off. It is now registered with the other notification settings alongside the low-stock alert, which is where anyone would look for it. The workflow event behind it fires regardless of the email preference, so you can automate on an expiring batch even with the mail muted.

Why the reorder point is the weak link

Everything above hangs off numbers you type. The reorder point is a plain figure on the item — not derived, not seasonal, not per store, and not per location. Two things can tell you what it ought to be: the Inventory Turnover & DIO report, which gives you turns and days-of-inventory per item over any range you pick, and the per-item demand forecast, which estimates units per day from movement history with outlier capping and a sensitivity setting. Both exist. Neither writes anything back.

So the loop is: read the velocity, type the reorder point, and repeat next season. That is a real gap rather than a fatal one — but it is a gap with a specific consequence, which is that a reorder point set once in 2024 is still quietly driving your alerts today, against a demand curve nobody has looked at since.

In a continuous business that is a mild limitation. In a seasonal one it produces a specific failure: you set the point in March when the store is full and demand is heavy, and it then fires all through the dry season on items you have deliberately run down and will not replace until the next purchase. Three weeks of that and everybody has learned to ignore the alert — which is expensive, because the one time it matters is when you run out of a fast-moving product mid-season.

Continuous store Single-season store

A reorder point

Genuinely useful — replenishment is continuous, so crossing the line means order more today

Low-stock alert

Reliable while the season runs; noise for the eleven months when you are not buying

Dead-stock alert

Cuts both ways. Out of season everything looks dead, so the threshold has to be set past your quiet period

Expiry alert

This is where the seasonal store lives. Chemicals and treated seed carry dates, and the value at risk is real money

Value-at-risk review

The number a seasonal business should manage against — what is on the shelf, what it cost, and how long it has left

Read your own store against this. If your business sits on the right, expiry and holding value are your controls and the reorder point is close to decoration — set it, but do not build your rhythm on it.

Setting the two thresholds for a seasonal store

You buy once a year and sell over six to ten weeks

Set the dead-stock threshold past your quiet period

A 90-day default will alert on almost every line in the store by the middle of the dry season. Push it beyond the gap between your selling windows — 200 days or more for a single-season store — so the alert means "this did not sell in a whole cycle", which is the thing you actually want to know.

You have two seasons, long rains and short rains

Leave the default, or shorten it

Ninety days roughly matches the interval between selling windows, so an item idle for that long genuinely missed a season. This is the case the default was designed for.

Nothing you hold has an expiry date

Turn dead-stock alerting up and stop there

With no expiry dates the expiry alert has nothing to work with — it cannot warn about a date nobody entered. Holding cost and obsolescence are then your only stock risks, and the dead-stock scan plus the aging report cover both.

You hold agrochemicals or treated seed

Capture the expiry date at receiving, without exception

This is the single highest-value data-entry habit in a seasonal input store. The batch carries the date, the alert reads it, and the value-at-risk figure comes out of the batch cost. Skip it at goods-in and no downstream control can recover it.

You want the store to stop selling something

Use a hold, not a note

Placing stock on hold — quarantined, damaged, expired, returned or inspection-pending — genuinely removes it from every allocation query, so it cannot be sold or issued. A sticker on the shelf and a note in the description do not.

What a season of holding actually costs

One input store, one year, four lines

Purchased in February for the long rains KES 3.4m
Sold by mid-May KES 2.6m
Left on the shelf on 1 June KES 0.8m
Of that, chemicals expiring before the next season KES 260,000
Flagged by the expiry alert at the 90-day horizon KES 260,000
Recovered by discounting into the short rains KES 190,000
Written off after expiry, disposal recorded KES 70,000
The alert did not save the stock — it bought ninety days to decide what to do with it 73% recovered

Illustrative. The point of the horizon is not the warning, it is the notice period. At 90 days you can discount, transfer to a busier branch or negotiate a return; at 30 you can discount; at zero you can only dispose. Everything the alert is worth is spent in the first bucket.

The four things that will not happen for you

Being exact about these prevents the specific disappointment of assuming an alert covers a case it does not.

  • Nothing expires stock automatically. The expired status exists and no job ever sets it. A batch past its date is still ordinary available stock, sellable and issuable, until a person places it on hold or disposes of it. The alert tells you; it does not act.
  • Nothing checks remaining shelf life at receiving. You cannot require, say, 75% of shelf life remaining on delivery and have goods-in warn or refuse. A drum with two months left is received exactly like one with two years.
  • There is no supplier return window, so "we can send it back until August" is knowledge that lives with a person rather than a date the system holds.
  • A hold is per stock row, not per batch. One batch spread across four locations takes four holds, and missing the fourth leaves that stock sellable. Check the batch's locations before you consider it frozen.

The expired status exists and nothing sets it. A batch past its date is ordinary sellable stock until a human intervenes — the alert is a notice, not a control.

What we do and do not do

Seasonal stock control — the straight answer

What AWRA OpsHub does today

  • Low-stock alerting in real time, fired on the movement that crosses the reorder point, plus a daily digest — one chokepoint covering check-outs, sales, transfers and adjustments.
  • Batch expiry alerting, daily, bucketed at 30/60/90 days with an expired bucket and the value at risk, and limited to batches with stock still on hand.
  • A Batch Expiry (FEFO) report with a selectable window, and a Dead Stock & Aging report behind the dead-stock alert.
  • Dead-stock alerting, with the idle threshold configurable per organization, 0 to disable, and a stamp that clears when the item next moves so it cannot nag.
  • Enforced holds — quarantined, inspection-pending, damaged, expired, returned — filtered out of every allocation query, with quantity, reason and acting user recorded on hold, release and disposal.
  • Batch cost carried through landed cost, so the value-at-risk figures are your real cost rather than a list price.
  • An Inventory Turnover & DIO report over any date range, per item and overall, with non-movers flagged and CSV/PDF export — and a per-item demand forecast giving units per day from movement history, with outlier capping and a sensitivity setting.

What it does not do

  • The reorder point is typed, not derived. Velocity and turnover are both computed and neither is written back into the reorder point — you read one and type the other. There is no seasonal profile either, so one figure serves the whole year.
  • No par level per store or per location. One reorder point serves the item everywhere it is held.
  • Nothing auto-expires stock. Past-date batches stay available until a person holds or disposes of them.
  • No shelf-life policy at receiving and no supplier return window.
  • No temperature or sensor integration, so a cold-chain breach on treated seed or veterinary stock is invisible.
  • No seasonal buying plan. There is no purchase calendar or season entity — the one big annual purchase is an ordinary set of purchase orders.

The pattern is worth seeing: the alerting layer is now genuinely complete and automatic, and every input it reads is typed by a person. Data-entry discipline at goods-in — expiry dates, batch numbers, honest reorder points — is what turns three good alerts into three useful ones.

The rhythm that fits a seasonal store

  • At goods-in: batch number and expiry date on every dated line, no exceptions, before the delivery is signed for.
  • Once, before the season: reorder points reviewed against last season's actual sales, and the dead-stock threshold set past your quiet period.
  • Weekly in season: the low-stock digest read and acted on, because in season it means what it says.
  • Monthly out of season: the expiry horizon report, working the 90-day bucket first — that is where the options are.
  • At season end: the dead stock and aging report read line by line, and a decision recorded for each line rather than a plan to think about it.

Our take

For a store that buys once a year, expiry and holding value are the controls that matter and the reorder point is the one most likely to mislead you. Push the dead-stock threshold past your quiet period so the alert means something, capture expiry dates at goods-in without exception, and work the 90-day bucket rather than the 30 — the entire value of an expiry alert is the notice period it buys, and it is spent by the time the date arrives.

See stock alerting and batch expiry

Real-time low-stock triggers, a daily 30/60/90 expiry horizon with value at risk, dead-stock scanning you set the threshold for, and holds that genuinely stop issue.

Explore inventory management

Frequently asked questions

Does anything warn us before stock expires?

Yes. A daily scan alerts on any batch expiring within 90 days, bucketed at 30, 60 and 90 days with an expired bucket, and each bucket carries the value at risk computed from batch cost. It only alerts on batches with stock still on hand, because an alert about stock that is not there is how an alert gets muted. It also fires a workflow event per scan, so you can automate a response — raise a task, notify the storekeeper, start a supplier return — even if the email is switched off.

Will expired stock stop being sold automatically?

No, and this is the most important limitation to plan around. The expired status exists and no job sets it, so a batch past its expiry date remains ordinary available stock — sellable and issuable — until a person places it on hold or disposes of it. Holds are genuinely enforced once applied: held stock is filtered out of every allocation query. So the alert tells you and a human acts. Build that step into somebody's week.

How should we set a reorder point in a business that buys once a year?

Read it off the numbers that already exist, then type it — because nothing writes it for you. The Inventory Turnover & DIO report gives turns and days of inventory per item over any range, and the per-item demand forecast estimates units per day from movement history. Neither feeds the reorder point, so the loop is manual and worth doing once a season for your fast-moving lines only. There is no seasonal profile, so accept that whatever you type will over-fire out of season, and manage the quiet months on expiry and holding value instead.

What does the dead-stock alert do, and what should the threshold be?

A daily scan flags items with no movement for the number of days you configure — 90 by default, and 0 disables it entirely. It stamps the item when it alerts so it cannot re-alert daily, and clears that stamp the next time the item moves. For a single-season business, push the threshold past the gap between your selling windows, or the whole store will be flagged every dry season and the alert will be ignored when it matters.

Can we require a minimum remaining shelf life on deliveries?

No. There is no shelf-life policy at receiving, so goods-in cannot warn or refuse when a delivery arrives with too little life left, and there is no supplier return window held anywhere. Both are contract terms you enforce by inspecting the dates at the door — which is why capturing the expiry date at goods-in matters so much: it is the only moment the information is in front of somebody.

If a batch is bad, can we freeze it everywhere at once?

Not in one action. A hold applies to a stock row — an item at a location — so a batch spread across four locations takes four holds, and the one you miss stays sellable. Check the batch's locations from the traceability view before you treat it as frozen. What does work properly is the hold itself: held stock cannot be allocated, sold or issued, and the hold records quantity, reason and who applied it.

Are these alerts on by default, and can we turn them down?

Low-stock and expiry alerting are on by default, and the cadence can be set to daily, weekly, monthly or a custom interval per organization. The expiry alert's switch and cadence were missing from the notification settings screen until this batch — they existed in code and no page could reach them — so it is now listed beside the low-stock alert. Dead-stock alerting is on with a 90-day default and switches off by setting the threshold to 0.

Help Center

Need a quick answer while you read?

Run inventory, procurement, assets, sales, and field work with approved AWRA guidance for setup, migration, integrations, security, pricing, and support.

Search all approved AWRA public help articles.

Open Help Center