Batch and Expiry Tracking in Meztezz

by Meztezz Team

Every restaurant throws away food. The question is whether you find out on a slow Tuesday during a stock-take, or three days too late when a guest sends back a plate. Until now, Meztezz could capture an expiry date at delivery, but it treated all of one ingredient as a single fungible pile — it couldn’t tell Monday’s paneer from Wednesday’s. That has changed. Meztezz now records each delivery as its own dated batch, always reaches for the soonest-to-expire stock first, watches every batch in the background, and — if you let it — physically stops an expired ingredient from being cooked into a guest’s order.

This guide walks through the whole batch-and-expiry system in plain language: what a batch is, how to record one, how the “sellable vs expired” split works, how the kitchen and bar deplete stock in the right order, the alerts that warn you early, and the sale-block that turns “please remember to check the dates” into something the system enforces for you. It applies to food and ingredients first, but liquor can opt in too, and there’s a full section on that below. It picks up from Stock & Inventory in Practice — if you haven’t read that one, read it first; this post assumes you already know how stock moves in and out.

💡 A word on “batch”. A batch is one delivery of one item, with its own lot number and its own expiry date. Receive paneer twice in a week and you have two batches of paneer — same item, two different expiry dates, tracked separately. Everything in this post is built on that one idea.


The Walkthrough at a Glance

PartWhat you’ll learn
1. Turning Batch Tracking OnThe per-item switch, what “legacy” stock means, and why you can’t turn it back off carelessly.
2. Recording a Batch When Stock ArrivesThe one batch table that appears everywhere you add stock.
3. Sellable vs Expired On-HandWhy a number suddenly reads (8 sellable · 2 expired).
4. Selling the Oldest First (FEFO)What “first-expiry, first-out” means, and how the kitchen and bar always reach for the soonest-to-expire batch.
5. Expiry Alerts & the Background SweepThe watcher that warns you days before stock turns.
6. Blocking Sales on Expired StockThe setting that stops expired food from reaching a guest.
7. Liquor Expiry — Two Ways to Track ItPer-location dates vs per-batch lots, and the bar’s expired-stock block.
8. Correcting a Batch Number or ExpiryFixing a typo’d lot or a wrong date without rewriting history.
9. On the Cloud DashboardWhat the owner sees remotely.
10. What It Doesn’t Do YetHonest limits to know before you build a process around it.

1. Turning Batch Tracking On — Inventory → Edit Stock Item

Batch tracking is off by default and switched on per item. You turn it on for the things where a date actually matters — dairy, meat, fish, fresh produce, packaged goods with a shelf life, and any regulated item — and leave it off for stable staples like salt or rice where chasing lot numbers would just be busywork.

To turn it on, open the item from More → Inventory, tap Edit Stock Item, and switch on “Track batch number & expiry”. The help text under the toggle sums up the intent: “Enable for perishables, dairy, meat, and regulated items. Receiving will capture batch # and expiry, and consumption drains in FEFO order.” (FEFO — first-expiry, first-out — simply means the soonest-to-expire stock is used up first; Part 4 covers it in full.)

Two things happen the moment you flip it on:

  • Your existing stock isn’t lost — it’s seeded as a starting batch. Whatever is currently on hand becomes a single Legacy batch (shown with a Legacy badge), carrying the item’s current expiry date if it had one. You carry on receiving new, properly-dated batches from there.
  • From now on, expiry lives on the batch, not on the item as a whole.

💡 You can’t switch it back off while stock remains. If you try to disable tracking on an item that still has batches with stock left, Meztezz refuses: “This item still has batches with stock remaining. Zero them out (via wastage, transfer, or sale) before disabling batch tracking.” This is deliberate — silently collapsing several dated batches back into one undated pile would throw away exactly the information you turned the feature on to keep.


2. Recording a Batch When Stock Arrives

Once an item is batch-tracked, every screen that adds stock for it shows the same batch entry table — one row per batch with Qty, Batch #, and Expiry columns, plus an Add batch button. That last button matters: a single delivery can be split across several batches. Half a case of milk expiring on the 20th and half on the 27th? Two rows, two dates, one receipt.

The batch table appears in every place stock comes in:

