Class: Edi::Wayfair::InventoryMessageProcessor

Inherits:
BaseEdiService show all
Defined in:
app/services/edi/wayfair/inventory_message_processor.rb

Overview

Builds Wayfair inventory-advice (inventory.save, feedKind TRUE_UP)
GraphQL mutations for our catalog items and queues them as outbound
EdiCommunicationLog records for InventoryMessageSender to transmit.

Constant Summary

Constants included from RequestIdentifiable

RequestIdentifiable::REQUEST_ID_HEADERS

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

#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

#partner_request_id

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

#build_mutation(catalog_items: nil, states: nil) ⇒ String

Builds a single inventory.save mutation for a batch of catalog items.

Parameters:

  • catalog_items (Array<CatalogItem>) (defaults to: nil)

    items in this batch

  • states (Array<String>, nil) (defaults to: nil)

    unused, kept for interface compatibility

Returns:

  • (String)

    the GraphQL mutation payload



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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'app/services/edi/wayfair/inventory_message_processor.rb', line 62

def build_mutation(catalog_items: nil, states: nil) # rubocop:disable Lint/UnusedMethodArgument
  logger.info "#{catalog_items.size} items in inventory payload"
  %(
    mutation save {
      inventory {
        save(
          inventory: [
            #{catalog_items.map { |ci| catalog_item_to_inventory_row(ci) }.join(', ')}
          ],
          feedKind: TRUE_UP
        ) {
          id,
          handle,
          status,
          submittedAt,
          completedAt,
          errors {
            key,
            message
          }
        }
      }
    }
  ).squish

  # mutation_str = %(
  # mutation save {
  #   inventory {
  #     save(inventory: [{supplierId: 7083, supplierPartNumber: \\\"WSHC-240-00483\\\",
  #                       quantityOnHand: 4, discontinued: false}], feedKind: TRUE_UP) {
  #       id
  #       handle
  #       status
  #       submittedAt
  #       completedAt
  #       errors {
  #         key
  #         message
  #       }
  #     }
  #   }
  # }
  # ).squish

  # mutation_str
end

#catalog_item_to_inventory_row(ci) ⇒ String

Serializes one catalog item as an inventory row of the mutation.

Parameters:

Returns:

  • (String)

    the GraphQL inventory row fragment



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
# File 'app/services/edi/wayfair/inventory_message_processor.rb', line 112

def catalog_item_to_inventory_row(ci)
  discontinued = ci.discontinued? || ci.pending_discontinue? || ci.in_hide_from_feed_state?
  if discontinued
    "{ supplierId: #{orchestrator.warehouse_code}, supplierPartNumber: \\\"#{ci.reported_vendor_sku}\\\", quantityOnHand: 0, discontinued: true }"
  else
    # total_available = ci.reported_stock
    # if total_available < 10
    #   global_next_available_date = nil
    #   global_next_available_qty = nil
    #   next_available_by_warehouse = ci.next_available_by_warehouse
    #   next_available_by_warehouse.each do |warehouse_name, on_order_data|
    #     next unless on_order_data && on_order_data.next_available_date
    #     global_next_available_date ||= on_order_data.next_available_date.iso8601 # "2020-11-01T00:00:00+00:00"
    #     global_next_available_qty ||= on_order_data.next_available_qty
    #   end
    # end
    # Wayfair bears cross-border fulfillment costs for Canadian offers. CA
    # may therefore use the catalog/item-configured alternate-warehouse
    # share; US remains tied to its primary warehouse.
    use_alternate_warehouse = orchestrator.partner == :wayfair_ca
    quantity = ci.reported_stock(use_alternate_warehouse:)
    "{ supplierId: #{orchestrator.warehouse_code}, " \
      "supplierPartNumber: \\\"#{ci.reported_vendor_sku}\\\", quantityOnHand: #{quantity}, " \
      "productNameAndOptions: \\\"#{orchestrator.clean_string(ci.reported_name)}\\\", discontinued: false }"
  end
end

#load_catalog_items(states: nil) ⇒ ActiveRecord::Relation<CatalogItem>

Loads reportable catalog items across the orchestrator's customers.

Parameters:

  • states (Array<String>, nil) (defaults to: nil)

    catalog item states to include

Returns:



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'app/services/edi/wayfair/inventory_message_processor.rb', line 41

def load_catalog_items(states: nil)
  states ||= %w[active require_vendor_update pending_vendor_update pending_discontinue]
  catalog_item_ids = []
  orchestrator.customers.each do |customer|
    catalog_items = customer.catalog.catalog_items.where(state: states).not_hidden_from_catalog
    catalog_items = customer.catalog.catalog_items.where(state: states + ['discontinued']) if Rails.env.development?
    # When our catalog requires third party part number, do not grab those catalog items without one
    catalog_items = catalog_items.where.not(third_party_part_number: nil) if customer.catalog.third_party_part_number_required
    catalog_items = catalog_items.where('third_party_sku ~ ?', customer.catalog.third_party_sku_filter_regex) if customer.catalog.is_active_third_party_sku_filter
    catalog_item_ids += catalog_items.ids
  end
  CatalogItem.where(id: catalog_item_ids.uniq)
             .with_item
             .eager_load(:store_item, :item)
             .order(Item[:sku])
end

#process(catalog_items: nil, states: nil) ⇒ EdiCommunicationLog?

Builds the inventory mutation in batches and queues each batch.

Parameters:

  • catalog_items (ActiveRecord::Relation<CatalogItem>, nil) (defaults to: nil)

    items to
    report; nil loads them from the orchestrator's customers

  • states (Array<String>, nil) (defaults to: nil)

    catalog item states to include when loading

Returns:



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'app/services/edi/wayfair/inventory_message_processor.rb', line 18

def process(catalog_items: nil, states: nil)
  ecl = nil
  EdiCommunicationLog.transaction do
    logger.info "Creating inventory advice for partner #{orchestrator.partner}"
    catalog_items ||= load_catalog_items(states: states)
    catalog_items.in_batches(of: 200).each_with_index do |catalog_items_batch, _batch_index|
      data = build_mutation(catalog_items: catalog_items_batch, states: states)
      ecl = EdiCommunicationLog.create_outbound_file_from_data(
        data: data,
        file_extension: 'inv',
        partner: orchestrator.partner,
        category: 'inventory_advice',
        resources: catalog_items,
        file_info: {}
      )
    end
  end
  ecl
end