Class: Edi::Walmart::Orchestrator

Inherits:
BaseOrchestrator show all
Defined in:
app/services/edi/walmart/orchestrator.rb

Overview

The core class of our Walmart API integration, the factory for all processor

Constant Summary collapse

GOLIVE_DATE_STR =

Golive date str.

'July 25, 2025'
EARLY_LABEL_PURCHASE_ENABLED_US =

Enable early label purchase for Walmart orders (labels purchased at order release, not ship-label time)
Set to true to enable, false to disable

false
EARLY_LABEL_PURCHASE_ENABLED_CA =

Early label purchase enabled ca.

false
IN_FLIGHT_FEED_WINDOW =

How long a still-ingesting inventory feed suppresses the next submission.
See #inventory_feed_in_flight?.

4.hours

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

#config, #logger, #options

Class Method Summary collapse

Instance Method Summary collapse

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, #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_product_data_flow, execute_product_data_flow, #ignore_back_orders, #initialize, orchestrator_for_customer_id, orchestrators, #pending_discontinue_lifetime, #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

.execute_feed_submission_result_processor(options = {}) ⇒ void

This method returns an undefined value.

Parameters:

Options Hash (options):

  • logger (Logger)

    logger to use (defaults to Rails.logger)



94
95
96
# File 'app/services/edi/walmart/orchestrator.rb', line 94

def self.execute_feed_submission_result_processor(options = {})
  orchestrators(options).each { |o| o.feed_submission_result_processor.process }
end

.partnersHash{Symbol=>Hash}

Returns the Walmart partner configuration hash.

Returns:

  • (Hash{Symbol=>Hash})

    mapping of partner key to partner configuration



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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'app/services/edi/walmart/orchestrator.rb', line 25

def self.partners
  {
    walmart_seller_us: {
      active: true,
      partner: :walmart_seller_us,
      customer_id: 23_041_827,
      fulfillment_center_id: '10002649057',
      locales: ['en_US'],
      business_unit: 'WALMART_US',
      default_locale: 'en',
      inventory_message_enabled: true,
      support_contact: 'Soumitro.Biswas0@walmart.com',
      price_message_enabled: true,
      ship_with_walmart_enabled: true, # Enable "Ship with Walmart" discounted shipping rates
      returns_report_enabled: false, # Dark launch: opt in to Returns API ingestion (GET /v3/returns) per partner
      early_label_purchase_enabled: EARLY_LABEL_PURCHASE_ENABLED_US,
      transporter: :http_walmart_seller_api,
      transporter_profile: :walmart_seller_us_api,
      inventory_message_remote_path: "https://#{Heatwave::Configuration.fetch(:walmart_seller_us_api, :api_host)}/v3/inventory",
      feed_message_remote_path: "https://#{Heatwave::Configuration.fetch(:walmart_seller_us_api, :api_host)}/v3/feeds",
      order_message_remote_path: "https://#{Heatwave::Configuration.fetch(:walmart_seller_us_api, :api_host)}/v3/orders",
      items_remote_path: "https://#{Heatwave::Configuration.fetch(:walmart_seller_us_api, :api_host)}/v3/items",
      ship_with_walmart_remote_path: "https://#{Heatwave::Configuration.fetch(:walmart_seller_us_api, :api_host)}/v3/shipping/labels",
      failure_timeout_in_minutes: 1440,
      # 2h, not hourly: Walmart ingestion runs 1+ hours (CA) to several (US), so
      # hourly submission queued several feeds for the same SKUs on their side.
      execute_inventory_flow_every_x_hour: 2,
      execute_price_flow_every_x_hour: 24,
      execute_order_flow_every_x_hour: 1,
      listing_message_feed_enabled: false,
      currency: 'USD'
    },
    walmart_seller_ca: {
      active: true,
      partner: :walmart_seller_ca,
      customer_id: 21_009_368,
      fulfillment_center_id: '10001201755',
      locales: %w[en_CA fr_CA],
      business_unit: 'WALMART_CA',
      default_locale: 'en',
      inventory_message_enabled: true,
      support_contact: 'Soumitro.Biswas0@walmart.com',
      price_message_enabled: true,
      ship_with_walmart_enabled: true, # Enable "Ship with Walmart" discounted shipping rates
      returns_report_enabled: false, # Dark launch: opt in to Returns API ingestion (GET /v3/returns) per partner
      early_label_purchase_enabled: EARLY_LABEL_PURCHASE_ENABLED_CA,
      transporter: :http_walmart_seller_api,
      transporter_profile: :walmart_seller_ca_api,
      # Use global endpoints with WM_MARKET header (set via profile[:market])
      # See: https://developer.walmart.com/global-marketplace/reference/tokenapi
      inventory_message_remote_path: "https://#{Heatwave::Configuration.fetch(:walmart_seller_ca_api, :api_host)}/v3/inventory",
      feed_message_remote_path: "https://#{Heatwave::Configuration.fetch(:walmart_seller_ca_api, :api_host)}/v3/feeds",
      order_message_remote_path: "https://#{Heatwave::Configuration.fetch(:walmart_seller_ca_api, :api_host)}/v3/orders",
      items_remote_path: "https://#{Heatwave::Configuration.fetch(:walmart_seller_ca_api, :api_host)}/v3/items",
      ship_with_walmart_remote_path: "https://#{Heatwave::Configuration.fetch(:walmart_seller_ca_api, :api_host)}/v3/shipping/labels",
      failure_timeout_in_minutes: 1440,
      # See the US note — same 2h cadence for the same reason.
      execute_inventory_flow_every_x_hour: 2,
      execute_price_flow_every_x_hour: 24,
      execute_order_flow_every_x_hour: 1,
      listing_message_feed_enabled: false,
      currency: 'CAD'
    }
  }
