Free AuditEnterprise AIShelfSense
Back to Blog
ShelfSense by ShelfLifeProOct 21, 20267 min read

Inventory CSV Export: The Columns an Expiry Check Needs

Exporting stock from your POS to CSV? Here are the six columns an expiry check needs, the date formats that break imports, and how to check the file first.

SE

ShelfLifePro Editorial Team

Inventory management insights for retail and pharmacy

Why the export is where expiry checks stall

You open the POS back office, find "Export inventory," click it, and a file lands in your downloads folder. It's got product names, quantities, maybe a retail price. What it doesn't have is a single expiry date.

So the question you actually wanted answered, "what's going out of date before it sells?", can't be asked of that file. The export ran fine. It just exported the wrong things.

This post covers what an inventory CSV export needs to contain before an expiry check can run on it, the date formats that quietly wreck an import, and a short routine for checking the file before you upload it anywhere.

How a POS ends up with the wrong columns

A point-of-sale system is built around the sale: what scanned, at what price, through which register. Stock on hand is a by-product. It's the number that goes down when something sells and up when someone receives a delivery.

That design causes two problems. First, quantity is usually held per SKU, not per delivery. Say two cases of the same yogurt arrive a week apart: the system adds them into one number and forgets they ever had different dates. Second, expiry either gets written on a receiving sheet, typed into a notes field nobody exports, or never gets recorded at all.

We go into this gap in more depth in expiry date tracking with your existing POS. The short version: if your POS never stored the batch and the date, no export setting will produce them.

The six columns an expiry check can't run without

These are the minimum. Missing any one of them and the check either can't run or gives you an answer you can't act on.

  • SKU: the code your system uses for the item. It has to be unique and identical to the code in your sales data, otherwise nothing can be matched up later.
  • Description: the product name as staff would recognise it on the shelf. Its job is to make a flagged line findable by a human.
  • Quantity on hand: units, not cases, unless every row uses the same unit. A mix of "each" and "case of 12" in one column throws every calculation off.
  • Unit cost: what you paid, not the shelf price. Money at risk is units times cost. Retail price overstates the loss and hides which items actually hurt.
  • Batch or lot number: the thing that separates one delivery from the next. If your products don't carry lot codes, the receiving date works as a stand-in.
  • Expiry date: one date per row, in one consistent format (more on that below).

The rule that ties these together: one row per batch, not one row per SKU. If a product has three batches on the shelf, it gets three rows that share a SKU, each with its own quantity, lot and date.

Worked example: one SKU, two batches

Worked example: picture a store holding 24 tubs of a yogurt that cost $1.80 each. A per-SKU export shows one row: 24 units, expiry blank, or showing whatever date someone last typed.

Now split it by batch. Row one: 10 units, expiring this Friday. Row two: 14 units, expiring in five weeks. Suddenly there's a real call to make. If the item sells about one tub a day, roughly 7 of those 10 won't clear by Friday. That's 7 Γ— $1.80 = $12.60 at risk, and it's worth a markdown today. The second batch needs nothing yet.

The per-SKU row hid all of that. Same stock, same shelf, different column structure.

Free Tool

Not sure how much you're losing to expiry?

Run a free inventory waste audit, find your bleeding SKUs in 60 seconds. No sign-up required.

Run free audit

Columns that sharpen the check

None of these are mandatory, but each one makes the output more useful:

  • Last sale date: separates "slow but moving" from "hasn't sold in weeks". Paired with sales history, it's the backbone of a dead stock analysis from your sales export.
  • Units sold over a recent window: lets you estimate sell-through rate, which is what turns an expiry date into a "will it clear in time?" answer.
  • Supplier: tells you who to call about a return or credit before the date passes, not after.
  • Category or department: makes the flagged list routable to the right person (dairy lead, pharmacy tech, whoever).
  • Location: store, back room, or cooler, if you run more than one.

Date formats that break imports

