Alfred Purchase Orders

Review Inventory Transfers

Review Inventory Transfers is an audit-grade report that lists every native Shopify inventory transfer in your store. It pulls live from Shopify so transfers created in Shopify Admin, by other apps, and by Alfred all appear together. Each row aggregates total products, units, and historical inventory cost; expanding any row shows per-product detail with the unit cost we used and how the line total was computed. The report is designed for periodic review, end-of-month reconciliation, accounting handoff, and audit support — so the cost logic is documented in full below and the CSV export is structured for spreadsheet and accounting workflows.

What You Can Do

Audit All Transfers

Native Shopify data, not just Alfred's

Every inventory transfer in your Shopify store appears, regardless of who created it. Alfred-created transfers get a small badge with a click-through to the in-app detail page; transfers created in Shopify Admin or by other apps show up alongside, with the same fields.

Best for: Periodic catch-up reviews, internal audits, year-end reconciliation.

Row-Level Cost Detail

Per-product, per-line

Click any transfer row to expand it. The expanded view lists every line item with product/variant title, SKU, units, the unit cost Alfred used, and the resulting line cost. The unit cost is the historical cost effective at the transfer's creation date — see the Cost Calculation section below for the full lookup chain.

Best for: Verifying cost figures before exporting to accounting; spot-checking a single transfer; resolving 'why is this number what it is.'

Key Concepts

What Is This Report?

Review Inventory Transfers is a read-only window into Shopify's native InventoryTransfer records, decorated with Alfred-side metadata (historical cost, local-session linkage). It does NOT create, modify, ship, or cancel transfers — those flows live in the Transfer Between Locations and Stock Transfer detail pages. The intent here is reporting and audit: see what happened, when, where, and what it was worth.

Where the Data Comes From