end

Instance Method Details

#acknowledge_message_enabled?Boolean

Whether acknowledge messages are configured for this partner.

Returns:

  • (Boolean)


165
166
167
# File 'app/services/edi/walmart/orchestrator.rb', line 165

def acknowledge_message_enabled?
  try(:order_message_remote_path).present?
end

#acknowledge_message_senderAcknowledgeMessageSender, Edi::NullProcessor

Builds the sender that submits order acknowledgements to Walmart.



172
173
174
175
176
# File 'app/services/edi/walmart/orchestrator.rb', line 172

def acknowledge_message_sender
  return Edi::NullProcessor.new(self, :acknowledge_message_sender, options) unless acknowledge_message_enabled?

  AcknowledgeMessageSender.new(self, options)
end

#buy_box_status_enabled?Boolean

Whether buy box status can be fetched for this partner.

Returns:

  • (Boolean)


336
337
338
# File 'app/services/edi/walmart/orchestrator.rb', line 336

def buy_box_status_enabled?
  try(:product_pricing_remote_path).present?
end

#buy_box_status_retrieverBuyBoxStatusRetriever, Edi::NullProcessor

Builds the retriever that fetches buy box status from Walmart.

Returns:



343
344
345
346
347
# File 'app/services/edi/walmart/orchestrator.rb', line 343

def buy_box_status_retriever
  return Edi::NullProcessor.new(self, :buy_box_status_retriever, options) unless buy_box_status_enabled?

  BuyBoxStatusRetriever.new(self, options)
end

#catalog_item_information_enabled?Boolean

Whether catalog item information can be fetched for this partner.

Returns:

  • (Boolean)


320
321
322
# File 'app/services/edi/walmart/orchestrator.rb', line 320

def catalog_item_information_enabled?
  try(:items_remote_path).present?
end

#catalog_item_information_processorCatalogItemInformationProcessor, Edi::NullProcessor

Builds the processor that handles catalog item information.



388
389
390
391
392
# File 'app/services/edi/walmart/orchestrator.rb', line 388

