From Inbox Chaos to a Price-File Process
Price files arrive as email attachments, from six different people at four suppliers, on no schedule anyone agreed to, in whatever format the sender's system exports. The instinct is to fix the parsing. The parsing is rarely the problem. The problem is that three months later nobody can answer "what did this part cost us in March," and nobody knows whether the file that arrived on the 14th was ever applied.
The four ways it actually fails
Every store that buys wholesale hits the same four failures, in roughly this order:
- The file arrives and nobody opens it. No owner, no due date, and the attachment is two hundred messages down by the time anyone remembers. The cost increase is live on your invoices weeks before it is live in your numbers.
- The file is opened and partially applied. Someone updates the forty lines they recognise and stops. There is no record of which forty, so the next diff compares a mix of new and old costs and produces nonsense.
- Two versions of the same file. The supplier sends a correction and calls it
PriceList_Sept_FINAL_v2.xlsx. Later, nobody can tell which one was used, and the answer is not recoverable from anything you kept. - No before and after. Shopify holds one cost per variant with no history. Once you overwrite it, the previous cost is gone. Not "hard to find" — gone. Every margin question about the past becomes unanswerable.
Notice that only the second one is about spreadsheets. The rest are about records and ownership, which is why buying a better importer doesn't fix them.
Start with the archive, not the automation
The cheapest step is also the one that resolves most of the pain, and it needs a folder rather than software.
A naming convention that sorts usefully and carries the two dates that matter:
supplier_effective-date_received-date_originalname.ext
acme_2026-09-01_2026-08-14_pricelist.xlsx
midwest_2026-08-01_2026-08-14_PriceList_Sept_FINAL_v2.xlsx
northline_unknown_2026-08-17_export.csv
Two dates, because they answer different questions. Received tells you when you had the information and therefore when you could have acted. Effective tells you which invoices the price applies to, which is the date your margin history actually cares about. They routinely differ by weeks in both directions: a file dated for September arriving in mid-August, or a "correction" arriving in October that has been in force since the first.
When the file carries no effective date, write unknown rather than guessing, and then ask. It is the smallest possible request to make of a supplier and one of the few they grant immediately — the same class of ask as the file-quality items in negotiating as a small account.
One row per file: the intake log
A single sheet, appended to every time a file lands. It is the answer to "was this applied, by whom, when" and it takes ninety seconds to fill in.
| Supplier | Received | Effective | Lines | Basis | Applied | Note |
|---|---|---|---|---|---|---|
| Acme | 2026-08-14 | 2026-09-01 | 1,240 | Net, per unit | 2026-08-15 | 9 lines held for price review |
| Midwest | 2026-08-14 | 2026-08-01 | 318 | List × 0.62 | 2026-08-15 | Supersedes the 08-02 file |
| Northline | 2026-08-17 | unknown | 4,902 | Net, per M | — | Effective date requested |
| Acme | 2026-08-02 | 2026-08-01 | 1,237 | Net, per unit | 2026-08-04 | — |
The basis column earns its place on its own. A file quoted as list price times a multiplier and a file quoted net look identical until you compare them, and multiplier files change by moving the multiplier while every printed number stays the same — the mechanics are in industrial price books and multipliers. Recording the basis at intake means a later diff can't silently compare two different things.
Normalise before you compare anything
Four normalisations, in this order, before a single line is diffed:
- Per selling unit. A per-pack price against a per-unit price is the most common way a price review produces confident nonsense. If the file gives pack quantity, divide. If it doesn't, get it — a pack change with a flat price is a real cost increase that no diff will report.
- Cost basis. Apply the multiplier, or the column discount, or the contract tier, so both sides of the comparison are net cost to you.
- Unit of measure. Per-M, per-foot, per-hundred, per-each. Wire, fasteners and consumables switch between these more often than anyone expects, and a per-M price read as per-each is off by a factor of a thousand.
- Currency. Fix a rate and record which rate you used, so a cost "increase" that is only an exchange-rate move is identifiable as one.
These four cover most of the traps catalogued in reading a supplier price list without getting burned. Getting them wrong doesn't produce an obvious error — it produces plausible numbers, which is worse.
The diff: three questions per line
Once both files are normalised, only three things matter for each line, and everything else is noise:
1. did the cost move?
2. by how much?
3. does the new cost break my floor at the current retail?
margin = (price − cost) ÷ price
price to hold M = cost ÷ (1 − M)
Question three is the one that decides your afternoon. A file with a hundred and fifty movements is not a hundred and fifty decisions — most increases are absorbed by the margin you already have. A run against a 35% floor, using the Acme file from the log above:
| SKU | Retail | Old cost | New cost | Change | Margin before | Margin after | Price to hold 35% |
|---|---|---|---|---|---|---|---|
| A-1140 | $24.95 | $13.10 | $13.10 | — | 47.5% | 47.5% | — |
| B-2207 | $39.95 | $24.00 | $25.92 | +8.0% | 39.9% | 35.1% | $39.88 |
| C-0318 | $12.50 | $7.80 | $8.61 | +10.4% | 37.6% | 31.1% | $13.25 |
| D-5561 | $99.00 | $61.40 | $63.86 | +4.0% | 38.0% | 35.5% | $98.25 |
| E-8802 | $54.00 | $31.00 | $28.55 | −7.9% | 42.6% | 47.1% | — |
| F-1023 | $18.95 | $10.20 | $12.85 | +26.0% | 46.2% | 32.2% | $19.77 |
Read the rows against each other and the point of the third column becomes obvious. B-2207 rose 8% and needs no action at all: the price that would hold 35% is $39.88, below the $39.95 already on the site. D-5561 is the same story at 4%. F-1023 rose 26% and is 2.8 points under the floor, needing $19.77 to recover it. And C-0318 is the row a percentage-based review misses entirely — a 10.4% increase, unremarkable in a list sorted by size of change, that lands 3.9 points under the floor because the line had less margin to give.
Twelve hundred lines, nine decisions. That ratio is what makes the process fit in an hour, and it only exists if the floor test runs on every line rather than on the ones that caught someone's eye.
Applying: two writes, not one
Costs and prices are separate operations with separate risk profiles, and merging them is how stores end up repricing a catalog by accident.
- Cost changes apply in bulk, all of them, including the decreases. A cost you decline to update is a cost that is silently wrong, and it will corrupt the next diff as well as every report in between. The mechanics for Shopify are in bulk-updating cost per item.
- Price changes apply deliberately, line by line, only where a floor broke. The suggested price is the start of that decision, not the end of it: rounding, price-point psychology, competitive position and MAP all sit between $19.77 and what you actually publish.
Then record the applied date in the intake log. This is the step that gets skipped and the one that makes the next month possible — the diff has to know which file is the baseline, and "the last one, probably" is not a baseline.
The unmatched pile is where processes die
Every file contains lines you cannot match to anything in your catalog. Ten to thirty per cent is normal, and the natural response — skip them, deal with it later — is what turns a process back into chaos, because the same lines come back next month and the month after.
Three buckets, three different decisions:
- New to the supplier. Decide once: list it or ignore it. Then record the decision. An "ignore" that isn't written down is a line you will re-evaluate every single month for years.
- Renamed or re-numbered. The part is in your catalog under a different code. Create a permanent alias linking their code to yours. A per-file find-and-replace solves this month and nothing else.
- Gone from the file. The most urgent bucket and the one that looks like nothing. A part that vanished is either discontinued or superseded, and both need action while you still have stock and can still order the replacement — see core charges, MAP and supersessions for how supersession chains behave.
Aliases and ignore-decisions have to persist across files. That is the single largest difference between a process that gets easier every month and one that costs the same hour forever.
Making the files arrive predictably
Most of the chaos is upstream and is cheaper to fix there.
- One address, not one person. A dedicated mailbox —
pricing@yourstore.com— given to every supplier contact. Files stop living in one buyer's personal inbox, and someone else can run the review when they're away. - A schedule you can hold them to. "First business day of the month" is better than "when we update it," even if they miss it sometimes, because a missed file is now visible.
- The same format and the same filename every time. Suppliers change export tools; ask to be told when they do. A column that moves position breaks an import silently.
- Four columns worth asking for: effective date, pack quantity, unit of measure, and a status flag for discontinued items. None of these cost the supplier margin, which is exactly why they are gettable.
An hour a month
| Step | Time | Output |
|---|---|---|
| Archive and log intake | 5 min | File saved under the naming rule, one row in the log |
| Normalise | 10 min | Net cost per selling unit, one currency, one UOM |
| Diff against the last applied file | 5 min | Changed lines, sorted by floor breach |
| Review the breaches | 20 min | New retail decided for each, or an accepted lower margin |
| Apply costs, then prices | 10 min | Costs written in bulk, prices written line by line |
| Work the unmatched pile | 10 min | Aliases created, ignores recorded, discontinued flagged |
An hour per supplier file, and less every month as the alias list fills in. Compare that with the alternative, which is not zero — it's the same work done under pressure once a quarter, on lines someone happened to notice, with no record of what was decided.
The archive is the piece to start with today, because it is the only step you cannot do retroactively. Everything else can be built later on top of a folder of files you kept; nothing can be built on top of files you didn't.
Check the file against your real margins
Drop a supplier price list and your Shopify product export into the free Supplier Price Margin Checker: cost movement per SKU, margin at your current retail, and a suggested price to hold your target — matched by SKU, entirely in your browser.
Open the free checker ↗