Alerts and Expiry
Query low-stock, expiring, and expired batches and act on them before they cost you a sale or a write-off.
You watch three alert feeds defined in apps/server/src/features/alerts/route.ts, plus the expiring-batch query in apps/server/src/features/purchases/route.ts. Check them on a schedule and act the same day.
Watch low-stock medicines
Call GET /alerts/low-stock with an optional branch_id. With a branch, the server recomputes sellable stock from the stock_movements ledger via sumStockByMedicine in apps/server/src/features/alerts/queries.ts; without it, the same sum covers the whole organisation. Every row carries deficit = threshold - stock, sorted worst-first.
curl -H "Authorization: Bearer $TOKEN" "http://localhost:8000/api/v1/alerts/low-stock?branch_id=$BRANCH_ID"
Turn each alert into a purchase order line. Fetch GET /purchase-orders/suggested?branch_id=$BRANCH_ID for the ready-made suggested_quantity, then draft the order as described in /inventory/purchasing-and-purchase-orders. If a sibling branch holds surplus, transfer instead following /inventory/transfers-and-stockcount.
Catch batches before they expire
Call GET /alerts/expiry?days=90&branch_id=$BRANCH_ID for batches expiring inside the window, ordered soonest-first with days_to_expiry, qty_remaining, and unit_cost. The default window is 90 days when you omit days. Recalled and quarantined batches are excluded automatically.
curl -H "Authorization: Bearer $TOKEN" "http://localhost:8000/api/v1/alerts/expiry?days=60&branch_id=$BRANCH_ID"
Push soon-expiring batches to the front of FEFO dispensing, mark them down or return them to the supplier per your policy, and transfer slow movers to a higher-volume branch. The purchases feature exposes the same window as GET /purchases/expiring?days=90&limit=6 when you only need the next few rows for a dashboard card.
Clear expired stock
Call GET /alerts/expired?branch_id=$BRANCH_ID to list batches past expiry that still hold quantity. This endpoint requires the admin role, so run it from an admin session or ask one to pull it for you.
curl -H "Authorization: Bearer $TOKEN" "http://localhost:8000/api/v1/alerts/expired?branch_id=$BRANCH_ID"
For each row, quarantine the physical units, then call PUT /purchases/:batchId/write-off to zero the batch and record the WRITE_OFF movement. Verify the batch disappears from the next expiry pull and the medicine movement history in /inventory/medicines-and-batches shows the adjustment.
Build a daily alert routine
You check low stock every morning, expiry weekly, and expired daily until the shelf is clean. Start with the branch-scoped low-stock feed, convert deficits into purchase order lines or transfers, then scan the 60-day expiry window for batches to push through FEFO first.
curl -H "Authorization: Bearer $TOKEN" "http://localhost:8000/api/v1/alerts/low-stock?branch_id=$BRANCH_ID"
curl -H "Authorization: Bearer $TOKEN" "http://localhost:8000/api/v1/alerts/expiry?days=30&branch_id=$BRANCH_ID"
Log who reviewed the feeds and what action each row received. Unactioned alerts repeat tomorrow, so close every row with an order, a transfer, a markdown, or a write-off and confirm the count drops on the next pull. Keep low_stock_threshold values honest in /inventory/medicines-and-batches so the deficit math reflects real cover days.
curl -H "Authorization: Bearer $TOKEN" "http://localhost:8000/api/v1/purchases/expiring?days=90&limit=6&branch_id=$BRANCH_ID"
Pin that short expiring list to your dashboard so the team sees the next six risks without opening the full report. Record expiry dates at goods receipt and reject deliveries with short dates that your supplier will not take back.
Reading the feeds changes nothing by itself. It is the actions you take on each row, like the WRITE_OFF below, that land in the movement ledger, so your future self can prove the stock was handled in time.
Next steps
Return to /inventory/purchasing-and-purchase-orders to reorder what low-stock alerts surfaced, and use /inventory/transfers-and-stockcount to rebalance branches before you place a supplier order.
Schedule the next review before you leave so nothing slips a day.