Every fetch hits Shopify's Admin GraphQL API live (cached server-side for 5 minutes per filter combination so repeat loads of the same view are instant). The base transfer record — name, ID, reference, dates, origin/destination, status, shipment receive dates — comes straight from Shopify. Line items and their unit costs are hydrated from Alfred's local database using the cost-history chain described below. Because the source of truth is Shopify itself, transfers created or modified outside Alfred appear without any sync delay (you'll see them the next time you load the report).

How Inventory Cost Is Calculated — Full Logic

Cost matters for taxes and accounting, so the full lookup chain is documented here. For each line item in each transfer, Alfred resolves a unit cost using this priority order: (1) the most recent ProductCostHistory row for that variant in your shop whose effective date is on or before the transfer's creation date with a non-null cost — this captures the cost that was in force WHEN THE TRANSFER WAS CREATED (e.g. if you imported a PO with $5/unit cost on May 1 and a new PO with $5.50/unit on June 1, a transfer created May 15 uses $5, while a transfer created June 5 uses $5.50); (2) if no historical cost row predates the transfer, the variant's current ProductInventory.unitCost (typically populated from Shopify's per-variant cost field on the most recent inventory sync); (3) if both are null, the unit cost is left blank ('—' on screen, empty in CSV). The LINE COST is then unit_cost × line quantity (totalQuantity from Shopify). The TRANSFER TOTAL COST is the sum of all line costs whose unit_cost is non-null. The number of transfers where every line was non-null vs. where some lines had to be left out is summarized in the Total Cost card under the table — when transfers are fully excluded from the cost total (no unit cost on any line), the card surfaces an explicit 'N transfers excluded (no cost data)' subline.

Cost Tie-Break Rules

If your ProductCostHistory contains multiple rows for the same variant at the same effective date (common when a single PO is received in two shipments on the same day), Alfred resolves the tie deterministically: most recent effective date wins; within the same date, most recent createdAt timestamp wins. The result is stable across reloads — refreshing the report will not flip a transfer's cost back and forth between two same-date entries.

What 'Inventory Cost' Includes — and What It Doesn't

The cost figure here is the per-unit MERCHANDISE cost at the time of the transfer — typically your unit cost from a purchase order or your Shopify variant cost field. It does NOT automatically include: shipping & freight (only included if you've allocated it into your ProductCostHistory via a landed-cost PO close), import duties or customs fees (same — only if allocated), taxes (sales tax, VAT, etc.), or any operational costs (labor, packaging, warehousing). If you need a true LANDED cost for accounting, make sure your purchase orders allocate shipping/customs into ProductCostHistory at close time — Alfred's PO close flow does this when you enable the allocation fields. For transfers themselves, no additional cost is added: this report shows the merchandise value of units that moved, not the cost of the movement.

Currency

All monetary values render in your display currency. Alfred resolves the currency in this order: (1) Configurations → Store Settings → 'Default display currency' if you've set an explicit override; (2) your Shopify shop's selling currency (read live from Shopify when no override is set); (3) USD as a last resort. The CSV export includes a currency_code column on every row so the file is self-describing — open it next year and you'll know exactly which currency the numbers were in. Per-PO and per-supplier currency fields (on Purchase Orders and Supplier detail pages) are separate and continue to display in their own transactional currency — those represent actual purchase amounts in the original transaction currency, not display preference.

Date Filter — Latest Activity vs Created Date

The date range filter has a toggle: 'Latest activity' (default) or 'Created date'. Latest activity sorts and filters by the most recent receive date across the transfer's shipments — i.e. when units actually moved. For transfers with no shipments received yet (drafts, just-created), the filter falls back to the transfer's creation date because creation IS an activity. Created date filters strictly by the transfer's creation timestamp regardless of receive status. Use Latest activity for 'what happened this month' reviews and reconciliation; use Created date when you want to see transfers initiated in a specific window regardless of whether they've shipped yet.

Completed Column Semantics

The Completed column shows the literal latest receive date — max(shipment.dateReceived) across all of the transfer's shipments. It's blank (—) for transfers that have not had any shipment received. This is intentionally STRICTER than the Latest activity filter: the column is a fact about the transfer ('when was the last unit received'), while the filter is a navigational convenience ('show me transfers that have had activity in this window, including new ones'). The two definitions are different on purpose — both are useful.

Summary Totals Scope

The four summary cards above the table — Transfers, Unique products, Total units, Total cost — reflect the CURRENTLY-LOADED rows that match your filters. When you click 'Load more transfers,' the totals update to include the additional page. The cost total sums all rows where the transfer has a computable total; rows where every line was missing cost data are counted in the 'N transfers excluded' subline beneath the total. Unique products is a distinct count of variantIDs across all expanded line items in the loaded set.

Alfred-Created Transfers

Transfers that Alfred created (via Transfer Between Locations or Balance Stock) carry an 'alfred' tag in Shopify and are matched in the report by their Shopify transfer ID against Alfred's local InventorySession records. When a match is found you'll see a small 'Alfred' badge on the row and the Alfred-side session name shown as a clickable link beneath the Shopify name. Clicking it takes you to the Alfred transfer detail page, where the back button returns you to this report with your filters preserved.

Search Scope

The search field matches against transfer name, transfer ID, reference field, origin location name, and destination location name. It uses Shopify's native search syntax server-side, so partial matches and case-insensitivity work as expected. Product name and SKU search across line items is NOT in the search field today — to find transfers containing a specific SKU, expand transfers individually or use the CSV export and grep the result. (Line-item search across the report is on the future roadmap; the current scope reflects what Shopify's transfer search supports out of the box.)

CSV Export

The 'Export to CSV' button writes a UTF-8 file with a BOM (for Excel and Numbers compatibility), CRLF line endings, and RFC 4180-compliant quoting. The structure is DENORMALIZED — one row per LINE ITEM, with the parent transfer's context columns repeated on each line. Transfer-level totals (total products, total units, total cost) appear ONLY on the first line of each transfer; subsequent lines for the same transfer leave those three columns blank so pivot-table SUMs don't double-count multi-line transfers. Every row carries a currency_code column so the file is unambiguous. The export reflects whatever's currently visible after your filters and Load-more clicks — not all transfers in your store. Cost figures are emitted as raw decimal numbers (e.g. 12.50, not '$12.50') so spreadsheet math, pivots, and accounting imports work as expected.

Performance and Pagination

The report loads 25 transfers at a time. On first load for a given filter set, Alfred fetches the transfer list from Shopify and then eagerly hydrates per-line cost data for all 25 — this takes 3–5 seconds for a typical page. Subsequent loads of the same filter combination are served from a 5-minute cache and feel instant. Click 'Load more transfers' to append the next 25; eager hydration repeats for the new page only. Date range is capped at 93 days to keep cost computation bounded and the report responsive.

How to Use

1

1. Open the Report

From the Inventory Transfers landing page (Alfred Purchase Orders → Inventory Transfers), click the 'Review Inventory Transfers' card. The report opens with the default filter applied (last 30 days, Latest activity mode, no location or status filters).

2

2. Narrow the View with Filters

Pick a date range using the date picker (presets include Last 7/14/30/60/90 days, Week-to-date, Month-to-date, Quarter-to-date, and prior periods). Toggle Latest activity vs Created date depending on whether you're auditing what HAS happened or what was scheduled. Open Origin and Destination dropdowns to multi-select specific locations. Use Status to filter to Draft, Ready to ship, In progress, Transferred, Cancelled, or Other. Type into the search field for a transfer name, ID, reference, or location.

3

3. Glance at the Summary Cards

Above the table, four cards show Transfers, Unique products, Total units, and Total cost — all in your selected currency. Use these for a quick sanity check before drilling into rows: 'Did I expect 12 transfers this period? Does $48K total inventory cost seem right?' If the total cost card flags 'N transfers excluded (no cost data),' those transfers had no resolvable unit cost on any line — investigate them individually if accuracy matters for your downstream use.

4

4. Drill Into Specific Transfers

Click any row to expand it. The expanded view lists every line item with product/variant title, SKU, units, unit cost, and line cost. Verify cost figures against your accounting records here. If something looks off, the Cost Calculation logic in this page documents exactly which ProductCostHistory or ProductInventory value was used.

6

6. Sort by Any Column

Click any column header to sort by that column (ascending on first click, descending on second). Common sorts: by Total cost descending to find your highest-value transfers; by Completed ascending to find the oldest-received transfers in your window; by Origin or Destination alphabetically to group by location.

7

7. Load More if Needed

If your filter range surfaces more than 25 transfers, a 'Load more transfers' button appears at the bottom of the table. Click it to fetch the next 25 (and eagerly compute their costs). The summary totals at the top of the page update to include the additional rows.

8

8. Export to CSV for Accounting

Click 'Export to CSV' in the top right. A CSV file downloads with one row per line item, parent transfer context repeated, transfer-level totals on the first line of each transfer, and a currency_code column on every row. Open it in Excel, Numbers, Google Sheets, or hand it off to your accountant — the format is designed for downstream pivot tables, lookups, and accounting imports.

Tips & Best Practices

  • Set your display currency in Configurations → Store Settings before exporting CSVs for accounting — the currency_code column will reflect that choice and the figures in the file will match what you saw on screen.
  • If a transfer's Total cost is showing '—' or excluded from the summary, expand the row: every line will show unit cost as '—' too. The fix is usually to set a unit cost on the variant in Shopify or to import a PO that records the cost — then future transfers will have data.
  • Use Created date mode (not Latest activity) when reconciling against PO close dates — both reference the moment the transfer record was created, which usually aligns with the PO closure window in your accounting system.
  • Save shareable links to specific filter views by copying the URL after applying filters. Send a teammate a link with the date range, locations, and status pre-set so they're looking at the same data you are.
  • If you create many transfers in Shopify Admin (not Alfred) and want them quickly visible here, no sync is required — Alfred reads Shopify live for this report. Refresh the page to pick up brand-new transfers (within the 5-minute server cache window).
  • For year-end reconciliation, run two exports: one for the calendar year in Latest activity mode (what was received) and one in Created date mode (what was committed). Compare totals to identify carry-over transfers — transfers created in the prior period but received in the new one.
  • If your shop has historical cost data in another system (e.g. an ERP), import it into ProductCostHistory before relying on this report for tax filings. Alfred uses ProductCostHistory as the primary source for historical-at-transfer-date costing.

Frequently Asked Questions