Class: Edi::Amazon::FeedMessageSender

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

Constant Summary

Constants included from Edi::AddressAbbreviator

Edi::AddressAbbreviator::MAX_LENGTH

Instance Attribute Summary

Attributes inherited from BaseEdiService

#orchestrator

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, #options, #tagged_logger

Constructor Details

This class inherits a constructor from Edi::BaseEdiService

Instance Method Details

#ecl_in_queueObject



130
131
132
133
134
135
# File 'app/services/edi/amazon/feed_message_sender.rb', line 130

def ecl_in_queue
  EdiCommunicationLog.requiring_processing
                     .where(partner: orchestrator.partner)
                     .where(category: feed_category)
                     .order(:created_at)
end

#instantiate_transporter(transporter, transporter_profile = nil, options = {}) ⇒ Object



137
138
139
140
141
142
143
144
145
146
# File 'app/services/edi/amazon/feed_message_sender.rb', line 137

def instantiate_transporter(transporter, transporter_profile = nil, options = {})
  case transporter
  when :http_seller_api
    Transport::HttpSellerApiConnection.new({ profile: transporter_profile }.merge(options))
  when :http_api_upload
    Transport::HttpApiUploadConnection.new({ profile: transporter_profile }.merge(options))
  else
    raise "Unknown transporter: #{transporter}"
  end
end

#process(edi_communication_logs = nil) ⇒ Object

res_feed_id = res[:feedId]



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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'app/services/edi/amazon/feed_message_sender.rb', line 66

def process(edi_communication_logs = nil)
  feed_transport = instantiate_transporter(orchestrator.transporter, orchestrator.transporter_profile)

  edi_communication_logs ||= ecl_in_queue
  [edi_communication_logs].flatten.each do |ecl|
    logger.info "Sending feed data to #{orchestrator.partner}"
    # STEP 1 Create Feed Document
    # VERY IMPORTANT contentType must match Content-Type header in the subsequent upload PUT request exactly!
    ct = if ecl.data_type == 'xml'
           'text/xml; charset=UTF-8'
         else
           'application/json'
         end
    data = %({'contentType':'#{ct}'})
    res = feed_transport.send_data(data, "#{orchestrator.feed_message_remote_path}/documents", 'POST')
    ecl.notes = "HTTP CODE: #{res[:http_result]&.code}, HTTP BODY: #{res[:http_result]&.body}, HTTP METHOD: 'POST', Timestamp: #{Time.current.to_datetime.to_fs(:crm_default)}"
    logger.info "Result: HTTP CODE: #{res[:http_result]&.code}, HTTP BODY: #{res[:http_result]&.body}"
    if res[:success] && (data = res[:http_result]&.body.to_s).present?
      json_hash = JSON.parse(data).with_indifferent_access
      url = json_hash[:url]
      res_feed_document_id = json_hash[:feedDocumentId]
      # STEP 2 & 3 Contruct and Upload Feed Document from the signed feed document upload url returned, no auth needed
      # VERY IMPORTANT Content-Type header must match contentType in the previous Create Feed Document request exactly!
      feed_document_uploader = instantiate_transporter(:http_api_upload, nil, { headers: { 'Content-Type': ct } })
      res = feed_document_uploader.send_data(ecl.data, url, 'POST')
      ecl.notes += " | HTTP CODE: #{res[:http_result]&.code}, HTTP BODY: #{res[:http_result]&.body}, Timestamp: #{Time.current.to_datetime.to_fs(:crm_default)}"
      if res[:success]
        # STEP 4 Create Feed
        data = %(
          {
            "feedType":"#{feed_type}",
            "marketplaceIds": ["#{orchestrator.marketplace}"],
            "inputFeedDocumentId": "#{res_feed_document_id}"
          }
        )
        res = feed_transport.send_data(data, "#{orchestrator.feed_message_remote_path}/feeds", 'POST')
        ecl.notes += " | HTTP CODE: #{res[:http_result]&.code}, HTTP BODY: #{res[:http_result]&.body}, Timestamp: #{Time.current.to_datetime.to_fs(:crm_default)}"
        logger.info "Result: HTTP CODE: #{res[:http_result]&.code}, HTTP BODY: #{res[:http_result]&.body}"
        if res[:success] && (data = res[:http_result]&.body.to_s).present?
          json_hash = JSON.parse(data).with_indifferent_access
          res_feed_id = json_hash[:feedId]
          ecl.transaction_id = res_feed_id
          ecl.transmit_datetime = Time.current
          ecl.start_process!
        else
          ecl.error
        end
      else
        ecl.error
      end
    else
      ecl.error
    end
  rescue HTTP::RateLimitExceededError => e
    retry_after_seconds = e.retry_after.to_i.positive? ? e.retry_after.to_i : 1.hour.to_i
    transmit_after_time = Time.current + retry_after_seconds
    ecl.update_columns(transmit_after: transmit_after_time)
    logger.warn "Amazon SP-API rate limited for ECL #{ecl.id} (#{feed_category}/#{orchestrator.partner}). " \
                "Scheduled retry via transmit_after: #{transmit_after_time.iso8601} " \
                "(#{retry_after_seconds}s from now). #{e.message}"
  end
  edi_communication_logs
end