# Product Lookup

## Overview  
Product Lookups provide alternative identifiers for products, enabling the same product to be referenced by multiple codes. This is essential when integrating with marketplaces, handling barcodes, or managing multi-pack configurations where one identifier needs to map to a different product or quantity.

The primary use case is marketplace integration. Different sales channels often use different SKUs for the same physical product. Amazon might use one SKU, eBay another, and Shopify yet another. Product Lookups let you map all these external identifiers back to a single product in Finale, so when an order comes in from any channel, the system knows exactly which product to pick and ship.

Multi-pack support is another critical function. You might sell a 3-pack version of a product with its own SKU. A Product Lookup can map that 3-pack SKU to the single-unit product with a packing factor of "3/1", so when someone orders one 3-pack, the system automatically knows to allocate 3 units of the base product. This eliminates the need to maintain separate product records for every pack size variation.

Barcode scanning in warehouse operations relies heavily on Product Lookups. When receiving shipments, picking orders, or conducting cycle counts, workers scan barcodes that may not match your internal SKU. Product Lookups translate those scanned codes into the correct product, ensuring accuracy throughout the fulfillment process.

Each Product Lookup can be marked as active or inactive, and can specify a packing factor that controls quantity conversions. Some lookups are designated as "Finale short codes" - simplified codes used internally for quick product identification. The type field distinguishes between regular lookups and these special short codes, helping warehouse staff work more efficiently.

---

### GraphQL API  
The `productLookup` collection provides access to productLookup data via the GraphQL API. All queries use the Relay connection specification with cursor-based pagination.

**Query Name:**`productLookupViewConnection`

**Available Features:**

- Cursor-based pagination (first/last/after/before)
- 3 filter options
- 9 sortable fields
- 1 relations to other collections

## Query Examples

### Basic Query  
The `productLookup` collection is accessed via the `productLookupViewConnection` query, which returns a Relay-style connection with pagination support.

