Class: Edi::Amazon::PriceMessageProcessor

Inherits:
BaseEdiService show all
Defined in:
app/services/edi/amazon/price_message_processor.rb

Overview

Service object: price message processor.

Constant Summary

Constants included from Edi::AddressAbbreviator

Edi::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 Edi::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

#append_catalog_item(messages, ci, idx, sku, fba = false) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'app/services/edi/amazon/price_message_processor.rb', line 73

def append_catalog_item(messages, ci, idx, sku, fba = false)
  discontinued = ci.discontinued? || ci.pending_discontinue? || ci.in_hide_from_feed_state?
  return if fba && discontinued # Don't know what else to do?

  pt = ci.amazon_listing_reported_product_type || ci.amazon_reported_product_type || ci.amazon_desired_product_type || 'SPACE_HEATER'
  patches = get_amazon_json_patches(ci, product_type: pt, fba:)
  return unless pt.present? && patches.any?

  message = {
    messageId: idx,
    sku: sku,
    operationType: 'PATCH', # Here we are only implementing the PATCH operations
    productType: pt.upcase,
    patches: patches
  }
  messages << message
  messages
end

#append_catalog_items(catalog_items) ⇒ Object



62
63
64
65
66
67
68
69
70
71
# File 'app/services/edi/amazon/price_message_processor.rb', line 62

def append_catalog_items(catalog_items)
  # see: https://github.com/amzn/selling-partner-api-models/blob/main/schemas/feeds/listings-feed-message-schema-v2.json
  idx = 0
  messages = []
  catalog_items.find_each do |ci|
    append_catalog_item(messages, ci, idx += 1, ci.reported_vendor_sku, false)
    append_catalog_item(messages, ci, idx += 1, ci.amazon_fba_sku, true) if ci.has_amazon_fba?
  end
  messages
end

#build_json(catalog_items: nil, states: nil) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'app/services/edi/amazon/price_message_processor.rb', line 47

def build_json(catalog_items: nil, states: nil)
  # see: https://github.com/amzn/selling-partner-api-models/blob/main/schemas/feeds/listings-feed-schema-v2.json
  catalog_items ||= load_catalog_items(states:)
  logger.info "#{catalog_items.size} items in json listing feed payload"
  feed_hash = {
    header: {
      sellerId: orchestrator.merchant_id,
      version: '2.0',
      issueLocale: 'en_US'
    },
    messages: append_catalog_items(catalog_items)
  }
  feed_hash.to_json
end

#get_amazon_json_patches(catalog_item, product_type: nil, fba: false) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'app/services/edi/amazon/price_message_processor.rb', line 92

def get_amazon_json_patches(catalog_item, product_type: nil, fba: false)
  # see: https://developer-docs.amazon.com/sp-api/docs/listings-items-api-v2021-08-01-reference#listingsitempatchrequest
  # see: https://developer-docs.amazon.com/sp-api/docs/listings-items-api-v2021-08-01-reference#patchoperation
  # see: https://developer-docs.amazon.com/sp-api/docs/listing-workflow-migration-tutorial#migrating-pricing-feeds-workflows
  # "patches": [
  #   {
  #     "op": "replace",
  #     "path": "/attributes/purchasable_offer",
  #     "value": [
  #       {
  #         "audience": "ALL",
  #         "currency": "USD",
  #         "our_price": [
  #           {
  #             "schedule": [
  #               {
  #                 "value_with_tax": 30.00
  #               }
  #             ]
  #           }
  #         ]
  #       }
  #     ]
  #   },
  #   ... (more patches, if applicable)
  # ]
  amazon_product_listing_generator = Edi::Amazon::JsonListingGenerator::Factory.generator_for_catalog_item(catalog_item, product_type:, attribute_actions: { purchasable_offer: :replace, list_price: :replace }, fba:,
business_price_available: orchestrator.try(:business_price_available))
  amazon_product_listing_generator.get_patches
end

#load_catalog_items(states: nil, use_delta_since_last_message: false) ⇒ Object



36
37
38
39
40
41
42
43
44
45
# File 'app/services/edi/amazon/price_message_processor.rb', line 36

def load_catalog_items(states: nil, use_delta_since_last_message: false)
  states ||= %w[active require_vendor_update pending_vendor_update pending_discontinue]
  catalog_items = orchestrator.customer.catalog
                              .catalog_items
                              .for_edi_feeds_by_states(states)
                              .amazons_with_asins
                              .with_item.eager_load(:store_item, :item)
  catalog_items = catalog_items.edi_delta_feeds_for_partner_price_advice(orchestrator.partner) if use_delta_since_last_message
  catalog_items.order(StoreItem[:qty_available])
end

#process(catalog_items: nil, states: nil, use_delta_since_last_message: false) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'app/services/edi/amazon/price_message_processor.rb', line 6

def process(catalog_items: nil, states: nil, use_delta_since_last_message: false)
  # see: https://developer-docs.amazon.com/sp-api/docs/listings-feed-type-values#listings-feed
  # see: https://developer-docs.amazon.com/sp-api/docs/building-listings-management-workflows-guide#should-i-submit-in-bulk-using-the-json_listings_feed-or-individually-with-the-listings-items-api
  # see: https://developer-docs.amazon.com/sp-api/docs/listings-items-api-v2021-08-01-reference#patchlistingsitem
  logger.info "Creating price feed for partner #{orchestrator.partner}"
  catalog_items ||= load_catalog_items(states:, use_delta_since_last_message:)
  return :empty_set if catalog_items.blank?

  # Here we want to handle whether to send a feed for many catalog items or a single patch for a single catalog item to avoid all the 429 throttling when sending multiple feeds
  if catalog_items.size == 1
    ci = catalog_items.first
    ci.amazon_send_patch_listing_information(attribute_actions: { purchasable_offer: :replace, list_price: :replace })
  else
    ecl = nil
    EdiCommunicationLog.transaction do
      data_json = build_json(catalog_items:, states:)
      ecl = EdiCommunicationLog.create_outbound_file_from_data(
        data: data_json,
        data_type: 'json',
        file_extension: 'pri',
        partner: orchestrator.partner,
        category: 'price_advice',
        resources: catalog_items,
        file_info: {}
      )
    end
    ecl
  end
end