def catalog_item_information_processor
  return Edi::NullProcessor.new(self, :catalog_item_information_processor, options) unless catalog_item_information_enabled?

  CatalogItemInformationProcessor.new(self, options)
end

#catalog_item_information_retrieverCatalogItemInformationRetriever, Edi::NullProcessor

Builds the retriever that fetches catalog item information from Walmart.



327
328
329
330
331
# File 'app/services/edi/walmart/orchestrator.rb', line 327

def catalog_item_information_retriever
  return Edi::NullProcessor.new(self, :catalog_item_information_retriever, options) unless catalog_item_information_enabled?

  CatalogItemInformationRetriever.new(self, options)
end

#confirm_message_enabled?Boolean

Whether confirmation messages are configured for this partner.

Returns:

  • (Boolean)


126
127
128
# File 'app/services/edi/walmart/orchestrator.rb', line 126

def confirm_message_enabled?
  try(:order_message_remote_path).present?
end

#confirm_message_processorConfirmMessageProcessor, Edi::NullProcessor

Builds the processor that confirms Walmart orders.



147
148
149
150
151
# File 'app/services/edi/walmart/orchestrator.rb', line 147

def confirm_message_processor
  return Edi::NullProcessor.new(self, :confirm_message_processor, options) unless confirm_message_enabled?

  ConfirmMessageProcessor.new(self, options)
end

#confirm_message_senderConfirmMessageSender, Edi::NullProcessor

Builds the sender that submits order confirmations to Walmart.



156
157
158
159
160
# File 'app/services/edi/walmart/orchestrator.rb', line 156

def confirm_message_sender
  return Edi::NullProcessor.new(self, :confirm_message_sender, options) unless confirm_message_enabled?

  ConfirmMessageSender.new(self, options)
end

#confirm_outbound_processing?Boolean

Walmart feeds use a two-stage state machine (processing -> complete).

Returns:

  • (Boolean)


575
576
577
# File 'app/services/edi/walmart/orchestrator.rb', line 575

def confirm_outbound_processing?
  true
end

#delete_listing_message_processorDeleteListingMessageProcessor, Edi::NullProcessor

Builds the processor that generates delete-listing messages.

Returns:



429
430
431
432
433
# File 'app/services/edi/walmart/orchestrator.rb', line 429

def delete_listing_message_processor
  return Edi::NullProcessor.new(self, :delete_listing_message_processor, options) unless listing_message_enabled?

  DeleteListingMessageProcessor.new(self, options)
end

#discontinue_flow_processorDiscontinueFlowProcessor

Builds the processor that handles discontinued items.



568
569
570
# File 'app/services/edi/walmart/orchestrator.rb', line 568

def discontinue_flow_processor
  DiscontinueFlowProcessor.new(self, options)
end

#early_label_purchase_enabled?Boolean

Check if early label purchase is enabled for this partner
When enabled, labels are purchased at order release instead of at ship-label time
Set to false to disable the feature; set to true to enable it

Returns:

  • (Boolean)

    true if early label purchase is enabled



140
141
142
# File 'app/services/edi/walmart/orchestrator.rb', line 140

def early_label_purchase_enabled?
  try(:early_label_purchase_enabled) == true && ship_with_walmart_enabled?
end

#execute_discontinue_flowBoolean?

Runs the Walmart discontinue flow.

Returns:

  • (Boolean, nil)

    false when skipped, otherwise the processor result



559
560
561
562
563
# File 'app/services/edi/walmart/orchestrator.rb', line 559

def execute_discontinue_flow
  return false unless active

  discontinue_flow_processor.process
end

#execute_inventory_flow(use_delta_since_last_message: false) ⇒ Boolean?

Runs the Walmart inventory feed flow.

Parameters:

  • use_delta_since_last_message (Boolean) (defaults to: false)

    whether to send only inventory changes since the last message

Returns:

  • (Boolean, nil)

    false when skipped, otherwise the sender result



503
504
505
506
507
508
509
# File 'app/services/edi/walmart/orchestrator.rb', line 503

