Custom Fields

Custom Fields

Overview

Custom fields allow you to extend Finale collections with account-specific data fields that suit your unique business needs. Unlike standard fields that are the same for all Finale accounts, custom fields are user-defined and can vary from one account to another.

Each custom field is exposed in the GraphQL API with a field name like user10000, user10001, etc. The field name itself doesn't indicate what the field represents—one account might use user10000 for "Product Color" while another uses it for "Vendor SKU". This makes custom fields flexible but requires using the dataSetMeta query to discover what each field represents in your specific account.

Custom fields are available on multiple collection types including products, orders, invoices, shipments, returns, journal entries, and payments. The specific custom fields configured for each collection type can differ based on your account's customization settings.

Discovering Custom Fields

To find which custom fields are available in your account and what they represent, use the dataSetMeta query. This query returns metadata about each field including its label, data type, and status.

Example: Discovering Product Custom Fields

query {
  dataSetMeta(purpose: "graphql") {
    dataSets(name: "product") {
      fields {
        name
        label
        dataType
        enabled
      }
    }
  }
}

Example Response

{
  "data": {
    "dataSetMeta": {
      "dataSets": [
        {
          "fields": [
            {
              "name": "user10000",
              "label": "Product Color",
              "dataType": "string",
              "enabled": true
            },
            {
              "name": "user10001",
              "label": "Vendor SKU",
              "dataType": "string",
              "enabled": true
            },
            {
              "name": "user10002",
              "label": "Last Inspection Date",
              "dataType": "date",
              "enabled": true
            }
          ]
        }
      ]
    }
  }
}

From this response, you can see that:

  • user10000 represents "Product Color"
  • user10001 represents "Vendor SKU"
  • user10002 represents "Last Inspection Date" and is a date field

Filtering the Results

Since the dataSetMeta query returns all fields (standard and custom), you can identify custom fields by looking for field names that match the pattern user##### where ##### is a five-digit number.

You can also filter to only active custom fields by checking enabled: true in the response.

Querying Custom Fields

Once you know which custom fields exist in your account, you can query them like any other field.

Basic Custom Field Query

query {
  product(first: 10) {
    edges {
      node {
        productId
        description
        user10000  # Product Color
        user10001  # Vendor SKU
        user10002  # Last Inspection Date
      }
    }
  }
}

Example Response

{
  "data": {
    "product": {
      "edges": [
        {
          "node": {
            "productId": "WIDGET-100",
            "description": "Premium Widget",
            "user10000": "Blue",
            "user10001": "VND-12345",
            "user10002": "2024-01-15"
          }
        }
      ]
    }
  }
}

Using Formatting Options

Custom fields support the standard formatter and timezone parameters:

query {
  product(first: 10) {
    edges {
      node {
        productId
        user10002(
          formatter: "date"
          timezone: "America/Los_Angeles"
        )
      }
    }
  }
}

Filtering by Custom Fields

Custom fields can be used as filter parameters in your queries, allowing you to find records based on custom field values.

Filtering by Text Custom Fields

Text-based custom fields appear as list parameters in filters:

query {
  product(
    first: 10
    user10000: ["Blue", "Red"]  # Filter by Product Color
  ) {
    edges {
      node {
        productId
        user10000
      }
    }
  }
}

Filtering by Date Custom Fields

Date-based custom fields use date range filters:

query {
  product(
    first: 10
    user10002: {  # Last Inspection Date
      start: "2024-01-01"
      end: "2024-12-31"
    }
  ) {
    edges {
      node {
        productId
        user10002
      }
    }
  }
}

Combining Custom Field Filters

You can filter by multiple custom fields simultaneously:

query {
  product(
    first: 10
    user10000: ["Blue"]         # Color is Blue
    user10001: ["VND-12345"]    # Specific vendor SKU
  ) {
    edges {
      node {
        productId
        user10000
        user10001
      }
    }
  }
}

Data Types

Custom fields support several data types, though they all appear as String type in the GraphQL schema. The underlying data type determines how the field should be formatted and filtered.

String Fields

Most custom fields are text fields with a 255 character limit:

{
  product(first: 5) {
    edges {
      node {
        user10000  # Returns: "Blue"
        user10001  # Returns: "VND-12345"
      }
    }
  }
}

Date Fields

Date custom fields store date values and support date range filtering:

{
  product(
    first: 5
    user10002: { start: "2024-01-01", end: "2024-12-31" }
  ) {
    edges {
      node {
        user10002  # Returns: "2024-03-15"
      }
    }
  }
}

Picklist Fields

Picklist custom fields have a predefined set of valid values. Use dataSetMeta to discover the available options:

query {
  dataSetMeta(purpose: "graphql") {
    dataSets(name: "product") {
      fields {
        name
        label
        optionList {
          value
          label
        }
      }
    }
  }
}

