Importing locations and stock
Lodsted counts your Shopify stock into the receiving location at install. Two spreadsheet imports then get an existing warehouse in place in an afternoon: one file for the locations, one that puts the stock away bin by bin, with cost and age for anything Shopify did not know about. Both imports are Admin only.
Before you import
- Products first. Both files name SKUs, and a SKU that Lodsted does not know stops the file. Products come from Shopify during sync; on a fresh install use Refresh from Shopify on the Setup page's product review, then check the Inventory page lists your SKUs. Add any warehouse-only SKUs in Shopify.
- Locations before stock. The stock file names locations, and a location that does not exist stops the file. Import or create locations first.
- Decide the code scheme. Codes are letters and digits only; see Location codes. The first two characters are the zone, any two-digit number; zone 01 is picking, everything else is storage. An all-digit code is shown with dashes (
01-02-0304); a code with letters is shown as typed (01A01). - Count the shelves, or export from the old system, into a spreadsheet with one row per location, and one row per SKU-and-location (or per lot, if you know the receipt dates) for stock. The stock file says where things are; Lodsted already knows how many Shopify thought there were.
How an import works
The Import button on the Locations page and on the Inventory page opens the same kind of window:
- Read the column table
It lists every column the file may have, whether it is required and what it means. Download template saves a one-line example file you can fill in.
- Choose the file, or paste
Choose a
.csv,.txtor.tsvfile, or copy the cells from a spreadsheet (including the header row) and paste them into the box. The window counts the data lines it sees. - Import
Lodsted checks every line before changing anything. If every line is good, the file is applied and the page reloads. If any line is bad, nothing is applied; the window stays open with a table of line number, row and problem. Fix those lines in the spreadsheet and import again.
File rules, both imports
- The first non-blank line is the header and names the columns. Columns can be in any order; extra columns are ignored.
- Column names are matched loosely:
Received Date,received_dateandreceiveddateare the same column; case does not matter. - Cells are separated by commas, or by tabs if the line has any (which is what a spreadsheet paste produces). A cell that contains a comma can be wrapped in double quotes.
- Blank lines are skipped. Numbers may carry
$and thousands separators. - SKUs and location codes are upper-cased, and dashes or spaces in location codes are dropped, so
01-a-01and01A01are the same location.
The locations file
| Column | Required | Meaning |
|---|---|---|
location | Yes | The location code, such as 01A01. A code that already exists is updated; a new one is created. A code may appear only once in the file. |
sku | No | The product picked from this location (a pick face). The product must already exist. Leave blank for storage locations. |
min | No | The warning level for replenishment. Whole number, 0 or more; blank means 0. |
max | No | How many units the bin holds; replenishment fills to it. Whole number, 0 or more; blank means 0 (no max). Min may not exceed a non-zero max. |
active | No | yes or no (also y/n, true/false, 1/0). Blank means yes. No means the location's stock is not usable; see active and inactive. |
There is no zone column: the zone is the first two characters of the location code (01A01 is zone 01,
90REC is zone 90). Only zone 01 changes behavior (picking); every other zone is storage.
Example
location,sku,min,max,active
01A01,GB-PRO-DZ,6,24,yes
01A02,GB-SOFT-DZ,6,24,yes
01B01,GLOVE-L,2,12,yes
02A01,,,,yes
02A02,,,,yes
90REC,,,,no
Three pick faces with their SKU and replenishment levels, two bulk bins, and a receiving bin set inactive so deliveries put there are not promised to orders until they are moved.
What the import does and does not do
- Creates missing locations and updates existing ones (SKU, min, max, active). Re-uploading a corrected file is safe.
- Sets the primary flag when a SKU is given. A zone 01 row with a SKU becomes that SKU's primary pick location, the bin waves pick first, replenishment fills and the receive screen's P button uses. A SKU has one primary, so list each SKU on one pick-face row; a second pick face for the same SKU is created from the Locations page.
- Does not fill the aisle, rack, shelf and bin parts; only the code. The Create Locations form fills those when you create by hand, and nothing in the daily screens depends on them.
- Does not delete locations that are missing from the file.
Typical errors
| Message | Fix |
|---|---|
| The header must name a 'location' column | The first line is not a header, or the column is named something else. Rename it location. |
| SKU 'X' does not exist; add the product first | Sync products from Shopify, or correct the SKU spelling. |
| location appears more than once in the file | Two rows normalize to the same code (for example 01-A-01 and 01A01). Keep one. |
| min (10) is greater than max (5) | Swap or correct the numbers. |
The stock (inventory) file
Where the stock starts: the opening count
When Lodsted is installed it counts your Shopify stock once. Right after it pulls the product catalog, every
product that Shopify tracks is received into 90REC, the receiving location, at the quantity Shopify
shows for your fulfillment location: one lot per product, dated that day, at the product's current cost, with
the reference Opening count. Untracked products and products with nothing in stock get no lot.
Lodsted therefore starts out holding exactly what Shopify had, so the first stock push back to Shopify changes
nothing, and the Activity feed records the count.
The count runs once. A store that already holds any stock in Lodsted is left alone. Until a tenant holds some stock, from the count or from an import, Lodsted sends no quantities to Shopify at all, so a fresh install can never zero the storefront.
What a row does: put-away
This file puts that stock away. Each row names where a product belongs and how many should be there. Lodsted meets the quantity in two steps:
- Move from 90REC first. Whatever the product has waiting in
90RECmoves to the row's location, oldest lot first, each lot keeping its cost, received date and reference. A Moved transaction is written per lot. - Receive the rest. If the row asks for more than
90RECholds, the difference is received at the location as a new lot, the same way a purchase order receipt is, using the row's cost, date and reference, with a Received transaction stamped with the import time and your name.
Ask for less than 90REC holds and the remainder stays in 90REC; nothing is ever reduced. A row
whose location is 90REC itself is a plain receipt into receiving. The result table after the import says
what happened to each row: "moved 24 from 90REC", "moved 6 from 90REC, received 4", or "received 500".
| Column | Required | Meaning |
|---|---|---|
sku | Yes | The product. Must exist. |
location | Yes | Where the stock belongs. Must exist (import locations first). Active or inactive both work. |
quantity | Yes | How many should end up at the location, a whole number above zero. For a SKU and bin with several receipt dates, use one row per lot. |
cost | No | Cost per unit for any stock received new, 0 or more. Blank means the product's current cost. Stock moved from 90REC keeps its own cost. |
received | No | The date newly received stock arrived: 4/4/26, 04/04/2026 or 2026-04-04. Blank means today. A future date is refused. Moved stock keeps its own date. |
po | No | A purchase order number or other reference for newly received stock, shown on the lot and the transaction. |
Example
After install, 90REC holds 240 GB-PRO-DZ, 6 GLOVE-L and no TEE-100 (Shopify did not track it). The file:
sku,location,quantity,cost,received,po
GB-PRO-DZ,01A01,24,,,
GB-PRO-DZ,02A01,192,,,
GLOVE-L,01B01,10,9.75,,
TEE-100,90REC,500,4.10,2026-10-10,
TEE-100,01C01,40,,,
| Row | Result | Why |
|---|---|---|
| GB-PRO-DZ → 01A01 | moved 24 from 90REC | Receiving had 240; the opening lot's cost and date travel with the 24. |
| GB-PRO-DZ → 02A01 | moved 192 from 90REC | 216 of the 240 are now put away; 24 remain in 90REC, which is the count's excess over what was found on the shelves. |
| GLOVE-L → 01B01 | moved 6 from 90REC, received 4 | The shelf held more than Shopify knew; the extra 4 are a new lot at $9.75 dated today. |
| TEE-100 → 90REC | received 500 | A row for receiving itself is a plain receipt, here at $4.10 dated 10/10. |
| TEE-100 → 01C01 | moved 40 from 90REC | Rows run in file order, so the 40 come out of the 500 just received. |
What the import does
- Moves first, receives second, never reduces. Whatever is left in
90RECafter the import is stock Shopify counted that you did not find on a shelf: count again, then adjust it out (Admin, with a reason) or move it where it was found. - Importing the same file twice is not harmless: on the second pass
90RECis empty, so every row is received again and the shelves double. Import once; correct mistakes with adjustments. - Writes one Moved transaction per lot moved and one Received transaction per row that received, all visible on the Transactions page with your name.
- Recalculates demand afterwards, so orders that were short become waveable and the next stock push tells Shopify. Moving stock between locations does not change the total Shopify sees.
- Stock in an inactive location is recorded but shows under Unavail and is not counted in what Shopify is sent, until the location is activated or the stock moved.
The opening count lands in 90REC,
which is created active. If you make it inactive before importing, everything in it becomes unavailable and the next
stock push would send Shopify zeros. Put the stock away first; set 90REC inactive afterwards if you want
deliveries to wait there unsold.
Typical errors
| Message | Fix |
|---|---|
| The header must name a 'sku' column (columns: sku, location, quantity, cost, received, po) | Rename the header cells to the names in the table. |
| location 'X' does not exist; import or create it first | Run the locations import, or correct the code. |
| quantity must be a whole number above zero | Remove zero-quantity rows; use whole units. |
| received must be a date such as 4/4/26 or 2026-04-04 | Format the column as text in the spreadsheet before exporting, or use ISO dates. |
| received date is in the future | Check the year. |
A go-live sequence
- Set the warehouse time zone so import dates land on the right day.
- Confirm products are in (the Inventory page lists the SKUs) and that the opening count landed: the Inventory page shows the tracked products in
90REC, and the Activity feed has an "Opening count" line. - Import locations, with each SKU on its home pick-face row so the primary is set. Leave
90RECactive for now. - Count the shelves, or export counts from the old system, one row per SKU and bin.
- Import stock. Read the result table: "moved" rows came out of the opening count, "received" rows are stock Shopify did not know about.
- Look at what is left in
90RECon the Inventory page. That is the gap between Shopify's count and the shelves; recount, then adjust or move it. - Spot-check a few SKUs: On Hand per bin, Received dates, cost in Total Value.
- Run Setup › Products and stock tracking for any products Shopify was not tracking (they got no opening lot); once tracked, the next push sends their counts.
- Set
90RECinactive if deliveries should wait there unsold. Create a small test wave.
Every install carries a location coded 90REC in zone
90, the receiving dock: the opening count lands there, the receive screen's S button fills it in, and the
stock import puts away from it. Keep it active until the put-away is done; after that, set it inactive (the locations
file above does that with active = no, or edit it on the Locations page) if deliveries should wait there unsold.