Class: Edi::Wayfair::TaxonomyAttributeRetriever

Inherits:
BaseEdiService show all
Includes:
CatalogApiTransport
Defined in:
app/services/edi/wayfair/taxonomy_attribute_retriever.rb

Overview

Retrieves taxonomy attributes from Wayfair's Product Catalog API
Uses the attributesByFilter GraphQL query to get attribute definitions
for a specific taxonomy category.

These attributes define what product data can be updated via
the updateMarketSpecificCatalogItems mutation.

API Documentation: https://developer.wayfair.io/posts/docs/product-catalog-update-api/reference/GraphQL/v1.0.0

Constant Summary collapse

CATALOG_API_URL =

Product Catalog API endpoint (different from Supplier Catalog API)

'https://api.wayfair.io/v1/product-catalog-api/graphql'
SANDBOX_CATALOG_API_URL =

URL for sandbox catalog api.

'https://api.wayfair.io/sandbox/v1/product-catalog-api/graphql'
ATTRIBUTES_BY_FILTER_QUERY =

GraphQL query to retrieve taxonomy attributes for a category (class).
Selection verified against the live sandbox schema 2026-06-12: the input
field is classId (the API renamed taxonomy category -> class) and the
result is a LIST of AttributesByFilterResult ({ classId, attributes,
conditionalityRules, ... }) — there is no top-level taxonomyCategoryId,
and the attribute-level list field is classIds (not taxonomyCategoryIds).

<<~GRAPHQL.squish
  query GetTaxonomyAttributesByFilter($input: AttributesFilterInput!) {
    attributesByFilter(input: $input) {
      classId
      attributes {
        taxonomyAttributeId
        parentAttributeId
        title
        description
        requirement
        answerType
        isActive
        isMultiValue
        isNotApplicableEligible
        isUnavailableEligible
        isCustomEligible
        classIds
        relatedAttributeIds
        valueFormat {
          canValueBeCustomized
          canValueBeSetToUnavailable
          canValueBeSetToNotApplicable
          datatype
        }
        possibleAttributeValues {
          value
          definition
        }
        childAttributes {
          taxonomyAttributeId
          parentAttributeId
          title
          description
          valueFormat {
            canValueBeCustomized
            canValueBeSetToUnavailable
            canValueBeSetToNotApplicable
            datatype
          }
          possibleAttributeValues {
            value
            definition
          }
        }
      }
      conditionalityRules {
        taxonomyAttributeId
        rules {
          upstreamCondition {
            taxonomyAttributeId
            answers
            operation
          }
          downstreamConditions {
            taxonomyAttributeId
            validationType
            answers
            operation
          }
        }
      }
    }
  }
GRAPHQL

Constants included from CatalogApiTransport

CatalogApiTransport::CATALOG_API_BASE, CatalogApiTransport::CATALOG_AUTH_URL

Constants included from AddressAbbreviator

AddressAbbreviator::MAX_LENGTH

Instance Attribute Summary

Attributes inherited from BaseEdiService

#orchestrator

Attributes inherited from BaseService

#options

Instance Method Summary collapse

Methods inherited from BaseEdiService

#duplicate_po_already_notified?, #initialize, #mark_duplicate_po_as_notified, #report_order_creation_issues, #safe_process_edi_communication_log

Methods included from AddressAbbreviator

#abbreviate_street, #collect_street_originals, #record_address_abbreviation_notes

Methods inherited from BaseService

#initialize, #log_debug, #log_error, #log_info, #log_warning, #logger, #tagged_logger

Constructor Details

This class inherits a constructor from Edi::BaseEdiService

Instance Method Details

#process(taxonomy_category_id:, brand: 'WAYFAIR', country: 'UNITED_STATES', locale: 'en-US', wayfair_schema: nil) ⇒ WayfairSchema?

Fetch taxonomy attributes for a category

Parameters:

  • taxonomy_category_id (Integer)

    The Wayfair taxonomy category ID (e.g., 997)

  • brand (String) (defaults to: 'WAYFAIR')

    Brand context (WAYFAIR, ALLMODERN, etc.)

  • country (String) (defaults to: 'UNITED_STATES')

    Country context (UNITED_STATES, CANADA, etc.)

  • locale (String) (defaults to: 'en-US')

    Locale (en-US, en-CA, etc.)

  • wayfair_schema (WayfairSchema) (defaults to: nil)

    Optional existing schema to update

Returns:

  • (WayfairSchema, nil)

    The created/updated schema or nil on failure



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'app/services/edi/wayfair/taxonomy_attribute_retriever.rb', line 98

def process(taxonomy_category_id:, brand: 'WAYFAIR', country: 'UNITED_STATES', locale: 'en-US', wayfair_schema: nil)
  # Wire field is `classId` (String/ID); we keep the taxonomy_category_id
  # naming internally because the DB column and callers use it.
  variables = {
    input: {
      classId: taxonomy_category_id.to_s,
      marketContext: {
        brand: brand.to_s.upcase,
        country: country.to_s.upcase,
        locale: locale
      }
    }
  }

  logger.info "Wayfair Taxonomy: Fetching attributes for category #{taxonomy_category_id} (#{brand}/#{country}/#{locale})"
  logger.debug "Wayfair Taxonomy: Request URL: #{catalog_api_url}"

  transport = build_catalog_transport
  query_payload = build_graphql_payload(ATTRIBUTES_BY_FILTER_QUERY, variables)

  result = transport.send_request('POST', catalog_api_url, query_payload, transport.build_request_headers)
  http_response = result[:http_res]

  unless http_response&.status&.between?(200, 299)
    logger.error "Wayfair Taxonomy: Request failed with status #{http_response&.status}"
    return nil
  end

  response_body = http_response.body.to_s
  json_data = JSON.parse(response_body).with_indifferent_access

  if json_data[:errors].present?
    logger.error "Wayfair Taxonomy: GraphQL errors: #{json_data[:errors]}"
    return nil
  end

  schema_data = json_data.dig(:data, :attributesByFilter)
  if schema_data.blank?
    logger.warn "Wayfair Taxonomy: No attributes returned for category #{taxonomy_category_id}"
    return nil
  end

  # Create or update the WayfairSchema record
  wayfair_schema ||= WayfairSchema.find_or_initialize_by(
    taxonomy_category_id: taxonomy_category_id,
    brand: brand.to_s.upcase,
    country: country.to_s.upcase,
    locale: locale
  )

  wayfair_schema.schema = schema_data
  wayfair_schema.category_name = extract_category_name(schema_data)

  if wayfair_schema.save
    attributes_count = extract_attributes_list(schema_data).size
    logger.info "Wayfair Taxonomy: Saved schema for category #{taxonomy_category_id} with #{attributes_count} attributes"
    wayfair_schema
  else
    logger.error "Wayfair Taxonomy: Failed to save schema: #{wayfair_schema.errors.full_messages.join(', ')}"
    nil
  end
end