Class: Edi::Amazon::Orchestrator
- Inherits:
-
BaseOrchestrator
- Object
- BaseOrchestrator
- Edi::Amazon::Orchestrator
- Defined in:
- app/services/edi/amazon/orchestrator.rb
Constant Summary collapse
- GOLIVE_DATE_STR =
'October 11, 2024'
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
- .execute_feed_submission_result_processor(options = {}) ⇒ Object
- .partners ⇒ Object
- .populate_items_from_all_partners(limit: nil, skus: nil, force: false) ⇒ Object
Instance Method Summary collapse
- #a_plus_content_processor ⇒ Object
- #a_plus_content_remote_path ⇒ Object
- #a_plus_content_retriever ⇒ Object
- #acknowledge_message_enabled? ⇒ Boolean
- #acknowledge_message_sender ⇒ Object
- #buy_box_status_enabled? ⇒ Boolean
- #buy_box_status_retriever ⇒ Object
- #buy_shipping_client ⇒ Object
- #buy_shipping_enabled? ⇒ Boolean
- #catalog_item_information_enabled? ⇒ Boolean
- #catalog_item_information_processor ⇒ Object
- #catalog_item_information_retriever ⇒ Object
- #confirm_message_enabled? ⇒ Boolean
- #confirm_message_processor ⇒ Object
- #confirm_message_sender ⇒ Object
-
#confirm_outbound_processing? ⇒ Boolean
Amazon is a two stage process on , processing.
- #connection_info ⇒ Object
- #delete_listing_from_catalog_item(catalog_item: nil, amazon_variation: nil, http_method: 'DELETE', attribute_actions: nil, use_fba_sku: false) ⇒ Object
- #delete_listing_message_processor ⇒ Object
- #discontinue_flow_processor ⇒ Object
- #execute_discontinue_flow ⇒ Object
- #execute_fba_order_flow ⇒ Object
- #execute_inventory_flow(use_delta_since_last_message: false) ⇒ Object
- #execute_listing_message_feed_flow ⇒ Object
- #execute_order_flow ⇒ Object
- #execute_order_status_verification ⇒ Object
- #execute_price_flow(use_delta_since_last_message: false) ⇒ Object
- #fba_order_message_enabled? ⇒ Boolean
- #fba_order_message_processor ⇒ Object
- #fba_order_message_retriever ⇒ Object
- #fba_pull_orders_by_po_numbers(po_numbers) ⇒ Object
- #feed_submission_result_processor ⇒ Object
- #inventory_message_enabled? ⇒ Boolean
- #inventory_message_processor ⇒ Object
- #inventory_message_sender ⇒ Object
- #invoice_message_enabled? ⇒ Boolean
- #invoice_message_processor ⇒ Object
- #listing_item_information_processor ⇒ Object
- #listing_item_information_retriever ⇒ Object
- #listing_item_schema_processor ⇒ Object
- #listing_item_schema_retriever ⇒ Object
- #listing_message_enabled? ⇒ Boolean
- #listing_message_feed_enabled? ⇒ Boolean
- #listing_message_feed_processor ⇒ Object
- #listing_message_feed_sender ⇒ Object
- #listing_message_processor ⇒ Object
- #listing_message_sender ⇒ Object
- #listing_schema_message_enabled? ⇒ Boolean
- #order_message_enabled? ⇒ Boolean
- #order_message_processor ⇒ Object
- #order_message_retriever ⇒ Object
- #order_status_verification_enabled? ⇒ Boolean
- #order_status_verifier ⇒ Object
- #orders_with_amazon_id_po(order_id) ⇒ Object
-
#populate_items_from_catalog(limit: nil, skus: nil, force: false) ⇒ Object
A method to populate our item data with amazon's catalog data limit: how many records to process skus: specific skus to process force: normally we only will pull if the information is not present, use this to force a reset.
- #price_message_enabled? ⇒ Boolean
- #price_message_processor ⇒ Object
- #price_message_sender ⇒ Object
- #pull_amazon_variation_listing_information(amazon_variation) ⇒ Object
- #pull_buy_box_status(catalog_item) ⇒ Object
- #pull_catalog_information(catalog_item) ⇒ Object
- #pull_listing_information(catalog_item) ⇒ Object
- #pull_listing_schema(catalog_item, product_type = nil) ⇒ Object
- #pull_schema(product_type) ⇒ Object
- #pull_schema_for_locale(product_type, locale, amazon_schema: nil) ⇒ Object
- #push_listing_from_amazon_variation(amazon_variation) ⇒ Object
- #push_listing_from_catalog_item(catalog_item, http_method: 'PATCH', attribute_actions: nil, use_fba_sku: false) ⇒ Object
- #return_notification_message_enabled? ⇒ Boolean
- #return_notification_message_processor ⇒ Object
- #ship_code_mapper ⇒ Object
-
#store_competitor_seller_ids(catalog_item, offers, our_merchant_id) ⇒ Object
Store competitor seller IDs from Buy Box status for discovery Creates AmazonCompetitor records (without names) for any new seller IDs found.
Methods inherited from BaseOrchestrator
all_orchestrators_class, build, 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?, #test_mode?
Constructor Details
This class inherits a constructor from Edi::BaseOrchestrator
Class Method Details
.execute_feed_submission_result_processor(options = {}) ⇒ Object
347 348 349 |
# File 'app/services/edi/amazon/orchestrator.rb', line 347 def self.execute_feed_submission_result_processor( = {}) orchestrators().each { |o| o.feed_submission_result_processor.process } end |
.partners ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 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 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 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 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 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 |
# File 'app/services/edi/amazon/orchestrator.rb', line 12 def self.partners { amazon_seller_central_us: { active: true, partner: :amazon_seller_central_us, customer_id: 5_322_434, fba_store_id: 3, marketplace: 'ATVPDKIKX0DER', merchant_id: 'A1ALB70A8YMUCH', locales: ['en_US'], # aws_access_key_id: Heatwave::Configuration.fetch(:amazon_mws, :aws_access_key_id), # aws_secret_access_key: Heatwave::Configuration.fetch(:amazon_mws, :aws_secret_access_key), order_status_verification_enabled: true, inventory_message_enabled: true, support_contact: 'https://sellercentral.amazon.com/gp/mws/contactus.html', price_message_enabled: true, business_price_available: true, listing_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_api, :api_host)}/listings/2021-08-01/items/", listing_message_feed_enabled: true, product_type_schema_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_api, :api_host)}/definitions/2020-09-01/productTypes/", listing_schema_message_enabled: true, transporter: :http_seller_api, transporter_profile: :amazon_sc_seller_api, acknowledge_only_on_pending_ship_confirm: true, order_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_api, :api_host)}/orders/v0/orders", catalog_item_information_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_api, :api_host)}/catalog/2022-04-01/items/", product_pricing_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_api, :api_host)}/products/pricing/v0/items/", a_plus_content_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_api, :api_host)}/aplus/2020-11-01", feed_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_api, :api_host)}/feeds/2021-06-30", buy_shipping_enabled: true, buy_shipping_business_id: 'AmazonShipping_US', failure_timeout_in_minutes: 1440, execute_inventory_flow_every_x_hour: 24, # once a day for full inventory feed execute_price_flow_every_x_hour: 24, # once a day for full price feed execute_listing_message_feed_flow_every_x_hour: 24, # once a day for full feed currency: 'USD' }, amazon_seller_central_ca: { active: true, partner: :amazon_seller_central_ca, customer_id: 5_768_174, fba_store_id: 5, marketplace: 'A2EUQ1WTGCTBG2', merchant_id: 'A1ALB70A8YMUCH', locales: %w[en_CA fr_CA], # aws_access_key_id: Heatwave::Configuration.fetch(:amazon_mws, :aws_access_key_id), # aws_secret_access_key: Heatwave::Configuration.fetch(:amazon_mws, :aws_secret_access_key), order_status_verification_enabled: true, inventory_message_enabled: true, support_contact: 'https://sellercentral.amazon.com/gp/mws/contactus.html', price_message_enabled: true, business_price_available: true, listing_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_api, :api_host)}/listings/2021-08-01/items/", listing_message_feed_enabled: true, product_type_schema_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_api, :api_host)}/definitions/2020-09-01/productTypes/", listing_schema_message_enabled: true, transporter: :http_seller_api, transporter_profile: :amazon_sc_seller_api, acknowledge_only_on_pending_ship_confirm: true, order_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_api, :api_host)}/orders/v0/orders", catalog_item_information_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_api, :api_host)}/catalog/2022-04-01/items/", product_pricing_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_api, :api_host)}/products/pricing/v0/items/", a_plus_content_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_api, :api_host)}/aplus/2020-11-01", feed_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_api, :api_host)}/feeds/2021-06-30", buy_shipping_enabled: false, failure_timeout_in_minutes: 1440, execute_inventory_flow_every_x_hour: 24, # once a day for full inventory feed execute_price_flow_every_x_hour: 24, # once a day for full price feed execute_listing_message_feed_flow_every_x_hour: 24, # once a day for full feed currency: 'CAD' }, amazon_seller_central_fr: { active: true, partner: :amazon_seller_central_fr, customer_id: 22_447_665, marketplace: 'A13V1IB3VIYZZH', merchant_id: 'A1U07I6I50BN2R', locales: ['fr'], language_tag: 'fr_FR', inventory_message_enabled: true, support_contact: 'https://sellercentral.amazon.com/gp/mws/contactus.html', price_message_enabled: true, business_price_available: true, listing_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/listings/2021-08-01/items/", listing_message_feed_enabled: false, product_type_schema_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/definitions/2020-09-01/productTypes/", listing_schema_message_enabled: true, transporter: :http_seller_api, transporter_profile: :amazon_sc_seller_eu_api, acknowledge_only_on_pending_ship_confirm: true, order_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/orders/v0/orders", catalog_item_information_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/catalog/2022-04-01/items/", a_plus_content_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/aplus/2020-11-01/", feed_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/feeds/2021-06-30", failure_timeout_in_minutes: 480, execute_inventory_flow_every_x_hour: 24, # once a day for full inventory feed execute_price_flow_every_x_hour: 24, # once a day for full price feed execute_listing_message_feed_flow_every_x_hour: 24, # once a day for full feed currency: 'EUR' }, amazon_seller_central_be: { active: true, partner: :amazon_seller_central_be, customer_id: 23_325_148, marketplace: 'AMEN7PMS3EDWL', merchant_id: 'A1U07I6I50BN2R', locales: ['fr'], language_tag: 'fr_FR', inventory_message_enabled: true, support_contact: 'https://sellercentral.amazon.com/gp/mws/contactus.html', price_message_enabled: true, business_price_available: false, listing_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/listings/2021-08-01/items/", listing_message_feed_enabled: false, product_type_schema_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/definitions/2020-09-01/productTypes/", listing_schema_message_enabled: true, transporter: :http_seller_api, transporter_profile: :amazon_sc_seller_eu_api, acknowledge_only_on_pending_ship_confirm: true, order_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/orders/v0/orders", catalog_item_information_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/catalog/2022-04-01/items/", a_plus_content_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/aplus/2020-11-01/", feed_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/feeds/2021-06-30", failure_timeout_in_minutes: 480, execute_inventory_flow_every_x_hour: 24, # once a day for full inventory feed execute_price_flow_every_x_hour: 24, # once a day for full price feed execute_listing_message_feed_flow_every_x_hour: 24, # once a day for full feed currency: 'EUR' }, amazon_seller_central_de: { active: true, partner: :amazon_seller_central_de, customer_id: 18_007_732, marketplace: 'A1PA6795UKMFR9', merchant_id: 'A1U07I6I50BN2R', locales: ['de'], language_tag: 'de_DE', inventory_message_enabled: true, support_contact: 'https://sellercentral.amazon.com/gp/mws/contactus.html', price_message_enabled: true, business_price_available: true, listing_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/listings/2021-08-01/items/", listing_message_feed_enabled: false, product_type_schema_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/definitions/2020-09-01/productTypes/", listing_schema_message_enabled: true, transporter: :http_seller_api, transporter_profile: :amazon_sc_seller_eu_api, acknowledge_only_on_pending_ship_confirm: true, order_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/orders/v0/orders", catalog_item_information_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/catalog/2022-04-01/items/", a_plus_content_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/aplus/2020-11-01/", feed_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/feeds/2021-06-30", failure_timeout_in_minutes: 480, execute_inventory_flow_every_x_hour: 24, # once a day for full inventory feed execute_price_flow_every_x_hour: 24, # once a day for full price feed execute_listing_message_feed_flow_every_x_hour: 24, # once a day for full feed currency: 'EUR' }, amazon_seller_central_es: { active: true, partner: :amazon_seller_central_es, customer_id: 22_308_935, marketplace: 'A1RKKUPIHCS9HS', merchant_id: 'A1U07I6I50BN2R', locales: ['es'], language_tag: 'es_ES', inventory_message_enabled: true, support_contact: 'https://sellercentral.amazon.com/gp/mws/contactus.html', price_message_enabled: true, business_price_available: true, listing_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/listings/2021-08-01/items/", listing_message_feed_enabled: false, product_type_schema_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/definitions/2020-09-01/productTypes/", listing_schema_message_enabled: true, transporter: :http_seller_api, transporter_profile: :amazon_sc_seller_eu_api, acknowledge_only_on_pending_ship_confirm: true, order_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/orders/v0/orders", catalog_item_information_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/catalog/2022-04-01/items/", a_plus_content_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/aplus/2020-11-01/", feed_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/feeds/2021-06-30", failure_timeout_in_minutes: 480, execute_inventory_flow_every_x_hour: 24, # once a day for full inventory feed execute_price_flow_every_x_hour: 24, # once a day for full price feed execute_listing_message_feed_flow_every_x_hour: 24, # once a day for full feed currency: 'EUR' }, amazon_seller_central_it: { active: true, partner: :amazon_seller_central_it, customer_id: 22_788_055, marketplace: 'APJ6JRA9NG5V4', merchant_id: 'A1U07I6I50BN2R', locales: ['it'], language_tag: 'it_IT', inventory_message_enabled: true, support_contact: 'https://sellercentral.amazon.com/gp/mws/contactus.html', price_message_enabled: true, business_price_available: true, listing_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/listings/2021-08-01/items/", listing_message_feed_enabled: false, product_type_schema_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/definitions/2020-09-01/productTypes/", listing_schema_message_enabled: true, transporter: :http_seller_api, transporter_profile: :amazon_sc_seller_eu_api, acknowledge_only_on_pending_ship_confirm: true, order_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/orders/v0/orders", catalog_item_information_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/catalog/2022-04-01/items/", a_plus_content_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/aplus/2020-11-01/", feed_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/feeds/2021-06-30", failure_timeout_in_minutes: 480, execute_inventory_flow_every_x_hour: 24, # once a day for full inventory feed execute_price_flow_every_x_hour: 24, # once a day for full price feed execute_listing_message_feed_flow_every_x_hour: 24, # once a day for full feed currency: 'EUR' }, amazon_seller_central_nl: { active: true, partner: :amazon_seller_central_nl, customer_id: 23_325_157, marketplace: 'A1805IZSGTT6HS', merchant_id: 'A1U07I6I50BN2R', locales: ['de'], language_tag: 'nl_NL', inventory_message_enabled: true, support_contact: 'https://sellercentral.amazon.com/gp/mws/contactus.html', price_message_enabled: true, business_price_available: false, listing_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/listings/2021-08-01/items/", listing_message_feed_enabled: false, product_type_schema_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/definitions/2020-09-01/productTypes/", listing_schema_message_enabled: true, transporter: :http_seller_api, transporter_profile: :amazon_sc_seller_eu_api, acknowledge_only_on_pending_ship_confirm: true, order_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/orders/v0/orders", catalog_item_information_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/catalog/2022-04-01/items/", a_plus_content_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/aplus/2020-11-01/", feed_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/feeds/2021-06-30", failure_timeout_in_minutes: 480, execute_inventory_flow_every_x_hour: 24, # once a day for full inventory feed execute_price_flow_every_x_hour: 24, # once a day for full price feed execute_listing_message_feed_flow_every_x_hour: 24, # once a day for full feed currency: 'EUR' }, amazon_seller_central_pl: { active: true, partner: :amazon_seller_central_pl, customer_id: 23_325_160, marketplace: 'A1C3SOZRARQ6R3', merchant_id: 'A1U07I6I50BN2R', locales: ['pl'], language_tag: 'pl_PL', inventory_message_enabled: true, support_contact: 'https://sellercentral.amazon.com/gp/mws/contactus.html', price_message_enabled: true, business_price_available: false, listing_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/listings/2021-08-01/items/", listing_message_feed_enabled: false, product_type_schema_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/definitions/2020-09-01/productTypes/", listing_schema_message_enabled: true, transporter: :http_seller_api, transporter_profile: :amazon_sc_seller_eu_api, acknowledge_only_on_pending_ship_confirm: true, order_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/orders/v0/orders", catalog_item_information_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/catalog/2022-04-01/items/", a_plus_content_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/aplus/2020-11-01/", feed_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/feeds/2021-06-30", failure_timeout_in_minutes: 480, execute_inventory_flow_every_x_hour: 24, # once a day for full inventory feed execute_price_flow_every_x_hour: 24, # once a day for full price feed execute_listing_message_feed_flow_every_x_hour: 24, # once a day for full feed currency: 'PLN' }, amazon_seller_central_se: { active: true, partner: :amazon_seller_central_se, customer_id: 23_325_161, marketplace: 'A2NODRKZP88ZB9', merchant_id: 'A1U07I6I50BN2R', locales: ['se'], language_tag: 'sv_SE', inventory_message_enabled: true, support_contact: 'https://sellercentral.amazon.com/gp/mws/contactus.html', price_message_enabled: true, business_price_available: false, listing_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/listings/2021-08-01/items/", listing_message_feed_enabled: false, product_type_schema_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/definitions/2020-09-01/productTypes/", listing_schema_message_enabled: true, transporter: :http_seller_api, transporter_profile: :amazon_sc_seller_eu_api, acknowledge_only_on_pending_ship_confirm: true, order_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/orders/v0/orders", catalog_item_information_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/catalog/2022-04-01/items/", a_plus_content_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/aplus/2020-11-01/", feed_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/feeds/2021-06-30", failure_timeout_in_minutes: 480, execute_inventory_flow_every_x_hour: 24, # once a day for full inventory feed execute_price_flow_every_x_hour: 24, # once a day for full price feed execute_listing_message_feed_flow_every_x_hour: 24, # once a day for full feed currency: 'SEK' }, amazon_seller_central_uk: { active: false, partner: :amazon_seller_central_uk, customer_id: 23_325_163, marketplace: 'A1F83G8C2ARO7P', merchant_id: 'A1U07I6I50BN2R', locales: ['en-UK'], language_tag: 'en_UK', inventory_message_enabled: true, support_contact: 'https://sellercentral.amazon.com/gp/mws/contactus.html', price_message_enabled: true, business_price_available: true, listing_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/listings/2021-08-01/items/", listing_message_feed_enabled: false, product_type_schema_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/definitions/2020-09-01/productTypes/", listing_schema_message_enabled: true, transporter: :http_seller_api, transporter_profile: :amazon_sc_seller_eu_api, acknowledge_only_on_pending_ship_confirm: true, order_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/orders/v0/orders", catalog_item_information_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/catalog/2022-04-01/items/", a_plus_content_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/aplus/2020-11-01/", feed_message_remote_path: "https://#{Heatwave::Configuration.fetch(:amazon_sc_seller_eu_api, :api_host)}/feeds/2021-06-30", failure_timeout_in_minutes: 480, execute_inventory_flow_every_x_hour: 24, # once a day for full inventory feed execute_price_flow_every_x_hour: 24, # once a day for full price feed execute_listing_message_feed_flow_every_x_hour: 24, # once a day for full feed currency: 'GBP' } } end |
.populate_items_from_all_partners(limit: nil, skus: nil, force: false) ⇒ Object
1067 1068 1069 1070 1071 1072 1073 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1067 def self.populate_items_from_all_partners(limit: nil, skus: nil, force: false) res = {} orchestrators.each do |orchestrator| res[orchestrator.partner] = orchestrator.populate_items_from_catalog(limit:, skus:, force:) end res end |
Instance Method Details
#a_plus_content_processor ⇒ Object
539 540 541 542 543 |
# File 'app/services/edi/amazon/orchestrator.rb', line 539 def a_plus_content_processor return Edi::NullProcessor.new(self, :a_plus_content_processor, ) unless a_plus_content_remote_path.present? APlusContentProcessor.new(self, ) end |
#a_plus_content_remote_path ⇒ Object
529 530 531 |
# File 'app/services/edi/amazon/orchestrator.rb', line 529 def a_plus_content_remote_path try(:a_plus_content_remote_path) end |
#a_plus_content_retriever ⇒ Object
533 534 535 536 537 |
# File 'app/services/edi/amazon/orchestrator.rb', line 533 def a_plus_content_retriever return Edi::NullProcessor.new(self, :a_plus_content_retriever, ) unless a_plus_content_remote_path.present? APlusContentRetriever.new(self, ) end |
#acknowledge_message_enabled? ⇒ Boolean
383 384 385 |
# File 'app/services/edi/amazon/orchestrator.rb', line 383 def try(:order_message_remote_path).present? end |
#acknowledge_message_sender ⇒ Object
387 388 389 390 391 |
# File 'app/services/edi/amazon/orchestrator.rb', line 387 def return Edi::NullProcessor.new(self, :acknowledge_message_sender, ) unless AcknowledgeMessageSender.new(self, ) end |
#buy_box_status_enabled? ⇒ Boolean
481 482 483 |
# File 'app/services/edi/amazon/orchestrator.rb', line 481 def buy_box_status_enabled? try(:product_pricing_remote_path).present? end |
#buy_box_status_retriever ⇒ Object
485 486 487 488 489 |
# File 'app/services/edi/amazon/orchestrator.rb', line 485 def buy_box_status_retriever return Edi::NullProcessor.new(self, :buy_box_status_retriever, ) unless buy_box_status_enabled? BuyBoxStatusRetriever.new(self, ) end |
#buy_shipping_client ⇒ Object
1127 1128 1129 1130 1131 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1127 def buy_shipping_client return nil unless buy_shipping_enabled? ShipWithAmazon.new(self) end |
#buy_shipping_enabled? ⇒ Boolean
1123 1124 1125 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1123 def buy_shipping_enabled? try(:buy_shipping_enabled) == true end |
#catalog_item_information_enabled? ⇒ Boolean
471 472 473 |
# File 'app/services/edi/amazon/orchestrator.rb', line 471 def catalog_item_information_enabled? try(:catalog_item_information_remote_path).present? end |
#catalog_item_information_processor ⇒ Object
515 516 517 518 519 |
# File 'app/services/edi/amazon/orchestrator.rb', line 515 def catalog_item_information_processor return Edi::NullProcessor.new(self, :catalog_item_information_processor, ) unless catalog_item_information_enabled? CatalogItemInformationProcessor.new(self, ) end |
#catalog_item_information_retriever ⇒ Object
475 476 477 478 479 |
# File 'app/services/edi/amazon/orchestrator.rb', line 475 def catalog_item_information_retriever return Edi::NullProcessor.new(self, :catalog_item_information_retriever, ) unless catalog_item_information_enabled? CatalogItemInformationRetriever.new(self, ) end |
#confirm_message_enabled? ⇒ Boolean
367 368 369 |
# File 'app/services/edi/amazon/orchestrator.rb', line 367 def try(:order_message_remote_path).present? end |
#confirm_message_processor ⇒ Object
371 372 373 374 375 |
# File 'app/services/edi/amazon/orchestrator.rb', line 371 def return Edi::NullProcessor.new(self, :confirm_message_processor, ) unless ConfirmMessageProcessor.new(self, ) end |
#confirm_message_sender ⇒ Object
377 378 379 380 381 |
# File 'app/services/edi/amazon/orchestrator.rb', line 377 def return Edi::NullProcessor.new(self, :confirm_message_sender, ) unless ConfirmMessageSender.new(self, ) end |
#confirm_outbound_processing? ⇒ Boolean
Amazon is a two stage process on , processing
613 614 615 |
# File 'app/services/edi/amazon/orchestrator.rb', line 613 def confirm_outbound_processing? true end |
#connection_info ⇒ Object
462 463 464 465 466 467 468 469 |
# File 'app/services/edi/amazon/orchestrator.rb', line 462 def connection_info { marketplace:, merchant_id:, aws_access_key_id:, aws_secret_access_key: } end |
#delete_listing_from_catalog_item(catalog_item: nil, amazon_variation: nil, http_method: 'DELETE', attribute_actions: nil, use_fba_sku: false) ⇒ Object
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1000 def delete_listing_from_catalog_item(catalog_item: nil, amazon_variation: nil, http_method: 'DELETE', attribute_actions: nil, use_fba_sku: false) raise 'Must provide either a catalog_item or an amazon_variation' unless catalog_item || amazon_variation raise 'Catalog Item not an amazon item or not in the right state' if catalog_item && !catalog_item.amazon_catalog_item? listing = catalog_item || amazon_variation res = [] result = .process(listing, http_method:, attribute_actions:, use_fba_sku:) if result.success? Rails.logger.debug { "orchestrator#delete_listing_from_catalog_item for #{listing}, ecl: #{result.data}" } res << .process(result.data, catalog_item_or_variation: listing, http_method:, use_fba_sku:) else Rails.logger.error "orchestrator#delete_listing_from_catalog_item for #{listing} failed: #{result.error}" res << false end res end |
#delete_listing_message_processor ⇒ Object
557 558 559 560 561 |
# File 'app/services/edi/amazon/orchestrator.rb', line 557 def return Edi::NullProcessor.new(self, :delete_listing_message_processor, ) unless DeleteListingMessageProcessor.new(self, ) end |
#discontinue_flow_processor ⇒ Object
563 564 565 566 567 |
# File 'app/services/edi/amazon/orchestrator.rb', line 563 def discontinue_flow_processor return Edi::NullProcessor.new(self, :discontinue_flow_processor, ) unless DiscontinueFlowProcessor.new(self, ) end |
#execute_discontinue_flow ⇒ Object
606 607 608 609 610 |
# File 'app/services/edi/amazon/orchestrator.rb', line 606 def execute_discontinue_flow return false unless active discontinue_flow_processor.process end |
#execute_fba_order_flow ⇒ Object
1112 1113 1114 1115 1116 1117 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1112 def execute_fba_order_flow return unless active .process .process end |
#execute_inventory_flow(use_delta_since_last_message: false) ⇒ Object
583 584 585 586 587 588 589 590 |
# File 'app/services/edi/amazon/orchestrator.rb', line 583 def execute_inventory_flow(use_delta_since_last_message: false) return false unless active .process(use_delta_since_last_message:) # Generate an inventory feed message .process # Send it sleep(1) execute_fba_order_flow # put it here for daily processing for now: need this to run less frequently or to remove ECLs where we skip all the processed fba_orders end |
#execute_listing_message_feed_flow ⇒ Object
599 600 601 602 603 604 |
# File 'app/services/edi/amazon/orchestrator.rb', line 599 def return false unless active .process # Generate a listing message feed message .process # Send it end |
#execute_order_flow ⇒ Object
569 570 571 572 573 574 575 576 577 578 579 580 581 |
# File 'app/services/edi/amazon/orchestrator.rb', line 569 def execute_order_flow return unless active .process sleep(1) .process sleep(1) .process sleep(1) .process # 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_order_status_verification ⇒ Object
1090 1091 1092 1093 1094 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1090 def execute_order_status_verification return unless active && order_status_verification_enabled? order_status_verifier.process end |
#execute_price_flow(use_delta_since_last_message: false) ⇒ Object
592 593 594 595 596 597 |
# File 'app/services/edi/amazon/orchestrator.rb', line 592 def execute_price_flow(use_delta_since_last_message: false) return false unless active .process(use_delta_since_last_message:) # Generate a price feed message .process # Send it end |
#fba_order_message_enabled? ⇒ Boolean
1096 1097 1098 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1096 def try(:order_message_remote_path).present? && try(:fba_store_id).present? end |
#fba_order_message_processor ⇒ Object
1106 1107 1108 1109 1110 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1106 def return Edi::NullProcessor.new(self, :fba_order_message_processor, ) unless FbaOrderMessageProcessor.new(self, ) end |
#fba_order_message_retriever ⇒ Object
1100 1101 1102 1103 1104 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1100 def return Edi::NullProcessor.new(self, :fba_order_message_retriever, ) unless FbaOrderMessageRetriever.new(self, ) end |
#fba_pull_orders_by_po_numbers(po_numbers) ⇒ Object
1119 1120 1121 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1119 def fba_pull_orders_by_po_numbers(po_numbers) .process(po_numbers:) end |
#feed_submission_result_processor ⇒ Object
457 458 459 460 |
# File 'app/services/edi/amazon/orchestrator.rb', line 457 def feed_submission_result_processor # Its amazon its always enabled FeedSubmissionResultProcessor.new(self, ) end |
#inventory_message_enabled? ⇒ Boolean
409 410 411 |
# File 'app/services/edi/amazon/orchestrator.rb', line 409 def end |
#inventory_message_processor ⇒ Object
413 414 415 416 417 |
# File 'app/services/edi/amazon/orchestrator.rb', line 413 def return Edi::NullProcessor.new(self, :inventory_message_processor, ) unless InventoryMessageProcessor.new(self, ) end |
#inventory_message_sender ⇒ Object
419 420 421 422 423 |
# File 'app/services/edi/amazon/orchestrator.rb', line 419 def return Edi::NullProcessor.new(self, :inventory_message_sender, ) unless InventoryMessageSender.new(self, ) end |
#invoice_message_enabled? ⇒ Boolean
393 394 395 |
# File 'app/services/edi/amazon/orchestrator.rb', line 393 def false end |
#invoice_message_processor ⇒ Object
397 398 399 |
# File 'app/services/edi/amazon/orchestrator.rb', line 397 def Edi::NullProcessor.new(self, :invoice_message_processor, ) end |
#listing_item_information_processor ⇒ Object
497 498 499 500 501 |
# File 'app/services/edi/amazon/orchestrator.rb', line 497 def listing_item_information_processor return Edi::NullProcessor.new(self, :listing_item_information_processor, ) unless ListingItemInformationProcessor.new(self, ) end |
#listing_item_information_retriever ⇒ Object
491 492 493 494 495 |
# File 'app/services/edi/amazon/orchestrator.rb', line 491 def listing_item_information_retriever return Edi::NullProcessor.new(self, :listing_item_information_retriever, ) unless ListingItemInformationRetriever.new(self, ) end |
#listing_item_schema_processor ⇒ Object
509 510 511 512 513 |
# File 'app/services/edi/amazon/orchestrator.rb', line 509 def listing_item_schema_processor return Edi::NullProcessor.new(self, :listing_item_schema_processor, ) unless ListingItemSchemaProcessor.new(self, ) end |
#listing_item_schema_retriever ⇒ Object
503 504 505 506 507 |
# File 'app/services/edi/amazon/orchestrator.rb', line 503 def listing_item_schema_retriever return Edi::NullProcessor.new(self, :listing_item_schema_retriever, ) unless ListingItemSchemaRetriever.new(self, ) end |
#listing_message_enabled? ⇒ Boolean
521 522 523 |
# File 'app/services/edi/amazon/orchestrator.rb', line 521 def try(:listing_message_remote_path).present? end |
#listing_message_feed_enabled? ⇒ Boolean
441 442 443 |
# File 'app/services/edi/amazon/orchestrator.rb', line 441 def end |
#listing_message_feed_processor ⇒ Object
451 452 453 454 455 |
# File 'app/services/edi/amazon/orchestrator.rb', line 451 def return Edi::NullProcessor.new(self, :listing_message_feed_processor, ) unless ListingMessageFeedProcessor.new(self, ) end |
#listing_message_feed_sender ⇒ Object
445 446 447 448 449 |
# File 'app/services/edi/amazon/orchestrator.rb', line 445 def return Edi::NullProcessor.new(self, :listing_message_feed_sender, ) unless ListingMessageFeedSender.new(self, ) end |
#listing_message_processor ⇒ Object
551 552 553 554 555 |
# File 'app/services/edi/amazon/orchestrator.rb', line 551 def return Edi::NullProcessor.new(self, :listing_message_processor, ) unless ListingMessageProcessor.new(self, ) end |
#listing_message_sender ⇒ Object
545 546 547 548 549 |
# File 'app/services/edi/amazon/orchestrator.rb', line 545 def return Edi::NullProcessor.new(self, :listing_message_sender, ) unless ListingMessageSender.new(self, ) end |
#listing_schema_message_enabled? ⇒ Boolean
525 526 527 |
# File 'app/services/edi/amazon/orchestrator.rb', line 525 def try(:listing_schema_message_enabled).present? end |
#order_message_enabled? ⇒ Boolean
351 352 353 |
# File 'app/services/edi/amazon/orchestrator.rb', line 351 def try(:order_message_remote_path).present? end |
#order_message_processor ⇒ Object
361 362 363 364 365 |
# File 'app/services/edi/amazon/orchestrator.rb', line 361 def return Edi::NullProcessor.new(self, :order_message_processor, ) unless OrderMessageProcessor.new(self, ) end |
#order_message_retriever ⇒ Object
355 356 357 358 359 |
# File 'app/services/edi/amazon/orchestrator.rb', line 355 def return Edi::NullProcessor.new(self, :order_message_retriever, ) unless OrderMessageRetriever.new(self, ) end |
#order_status_verification_enabled? ⇒ Boolean
1080 1081 1082 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1080 def order_status_verification_enabled? !!try(:order_status_verification_enabled) && try(:order_message_remote_path).present? end |
#order_status_verifier ⇒ Object
1084 1085 1086 1087 1088 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1084 def order_status_verifier return Edi::NullProcessor.new(self, :order_status_verifier, ) unless order_status_verification_enabled? OrderStatusVerifier.new(self, ) end |
#orders_with_amazon_id_po(order_id) ⇒ Object
1075 1076 1077 1078 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1075 def orders_with_amazon_id_po(order_id) # Here we look for either EDI orders with edi_po_number matching order_id or manual orders with payments with the po_number matching order_id (customer.orders.where(edi_po_number: order_id).to_ary + customer.orders.with_payments.where('payments.po_number = ?', order_id).to_ary).uniq end |
#populate_items_from_catalog(limit: nil, skus: nil, force: false) ⇒ Object
A method to populate our item data with amazon's catalog data
limit: how many records to process
skus: specific skus to process
force: normally we only will pull if the information is not present, use this to force a reset
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1053 def populate_items_from_catalog(limit: nil, skus: nil, force: false) res = [] catalog = customer_catalog catalog_items = catalog.catalog_items.amazons_with_asins.available_for_edi_feeds # Note that this should probably be specific to the locale so leverage mobility TODO catalog_items = catalog_items.where(items: { amazon_title: [nil, ''] }) unless force catalog_items = catalog_items.limit(limit) if limit catalog_items = catalog_items.where(items: { sku: skus }) if skus.present? catalog_items.each do |catalog_item| res << { name: catalog_item.to_s, catalog_item_id: catalog_item.id, res: pull_catalog_information(catalog_item) } end res end |
#price_message_enabled? ⇒ Boolean
425 426 427 |
# File 'app/services/edi/amazon/orchestrator.rb', line 425 def end |
#price_message_processor ⇒ Object
435 436 437 438 439 |
# File 'app/services/edi/amazon/orchestrator.rb', line 435 def return Edi::NullProcessor.new(self, :price_message_processor, ) unless PriceMessageProcessor.new(self, ) end |
#price_message_sender ⇒ Object
429 430 431 432 433 |
# File 'app/services/edi/amazon/orchestrator.rb', line 429 def return Edi::NullProcessor.new(self, :price_message_sender, ) unless PriceMessageSender.new(self, ) end |
#pull_amazon_variation_listing_information(amazon_variation) ⇒ Object
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 |
# File 'app/services/edi/amazon/orchestrator.rb', line 900 def pull_amazon_variation_listing_information(amazon_variation) sku = amazon_variation.reported_vendor_sku(partner) # Listing info is marketplace-specific, not locale-specific. # The API call doesn't use the locale parameter, so we only need one call per marketplace. primary_locale = locales.first ecl = listing_item_information_retriever.process( sku: sku, locale: primary_locale, file_info: { sku: sku, locale: primary_locale } ) if ecl Rails.logger.debug { "orchestrator#pull_amazon_variation_listing_information, ecl: #{ecl}" } [{ primary_locale => listing_item_information_processor.process(ecl, catalog_item_or_amazon_variation: amazon_variation, locale: primary_locale) }] else Rails.logger.error "orchestrator#pull_amazon_variation_listing_information for amazon variation #{amazon_variation.id} yielded no ecl (sku #{sku} not found?)" [{ primary_locale => false }] end end |
#pull_buy_box_status(catalog_item) ⇒ Object
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 |
# File 'app/services/edi/amazon/orchestrator.rb', line 645 def pull_buy_box_status(catalog_item) asin = catalog_item.amazon_asin raise "No ASIN for catalog_item #{catalog_item.id}" unless asin.present? locale = 'en_US' # just put something in here item = catalog_item.item sku = catalog_item.reported_vendor_sku res = [] ecl = buy_box_status_retriever.process( asin: asin, file_info: { sku: sku, item_id: item.id, catalog_item_id: catalog_item.id } ) if ecl&.try(:data).present? && (json_hash = JSON.parse(ecl.data).with_indifferent_access).present? Rails.logger.debug { "orchestrator#pull_buy_box_status, catalog_item.id: #{catalog_item.id}, ecl: #{ecl}" } Rails.logger.debug { "orchestrator#pull_buy_box_status, json_hash: #{json_hash}" } ecl.edi_documents.create(catalog_item: catalog_item) status = json_hash.dig(:payload, :status).to_s.downcase if status == 'success' offers = json_hash.dig(:payload, :Offers) || [] # Convert each offer to indifferent access for consistent key handling # (nested hashes in arrays from JSON.parse don't inherit indifferent access) offers = offers.map(&:with_indifferent_access) # Find ALL offers from our merchant (there may be multiple: FBA vs MFN/FBM) our_offers = offers.select { |o| o[:SellerId] == merchant_id } if our_offers.any? # Separate FBA and MFN offers our_fba_offers = our_offers.select { |o| o[:IsFulfilledByAmazon] } our_mfn_offers = our_offers.reject { |o| o[:IsFulfilledByAmazon] } # Check if ANY of our offers is the buy box winner (FBA offer may win while MFN doesn't) is_buy_box_winner = our_offers.any? { |o| o[:IsBuyBoxWinner] } is_featured_merchant = our_offers.any? { |o| o[:IsFeaturedMerchant] } # Detect which fulfillment type is winning the buy box fba_winning = our_fba_offers.any? { |o| o[:IsBuyBoxWinner] } mfn_winning = our_mfn_offers.any? { |o| o[:IsBuyBoxWinner] } # Log the situation for visibility if our_fba_offers.any? && our_mfn_offers.any? Rails.logger.info { "Catalog item #{catalog_item.id}: Multiple offer types detected - FBA: #{our_fba_offers.count}, MFN: #{our_mfn_offers.count}" } if fba_winning Rails.logger.info { "Catalog item #{catalog_item.id}: FBA offer is the Buy Box winner" } elsif mfn_winning Rails.logger.info { "Catalog item #{catalog_item.id}: MFN offer is the Buy Box winner" } end end Rails.logger.debug { "Found #{our_offers.count} offer(s) for merchant #{merchant_id}: IsBuyBoxWinner=#{is_buy_box_winner}, IsFeaturedMerchant=#{is_featured_merchant}, FBA_winning=#{fba_winning}, MFN_winning=#{mfn_winning}" } else # No offer found for our merchant, set defaults is_buy_box_winner = false is_featured_merchant = false Rails.logger.debug { "No offer found for merchant #{merchant_id}, using defaults: IsBuyBoxWinner=#{is_buy_box_winner}, IsFeaturedMerchant=#{is_featured_merchant}" } end # Track buy box winner changes previous_buy_box_winner = catalog_item.is_amz_buy_box_winner new_buy_box_winner = is_buy_box_winner.nil? ? false : !!is_buy_box_winner # Ensure we never set nil values to prevent database constraint violations catalog_item.is_amz_buy_box_winner = new_buy_box_winner catalog_item.is_amz_featured_merchant = is_featured_merchant.nil? ? false : !!is_featured_merchant # Update change timestamp if buy box status changed catalog_item.amz_last_buy_box_winner_change = Time.current if previous_buy_box_winner != new_buy_box_winner # Check if we have an active offer on Amazon we_have_offer = our_offers.present? if we_have_offer # We have an offer - resolve any out_of_stock/no_buyable_offers flags catalog_item.amazon_catalog_item_flags .active .where(flag_type: %w[no_buyable_offers out_of_stock]) .find_each { |flag| flag.update!(resolved_at: Time.current) } # Auto-resolve "cannot_automatically_win_buy_box" flags when we become the Buy Box winner if is_buy_box_winner catalog_item.amazon_catalog_item_flags .active .where(flag_type: 'cannot_automatically_win_buy_box') .find_each { |flag| flag.update!(resolved_at: Time.current) } end else # We don't have an offer on Amazon despite successful status check # This likely means we're out of stock - create appropriate flags Rails.logger.info { "Catalog item #{catalog_item.id}: No offer found for merchant #{merchant_id} despite successful status. Creating out_of_stock flag." } # Create out_of_stock flag if not already present unless catalog_item.amazon_catalog_item_flags.active.by_flag_type('out_of_stock').exists? catalog_item.amazon_catalog_item_flags.create!( flag_type: 'out_of_stock', issues: 'Out of stock! No active offer found on Amazon for this listing.', our_price_at_flagging: catalog_item.amazon_price_with_tax ) end # Also create no_buyable_offers flag (we have no buyable offer) unless catalog_item.amazon_catalog_item_flags.active.by_flag_type('no_buyable_offers').exists? catalog_item.amazon_catalog_item_flags.create!( flag_type: 'no_buyable_offers', issues: 'No Buyable Offers from us! We have no active offer on Amazon.', our_price_at_flagging: catalog_item.amazon_price_with_tax ) end # Resolve any "cannot_automatically_win_buy_box" flags - the issue isn't pricing catalog_item.amazon_catalog_item_flags .active .where(flag_type: 'cannot_automatically_win_buy_box') .find_each { |flag| flag.update!(resolved_at: Time.current) } end # Store all competitor seller IDs for discovery (excluding our own offers) store_competitor_seller_ids(catalog_item, offers, merchant_id) Rails.logger.debug { "Setting catalog_item #{catalog_item.id}: is_amz_buy_box_winner=#{catalog_item.is_amz_buy_box_winner}, is_amz_featured_merchant=#{catalog_item.is_amz_featured_merchant}" } catalog_item.save! ecl.complete! if ecl.can_complete? elsif status == 'nobuyableoffers' # just mark it as not buy box because there are no offers previous_buy_box_winner = catalog_item.is_amz_buy_box_winner is_buy_box_winner = false is_featured_merchant = false # Ensure we never set nil values to prevent database constraint violations catalog_item.is_amz_buy_box_winner = is_buy_box_winner.nil? ? false : !!is_buy_box_winner catalog_item.is_amz_featured_merchant = is_featured_merchant.nil? ? false : !!is_featured_merchant # Update change timestamp if buy box status changed catalog_item.amz_last_buy_box_winner_change = Time.current if previous_buy_box_winner != catalog_item.is_amz_buy_box_winner # Check if this is an out-of-stock situation vs a real "no buyable offers" issue # Look at the stored retailer_information for fulfillmentAvailability quantity is_out_of_stock = false begin amazon_info = catalog_item.retailer_information&.with_indifferent_access || {} # Check en_US listing first, then try other locales listing_info = amazon_info.dig(:en_US, :listing, :payload) || amazon_info.dig('en_US', 'listing', 'payload') || amazon_info.values.first&.dig(:listing, :payload) || amazon_info.values.first&.dig('listing', 'payload') if listing_info.present? fulfillment_availability = listing_info[:fulfillmentAvailability] || listing_info['fulfillmentAvailability'] || [] # Check if all fulfillment channels report 0 quantity if fulfillment_availability.any? quantities = fulfillment_availability.map { |fa| fa[:quantity] || fa['quantity'] || 0 } is_out_of_stock = quantities.all?(&:zero?) end end rescue StandardError => e Rails.logger.warn { "Error checking fulfillment availability for catalog_item #{catalog_item.id}: #{e.}" } end # Always create no_buyable_offers flag when status is NoBuyableOffers # This ensures the item appears in "No Buyable Offers" filter unless catalog_item.amazon_catalog_item_flags.active.by_flag_type('no_buyable_offers').exists? catalog_item.amazon_catalog_item_flags.create!( flag_type: 'no_buyable_offers', issues: 'No Buyable Offers! This listing has no active offers on Amazon.', our_price_at_flagging: catalog_item.amazon_price_with_tax ) Rails.logger.info { "Created no_buyable_offers flag for catalog_item #{catalog_item.id}" } end if is_out_of_stock # Also create out_of_stock flag to indicate WHY there are no buyable offers # This allows the item to appear in both "No Buyable Offers" AND "Out of Stock" filters unless catalog_item.amazon_catalog_item_flags.active.by_flag_type('out_of_stock').exists? catalog_item.amazon_catalog_item_flags.create!( flag_type: 'out_of_stock', issues: 'Out of stock! This listing has no inventory reported to Amazon.', our_price_at_flagging: catalog_item.amazon_price_with_tax ) Rails.logger.info { "Created out_of_stock flag for catalog_item #{catalog_item.id}" } end else # Not out of stock - resolve any stale out_of_stock flags catalog_item.amazon_catalog_item_flags .active .by_flag_type('out_of_stock') .find_each { |flag| flag.update!(resolved_at: Time.current) } end Rails.logger.debug { "Setting default values for catalog_item #{catalog_item.id} due to no buyable offers" } catalog_item.save! ecl.complete! if ecl.can_complete? else Rails.logger.error "Failed to retrieve buy box status! Status: #{status}" ecl.notes = "Failed to retrieve buy box status! Status: #{status}" # Set default values to prevent database constraint violations previous_buy_box_winner = catalog_item.is_amz_buy_box_winner catalog_item.is_amz_buy_box_winner = false catalog_item.is_amz_featured_merchant = false # Update change timestamp if buy box status changed catalog_item.amz_last_buy_box_winner_change = Time.current if previous_buy_box_winner != catalog_item.is_amz_buy_box_winner Rails.logger.debug { "Setting default values for catalog_item #{catalog_item.id} due to unexpected status: #{status}" } catalog_item.save! if ecl.can_error? ecl.error! else ecl.save end res << { locale => false } end else Rails.logger.error "orchestrator#pull_buy_box_status for catalog_item.id: #{catalog_item.id} yielded no ecl!" # Set default values to prevent database constraint violations previous_buy_box_winner = catalog_item.is_amz_buy_box_winner catalog_item.is_amz_buy_box_winner = false catalog_item.is_amz_featured_merchant = false # Update change timestamp if buy box status changed catalog_item.amz_last_buy_box_winner_change = Time.current if previous_buy_box_winner != catalog_item.is_amz_buy_box_winner Rails.logger.debug { "Setting default values for catalog_item #{catalog_item.id} due to no ECL data" } catalog_item.save! res << { locale => false } end res << { locale => true } end |
#pull_catalog_information(catalog_item) ⇒ Object
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 |
# File 'app/services/edi/amazon/orchestrator.rb', line 617 def pull_catalog_information(catalog_item) item = catalog_item.item asin = catalog_item.amazon_asin raise "No ASIN for catalog_item #{catalog_item.id}" unless asin.present? res = [] locales.each do |locale| # en_US en_CA fr_CA ecl = catalog_item_information_retriever.process( asin: asin, locale:, file_info: { asin: asin, item_id: item.id, locale: } ) if ecl Rails.logger.debug { "orchestrator#pull_catalog_information, ecl: #{ecl}" } res << { locale => catalog_item_information_processor.process(ecl, catalog_item:, locale:) } else Rails.logger.error "orchestrator#pull_catalog_information for catalog item #{catalog_item.id} yielded no ecl (asin #{asin} not found?)" res << { locale => false } end end res end |
#pull_listing_information(catalog_item) ⇒ Object
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 |
# File 'app/services/edi/amazon/orchestrator.rb', line 874 def pull_listing_information(catalog_item) item = catalog_item.item sku = catalog_item.reported_vendor_sku # Listing info is marketplace-specific, not locale-specific. # The API call doesn't use the locale parameter, so we only need one call per marketplace. primary_locale = locales.first ecl = listing_item_information_retriever.process( sku: sku, locale: primary_locale, file_info: { sku: sku, item_id: item.id, catalog_item_id: catalog_item.id, locale: primary_locale } ) if ecl Rails.logger.debug { "orchestrator#pull_listing_information, ecl: #{ecl}" } [{ primary_locale => listing_item_information_processor.process(ecl, catalog_item_or_amazon_variation: catalog_item, locale: primary_locale) }] else Rails.logger.error "orchestrator#pull_listing_information for catalog item #{catalog_item.id} yielded no ecl (sku #{sku} not found?)" [{ primary_locale => false }] end end |
#pull_listing_schema(catalog_item, product_type = nil) ⇒ Object
975 976 977 978 |
# File 'app/services/edi/amazon/orchestrator.rb', line 975 def pull_listing_schema(catalog_item, product_type = nil) product_type ||= catalog_item.amazon_effective_desired_product_type pull_schema(product_type) end |
#pull_schema(product_type) ⇒ Object
923 924 925 926 927 |
# File 'app/services/edi/amazon/orchestrator.rb', line 923 def pull_schema(product_type) locales.map do |locale| # en_US en_CA fr_CA { locale => pull_schema_for_locale(product_type, locale) } end end |
#pull_schema_for_locale(product_type, locale, amazon_schema: nil) ⇒ Object
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 |
# File 'app/services/edi/amazon/orchestrator.rb', line 929 def pull_schema_for_locale(product_type, locale, amazon_schema: nil) amazon_schema = nil if product_type.blank? Rails.logger.error "orchestrator#pull_schema_for_locale called with blank product_type for partner #{partner}, locale #{locale} — skipping" return amazon_schema end ErrorReporting.scoped(partner: partner, product_type: product_type, locale: locale) do ecl = listing_item_schema_retriever.process( product_type: product_type, locale: locale, file_info: { product_type: product_type, locale: locale } ) if ecl ErrorReporting.scoped(edi_commmunication_log_id: ecl.id) do Rails.logger.debug { "orchestrator#pull_listing_schema, ecl: #{ecl}" } json_hash = JSON.parse(ecl.data).with_indifferent_access schema_authenticated_url = json_hash.dig(:schema, :link, :resource) if schema_authenticated_url && (response = HTTP.get(schema_authenticated_url))&.status&.success? json_schema = response.body.to_s catalog = customer_catalog amazon_marketplace = catalog.amazon_marketplace amazon_schema ||= AmazonSchema.amazon_channel_seller.where(amazon_marketplace: amazon_marketplace.id, locale: locale, product_type: product_type).first_or_initialize amazon_schema.schema = json_schema amazon_schema.save! ecl.complete! if ecl.can_complete? else Rails.logger.error "Failed to retrieve data from #{schema_authenticated_url}: #{response&.status}" ecl.notes = "Failed to retrieve data from #{schema_authenticated_url}: #{response&.status}" if ecl.can_error? ecl.error! else ecl.save end end end else Rails.logger.error "orchestrator#pull_listing_schema for product_type #{product_type} yielded no ecl (schema #{product_type} not found?)" end end amazon_schema end |
#push_listing_from_amazon_variation(amazon_variation) ⇒ Object
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1017 def push_listing_from_amazon_variation(amazon_variation) res = [] http_method = 'PUT' result = .process(amazon_variation, http_method:) if result.success? Rails.logger.debug { "orchestrator#push_listing_from_amazon_variation for amazon variation #{amazon_variation.id}, ecl: #{result.data}" } res << .process(result.data, catalog_item_or_variation: amazon_variation, http_method:) else Rails.logger.error "orchestrator#push_listing_from_amazon_variation for amazon variation #{amazon_variation.id} failed: #{result.error}" res << false end res end |
#push_listing_from_catalog_item(catalog_item, http_method: 'PATCH', attribute_actions: nil, use_fba_sku: false) ⇒ Object
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 |
# File 'app/services/edi/amazon/orchestrator.rb', line 980 def push_listing_from_catalog_item(catalog_item, http_method: 'PATCH', attribute_actions: nil, use_fba_sku: false) item = catalog_item.item raise 'Catalog item not an amazon item or not in the right state' unless catalog_item.amazon_catalog_item? && catalog_item.api_ready_state? res = [] result = .process(catalog_item, http_method:, attribute_actions:, use_fba_sku:) if result.success? Rails.logger.debug { "orchestrator#push_listing_from_catalog_item for catalog item #{catalog_item.id}, ecl: #{result.data}" } res << .process(result.data, catalog_item_or_variation: catalog_item, http_method:, use_fba_sku:) else fba_label = use_fba_sku ? ' (FBA)' : ' (FBM)' Rails.logger.error "orchestrator#push_listing_from_catalog_item for catalog item #{catalog_item.id}#{fba_label} failed: #{result.error}. " \ "ASIN: #{item.amazon_asin}, SKU: #{catalog_item.sku}, Partner: #{partner}." res << { error: true, message: result.error } end res end |
#return_notification_message_enabled? ⇒ Boolean
401 402 403 |
# File 'app/services/edi/amazon/orchestrator.rb', line 401 def false end |
#return_notification_message_processor ⇒ Object
405 406 407 |
# File 'app/services/edi/amazon/orchestrator.rb', line 405 def Edi::NullProcessor.new(self, :return_notification_message_processor, ) end |
#ship_code_mapper ⇒ Object
1133 1134 1135 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1133 def ship_code_mapper ShipCodeMapper.new(self) end |
#store_competitor_seller_ids(catalog_item, offers, our_merchant_id) ⇒ Object
Store competitor seller IDs from Buy Box status for discovery
Creates AmazonCompetitor records (without names) for any new seller IDs found
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 |
# File 'app/services/edi/amazon/orchestrator.rb', line 1139 def store_competitor_seller_ids(catalog_item, offers, our_merchant_id) return if offers.blank? competitor_offers = offers.reject { |o| o[:SellerId] == our_merchant_id } return if competitor_offers.empty? competitor_offers.each do |offer| seller_id = offer[:SellerId] next if seller_id.blank? # Create a placeholder record if this seller doesn't exist yet # Name will be nil until someone identifies them AmazonCompetitor.find_or_create_by(seller_id: seller_id) do |competitor| competitor.notes = "Discovered on #{Time.current.strftime('%Y-%m-%d')} from ASIN #{catalog_item.amazon_asin}" end rescue ActiveRecord::RecordNotUnique # Race condition - record already exists, which is fine end end |