Example response for a picklist field:

{
  "name": "user10003",
  "label": "Priority Level",
  "optionList": [
    { "value": "HIGH", "label": "High" },
    { "value": "MEDIUM", "label": "Medium" },
    { "value": "LOW", "label": "Low" }
  ]
}

Query using picklist values:

{
  product(
    first: 10
    user10003: ["HIGH", "MEDIUM"]
  ) {
    edges {
      node {
        productId
        user10003  # Returns: "HIGH" or "MEDIUM"
      }
    }
  }
}

Numeric Fields

Numeric custom fields store numbers but are returned as strings:

{
  product(first: 5) {
    edges {
      node {
        user10004  # Returns: "42.5" (as string)
      }
    }
  }
}

Supported Collections

Custom fields are available on the following collections:

Product

Product custom fields apply to all products (type: GOOD):

{
  product(first: 5) {
    edges {
      node {
        productId
        user10000
        user10001
      }
    }
  }
}

Order

Order custom fields vary by order type (Sales Orders, Purchase Orders, Transfer Orders). Each order type can have its own set of custom fields:

{
  order(first: 5, orderTypeId: ["SALES_ORDER"]) {
    edges {
      node {
        orderId
        user10000  # Sales Order specific field
      }
    }
  }
}

Invoice

Invoice custom fields vary by invoice type (Sales Invoices, Purchase Invoices, Supplier Credits):

{
  invoice(first: 5, invoiceTypeId: ["SALES_INVOICE"]) {
    edges {
      node {
        invoiceId
        user10000  # Sales Invoice specific field
      }
    }
  }
}

Shipment

Shipment custom fields apply to shipment records:

{
  shipment(first: 5) {
    edges {
      node {
        shipmentId
        user10000
      }
    }
  }
}

Return

Return custom fields apply to return transactions:

{
  return(first: 5) {
    edges {
      node {
        returnId
        user10000
      }
    }
  }
}

Journal Entry

Journal Entry custom fields vary by journal entry type (regular entries, average cost changes):

{
  journalEntry(first: 5, journalEntryTypeId: ["JOURNAL_ENTRY"]) {
    edges {
      node {
        journalEntryId
        user10000
      }
    }
  }
}

Payment

Payment custom fields vary by payment type (Sales Payments, Purchase Payments):

{
  payment(first: 5, paymentTypeId: ["SALES_PAYMENT"]) {
    edges {
      node {
        paymentId
        user10000
      }
    }
  }
}

Practical Example: Complete Workflow

Here's a complete example showing how to discover and use custom fields:

Step 1: Discover Available Custom Fields

query DiscoverCustomFields {
  dataSetMeta(purpose: "graphql") {
    dataSets(name: "product") {
      fields {
        name
        label
        dataType
        enabled
      }
    }
  }
}

Step 2: Query Products with Custom Fields

Based on the discovery, query the relevant custom fields:

query ProductsWithCustomFields {
  product(
    first: 20
    user10000: ["Blue", "Red"]  # Filter by Color
  ) {
    edges {
      node {
        productId
        description
        user10000  # Color
        user10001  # Vendor SKU
        user10002  # Last Inspection Date
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

Step 3: Query Specific Products by Custom Field

query FindProductByVendorSku {
  product(
    first: 1
    user10001: ["VND-12345"]  # Vendor SKU
  ) {
    edges {
      node {
        productId
        description
        user10001
        stockQuantityOnHand
      }
    }
  }
}

Limitations and Best Practices

Character Limits

Text-based custom fields have a maximum length of 255 characters. Values exceeding this limit will be truncated.

Active vs Inactive Fields

Custom fields can be marked as active or inactive in your account configuration. Inactive fields may still appear in the API but will have enabled: false in the dataSetMeta response. It's recommended to only query active fields.

Performance Considerations

Custom fields are stored differently than standard fields and may have different performance characteristics. When querying large datasets:

  • Only request custom fields you actually need
  • Use filtering to reduce result set size
  • Consider pagination for large results

Field Name Stability

The user##### field names are stable for a given account—once a custom field is created with a specific number, that number won't change. However, the labels and configurations can be modified, so use dataSetMeta to stay in sync with current field configurations.

Type-Specific Fields

For collections with multiple types (orders, invoices, journal entries, payments), remember that custom fields may be specific to certain types. Always filter by the appropriate type when querying type-specific custom fields.

Discovering Changes

Run the dataSetMeta query periodically or when custom field configurations may have changed to ensure your application stays synchronized with the current field definitions. This is particularly important if:

  • New custom fields are added to your account
  • Custom field labels are updated
  • Custom field data types are changed
  • Picklist options are modified

Field Naming Convention

Always use dataSetMeta to map between user##### field names and their human-readable labels. Never hardcode assumptions about what a specific user##### field represents, as this varies by account.