WhereWhat it’s for
Stock In (an item’s +In action)Split a received quantity across one or more batches.
Add Stock (the green button on the Stock Items sheet, Ctrl+N)Add stock to a chosen location; the dropdown shows current on-hand per location.
Adjust StockA Batch # and Expiry pair appears only for a positive adjustment, so a surplus correction becomes a real, dated batch — never an undated mystery pile.
Purchase Order receiveThe same Qty / Batch # / Expiry rows, so one PO line can land as several dated batches.
Import Opening StockThe CSV template carries Batch Number and Batch Expiry columns, so your starting stock imports as real batches.

Fractional quantities are fine in the Qty field — 0.25 L, 1.5 kg — for anything you buy by weight or volume.

Every batch you record is written onto the stock movement and shows up in the Movements log, so months later you can trace exactly which delivery a given stock-in came from. That trail is what makes a food-safety audit answerable instead of a guessing game.


3. Sellable vs Expired On-Hand

Here’s the change you’ll notice first. The moment a batch passes its expiry date, the item’s on-hand figure splits in two so the problem is visible at a glance. Instead of a single total, the Stock Items list shows the item as (X sellable · Y expired), and the per-location breakdown shows the same split. Items whose batches are all still fresh keep showing a plain total — no clutter where there’s no problem.

So a paneer line reading 8 sellable · 2 expired is telling you, without you opening anything, that 2 kg has turned and needs to come out of service. Before this, that 2 kg was just part of an undifferentiated “10 on hand”, and nobody would know until someone physically looked.

💡 Frozen at close. When you freeze a closing-stock period, the expired portion is captured as it stood at freeze time — it isn’t recomputed later. Your closing numbers reflect what was actually true on that date.


4. Selling the Oldest First (FEFO)

FEFO stands for first-expiry, first-out: always reach for the batch that expires soonest before touching a fresher one. It’s the single most important habit in any kitchen storeroom, and Meztezz now does it for you automatically rather than relying on whoever’s on the line to read the dates.

Where it happens — at KOT-ready. Stock is deducted when a kitchen ticket is marked Ready, not when the order is taken (that timing rule is the same one explained in the Stock & Inventory post). When the deduction runs, the engine walks the recipe and, for each raw material, picks stock in a fixed order:

  1. Batch-tracked stock first, oldest expiry first. The soonest-to-turn batch is consumed before any other.
  2. Then non-batch stock, oldest purchase first. Anything without batch tracking falls back to a simple first-in-first-out.

The same oldest-expiry-first logic governs the manual stock movements too:

  • Stock Out drains the oldest-expiry batch first, so when you remove expired stock you actually clear the expired batch. A Pick batch… link lets you override and remove from a specific batch instead. (Every Stock Out needs a Manager PIN.)
  • Transfer between locations is batch-aware — the oldest-expiry batches move first, carrying each batch’s number, expiry date, and cost to the destination, so expiry tracking travels with the stock. A Pick batch… link lets you move a chosen batch first if you need to.

💡 The warning and the deduction always agree. Before depleting, Meztezz runs a “dry-run” check for expired batches using the exact same recipe logic the real deduction uses. So the expired-stock warning you see and the stock that actually moves can never disagree — there’s no “it warned me but took something else” gap.


5. Expiry Alerts & the Background Sweep — More → Inventory → Alerts

You shouldn’t have to open a screen to find out something is about to turn. Meztezz runs a background sweep that watches every dated batch and raises alerts on its own.

When it runs. The sweep runs about a minute after the app starts, and again at each business-day rollover — the day boundary you set in Settings, not midnight. There’s no manual “run now” button; restarting the app forces a fresh sweep if you ever need one.

What it does (and doesn’t) do. It is alert-only — it never writes wastage and never changes stock on its own. It just raises alerts, or clears them when stock is no longer a problem. It also respects your master Low Stock Alerts switch: turn that off and expiry alerts stop with it. And it’s tidy about it — each item gets at most one open expiry alert, set to its most urgent batch. As a batch creeps closer to its date, that one alert escalates in place rather than piling up duplicates.

The four urgency levels. How urgent a batch is depends on how many days are left until it expires, measured against your business date. The day thresholds are configurable at Settings → Inventory → Alerts; the defaults are shown here:

Days until expiryLevelShown as
Already past (0 or fewer)ExpiredExpired
Within the critical window (default 3)CriticalCritical
Within the warning window (default 7)WarningWarning
Within the alert window (default 7)AlertApproaching
Further outno alert

Where the alerts show up:

  • Stock Alerts listMore → Inventory → Alerts (Unread / All / Resolved). Each expiry alert has a Resolve button.
  • Nav badge — the Inventory entry in the More menu shows an amber count of unresolved expiry alerts, so you see it from the menu without drilling in.
  • Expiring Soon widget — on the Stock Items sheet. It reads batches live, so it can flag an item even before the next sweep has raised a formal alert.
  • ReportsMore → Reports → Stock → Batch Expiry gives the full batch-by-batch report with value at risk (the unit cost × quantity tied up in each at-risk batch), so you can see not just what’s turning but what it’s worth.

6. Blocking Sales on Expired Stock

Alerts warn you. The sale-block enforces it. This is the part that changes expired stock from “something we hope a cook noticed” into “something the system will not let through”.

Where it lives. Settings → Inventory → AlertsBlock sales on expired stock. It is on by default.

What it does. When this is on and a staff member sends a KOT for a dish whose recipe would consume an expired batch, the ticket is held before any stock is touched:

  1. An Expired Batch dialog appears, listing each blocking batch with its value at risk (and a combined total), plus a field for an optional note. Value at risk shows ”–” for any batch with no recorded unit cost — so a Rs. 0-cost item reads ”–”, not a misleading Rs. 0.
  2. A manager enters their PIN to resolve. On resolve, the entire expired batch is written off as wastage and the KOT goes through — in one step. The wastage record keeps the manager’s note (or an automatic one if none was typed) and is tagged as an expired-batch resolution, so it shows in wastage reports and the raw-material ledger.

It covers every order type — dine-in Send KOT, and the pay-first flows where the KOT is generated automatically after payment (takeaway, prepaid delivery, fast-food dine-in, and aggregator orders).

On the Captain App, the waiter can’t clear it. The same check runs on a captain device, but the waiter is simply told the order is held on expired stock — a manager has to resolve it on the POS terminal. The floor can’t wave away a food-safety stop from a phone.

With the setting off, no dialog appears. The expired stock is used, and it’s counted toward the “Expired consumed today” figure on the inventory dashboard instead — so even if you choose not to block, you still see the cost of what went out expired.

💡 When does stock actually leave? Resolving an expired batch wastes that batch immediately. The dish’s normal recipe ingredients still deduct later, when the KOT is marked Ready — not when the order is created or paid. So right after a resolve, only the expired batch is gone; the rest of the recipe drops when the food is ready.


7. Liquor Expiry — Two Ways to Track It

Liquor is a special case because it’s always tracked as two units at once: sealed bottles and open ml (e.g. 3 sealed · 250 ml open). You never see a single combined total. How a liquor item tracks expiry depends on whether you switch on batch tracking for it.

7.1 Untracked liquor (the default)

The item carries one expiry date per storage location — a single, simple date for the bar, another for the store, and so on. You set it on the liquor branch of the Stock In, Add Stock, Adjust Stock, and Purchase Order receive screens (an “Expiry (optional)” field), entering it from the supplier invoice as stock arrives.

💡 The system keeps the sooner date. If a location already has an expiry and you enter a later one, Meztezz keeps the earlier of the two — the soonest-expiring stock always drives the alerts, and a later date never overwrites a sooner one.

7.2 Tracked liquor (opt in)

Switch on the same “Track batch number & expiry” toggle food uses, and liquor records each delivery as its own dated batch — so different lots of the same brand can expire on different dates, and the bar pours the soonest-expiring lot first, exactly like the kitchen does with food.

As with food, turning tracking on seeds your existing stock as a Legacy batch (the current sealed-bottle count plus the current per-location expiry; already-open bottles inherit that date). The intake screens then add an optional “Batch # (optional)” field beside the expiry, and the Purchase Order receive screen uses the full Qty / Batch # / Expiry table so one PO line can split across several lots.

7.3 The expired-liquor block at the bar

