Accounting & Finance

How do I calculate true COGS when inventory is split across my warehouse, a 3PL, and FBA?

Getting an accurate cost of goods sold when inventory sits in several places.

Last updated September 16, 2026

Perpetual inventory at landed cost, by location. Anything else invents phantom COGS.

Why periodic counting invents phantom COGS

Periodic math is beginning plus purchases minus ending. That only works if ending includes every node. Count your building and skip the 3PL, FBA inbound, Amazon Reserved, in-transit transfers, and returns sitting in QC, and those units disappear. The formula treats them as sold. That is phantom COGS: a year-end expense for inventory that is still in the world, just not in the room you counted. Shopify never held landed cost, so a Shopify export cannot close this. A 3PL on-hand file is units, not dollars. FBA is a day-old ledger. Amazon Reserved and units moving between Amazon warehouses often land as on-hand. Drop them from ending and you expense stock Amazon has not shipped. Publish them to Shopify and you sell units Amazon will not ship. Those are different bugs with the same root: Reserved is not sellable and not sold.

Valuing inventory by location

Value each location. Your warehouse, the 3PL, and FBA are three piles. Open internal shipments are in neither building until received. Leave them in-transit or valuation goes negative on one side and fat on the other. WAC is (qty on hand times old average, plus qty received times receipt cost) divided by total qty. Opening a PO does nothing. Cost moves when goods receive, when a supplier invoice disagrees with the PO, and when freight and duty post. One blended average across all sites is simpler and lies when FBA inbound fees, a 3PL receipt, and a factory-direct FOB channel do not share a cost. Cost-by-warehouse is the honest model if those piles truly cost different amounts. Either way, freight and duty capitalize into the location that received the goods. Sales tax does not. 3PL storage and pick-pack are fulfillment, not inbound COGS. They belong on contribution margin, not in the unit cost.

Reconcile valuation by location

Do not force the GL to match a Shopify export. Shopify never had the dollars. Cycle-count the 3PL against expected quantity, then journal the shrink. Reconcile valuation to the balance sheet by location and SKU before you argue that margin moved. A leftover $1 kit cost, a return booked as a zero-cost PO, or a negative on-hand will poison the average and then every later sale. FBA inbound that has not checked in is still yours. Returns in QC are still yours. Units on a truck between your building and the 3PL are still yours. Phantom COGS is almost never a costing theory problem. It is a missing location.

Late freight is a different post. Estimate on the receipt, sell, true-up when the invoice lands. This piece is the pile: every node, valued, before you trust COGS.

Run this with AI

Connect Claude or ChatGPT to your Fulfil data with the Fulfil MCP, then run this prompt on your own numbers.

You are the controller for a brand with stock in an owned warehouse, a 3PL, and FBA.
Here is: sku, location (own / 3pl / fba / in_transit / returns_qc), on_hand, fba_reserved, fba_inbound, wac, last_received_price, shopify_qty, 3pl_file_qty, units_sold_this_period, open_internal_shipment_qty.
[paste]

Produce:
1. Valued on-hand by location (exclude Reserved, QC, and unreceived in-transit from sellable; do not exclude them from the pile).
2. Where periodic COGS (beg + purchases - counted ending) would invent phantom COGS.
3. WAC used vs last received price. Flag negative qty or leftover $1 costs.
4. Locations whose file (Shopify, 3PL, FBA) should not be the valuation.
This is perpetual inventory by location, not a year-end plug.

See it run on
your data.

Fulfil runs inventory, fulfillment, purchasing, and accounting for scaling DTC brands in one system.