```graphql
query {
  productLookupViewConnection(first: 10) {
    edges {
      node {
        lotId
        lotIdUnprefixed
        notes
        packing
        productLookup
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

### Pagination  
Use cursor-based pagination to retrieve large datasets:

```graphql
# First page
query {
  productLookupViewConnection(first: 50) {
    edges {
      node { lotId }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

# Subsequent pages
query {
  productLookupViewConnection(first: 50, after: "cursor-from-previous-page") {
    edges {
      node { lotId }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}
```

### Filtering  
Apply filters to narrow results:

```graphql
query {
  productLookupViewConnection(
    first: 10
    productUrl: "/finaleengineer/api/product/100000"
  ) {
    edges {
      node { lotId }
    }
  }
}
```

### Sorting  
Sort results by one or more fields:

```graphql
query {
  productLookupViewConnection(
    first: 10
    sort: [{ field: "lotId", mode: "desc" }]
  ) {
    edges {
      node {
        lotId
              }
    }
  }
}
```

### Relations  
Query related data:

```graphql
query {
  productLookupViewConnection(first: 10) {
    edges {
      node {
        lotId
        product {
          title
          productUrl
        }
      }
    }
  }
}
```

## Summary and Aggregation  
This collection supports metrics aggregation through the `summary` field. You can calculate totals, averages, counts, and other aggregate values across filtered data.

**Note:** This collection does not support groupBy dimensions. For dimensional analysis, use collections like product, order, or invoice.

### Query Structure  
```graphql
productLookupViewConnection(filters...) {
  summary {
    errorCode
    errorMessage
    metrics {
      # Calculated metrics (see table below)
    }
  }
}
```

### Available Metrics  
This collection provides 1 metric that can be aggregated:

| Metric | Parameters | Description |
| --- | --- | --- |
| `count` | None | Count of items in the result set |

**Common Parameters:**

- `operator` - Aggregation function: `sum`, `mean`, `min`, `max`
- `transform` - Mathematical transformation: `abs`
- `dateRange` - Filter to specific date range
- `facilityUrlList` - Filter to specific facilities

### Examples  
#### Example 1: Total productLookup Metrics  
Calculate aggregate metrics across all productLookup records:

```graphql
query {
  productLookupViewConnection(first: 1) {
    summary {
      errorCode
      errorMessage
      metrics {
        totalCount: count
      }
    }
  }
}
```

Expected result structure:

```json
{
  "data": {
    "productLookupViewConnection": {
      "summary": {
        "errorCode": null,
        "errorMessage": null,
        "metrics": {
          "totalCount": [1523]
        }
      }
    }
  }
}
```

## Fields  
This collection has 9 fields:

- 7 simple fields
- 2 enum fields (with predefined values)
- 0 parameterized fields (accept query options)

### Simple Fields  
These fields return values directly without additional options.

#### `lotId`  
An optional identifier used to track specific batches or lots of inventory for products that require lot tracking. The lot ID allows businesses to distinguish between different production runs, manufacturing dates, or expiration batches of the same product. This field is particularly useful for perishable goods, pharmaceuticals, or any products requiring traceability.

When populated, the lot ID becomes part of the product's inventory short code (a system-generated lookup value) along with the product URL and normalized packing string. This three-part combination creates a unique identifier that can be scanned or referenced throughout inventory operations including receiving shipments, building products, transferring inventory, and conducting physical inventory counts.

**Label:** Lot ID

**Sortable:** Yes

---

#### `lotIdUnprefixed`  
The lot ID for this product lookup, formatted without the "Lot: " prefix. This field returns the same underlying lot ID value as the `lotId` field but strips the display prefix from the formatted output.

Lot IDs can be stored in three formats:

- **L_** prefix: Text-based lot IDs (e.g., "L_123" displays as "123" instead of "Lot: 123")
- **M** prefix: Manufacturing date format (e.g., "M20120512_A" displays as "Mfg: 5/12/2012 A" with the prefix, or "5/12/2012 A" without)
- **E** prefix: Expiration date format (e.g., "E20120512_B" displays as "Exp: 5/12/2012 B" with the prefix, or "5/12/2012 B" without)

This unprefixed version is primarily used when the lot ID needs to be stored or compared in its raw numeric or text form without the descriptive label, such as when populating form fields or when the context already indicates that the value is a lot ID. Query it using `lotIdUnprefixed(formatter: "none")` to get the unformatted value suitable for data processing.

**Label:** Lot ID unprefixed

**Sortable:** Yes

---

#### `notes`  
A text field for storing optional comments about the product lookup. For regular product lookups (scan type "UNSPECIFIED_TEXT"), this field can contain user-entered notes describing the lookup entry, such as "The red blaster" or other descriptive information. For Finale-generated short codes (scan type "INVENTORY_SHORT_CODE"), this field automatically displays "Finale short code" and cannot be edited by users. The field accepts up to 255 characters of Unicode text and can be imported when creating product lookups.

**Label:** Notes

**Sortable:** Yes

---

#### `packing`  
The packing format for this product lookup, stored as a normalized packing string that specifies how many units come in a case. The format is typically "X cs Y/Z" where X is the number of units per case, Y is the case quantity, and Z represents the inner pack configuration (e.g., "12 cs 12/1" means 12 units per case with a 12/1 configuration, or "6 cs 6/1" for 6 units per case).

This field is used to calculate total units when processing quantities in cases. For example, if a quantity is 2 cases with packing "12 cs 12/1", the total units would be 24. The system uses this to convert between case quantities and individual unit quantities throughout inventory, ordering, and shipping operations.

When the packing field is empty or null, it defaults to open stock (treated as 1 unit per case). The packing information can be parsed from user input formats like "12/1" or "6 cs 6/1" and is displayed in formatted strings for UI presentation. The packingUnits value derived from this field represents the unitsPerCase and is used in calculations for stock levels, order quantities, and pricing conversions.

**Label:** Packing

**Sortable:** Yes

---

#### `productLookup`  
A scannable identifier (such as a barcode, UPC, SKU, or other scan key) that can be used to look up a product. Product lookups are stored in the scan lookup collection and link products to various identifiers that can be scanned or entered to reference them. Each product lookup includes the scan key itself, optional packing information (units per case), and a status (Active/Inactive). Product lookups enable products to be identified through multiple different codes or barcodes, facilitating barcode scanning during inventory management, order fulfillment, and sales operations. When importing products from external systems, product lookups can be configured to import automatically or be suppressed using the ##noimport flag.

**Label:** Product lookup

**Sortable:** Yes

---

#### `productLookupUrl`  
The unique identifier for a product lookup record in the system. This field is automatically generated by the server and serves as the primary key for the productLookup collection, used throughout the system to reference specific product lookup entries.

Product lookup URLs are used to link scan keys (alternative product identifiers like barcodes, UPCs, or short codes) to products. When querying product lookup data, this URL can be passed as a parameter to retrieve specific lookup records, as demonstrated in GraphQL queries where `productLookupUrl` is used as a query argument to fetch individual product lookup details.

**Label:** scan lookup internal url

**Sortable:** Yes

---

#### `warning`  
A validation indicator that displays when the product lookup contains formatting issues that may prevent successful matching during integration syncs. The warning appears when the scan key contains leading or trailing whitespace, consecutive spaces, or non-standard whitespace characters like tabs. These formatting issues can cause the product lookup to fail matching against SKUs or product IDs being synced from external systems. When a product lookup has such issues, the warning displays as "Invalid space or character" to alert users to correct the formatting for reliable integration matching.

**Label:** Warning

**Sortable:** Yes

---

### Enum Fields  
These fields return one of a predefined set of values.

#### `status`  
Indicates whether the product lookup is currently active or inactive in the system. This field has two possible values: "Active" (internal value "SCAN_LOOKUP_ACTIVE") for product lookups that are currently in use, and "Inactive" (internal value "SCAN_LOOKUP_INACTIVE") for product lookups that have been deactivated. When a product lookup is marked as inactive, it cannot be edited or used in operations, effectively removing it from active use while preserving the historical record. This status is used to filter product lookups in queries and determines whether the lookup appears in lists and can be selected for new transactions. The status field is editable for regular product lookups but follows the same editability rules as other fields in the product lookup record.

**Label:** Status

**Sortable:** Yes

**Possible Values:**

- `SCAN_LOOKUP_ACTIVE` - Active
- `SCAN_LOOKUP_INACTIVE` - Inactive

---

#### `type`  
Indicates whether the product lookup is a regular scan key or a Finale-generated short code. This field has two possible values: "Regular" (corresponding to the internal value "UNSPECIFIED_TEXT") for user-created product lookups such as barcodes, UPCs, or custom SKUs, and "Finale short code" (internal value "INVENTORY_SHORT_CODE") for system-generated short codes that uniquely identify a product combined with specific packing and lot information. Short codes are automatically created by Finale to provide quick reference identifiers for product-packing-lot combinations and cannot be deleted or edited by users. When filtering or importing product lookups, this type distinction determines whether the entry represents a manually managed scan key or a system-managed identifier.

**Label:** Type

**Sortable:** Yes

**Possible Values:**

- `INVENTORY_SHORT_CODE` - Finale short code
- `UNSPECIFIED_TEXT` - Regular

## Relations  
### product  
- **Related Collection:** [product](https://developer.finaleinventory.com/reference/graphql-product)
- **Label:** Product

**Example Query:**

```graphql
query {
  productLookupViewConnection(first: 10) {
    edges {
      node {
        product {
          title
          productUrl
        }
      }
    }
  }
}
```

## Filters  
### productUrl  
- **Label:** Product
- **Type:** List|ProductUrlString
- **Enabled:** Yes

**Filter Type:** Reference to `product` collection

### status  
- **Label:** Status
- **Type:** List|String
- **Enabled:** Yes
- **Options:**
  - Active (SCAN_LOOKUP_ACTIVE)
  - Inactive (SCAN_LOOKUP_INACTIVE)

### type  
- **Label:** Type
- **Type:** List|String
- **Enabled:** Yes
- **Options:**
  - Finale short code (INVENTORY_SHORT_CODE)
  - Regular (UNSPECIFIED_TEXT)
