Class: Edi::Wayfair::CatalogItemMediaSender
- Inherits:
-
BaseEdiService
- Object
- BaseService
- BaseEdiService
- Edi::Wayfair::CatalogItemMediaSender
- Includes:
- CatalogApiTransport
- Defined in:
- app/services/edi/wayfair/catalog_item_media_sender.rb
Overview
Pushes product imagery to Wayfair via the Product Catalog Update API's
updateCatalogItemsMedia mutation, using public image URLs (our ImageKit
endpoint) — so we control the lead image and gallery instead of inheriting
whatever Wayfair scraped. Media updates are global (one call covers every
market the product sells in), batch up to 500, and support validateOnly.
API: https://developer.wayfair.io/posts/catalog-product-update (Step 2C).
Wire format verified in sandbox 2026-06-28 (returns requestId; input is
UpdateCatalogItemsMediaInput { supplierId, catalogItemsToUpdate:
[CatalogItemMediaInput { supplierPartNumber, mediaUrl, mediaType, leadImageOverride }],
validateOnly }).
Solves the borrowed-lead-image + "only one image" problems the Wayfair listing
audit surfaced (see ListingIssues::WayfairAdapter).
Defined Under Namespace
Classes: MediaResult
Constant Summary collapse
- CATALOG_UPDATE_API_URL =
Product Catalog Update API endpoints (same host as the update sender).
'https://api.wayfair.io/v1/product-catalog-api/graphql'- SANDBOX_CATALOG_UPDATE_API_URL =
Sandbox endpoint.
'https://api.wayfair.io/sandbox/v1/product-catalog-api/graphql'- UPDATE_MEDIA_MUTATION =
GraphQL mutation: async, returns a
requestIdto poll via
Edi::Wayfair::CatalogItemUpdateSender#check_status. <<~GRAPHQL.squish mutation UpdateCatalogItemsMedia($input: UpdateCatalogItemsMediaInput!) { updateCatalogEntitiesMutations { updateCatalogItemsMedia(input: $input) { requestId } } } GRAPHQL
- WAY_LEAD_IMAGE_TYPE =
Image profile types we publish to Wayfair, in priority order: the main shot
leads, then the numbered gallery images.We prefer the Wayfair-specific set (WAY_MAIN + WAY_I01…) when the item has any
WAY_* profiles; otherwise we default to the website set (WYS_MAIN + WYS_I01…).
So a Wayfair image classification, when present, overrides — and when absent,
Wayfair simply inherits the WarmlyYours.com imagery. 'WAY_MAIN'- WAY_GALLERY_IMAGE_PREFIX =
Prefix of the numbered Wayfair gallery images (WAY_I1, WAY_I2, …).
'WAY_I'- LEAD_IMAGE_TYPE =
Website lead image type, used when no WAY_* profiles exist.
'WYS_MAIN'- GALLERY_IMAGE_PREFIX =
Prefix of the numbered website gallery images (WYS_I1, WYS_I2, …).
'WYS_I'
Constants included from CatalogApiTransport
Edi::Wayfair::CatalogApiTransport::CATALOG_API_BASE, Edi::Wayfair::CatalogApiTransport::CATALOG_AUTH_URL
Constants included from RequestIdentifiable
RequestIdentifiable::REQUEST_ID_HEADERS
Constants included from AddressAbbreviator
AddressAbbreviator::MAX_LENGTH
Instance Attribute Summary
Attributes inherited from BaseEdiService
Attributes inherited from BaseService
Instance Method Summary collapse
-
#media_for(catalog_item) ⇒ Array<Hash>
The ordered public image URLs we'd publish for an item — lead first.
-
#process(catalog_item:, media: nil, validate_only: false, dry_run: false) ⇒ MediaResult
Push imagery for a catalog item.
Methods inherited from BaseEdiService
#amazon_feed_product_type, #duplicate_po_already_notified?, #initialize, #mark_duplicate_po_as_notified, #onboard_ordered_catalog_items, #report_order_creation_issues, #safe_process_edi_communication_log
Methods included from RequestIdentifiable
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
#media_for(catalog_item) ⇒ Array<Hash>
The ordered public image URLs we'd publish for an item — lead first.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'app/services/edi/wayfair/catalog_item_media_sender.rb', line 96 def media_for(catalog_item) profiles = catalog_item.store_item&.item&.image_profiles.to_a # Prefer the Wayfair-specific set; default to the website set when absent. lead_type, gallery_prefix = if profiles.any? { |p| p.image_type.to_s.start_with?('WAY_') } [WAY_LEAD_IMAGE_TYPE, WAY_GALLERY_IMAGE_PREFIX] else [LEAD_IMAGE_TYPE, GALLERY_IMAGE_PREFIX] end lead = profiles.find { |p| p.image_type == lead_type } gallery = profiles.select { |p| p.image_type.to_s.start_with?(gallery_prefix) } [lead, *gallery].compact .map { |profile| profile.image_url.to_s } .compact_blank .uniq .map.with_index { |url, index| { url:, lead: index.zero? } } end |
#process(catalog_item:, media: nil, validate_only: false, dry_run: false) ⇒ MediaResult
Push imagery for a catalog item.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'app/services/edi/wayfair/catalog_item_media_sender.rb', line 76 def process(catalog_item:, media: nil, validate_only: false, dry_run: false) supplier_part_number = supplier_part_number_for(catalog_item) media ||= media_for(catalog_item) return MediaResult.new(success: false, errors: ['No supplier part number for item'], media: []) if supplier_part_number.blank? return MediaResult.new(success: false, errors: ['No public image URLs to send'], media: []) if media.blank? input = build_media_input(supplier_part_number, media, validate_only:) if dry_run logger.info "Wayfair Media [DRY RUN]: would send #{media.size} image(s) for #{supplier_part_number}" return MediaResult.new(success: true, request_id: 'dry_run', errors: [], media:) end send_media(catalog_item, input, media) end |