Revenue By Location Report

Read-only: breaks down revenue by fulfillment location for multi-warehouse P&L and location performance.

shopify-admin-revenue-by-location-report


Purpose

Attributes order revenue to the fulfillment location that shipped the order. Produces a revenue breakdown by warehouse or fulfillment center, useful for multi-location P&L, location staffing decisions, and understanding where demand is being fulfilled from. Read-only — no mutations.


Prerequisites

  • Authenticated Shopify CLI session: shopify store auth --store --scopes read_orders
  • API scopes: read_orders

  • Parameters


    ParameterTypeRequiredDefaultDescription
    storestringyesStore domain (e.g., mystore.myshopify.com)
    days_backintegerno30Lookback window
    formatstringnohumanOutput format: human or json

    Safety


    > ℹ️ Read-only skill — no mutations are executed. Safe to run at any time.


    Workflow Steps


  • OPERATION: locations — query
  • Inputs: first: 50, active only

    Expected output: Location IDs and names for enrichment


  • OPERATION: orders — query
  • Inputs: query: "fulfillment_status:shipped created_at:>=''", first: 250, select fulfillments { assignedLocation }, totalPriceSet, pagination cursor

    Expected output: Fulfilled orders with location attribution


  • OPERATION: fulfillmentOrders — query (for open orders attribution)
  • Inputs: Per location, status: CLOSED, first: 250

    Expected output: Closed fulfillment orders for revenue attribution


  • Aggregate revenue by location; orders without location data attributed to "Unknown"

  • GraphQL Operations


    # locations:query — validated against api_version 2025-01
    query LocationsList {
      locations(first: 50, includeInactive: false) {
        edges {
          node {
            id
            name
          }
        }
      }
    }
    

    # orders:query — validated against api_version 2025-01
    query RevenueByLocation($query: String!, $after: String) {
      orders(first: 250, after: $after, query: $query) {
        edges {
          node {
            id
            name
            createdAt
            totalPriceSet {
              shopMoney {
                amount
                currencyCode
              }
            }
            fulfillments {
              assignedLocation {
                location {
                  id
                  name
                }
              }
              status
            }
          }
        }
        pageInfo {
          hasNextPage
          endCursor
        }
      }
    }
    

    # fulfillmentOrders:query — validated against api_version 2025-01
    query ClosedFulfillmentOrders($locationId: ID!, $after: String) {
      fulfillmentOrders(
        assignedLocationId: $locationId
        first: 250
        after: $after
        query: "status:closed"
      ) {
        edges {
          node {
            id
            order {
              id
              name
              totalPriceSet {
                shopMoney {
                  amount
                  currencyCode
                }
              }
            }
          }
        }
        pageInfo {
          hasNextPage
          endCursor
        }
      }
    }
    

    Session Tracking


    Claude MUST emit the following output at each stage. This is mandatory.


    On start, emit:

    ╔══════════════════════════════════════════════╗
    ║  SKILL: Revenue by Location Report           ║
    ║  Store: <store domain>                       ║
    ║  Started: <YYYY-MM-DD HH:MM UTC>             ║
    ╚══════════════════════════════════════════════╝
    

    After each step, emit:

    [N/TOTAL] <QUERY|MUTATION>  <OperationName>
              → Params: <brief summary of key inputs>
              → Result: <count or outcome>
    

    On completion, emit:


    For format: human (default):

    ══════════════════════════════════════════════
    REVENUE BY LOCATION  (<days_back> days)
      Total revenue:   $<amount>
      Orders included: <n>
    
      Location                Orders   Revenue    Share
      ─────────────────────────────────────────────────
      Warehouse A             <n>      $<n>       <pct>%
      Warehouse B             <n>      $<n>       <pct>%
      Output: revenue_by_location_<date>.csv
    ══════════════════════════════════════════════
    

    For format: json, emit:

    {
      "skill": "revenue-by-location-report",
      "store": "<domain>",
      "period_days": 30,
      "total_revenue": 0,
      "currency": "USD",
      "by_location": [],
      "output_file": "revenue_by_location_<date>.csv"
    }
    

    Output Format

    CSV file revenue_by_location_.csv with columns:

    location_id, location_name, order_count, total_revenue, currency, share_pct


    Error Handling

    ErrorCauseRecovery
    THROTTLEDAPI rate limit exceededWait 2 seconds, retry up to 3 times
    Order with no fulfillment locationUnfulfilled or POS orderAttribute to "Unassigned"
    Single-location storeAll revenue from one locationReport still valid, shows full total

    Best Practices

  • For multi-3PL operations, this report helps identify if one 3PL is handling a disproportionate share and may need capacity relief.
  • Revenue attribution here is based on fulfillment assignment, not customer shipping address — it reflects operational throughput per location, not geographic demand.
  • Pair with the inventory valuation report to calculate inventory turns per location (revenue / inventory value).