Price Update
Price Update is a margin-protected way to react to a supplier's new cost list in one sitting: paste or upload the new costs, preview exactly how each product's cost and price would change, hand-adjust anything, then apply the whole batch at once.
Overview
Instead of opening each product to change its Cost Price, you paste or upload a plain "identifier, new cost" list from your supplier and let the page match it against your catalogue by SKU, Barcode or exact product name.
For every match, the page suggests a new Selling Price that either keeps that product's current markup percentage, or targets a margin percentage you specify — so a cost increase does not silently erode your profit.
Nothing is written to your catalogue until you tick the rows you want and click Apply — right up to that point everything is a preview you can edit or discard.
Before You Start
- Only Managers and Admins can open this page — it is hidden from cashier accounts in the sidebar.
- Your supplier's cost list needs to be reduced to two columns per line: a product identifier (SKU, barcode, or exact product name) and the new cost — either typed/pasted directly or uploaded as a .csv/.txt file.
Step-by-Step Guide
1 Paste or upload the new cost list
- Choose how to "Match products by": SKU, Barcode, or Product name (exact).
- Optionally set a "Target margin %" — leave it blank to keep each product's existing markup instead of forcing a single margin across everything.
- Paste rows directly into the text box (one product per line, e.g. "HW-0042, 118.50") or click "Choose file" to upload a CSV/TXT file, which fills the box for you.
- Click "Preview changes".
2 Review the matched preview
- Rows that could not be matched to any product are summarised in a warning banner (up to 8 identifiers shown, with a "…" if there are more) — double-check your Match-by setting if this list is long.
- Matched rows show old cost → new cost (red if the cost went up, green if it went down) and old price → a suggested new price you can override in place.
- Each row also shows the old margin % → new margin % so you can sanity-check the effect before applying.
- Every row is pre-selected if its cost or price actually changed; untick any row you want to skip, or use the header checkbox to select/deselect everything.
3 Apply the update
- Adjust any suggested price by typing directly into its input box — your edit is used instead of the auto-suggested value.
- Click "Apply selected" and confirm the count in the prompt.
- A success toast reports how many products were updated; the form then resets so you can run another batch.
Every Field & Button, Explained
| Field / Button | What it does |
|---|---|
Match products by | SKU, Barcode, or Product name (exact) — determines which column of your product data the pasted identifiers are compared against. |
Target margin % (blank = keep current markup) | When set, every matched product's suggested price is calculated to hit this margin on the new cost; when blank, each product keeps its own existing markup percentage. |
Or upload a CSV file | Reads a .csv or .txt file straight into the paste box — no server upload, purely a local file read. |
Paste box (textarea) | One product per line as "identifier, new cost"; commas, semicolons and tabs are all accepted as separators, and quoted values are stripped. |
Preview changes | Sends the parsed rows to the server to match against your catalogue and calculate suggested new prices. |
Unmatched rows banner | Lists identifiers from your paste/upload that did not match any product under the chosen Match-by field. |
Select-all checkbox (table header) | Ticks or unticks every previewed row at once. |
Per-row checkbox | Include/exclude that specific product from the batch that gets applied. |
Cost column (old → new) | Red new-cost value means the cost rose versus the old cost; green means it fell. |
Price column (old → editable new) | The suggested new price is pre-filled and editable in place before you apply. |
Margin column (old % → new %) | Recalculated live as you edit the suggested price, based on the row's new cost. |
Apply selected | Writes cost and price to every checked product in one batch, after a confirmation prompt. |
Tips & Best Practices
- Run a small test batch (2–3 known products) the first time you use a new supplier's file format to confirm your Match-by column lines up before processing the full list.
- Leave Target margin % blank for routine cost updates so you preserve each product's existing pricing strategy — only set a target margin when you deliberately want to standardise margins across a batch.
- Always scan the unmatched-rows banner before applying — a long unmatched list usually means the wrong Match-by field is selected, not that those products don't exist.
Troubleshooting & FAQ
Most or all of my rows show as unmatched.
How is the suggested new price calculated?
Can I change a suggested price before applying it?
I don't see Price Update in my sidebar at all.
🧑💻 Developer Notes
Source component(s):
frontend-app/packages/pos-react-lib/src/pages/products/PriceUpdatePage.jsx
Backend endpoints used:
POST /products/price-update/previewPOST /products/price-update/apply
Related tables (db-core repositories):
Product
The managerOnly restriction is enforced by the sidebar/route-level nav guard (see navItems.jsx — price-update has managerOnly: true); the page component itself does not perform an additional in-page role check. Parsing accepts comma, semicolon or tab as the column separator and silently skips malformed or header lines (any line that does not end in a finite number).