Class: Edi::Wayfair::Orchestrator
- Inherits:
-
BaseOrchestrator
- Object
- BaseOrchestrator
- Edi::Wayfair::Orchestrator
- Defined in:
- app/services/edi/wayfair/orchestrator.rb
Overview
Orchestrates the Wayfair EDI integration (US 7083 / CA 24331) over Wayfair's
GraphQL APIs: inventory feeds, purchase-order retrieval/processing, order
acknowledgements and confirmations, packing-slip retrieval, and the daily
Supplier Catalog product-data pull.
Constant Summary collapse
- DOUBLE_QUOTE_CHARACTERS_TO_REPLACE =
['"', '“', '”', '“', '“', '«', '»', '“', '”', '„'].freeze
- SINGLE_QUOTE_CHARACTERS_TO_REPLACE =
last one is not a comma though it looks like it
['‘', '’', '‹', '›', '′', '‚'].freeze
- GOLIVE_DATE_STR =
"November 12, 2020"
'November 10, 2020'
Constants inherited from BaseOrchestrator
BaseOrchestrator::DEFAULT_PENDING_DISCONTINUE_LIFETIME, BaseOrchestrator::ORCHESTRATORS, BaseOrchestrator::RECOMMENDED_EXECUTE_FLOW_EVERY_X_HOUR
Instance Attribute Summary
Attributes inherited from BaseOrchestrator
Class Method Summary collapse
-
.partners ⇒ Hash{Symbol => Hash}
Partner configuration for both Wayfair regions.
Instance Method Summary collapse
-
#acknowledge_message_enabled? ⇒ Boolean
Whether order acknowledgement is enabled (follows order flow enablement).
- #acknowledge_message_sender ⇒ Edi::Wayfair::AcknowledgeMessageSender, Edi::NullProcessor
- #catalog_item_information_processor ⇒ Edi::Wayfair::CatalogItemInformationProcessor
-
#catalog_item_information_retriever ⇒ Edi::Wayfair::CatalogItemInformationRetriever
Catalog Item Information API methods Uses the new Supplier Catalog API at https://api.wayfair.io/v1/product-catalog-api/graphql.
-
#catalog_item_information_updater ⇒ Edi::Wayfair::CatalogItemInformationUpdater
Catalog Item Update methods Uses the inventory mutation to update product attributes.
-
#catalog_item_update_sender ⇒ Edi::Wayfair::CatalogItemUpdateSender
Catalog Update methods Uses the Product Catalog Update API with updateMarketSpecificCatalogItems mutation.
-
#catalog_update_coverage(catalog_item) ⇒ Hash
Get attribute coverage report for a catalog item.
-
#check_catalog_update_status(request_id) ⇒ CatalogItemUpdateSender::StatusResult
Check the status of a previous catalog update request.
-
#clean_string(str) ⇒ String
Sanitizes a free-text string for Wayfair messages by replacing the various Unicode double-quote characters with two single quotes and single-quote variants with a plain apostrophe.
-
#confirm_message_enabled? ⇒ Boolean
Whether order confirmation is enabled (follows order flow enablement).
- #confirm_message_processor ⇒ Edi::Wayfair::ConfirmMessageProcessor, Edi::NullProcessor
- #confirm_message_sender ⇒ Edi::Wayfair::ConfirmMessageSender, Edi::NullProcessor
-
#execute_inventory_flow ⇒ void
Runs the inventory flow: build the feed and send it.
-
#execute_order_flow ⇒ void
Runs the full purchase-order flow: retrieve, process, acknowledge, confirm.
-
#execute_product_data_flow ⇒ void
Pulls catalog information from Wayfair's Supplier Catalog API Updates retail prices, product identifiers, taxonomy data, and URLs Called by EdiProductDataFlowWorker (daily at 2:15 AM).
-
#feed_submission_result_enabled? ⇒ Boolean
Whether feed-submission results are polled for this partner.
- #feed_submission_result_processor ⇒ Edi::Wayfair::InventoryMessageProcessor, Edi::NullProcessor
-
#get_orders_query ⇒ String
GraphQL query fetching open purchase orders for this partner's supplier id.
-
#ignore_back_orders ⇒ Boolean
Whether back orders are ignored for this partner (Wayfair: never).
-
#inventory_message_enabled? ⇒ Boolean
Whether the inventory feed flow is enabled for this partner.
-
#inventory_message_processor ⇒ Edi::Wayfair::InventoryMessageProcessor, Edi::NullProcessor
Processor that builds the inventory feed payload.
-
#inventory_message_sender ⇒ Edi::Wayfair::InventoryMessageSender, Edi::NullProcessor
Sender that pushes the inventory feed to Wayfair.
-
#invoice_message_enabled? ⇒ Boolean
Whether the invoice flow is enabled for this partner (currently false).
- #invoice_message_processor ⇒ Edi::Wayfair::InvoiceMessageProcessor, Edi::NullProcessor
- #invoice_message_sender ⇒ Edi::Wayfair::InvoiceMessageSender, Edi::NullProcessor
-
#market_country ⇒ String
Get market country based on partner.
-
#market_locale ⇒ String
Get market locale based on partner.
-
#order_message_enabled? ⇒ Boolean
Whether the purchase-order flow is enabled for this partner.
-
#order_message_processor ⇒ Edi::Wayfair::OrderMessageProcessor, Edi::NullProcessor
Processor that turns a fetched order batch into Order records.
-
#order_message_retriever ⇒ Edi::Wayfair::OrderMessageRetriever, Edi::NullProcessor
Retriever that pulls open purchase orders from Wayfair's GraphQL API.
-
#packing_slip_enabled? ⇒ Boolean
Whether packing-slip retrieval is configured for this partner.
-
#packing_slip_processor ⇒ Edi::NullProcessor
No-op processor — packing slips are only retrieved, never processed.
- #packing_slip_retriever ⇒ Edi::Wayfair::PackingSlipRetriever, Edi::NullProcessor
-
#preview_catalog_update(catalog_item) ⇒ Hash
Preview what would be sent for a catalog item (for debugging).
-
#pull_catalog_information(sku) ⇒ Hash
Pull catalog information for a specific SKU.
-
#pull_catalog_information_all(page: 1, page_size: 25, dry_run: false) ⇒ Hash
Pull catalog information for all products (paginated).
-
#pull_catalog_read_v2 ⇒ void
Catalog Read v2 pass — Wayfair's own insights, live
catalogItemStatus, and the listing's populated taxonomy attributes. -
#pull_taxonomy_schema(taxonomy_category_id, brand: 'WAYFAIR', country: 'UNITED_STATES', locale: 'en-US') ⇒ WayfairSchema?
Pull taxonomy schema for a specific category.
-
#pull_taxonomy_schema_for_category(taxonomy_category_id, wayfair_schema: nil) ⇒ WayfairSchema?
Pull taxonomy schema for a category and update an existing WayfairSchema record.
-
#push_catalog_update(catalog_item, attributes: nil, dry_run: false, validate_only: false) ⇒ CatalogItemUpdateSender::UpdateResult
Push a catalog item update to Wayfair.
-
#push_inventory_update(sku, inventory_data:, dry_run: false) ⇒ Edi::Wayfair::CatalogItemInformationUpdater::UpdateResult
Update inventory data on Wayfair (quantity, discontinued status, etc.).
-
#return_notification_message_enabled? ⇒ Boolean
Whether the return-notification flow is configured for this partner.
- #return_notification_message_processor ⇒ Edi::Wayfair::ReturnNotificationMessageProcessor, Edi::NullProcessor
- #return_notification_message_sender ⇒ Edi::Wayfair::ReturnNotificationMessageSender, Edi::NullProcessor
-
#ship_code_mapper ⇒ Edi::Wayfair::ShipCodeMapper
Maps Wayfair ship codes to Heatwave shipping options.
-
#taxonomy_attribute_retriever ⇒ Edi::Wayfair::TaxonomyAttributeRetriever
Taxonomy Attribute methods Uses the Product Catalog API to fetch and cache taxonomy attribute definitions Similar to Amazon's product type schema system.
-
#wayfair_schema_for(taxonomy_category_id, refresh: false) ⇒ WayfairSchema?
Get or create WayfairSchema for a category, fetching from API if not cached.
Methods inherited from BaseOrchestrator
all_orchestrators_class, build, build_customer_id_to_partner_key_map, cached_build, cached_orchestrators, catalog_id_to_pending_discontinue_lifetime, catalog_ids_edi_enabled, #confirm_outbound_processing?, #customer, #customer_catalog, customer_id_to_partner_key_map, #customer_ids, customer_ids_edi_enabled, customer_ids_with_invoice_message_enabled, #customers, execute_discontinue_flow, execute_flow, execute_inventory_flow, execute_listing_message_feed_flow, execute_order_flow, execute_price_flow, #execute_price_flow, execute_product_data_flow, #initialize, orchestrator_for_customer_id, orchestrators, #pending_discontinue_lifetime, #price_message_enabled?, #product_data_enabled?, #should_execute_flow?, #should_execute_order_flow?, #should_execute_product_data_flow?, #supports_flow?, #test_mode?
Constructor Details
This class inherits a constructor from Edi::BaseOrchestrator
Class Method Details
.partners ⇒ Hash{Symbol => Hash}
Partner configuration for both Wayfair regions.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 23 def self.partners { wayfair_us: { active: true, partner: :wayfair_us, warehouse_code: '7083', customer_id: 175_360, transporter: :http_graphql_api, transporter_profile: :wayfair_api, inventory_transporter: :http_graphql_api, inventory_transporter_profile: :wayfair_api, inventory_enabled: true, order_enabled: true, invoice_enabled: false, product_data_enabled: true, # Catalog READ live in prod both regions (2026-06-12); daily worker pulls MSRP + canonical PDP URL + taxonomy packing_slip_remote_path: 'https://api.wayfair.com/v1/packing_slip', support_contact: 'supplierservicedesk@wayfair.com' }, wayfair_ca: { active: true, partner: :wayfair_ca, warehouse_code: '24331', customer_id: 2_727_071, transporter: :http_graphql_api, transporter_profile: :wayfair_api, inventory_transporter: :http_graphql_api, inventory_transporter_profile: :wayfair_api, inventory_enabled: true, order_enabled: true, invoice_enabled: false, product_data_enabled: true, # Catalog READ live in prod both regions (2026-06-12); daily worker pulls MSRP + canonical PDP URL + taxonomy packing_slip_remote_path: 'https://api.wayfair.com/v1/packing_slip', support_contact: 'supplierservicedesk@wayfair.com' } } end |
Instance Method Details
#acknowledge_message_enabled? ⇒ Boolean
Whether order acknowledgement is enabled (follows order flow enablement).
263 264 265 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 263 def try(:order_enabled).present? end |
#acknowledge_message_sender ⇒ Edi::Wayfair::AcknowledgeMessageSender, Edi::NullProcessor
268 269 270 271 272 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 268 def return Edi::NullProcessor.new(self, :acknowledge_message_sender, ) unless AcknowledgeMessageSender.new(self, ) end |
#catalog_item_information_processor ⇒ Edi::Wayfair::CatalogItemInformationProcessor
454 455 456 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 454 def catalog_item_information_processor CatalogItemInformationProcessor.new(self, ) end |
#catalog_item_information_retriever ⇒ Edi::Wayfair::CatalogItemInformationRetriever
Catalog Item Information API methods
Uses the new Supplier Catalog API at https://api.wayfair.io/v1/product-catalog-api/graphql
449 450 451 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 449 def catalog_item_information_retriever CatalogItemInformationRetriever.new(self, ) end |
#catalog_item_information_updater ⇒ Edi::Wayfair::CatalogItemInformationUpdater
The Wayfair inventory API has LIMITED capabilities:
- CAN update: quantity, discontinued status, product name
- CANNOT update: dimensions, pricing, images (these are read-only or Wayfair-managed)
Catalog Item Update methods
Uses the inventory mutation to update product attributes
500 501 502 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 500 def catalog_item_information_updater CatalogItemInformationUpdater.new(self, ) end |
#catalog_item_update_sender ⇒ Edi::Wayfair::CatalogItemUpdateSender
Catalog Update methods
Uses the Product Catalog Update API with updateMarketSpecificCatalogItems mutation
637 638 639 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 637 def catalog_item_update_sender CatalogItemUpdateSender.new(self, ) end |
#catalog_update_coverage(catalog_item) ⇒ Hash
Get attribute coverage report for a catalog item
694 695 696 697 698 699 700 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 694 def catalog_update_coverage(catalog_item) wayfair_schema = wayfair_schema_for(catalog_item.wayfair_taxonomy_category_id_in_effect) return { error: 'No schema available' } unless wayfair_schema generator = ListingGenerator::ListingGenerator.new(catalog_item, wayfair_schema: wayfair_schema) generator.attribute_coverage end |
#check_catalog_update_status(request_id) ⇒ CatalogItemUpdateSender::StatusResult
Check the status of a previous catalog update request
668 669 670 671 672 673 674 675 676 677 678 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 668 def check_catalog_update_status(request_id) catalog_item_update_sender.check_status(request_id) rescue StandardError => e Rails.logger.error "Wayfair check_catalog_update_status error: #{e.}" CatalogItemUpdateSender::StatusResult.new( success: false, status: 'ERROR', message: e., details: nil ) end |
#clean_string(str) ⇒ String
Sanitizes a free-text string for Wayfair messages by replacing the various
Unicode double-quote characters with two single quotes and single-quote
variants with a plain apostrophe.
526 527 528 529 530 531 532 533 534 535 536 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 526 def clean_string(str) # Ensure to replace all double quotes with two single quotes, along with all the various variations, based on testing and: # https://unicode-table.com/en/sets/quotation-marks/ DOUBLE_QUOTE_CHARACTERS_TO_REPLACE.each do |c| str = str.gsub(c, "''") end SINGLE_QUOTE_CHARACTERS_TO_REPLACE.each do |c| str = str.gsub(c, "'") end str end |
#confirm_message_enabled? ⇒ Boolean
Whether order confirmation is enabled (follows order flow enablement).
242 243 244 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 242 def try(:order_enabled).present? end |
#confirm_message_processor ⇒ Edi::Wayfair::ConfirmMessageProcessor, Edi::NullProcessor
247 248 249 250 251 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 247 def return Edi::NullProcessor.new(self, :confirm_message_processor, ) unless ConfirmMessageProcessor.new(self, ) end |
#confirm_message_sender ⇒ Edi::Wayfair::ConfirmMessageSender, Edi::NullProcessor
254 255 256 257 258 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 254 def return Edi::NullProcessor.new(self, :confirm_message_sender, ) unless ConfirmMessageSender.new(self, ) end |
#execute_inventory_flow ⇒ void
This method returns an undefined value.
Runs the inventory flow: build the feed and send it.
331 332 333 334 335 336 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 331 def execute_inventory_flow return unless active .process .process end |
#execute_order_flow ⇒ void
This method returns an undefined value.
Runs the full purchase-order flow: retrieve, process, acknowledge, confirm.
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 312 def execute_order_flow return unless active .process sleep(1) .process sleep(1) # we get packing slips inline directly from order batch queries # packing_slip_processor.process # sleep(1) .process sleep(1) .process sleep(1) end |
#execute_product_data_flow ⇒ void
This method returns an undefined value.
Pulls catalog information from Wayfair's Supplier Catalog API
Updates retail prices, product identifiers, taxonomy data, and URLs
Called by EdiProductDataFlowWorker (daily at 2:15 AM)
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 343 def execute_product_data_flow return unless active return unless product_data_enabled? logger.info "Wayfair: Starting product data flow for #{partner}" total_processed = 0 total_skipped = 0 total_errors = 0 page = 1 max_pages = 100 # Safety limit catalog_scan_ecls = [] catalog_scan_complete = false loop do if page > max_pages logger.warn "Wayfair: Product data flow reached the #{max_pages}-page safety limit; parent coverage was not replaced" break end result = pull_catalog_information_all(page: page, page_size: 25) catalog_scan_ecls << result[:ecl] if result[:ecl] # Per-item save errors must NOT halt the whole backfill — they make # result[:success] false (success = result.errors.empty?), so the old # `break` here stalled the sync on page 1 whenever a single item failed. # Tally the errors and keep paging; only stop when there is no further # page to fetch (page_info absent = hard failure / no data). if result[:result] total_processed += result[:result].processed total_skipped += result[:result].skipped total_errors += result[:result].errors.size end page_info = result[:page_info] unless page_info logger.warn "Wayfair: Product data flow stopped at page #{page}: #{result[:message] || 'no page info returned'}" total_errors += 1 unless result[:success] break end logger.warn "Wayfair: Product data flow page #{page} had #{result[:result]&.errors&.size} item error(s); continuing" unless result[:success] unless page_info['hasNextPage'] catalog_scan_complete = true break end page += 1 sleep(0.5) # Rate limiting between pages end if catalog_scan_complete coverage_result = RecordCatalogParentCoverage.call(catalog: customer&.catalog, ecls: catalog_scan_ecls) total_errors += coverage_result.errors.size logger.info "Wayfair: Parent coverage for #{partner}: #{coverage_result.updated} updated, " \ "#{coverage_result.errors.size} errors" else logger.warn "Wayfair: Parent coverage for #{partner} was not replaced because the v1 scan did not complete" end logger.info "Wayfair: Product data flow completed for #{partner}: " \ "#{total_processed} processed, #{total_skipped} skipped, #{total_errors} errors" pull_catalog_read_v2 end |
#feed_submission_result_enabled? ⇒ Boolean
Whether feed-submission results are polled for this partner.
277 278 279 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 277 def feed_submission_result_enabled? try(:feed_submission_result_remote_path).present? end |
#feed_submission_result_processor ⇒ Edi::Wayfair::InventoryMessageProcessor, Edi::NullProcessor
282 283 284 285 286 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 282 def feed_submission_result_processor return Edi::NullProcessor.new(self, :inventory_message_processor, ) unless feed_submission_result_enabled? InventoryMessageProcessor.new(self, ) end |
#get_orders_query ⇒ String
GraphQL query fetching open purchase orders for this partner's supplier id.
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 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 104 def get_orders_query %( query purchaseOrders { purchaseOrders( filters: [ { field: open, equals: \\"true\\" }, { field: supplierId, equals: \\"#{try(:warehouse_code)}\\" }, { field: poDate, greaterThan: \\"#{DateTime.parse(GOLIVE_DATE_STR).iso8601}\\" } ], limit: 10, ordering: [ { desc: \\"poDate\\" } ] ) { id, poNumber, poDate, estimatedShipDate, customerName, customerAddress1, customerAddress2, customerCity, customerState, customerCountry, customerPostalCode, orderType, shippingInfo { shipSpeed, carrierCode }, packingSlipUrl, warehouse { id, name, address { name, address1, address2, address3, city, state, country, postalCode } }, products { partNumber, quantity, price, event { id, type, name, startDate, endDate } }, shipTo { name, address1, address2, address3, city, state, country, postalCode, phoneNumber } } } ).squish end |
#ignore_back_orders ⇒ Boolean
Whether back orders are ignored for this partner (Wayfair: never).
441 442 443 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 441 def ignore_back_orders false end |
#inventory_message_enabled? ⇒ Boolean
Whether the inventory feed flow is enabled for this partner.
63 64 65 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 63 def try(:inventory_enabled).present? end |
#inventory_message_processor ⇒ Edi::Wayfair::InventoryMessageProcessor, Edi::NullProcessor
Processor that builds the inventory feed payload.
70 71 72 73 74 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 70 def return Edi::NullProcessor.new(self, :inventory_message_processor, ) unless InventoryMessageProcessor.new(self, ) end |
#inventory_message_sender ⇒ Edi::Wayfair::InventoryMessageSender, Edi::NullProcessor
Sender that pushes the inventory feed to Wayfair.
79 80 81 82 83 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 79 def return Edi::NullProcessor.new(self, :inventory_message_sender, ) unless InventoryMessageSender.new(self, ) end |
#invoice_message_enabled? ⇒ Boolean
Whether the invoice flow is enabled for this partner (currently false).
200 201 202 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 200 def try(:invoice_enabled).present? end |
#invoice_message_processor ⇒ Edi::Wayfair::InvoiceMessageProcessor, Edi::NullProcessor
205 206 207 208 209 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 205 def return Edi::NullProcessor.new(self, :invoice_message_processor, ) unless InvoiceMessageProcessor.new(self, ) end |
#invoice_message_sender ⇒ Edi::Wayfair::InvoiceMessageSender, Edi::NullProcessor
212 213 214 215 216 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 212 def return Edi::NullProcessor.new(self, :invoice_message_sender, ) unless InvoiceMessageSender.new(self, ) end |
#market_country ⇒ String
Get market country based on partner
608 609 610 611 612 613 614 615 616 617 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 608 def market_country case partner when :wayfair_us 'UNITED_STATES' when :wayfair_ca 'CANADA' else 'UNITED_STATES' end end |
#market_locale ⇒ String
Get market locale based on partner
622 623 624 625 626 627 628 629 630 631 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 622 def market_locale case partner when :wayfair_us 'en-US' when :wayfair_ca 'en-CA' else 'en-US' end end |
#order_message_enabled? ⇒ Boolean
Whether the purchase-order flow is enabled for this partner.
88 89 90 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 88 def try(:order_enabled).present? end |
#order_message_processor ⇒ Edi::Wayfair::OrderMessageProcessor, Edi::NullProcessor
Processor that turns a fetched order batch into Order records.
191 192 193 194 195 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 191 def return Edi::NullProcessor.new(self, :order_message_processor, ) unless OrderMessageProcessor.new(self, ) end |
#order_message_retriever ⇒ Edi::Wayfair::OrderMessageRetriever, Edi::NullProcessor
Retriever that pulls open purchase orders from Wayfair's GraphQL API.
95 96 97 98 99 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 95 def return Edi::NullProcessor.new(self, :order_message_processor, ) unless OrderMessageRetriever.new(self, ) end |
#packing_slip_enabled? ⇒ Boolean
Whether packing-slip retrieval is configured for this partner.
221 222 223 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 221 def packing_slip_enabled? try(:packing_slip_remote_path).present? end |
#packing_slip_processor ⇒ Edi::NullProcessor
No-op processor — packing slips are only retrieved, never processed.
235 236 237 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 235 def packing_slip_processor Edi::NullProcessor.new(self, :packing_slip_processor, ) # here we don't need to process anything, just retrieve end |
#packing_slip_retriever ⇒ Edi::Wayfair::PackingSlipRetriever, Edi::NullProcessor
226 227 228 229 230 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 226 def packing_slip_retriever return Edi::NullProcessor.new(self, :packing_slip_retriever, ) unless packing_slip_enabled? PackingSlipRetriever.new(self, ) end |
#preview_catalog_update(catalog_item) ⇒ Hash
Preview what would be sent for a catalog item (for debugging)
683 684 685 686 687 688 689 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 683 def preview_catalog_update(catalog_item) wayfair_schema = wayfair_schema_for(catalog_item.wayfair_taxonomy_category_id_in_effect) return { error: 'No schema available' } unless wayfair_schema generator = ListingGenerator::ListingGenerator.new(catalog_item, wayfair_schema: wayfair_schema) generator.preview end |
#pull_catalog_information(sku) ⇒ Hash
Pull catalog information for a specific SKU
461 462 463 464 465 466 467 468 469 470 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 461 def pull_catalog_information(sku) ecl = catalog_item_information_retriever.process(supplier_part_number: sku) return { success: false, ecl: nil, result: nil, message: 'No data returned from Wayfair API' } unless ecl result = catalog_item_information_processor.process(ecl) { success: result.errors.empty?, ecl: ecl, result: result } rescue StandardError => e Rails.logger.error "Wayfair pull_catalog_information error for #{sku}: #{e.}" { success: false, ecl: nil, result: nil, message: e. } end |
#pull_catalog_information_all(page: 1, page_size: 25, dry_run: false) ⇒ Hash
Pull catalog information for all products (paginated)
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 477 def pull_catalog_information_all(page: 1, page_size: 25, dry_run: false) ecl = catalog_item_information_retriever.process_all(page: page, page_size: page_size) return { success: false, ecl: nil, result: nil, message: 'No data returned from Wayfair API' } unless ecl result = catalog_item_information_processor.process(ecl, dry_run: dry_run) page_info = begin JSON.parse(ecl.data).dig('data', 'supplierCatalog', 'pageInfo') rescue StandardError nil end { success: result.errors.empty?, ecl: ecl, result: result, page_info: page_info } rescue StandardError => e Rails.logger.error "Wayfair pull_catalog_information_all error: #{e.}" { success: false, ecl: nil, result: nil, message: e. } end |
#pull_catalog_read_v2 ⇒ void
This method returns an undefined value.
Catalog Read v2 pass — Wayfair's own insights, live catalogItemStatus, and
the listing's populated taxonomy attributes. Feeds
ListingIssues::WayfairAdapter, which reconciles at 05:30 CT (this flow runs
02:15 CT), so without this call the whole v2 signal sits frozen at whenever
someone last ran the retriever by hand.
Deliberately runs AFTER the v1 pass: v1's isLive is always true even for a
discontinued SKU, so v1 writes status: LIVE unconditionally and would
clobber v2's authoritative catalogItemStatus if the order were reversed.
Isolated from the v1 result — a v2 outage must not fail the product-data
flow that keeps PDP URLs and taxonomy current.
423 424 425 426 427 428 429 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 423 def pull_catalog_read_v2 result = CatalogReadV2Retriever.new(self).pull logger.info "Wayfair: Catalog Read v2 for #{partner}: #{result.to_h}" rescue StandardError => e logger.error "Wayfair: Catalog Read v2 failed for #{partner}: #{e.class}: #{e.}" Appsignal.report_error(e) end |
#pull_taxonomy_schema(taxonomy_category_id, brand: 'WAYFAIR', country: 'UNITED_STATES', locale: 'en-US') ⇒ WayfairSchema?
Pull taxonomy schema for a specific category
553 554 555 556 557 558 559 560 561 562 563 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 553 def pull_taxonomy_schema(taxonomy_category_id, brand: 'WAYFAIR', country: 'UNITED_STATES', locale: 'en-US') taxonomy_attribute_retriever.process( taxonomy_category_id: taxonomy_category_id, brand: brand, country: country, locale: locale ) rescue StandardError => e Rails.logger.error "Wayfair pull_taxonomy_schema error for category #{taxonomy_category_id}: #{e.}" nil end |
#pull_taxonomy_schema_for_category(taxonomy_category_id, wayfair_schema: nil) ⇒ WayfairSchema?
Pull taxonomy schema for a category and update an existing WayfairSchema record.
Forwards arbitrary keyword arguments (**) to the taxonomy_attribute_retriever
for additional market-context options.
572 573 574 575 576 577 578 579 580 581 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 572 def pull_taxonomy_schema_for_category(taxonomy_category_id, wayfair_schema: nil, **) taxonomy_attribute_retriever.process( taxonomy_category_id: taxonomy_category_id, wayfair_schema: wayfair_schema, ** ) rescue StandardError => e Rails.logger.error "Wayfair pull_taxonomy_schema_for_category error: #{e.}" nil end |
#push_catalog_update(catalog_item, attributes: nil, dry_run: false, validate_only: false) ⇒ CatalogItemUpdateSender::UpdateResult
Push a catalog item update to Wayfair
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 647 def push_catalog_update(catalog_item, attributes: nil, dry_run: false, validate_only: false) catalog_item_update_sender.process( catalog_item: catalog_item, attributes: attributes, dry_run: dry_run, validate_only: validate_only ) rescue StandardError => e Rails.logger.error "Wayfair push_catalog_update error: #{e.}" CatalogItemUpdateSender::UpdateResult.new( success: false, request_id: nil, errors: [e.], ecl: nil, payload: nil ) end |
#push_inventory_update(sku, inventory_data:, dry_run: false) ⇒ Edi::Wayfair::CatalogItemInformationUpdater::UpdateResult
Update inventory data on Wayfair (quantity, discontinued status, etc.)
509 510 511 512 513 514 515 516 517 518 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 509 def push_inventory_update(sku, inventory_data:, dry_run: false) catalog_item_information_updater.process( supplier_part_number: sku, inventory_data: inventory_data, dry_run: dry_run ) rescue StandardError => e Rails.logger.error "Wayfair push_inventory_update error for #{sku}: #{e.}" CatalogItemInformationUpdater::UpdateResult.new(success: false, handle: nil, errors: [e.], ecl: nil) end |
#return_notification_message_enabled? ⇒ Boolean
Whether the return-notification flow is configured for this partner.
291 292 293 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 291 def try(:return_notification_message_remote_path).present? end |
#return_notification_message_processor ⇒ Edi::Wayfair::ReturnNotificationMessageProcessor, Edi::NullProcessor
296 297 298 299 300 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 296 def return Edi::NullProcessor.new(self, :return_notification_message_processor, ) unless ReturnNotificationMessageProcessor.new(self, ) end |
#return_notification_message_sender ⇒ Edi::Wayfair::ReturnNotificationMessageSender, Edi::NullProcessor
303 304 305 306 307 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 303 def return Edi::NullProcessor.new(self, :return_notification_message_sender, ) unless ReturnNotificationMessageSender.new(self, ) end |
#ship_code_mapper ⇒ Edi::Wayfair::ShipCodeMapper
Maps Wayfair ship codes to Heatwave shipping options.
434 435 436 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 434 def ship_code_mapper ShipCodeMapper.new(self) end |
#taxonomy_attribute_retriever ⇒ Edi::Wayfair::TaxonomyAttributeRetriever
Taxonomy Attribute methods
Uses the Product Catalog API to fetch and cache taxonomy attribute definitions
Similar to Amazon's product type schema system
543 544 545 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 543 def taxonomy_attribute_retriever TaxonomyAttributeRetriever.new(self, ) end |
#wayfair_schema_for(taxonomy_category_id, refresh: false) ⇒ WayfairSchema?
Get or create WayfairSchema for a category, fetching from API if not cached
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 |
# File 'app/services/edi/wayfair/orchestrator.rb', line 587 def wayfair_schema_for(taxonomy_category_id, refresh: false) schema = WayfairSchema.for_category(taxonomy_category_id) .for_brand('WAYFAIR') .for_country(market_country) .first # Return cached schema if available and not stale (less than 7 days old) return schema if schema.present? && !refresh && schema.updated_at > 7.days.ago # Fetch fresh schema from API. A failed refresh must NOT discard a schema we # already hold: `pull_taxonomy_schema` swallows its error and returns nil, so # returning it directly turned every stale-but-usable schema into "no schema # available" and blocked the caller outright. Canada hit this — its 7441/363 # schemas were 30 days old and the CA taxonomy pull fails, so every CA # re-class refused to build a payload despite a perfectly good cached schema. pull_taxonomy_schema(taxonomy_category_id, country: market_country) || schema end |