The same Block sales on expired stock switch guards the bar. If a drink on a KOT would pour a liquor whose stock at the bar has expired, the ticket is blocked and a “Cannot send KOT — Expired liquor” dialog appears. It lists each expired liquor with its on-hand split (N sealed · M ml open) and its value at risk, plus a combined total and an optional note. A manager enters a PIN and taps “Move to wastage & send KOT” to write off the expired liquor and send the ticket in one step; Cancel KOT backs out.

As with food, this in-screen resolve is on the POS terminal only — on a captain device the order is simply held until a manager clears it on the terminal. (This is separate from the liquor excise shortage guard, which can never be overridden.)

💡 Bar Sync never sets an expiry. If you use automated Bar Sync to bring bottle counts in from your EPOS, those deliveries never set or change a liquor expiry — there’s no date on the wire to carry. Add expiry dates by hand via Edit Stock Item (per-location for untracked liquor, or per-batch for tracked). It’s the one place liquor expiry stays a manual habit.


8. Correcting a Batch Number or Expiry Date

Typos happen — a mis-keyed lot code, or an expiry entered as the wrong month — and the mistake is often only spotted later, after some of the batch has been used. You can fix it without disturbing the quantity.

Where: open the item from More → Inventory (Edit Stock Item). For a batch-tracked item, a Batches section lists that item’s batches; each has an Edit button. To keep the list readable, fully-consumed batches (0 remaining) are hidden; batches with stock left — and any negative (deficit) rows — stay listed.

What you can change: the batch number and the expiry date only. Quantity and manufacturing date aren’t editable here — quantity corrections go through a stock adjustment instead.

A few rules worth knowing:

  • Manager PIN required to save any correction.
  • Clearing the expiry marks that batch as never-expiring (“no expiry”).
  • Past dates are allowed but flagged — if the corrected date is in the past, Meztezz warns that the batch will be treated as expired and may block KOTs that use it, then still lets you save (because that may well be the truth).
  • History is not rewritten. The correction is audit-logged, and the live batch reflects the new values, but past stock movements keep their original recorded numbers. The historical record stays intact.

Who can do it: the Batches section is visible to anyone with inventory view permission; the Edit button only appears for staff with inventory adjust permission.

💡 Moving a batch to another location isn’t done here. Use the Transfer operation under Stock Movements — for batch-tracked items that transfer is batch-aware (oldest-expiry batches move first, carrying their expiry and cost across).


9. On the Cloud Dashboard

Everything above happens on the terminal — that’s where stock actually moves. The cloud dashboard at app.meztezz.com is a read-only mirror for the owner watching from home, and a couple of the expiry surfaces flow up to it:

  • Reports → Stock → Alerts carries an Expiring Items card — the same warning-horizon list the terminal shows, with item, expiry date, and urgency badge.
  • Inventory → Alerts shows expiring/expired alert badges, and the Wastage report reflects the write-offs (including the expired-batch resolutions from Part 6).

The blow-by-blow batch operations — recording a batch, the FEFO deduction, resolving a sale-block — stay on the terminal, because the cloud never originates or edits operational data. For the full owner-side tour, see The Cloud Dashboard Tour and Reports That Actually Tell You Something.


10. What It Doesn’t Do Yet

In the same honest spirit as the rest of these guides, here’s where the edges are:

  • The sweep is alert-only. It warns you and raises badges, but it never wastes stock on its own. Expired stock leaves your books either when a manager resolves a sale-block, or when you record wastage by hand. Nothing disappears overnight without a person in the loop.
  • There’s no manual “run sweep now” button. The sweep runs on app start and at the business-day rollover. Restarting the app is the way to force a fresh pass.
  • Bar Sync deliveries don’t carry an expiry. Liquor brought in automatically from an EPOS has no date attached — you add those by hand (see Part 7.3).
  • Batch tracking is opt-in, per item. Items you never switch it on for behave exactly as before — a single fungible total, no batch rows. The power is there when you want it, not forced on staples that don’t need it.

Batch and expiry tracking is the difference between hoping the oldest milk gets used first and knowing it will. Turn it on for the handful of items where a date genuinely matters, record the date when stock arrives, and let the sweep and the sale-block do the remembering for you. Your team stops policing dates by eye, and your guests stop being the ones who discover a problem.

Questions, or something not behaving the way this post describes? Write to us at hello@meztezz.com — and if you haven’t yet, read Stock & Inventory in Practice for the wider stock loop this feature sits inside.