def execute_inventory_flow(use_delta_since_last_message: false)
  return false unless active
  return false if inventory_feed_in_flight?

  inventory_message_processor.process(use_delta_since_last_message:) # Generate an inventory feed message
  inventory_message_sender.process # Send it
end

#execute_listing_message_feed_flowBoolean?

Runs the Walmart listing message feed flow.

Returns:

  • (Boolean, nil)

    false when skipped, otherwise the sender result



549
550
551
552
553
554
# File 'app/services/edi/walmart/orchestrator.rb', line 549

def execute_listing_message_feed_flow
  return false unless active

  listing_message_feed_processor.process # Generate a listing message feed message
  listing_message_feed_sender.process # Send it
end

#execute_order_flowvoid

This method returns an undefined value.

Runs the Walmart order retrieval and acknowledgement flow.



438
439
440
441
442
443
444
445
446
447
448
449
450
451
# File 'app/services/edi/walmart/orchestrator.rb', line 438

def execute_order_flow
  return unless active

  order_message_retriever.process
  sleep(1)
  order_message_processor.process
  sleep(1)
  acknowledge_message_sender.process
  sleep(1)
  confirm_message_sender.process
  execute_returns_report_flow
  # sleep(1)
  # execute_fba_order_flow # need this to run less frequently or to remove ECLs where we skip all the processed fba_orders
end

#execute_price_flow(use_delta_since_last_message: false) ⇒ Boolean?

Runs the Walmart price feed flow.

Parameters:

  • use_delta_since_last_message (Boolean) (defaults to: false)

    whether to send only price changes since the last message

Returns:

  • (Boolean, nil)

    false when skipped, otherwise the sender result



539
540
541
542
543
544
# File 'app/services/edi/walmart/orchestrator.rb', line 539

def execute_price_flow(use_delta_since_last_message: false)
  return false unless active

  price_message_processor.process(use_delta_since_last_message:) # Generate a price feed message
  price_message_sender.process # Send it
end

#execute_returns_report_flow(start_time: nil, end_time: nil) ⇒ void

This method returns an undefined value.