Dates cause more failed uploads than every other column combined. A file can look perfect on screen and still be unreadable to whatever imports it. For example, watch for these:

  • Ambiguous day/month order: 03/04/2026 is March 4 in the US and April 3 almost everywhere else. If the importing tool guesses wrong, nothing errors. Your dates just shift by weeks.
  • Two-digit years: 03/04/26 forces another guess.
  • Excel serial numbers: a date cell copied as a value can turn into a bare number like 46100, which means nothing to a reader expecting a date.
  • Month-only dates: "MAR 2026" or "03/2026", common on pharmacy and supplement packaging. Decide on a rule (treat it as the last day of the month, say) and apply it consistently.
  • Placeholders: "N/A", "none", "TBD", a dash. Leave the cell blank instead, then deal with blanks on purpose.
  • Text months mixed with numbers: "4-Mar-26" in one row and "2026-03-04" in the next.

The safest format is YYYY-MM-DD. It sorts correctly as plain text and nobody misreads it. If your POS lets you choose an export date format, choose that one.

Two non-date traps belong here too. Spreadsheets strip leading zeros from SKUs, so "00451" becomes "451" and stops matching. They also turn long barcodes into scientific notation, which loses digits for good. Format SKU and barcode columns as text before you save, and if your descriptions contain commas, make sure they're wrapped in quotes so they don't split into extra columns.

Checking the file before you upload it

Five minutes here saves an afternoon of wondering why the results look strange. Run through this before the file goes anywhere:

  • Open it in a plain text editor once. You'll see the real contents: the actual date format, stray quote marks, a totals row at the bottom. Spreadsheet apps hide all of that.
  • Compare the row count to the POS. If the POS reports a certain number of active items and the file has far fewer, the export was filtered (active-only, one category, one location).
  • Sort by expiry date, both directions. For example, dates in 1900 or 2099 are placeholders or typos, and dates already in the past are either expired stock still on the shelf or bad data. Both are worth knowing about.
  • Filter for blanks in quantity, cost and expiry. Decide whether to fill them in, drop them, or accept that those rows won't be checked.
  • Look for negatives and zeros. A negative quantity means a sales or receiving error. A zero cost means the money-at-risk figure for that item will be wrong.
  • Check for duplicate SKU + batch pairs. Two identical rows double-count the stock.
  • Delete anything that isn't data: report titles above the header, subtotal rows, a "Generated on…" footer.

When your POS won't export batch or expiry

Some systems simply don't store them. You have two honest options.

One is to keep expiry in a separate sheet keyed on SKU and lot, filled in at receiving, then join it to the stock export. The expiry-tracking spreadsheet template is laid out for exactly that. It works as long as someone fills it in every delivery. Once receiving gets skipped on a busy day, the sheet goes stale without anyone noticing. That's the core weakness we cover in the limits of Excel inventory templates.

The other is to capture batch and date in a system that holds them natively, so the export comes out right every time.

Where the file goes next

A clean file is useful on its own. You can sort it and eyeball the next two weeks of dates yourself. Doing that every day across hundreds of rows, while working out sell-through and cost for each line, is where it stops being practical.

That daily pass is the job ShelfSense by ShelfLifePro does. It reads your stock, batch, cost and expiry records once a day and surfaces the few items worth acting on, ranked by money at risk, with the arithmetic shown so you can check it. It recommends and you approve. It never changes a price or places an order on its own. If you're on Tally, Shopify or WooCommerce, you export from them to CSV today, and a direct connection is available on request. Zoho Inventory connects read-only.

ShelfSense's free audit reads one CSV export, no account needed. Run the checklist above, then try it on your own file and see what turns up.

SE

ShelfLifePro Editorial Team

The ShelfLifePro editorial team covers inventory management, expiry tracking, and waste reduction for pharmacies, supermarkets, and retail businesses worldwide.

See what batch-level tracking actually looks like

ShelfLifePro tracks expiry by batch, automates FEFO rotation, and sends markdown alerts before stock expires. 14-day free trial, no credit card required.

Newsletter

The monthly expiry-tracking brief

One short email a month, only when there is something worth reading. FEFO tactics, markdown math, and real-world waste-reduction wins. Unsubscribe anytime.

No spam. Unsubscribe in one click.