Pulls the Walmart returns (previous day's window) and applies them to
our RMAs. The order flow runs hourly (+execute_order_flow_every_x_hour+)
but returns ingestion is a daily batch, so runs are limited by three
+Rails.cache+ keys: a 30-minute in-flight lock (+unless_exist+ — first
caller wins, so overlapping cycles don't double-fetch), a 24-hour
completion gate written ONLY after a window was actually retrieved, and
a 7-day pending-window marker recorded on failure so a window that keeps
failing past midnight is resumed (oldest first) instead of silently
dropped. Pass an explicit window (backfills) to bypass all three. Dark
unless the partner config carries +returns_report_enabled: true+.

Parameters:

  • start_time (Time, Date, String, nil) (defaults to: nil)

    explicit window start.

  • end_time (Time, Date, String, nil) (defaults to: nil)

    explicit window end.



467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
# File 'app/services/edi/walmart/orchestrator.rb', line 467

def execute_returns_report_flow(start_time: nil, end_time: nil)
  return unless returns_report_enabled?

  explicit_window = start_time.present? || end_time.present?
  done_key = "edi/walmart/returns_report_flow/#{partner}/#{Date.current.iso8601}"
  return if !explicit_window && Rails.cache.read(done_key)
  return unless explicit_window || Rails.cache.write("edi/walmart/returns_report_flow/lock/#{partner}", Time.current.iso8601, expires_in: 30.minutes, unless_exist: true)

  pending_key = "edi/walmart/returns_report_flow/pending/#{partner}"
  pending = !explicit_window && Rails.cache.read(pending_key)
  window = explicit_window ? { start_time:, end_time: } : JSON.parse(pending || '{}', symbolize_names: true)

  result = returns_report_retriever.process(**window)
  if result.nil? # failed — leave ungated and pin the window for a later cycle
    unless explicit_window
      # A window already pending and failing again is stuck — surface it
      # on AppSignal before the pending key quietly expires (7-day TTL).
      ErrorReporting.error('Walmart returns report window stuck retrying', partner:, window:) if pending
      ws, we = returns_report_retriever.resolve_window(window[:start_time], window[:end_time])
      Rails.cache.write(pending_key, { start_time: ws, end_time: we }.to_json, expires_in: 7.days, unless_exist: true)
    end
    return
  end

  Rails.cache.delete(pending_key)
  # A resumed pending window isn't today's pull — leave today ungated so
  # the current window is attempted on the next cycle.
  Rails.cache.write(done_key, Time.current.iso8601, expires_in: 24.hours) unless explicit_window || pending
  sleep(1)
  returns_report_processor.process
end

#feed_submission_result_processorFeedSubmissionResultProcessor

Builds the processor that checks feed submission results.



313
314
315
# File 'app/services/edi/walmart/orchestrator.rb', line 313

def feed_submission_result_processor
  FeedSubmissionResultProcessor.new(self, options)
end

#inventory_feed_in_flight?Boolean

Whether Walmart is still ingesting a recently submitted inventory feed.

Walmart ingestion has been running 1+ hours (CA) to several hours (US), well past
the submission interval, so without this guard multiple feeds covering the same
SKUs queue up on their side at once.

Bounded deliberately: a feed can sit in :processing for
+failure_timeout_in_minutes+ (24h) before the result processor calls it failed,
and blocking inventory that long is worse than overlapping. Past the window the
in-flight feed is treated as abandoned and a fresh one goes out.

Returns:



523
524
525
526
527
528
529
530
531
532
533
# File 'app/services/edi/walmart/orchestrator.rb', line 523

def inventory_feed_in_flight?
  in_flight = EdiCommunicationLog.where(partner: partner, category: 'inventory_advice', state: 'processing')
                                 .where(created_at: IN_FLIGHT_FEED_WINDOW.ago..)
                                 .order(:created_at)
                                 .last
  return false unless in_flight

  Rails.logger.info "[Walmart #{partner}] Skipping inventory flow — EdiCommunicationLog:#{in_flight.id} " \
                    "(feed #{in_flight.transaction_id}) still processing since #{in_flight.created_at}"
  true
end

#inventory_message_enabled?Boolean

Whether inventory messages are enabled for this partner.

Returns:

  • (Boolean)


235
236
237
238
239
240
# File 'app/services/edi/walmart/orchestrator.rb', line 235

def inventory_message_enabled?
  # `try` (not bare call) because per-partner attr_accessors are only
  # defined for keys actually present in the partner config hash —
  # mirrors the Amazon fix landed for AppSignal #5595.
  try(:inventory_message_enabled).present?
end

#inventory_message_processorInventoryMessageProcessor, Edi::NullProcessor

Builds the processor that generates inventory feed messages.



245
246
247
248
249
# File 'app/services/edi/walmart/orchestrator.rb', line 245

def inventory_message_processor
  return Edi::NullProcessor.new(self, :inventory_message_processor, options) unless inventory_message_enabled?

  InventoryMessageProcessor.new(self, options)
end

#inventory_message_senderInventoryMessageSender, Edi::NullProcessor

Builds the sender that submits inventory feeds to Walmart.



254
255
256
257
258
# File 'app/services/edi/walmart/orchestrator.rb', line 254

def inventory_message_sender
  return Edi::NullProcessor.new(self, :inventory_message_sender, options) unless inventory_message_enabled?

  InventoryMessageSender.new(self, options)
end

#invoice_message_enabled?Boolean

Invoice messages are not supported for Walmart partners.

Returns:

  • (Boolean)


181
182
183
# File 'app/services/edi/walmart/orchestrator.rb', line 181

def invoice_message_enabled?
  false
end

#invoice_message_processorEdi::NullProcessor

Returns a null processor because invoices are not supported.

Returns:



188
189
190
# File 'app/services/edi/walmart/orchestrator.rb', line 188

def invoice_message_processor
  Edi::NullProcessor.new(self, :invoice_message_processor, options)
end

#listing_item_information_processorListingItemInformationProcessor, Edi::NullProcessor

Builds the processor that handles listing item information.

Returns:



361
362
363
364
365
# File 'app/services/edi/walmart/orchestrator.rb', line 361

def listing_item_information_processor
  return Edi::NullProcessor.new(self, :listing_item_information_processor, options) unless listing_message_enabled?

  ListingItemInformationProcessor.new(self, options)
end

#listing_item_information_retrieverListingItemInformationRetriever, Edi::NullProcessor

Builds the retriever that fetches listing item information from Walmart.

Returns:



352
353
354
355
356
# File 'app/services/edi/walmart/orchestrator.rb', line 352

def listing_item_information_retriever
  return Edi::NullProcessor.new(self, :listing_item_information_retriever, options) unless listing_message_enabled?

  ListingItemInformationRetriever.new(self, options)
end

#listing_item_schema_processorListingItemSchemaProcessor, Edi::NullProcessor

Builds the processor that handles listing item schema.

Returns:



379
380
381
382
383
# File 'app/services/edi/walmart/orchestrator.rb', line 379

def listing_item_schema_processor
  return Edi::NullProcessor.new(self, :listing_item_schema_processor, options) unless listing_schema_message_enabled?

  ListingItemSchemaProcessor.new(self, options)
end

#listing_item_schema_retrieverListingItemSchemaRetriever, Edi::NullProcessor

Builds the retriever that fetches listing item schema from Walmart.

Returns:



370
371
372
373
374
# File 'app/services/edi/walmart/orchestrator.rb', line 370

def listing_item_schema_retriever
  return Edi::NullProcessor.new(self, :listing_item_schema_retriever, options) unless listing_schema_message_enabled?

  ListingItemSchemaRetriever.new(self, options)
end

#listing_message_enabled?Boolean

Whether listing messages are configured for this partner.

Returns:

  • (Boolean)


397
398
399
# File 'app/services/edi/walmart/orchestrator.rb', line 397

def listing_message_enabled?
  try(:listing_message_remote_path).present?
end

#listing_message_feed_enabled?Boolean

Whether listing message feeds are enabled for this partner.

Returns:

  • (Boolean)


288
289
290
# File 'app/services/edi/walmart/orchestrator.rb', line 288

def listing_message_feed_enabled?
  listing_message_feed_enabled
end

#listing_message_feed_processorListingMessageFeedProcessor, Edi::NullProcessor

Builds the processor that generates listing message feed messages.



304
305
306
307
308
# File 'app/services/edi/walmart/orchestrator.rb', line 304

def listing_message_feed_processor
  return Edi::NullProcessor.new(self, :listing_message_feed_processor, options) unless listing_message_feed_enabled?

  ListingMessageFeedProcessor.new(self, options)
end

#listing_message_feed_senderListingMessageFeedSender, Edi::NullProcessor

Builds the sender that submits listing message feeds to Walmart.



295
296
297
298
299
# File 'app/services/edi/walmart/orchestrator.rb', line 295

def listing_message_feed_sender
  return Edi::NullProcessor.new(self, :listing_message_feed_sender, options) unless listing_message_feed_enabled?

  ListingMessageFeedSender.new(self, options)
end

#listing_message_processorListingMessageProcessor, Edi::NullProcessor

Builds the processor that generates listing messages.

Returns:



420
421
422
423
424
# File 'app/services/edi/walmart/orchestrator.rb', line 420

def listing_message_processor
  return Edi::NullProcessor.new(self, :listing_message_processor, options) unless listing_message_enabled?

  ListingMessageProcessor.new(self, options)
end

#listing_message_senderListingMessageSender, Edi::NullProcessor

Builds the sender that submits listing messages to Walmart.

Returns:



411
412
413
414
415
# File 'app/services/edi/walmart/orchestrator.rb', line 411

def listing_message_sender
  return Edi::NullProcessor.new(self, :listing_message_sender, options) unless listing_message_enabled?

  ListingMessageSender.new(self, options)
end

#listing_schema_message_enabled?Boolean

Whether listing schema messages are enabled for this partner.

Returns:

  • (Boolean)


404
405
406
# File 'app/services/edi/walmart/orchestrator.rb', line 404

def listing_schema_message_enabled?
  try(:listing_schema_message_enabled).present?
end

#order_message_enabled?Boolean

Whether order messages are configured for this partner.

Returns:

  • (Boolean)


101
102
103
# File 'app/services/edi/walmart/orchestrator.rb', line 101

def order_message_enabled?
  try(:order_message_remote_path).present?
end

#order_message_processorOrderMessageProcessor, Edi::NullProcessor

Builds the processor that handles newly fetched Walmart orders.



117
118
119
120
121
# File 'app/services/edi/walmart/orchestrator.rb', line 117

def order_message_processor
  return Edi::NullProcessor.new(self, :order_message_processor, options) unless order_message_enabled?

  OrderMessageProcessor.new(self, options)
end

#order_message_retrieverOrderMessageRetriever, Edi::NullProcessor

Builds the retriever that fetches new Walmart orders.



108
109
110
111
112
# File 'app/services/edi/walmart/orchestrator.rb', line 108

def order_message_retriever
  return Edi::NullProcessor.new(self, :order_message_retriever, options) unless order_message_enabled?

  OrderMessageRetriever.new(self, options)
end

#orders_with_walmart_po(po_number) ⇒ ActiveRecord::Relation<Order>

Finds local orders matching the given Walmart purchase-order number.

Parameters:

  • po_number (String)

    the Walmart PO number to search for

Returns:

  • (ActiveRecord::Relation<Order>)


590
591
592
593
594
595
# File 'app/services/edi/walmart/orchestrator.rb', line 590

def orders_with_walmart_po(po_number)
  Order.joins(:customer)
       .where(customers: { id: customer_ids })
       .where(edi_po_number: po_number)
       .where('orders.created_at > ?', 13.months.ago)
end

#price_message_enabled?Boolean

Whether price messages are enabled for this partner.

Returns:

  • (Boolean)


263
264
265
# File 'app/services/edi/walmart/orchestrator.rb', line 263

def price_message_enabled?
  price_message_enabled
end

#price_message_processorPriceMessageProcessor, Edi::NullProcessor

Builds the processor that generates price feed messages.



279
280
281
282
283
# File 'app/services/edi/walmart/orchestrator.rb', line 279

def price_message_processor
  return Edi::NullProcessor.new(self, :price_message_processor, options) unless price_message_enabled?

  PriceMessageProcessor.new(self, options)
end

#price_message_senderPriceMessageSender, Edi::NullProcessor

Builds the sender that submits price updates to Walmart.



270
271
272
273
274
# File 'app/services/edi/walmart/orchestrator.rb', line 270

def price_message_sender
  return Edi::NullProcessor.new(self, :price_message_sender, options) unless price_message_enabled?

  PriceMessageSender.new(self, options)
end

#pull_all_catalog_information(dry_run: false) ⇒ Array<Object>

Pulls Walmart catalog information for all catalog items, paginated.

Parameters:

  • dry_run (Boolean) (defaults to: false)

    when true, process without persisting changes

Returns:

  • (Array<Object>)

    results from each page processor run



628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
# File 'app/services/edi/walmart/orchestrator.rb', line 628

def pull_all_catalog_information(dry_run: false)
  results = []
  offset = 0
  limit = 200

  loop do
    ecl = catalog_item_information_retriever.process_all(offset: offset, limit: limit)
    break unless ecl

    result = catalog_item_information_processor.process(ecl, dry_run: dry_run)
    results << result

    # Check for more pages
    data = JSON.parse(ecl.data).with_indifferent_access
    total_items = data[:totalItems].to_i
    break if offset + limit >= total_items

    offset += limit
    sleep(0.5)
  end

  results
end

#pull_catalog_information(catalog_item) ⇒ Object?

Pulls Walmart catalog information for a single catalog item.

Parameters:

  • catalog_item (CatalogItem)

    the catalog item to refresh

Returns:

  • (Object, nil)

    the processor result, or nil when the SKU is not found

Raises:

  • (RuntimeError)

    if the catalog item has no SKU



602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
# File 'app/services/edi/walmart/orchestrator.rb', line 602

def pull_catalog_information(catalog_item)
  sku = catalog_item.reported_vendor_sku || catalog_item.sku
  raise "No SKU for catalog_item #{catalog_item.id}" if sku.blank?

  ecl = catalog_item_information_retriever.process(
    sku: sku,
    file_info: {
      sku: sku,
      catalog_item_id: catalog_item.id,
      item_id: catalog_item.item_id
    }
  )

  if ecl
    Rails.logger.debug { "Walmart orchestrator#pull_catalog_information, ecl: #{ecl.id}" }
    catalog_item_information_processor.process(ecl)
  else
    Rails.logger.error "Walmart orchestrator#pull_catalog_information for catalog item #{catalog_item.id} yielded no ecl (sku #{sku} not found?)"
    nil
  end
end

#return_notification_message_enabled?Boolean

Return notifications are not supported for Walmart partners.

Returns:

  • (Boolean)


195
196
197
# File 'app/services/edi/walmart/orchestrator.rb', line 195

def return_notification_message_enabled?
  false
end

#return_notification_message_processorEdi::NullProcessor

Returns a null processor because return notifications are not supported.

Returns:



202
203
204
# File 'app/services/edi/walmart/orchestrator.rb', line 202

def return_notification_message_processor
  Edi::NullProcessor.new(self, :return_notification_message_processor, options)
end

#returns_report_enabled?Boolean

Whether Walmart returns ingestion (GET /v3/returns) is enabled for this
partner. try (not bare call) because per-partner attr_accessors are
only defined for keys actually present in the partner config hash —
partners without an explicit returns_report_enabled: key stay dark
instead of raising NameError (same pattern as inventory_message_enabled?
after AppSignal #5595).

Returns:

  • (Boolean)


214
# File 'app/services/edi/walmart/orchestrator.rb', line 214

def returns_report_enabled? = try(:returns_report_enabled).present?

#returns_report_processorReturnsReportProcessor, Edi::NullProcessor

Returns the processor when
enabled, a null processor otherwise.

Returns:



226
227
228
229
230
# File 'app/services/edi/walmart/orchestrator.rb', line 226

def returns_report_processor
  return Edi::NullProcessor.new(self, :returns_report_processor, options) unless returns_report_enabled?

  ReturnsReportProcessor.new(self, options)
end

#returns_report_retrieverReturnsReportRetriever, Edi::NullProcessor

Returns the retriever when
enabled, a null processor otherwise.

Returns:



218
219
220
221
222
# File 'app/services/edi/walmart/orchestrator.rb', line 218

def returns_report_retriever
  return Edi::NullProcessor.new(self, :returns_report_retriever, options) unless returns_report_enabled?

  ReturnsReportRetriever.new(self, options)
end

#ship_code_mapperShipCodeMapper

Builds the mapper that translates shipping codes for Walmart.

Returns:



582
583
584
# File 'app/services/edi/walmart/orchestrator.rb', line 582

def ship_code_mapper
  ShipCodeMapper.new(self)
end

#ship_with_walmart_enabled?Boolean

Check if "Ship with Walmart" (SWW) discounted shipping is enabled for this partner

Returns:

  • (Boolean)

    true if SWW rates and label purchasing are enabled



132
133
134
# File 'app/services/edi/walmart/orchestrator.rb', line 132

def ship_with_walmart_enabled?
  try(:ship_with_walmart_enabled) == true && try(:ship_with_walmart_remote_path).present?
end