Class: Edi::Amazon::JsonListingGenerator::BaseGenerator
- Inherits:
-
BaseService
- Object
- BaseService
- Edi::Amazon::JsonListingGenerator::BaseGenerator
- Includes:
- Memery
- Defined in:
- app/services/edi/amazon/json_listing_generator/base_generator.rb
Overview
Service object: base generator.
Defined Under Namespace
Classes: GenerateResult
Constant Summary collapse
- OFFER_ATTRIBUTES =
Offer/fulfillment attributes — excluded from the DEFAULT product-listing payload.
They are submitted through their own channels: price via price_advice (purchasable_offer,
list_price), inventory via inventory_advice (fulfillment_availability). condition_type and
skip_offer are offer-creation controls that don't belong in a LISTING_PRODUCT_ONLY submission
(Amazon rejects them with INVALID_ATTRIBUTE / 90000900). Callers that genuinely need these
(the price/inventory feeds) pass an explicit attribute_actions hash, which bypasses the default.
NOTE: merchant_suggested_asin is intentionally NOT here — it identifies the product/ASIN and
is accepted on a product-only PUT. %i[purchasable_offer list_price fulfillment_availability condition_type skip_offer].freeze
Instance Attribute Summary collapse
-
#amazon_schema ⇒ Object
readonly
Returns the value of attribute amazon_schema.
-
#attribute_actions ⇒ Object
readonly
Returns the value of attribute attribute_actions.
-
#business_price_available ⇒ Object
readonly
Returns the value of attribute business_price_available.
-
#catalog_item ⇒ Object
readonly
Returns the value of attribute catalog_item.
-
#fba ⇒ Object
readonly
Returns the value of attribute fba.
-
#item ⇒ Object
readonly
Returns the value of attribute item.
-
#language_tag ⇒ Object
readonly
Returns the value of attribute language_tag.
-
#locale ⇒ Object
readonly
Returns the value of attribute locale.
-
#marketplace_country_iso ⇒ Object
readonly
Returns the value of attribute marketplace_country_iso.
-
#marketplace_id ⇒ Object
readonly
Returns the value of attribute marketplace_id.
-
#missing_attributes ⇒ Object
readonly
Returns the value of attribute missing_attributes.
-
#product_type ⇒ Object
readonly
Returns the value of attribute product_type.
-
#variation ⇒ Object
readonly
Returns the value of attribute variation.
Attributes inherited from BaseService
Class Method Summary collapse
-
.default_product_attribute_actions(schema_keys) ⇒ Object
Default action set for a full product listing PUT: every schema attribute set to :replace, minus OFFER_ATTRIBUTES and the other_*_image_locator attributes (only reliably settable via Seller Central bulk upload, per Christian Billen's (cbillen@warmlyyours.com) email of 11/21/25 with subject 'Amazon patch/put').
Instance Method Summary collapse
-
#append_attribute(attributes_hash, attribute, include_nil: false) ⇒ Object
Appends an attribute to the given attributes hash based on the attribute name.
-
#build_attributes(include_nil: false) ⇒ Object
Builds a hash of attributes for a product listing.
- #enum_mapper ⇒ Object
- #generate ⇒ Object
- #get_patches ⇒ Object
-
#initialize(catalog_item, locale: nil, attribute_actions: nil, product_type: nil, logger: nil, variation: nil, marketplace_id: nil, fba: false, language_tag: nil, business_price_available: true) ⇒ BaseGenerator
constructor
A new instance of BaseGenerator.
- #product_data_hash ⇒ Object
Methods inherited from BaseService
#log_debug, #log_error, #log_info, #log_warning, #logger, #process, #tagged_logger
Constructor Details
#initialize(catalog_item, locale: nil, attribute_actions: nil, product_type: nil, logger: nil, variation: nil, marketplace_id: nil, fba: false, language_tag: nil, business_price_available: true) ⇒ BaseGenerator
Returns a new instance of BaseGenerator.
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 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 37 def initialize(catalog_item, locale: nil, attribute_actions: nil, product_type: nil, logger: nil, variation: nil, marketplace_id: nil, fba: false, language_tag: nil, business_price_available: true) raise ArgumentError, "catalog_item is required for #{self.class.name}" if catalog_item.nil? @catalog_item = catalog_item @variation = variation @item = catalog_item.item @product_type = product_type || @variation&.amazon_desired_product_type || catalog_item.amazon_product_type_in_effect @locale = locale || @catalog_item.amazon_locales.first # Normalize locale @language_tag = language_tag || @locale.to_s.tr('-', '_').presence # Ensure we use a normalized tag @business_price_available = business_price_available @marketplace_id = marketplace_id || @catalog_item.catalog.amazon_marketplace.marketplace_identifier # MUST be present @marketplace = AmazonMarketplace.find_by(marketplace_identifier: @marketplace_id) @marketplace_country_iso = @marketplace.country.iso if @locale.blank? raise ArgumentError, "Cannot initialize #{self.class.name} without locale defined, product_type: #{@product_type}, @marketplace&.id: #{@marketplace&.id}, catalog_item&.sku: #{@catalog_item&.sku}, variation&.id: #{@variation&.id}" end raise ArgumentError, "Cannot initialize #{self.class.name} for CatalogItem[#{@catalog_item&.id}] (sku: #{@catalog_item&.sku}) — no product_type set. Assign an amazon_product_type on the catalog item or variation first." if @product_type.blank? @amazon_schema = AmazonSchema.amazon_channel_seller.where(product_type: @product_type).where(amazon_marketplace_id: @marketplace.id).first # If we don't have the schema, try to pull it if @amazon_schema.blank? @catalog_item.amazon_pull_listing_schema(@product_type) @amazon_schema = AmazonSchema.amazon_channel_seller.where(product_type: @product_type).where(amazon_marketplace_id: @marketplace.id).first end # If we still don't have the schema raise the error raise ArgumentError, "Cannot initialize #{self.class.name} for CatalogItem[#{@catalog_item&.id}] (sku: #{@catalog_item&.sku}) without #{@product_type} schema present for marketplace: #{@marketplace.name}" if @amazon_schema.blank? # Pass attributes and actions as a hash of symbols,. # For e.g. for inventory we pass: # see: https://developer-docs.amazon.com/sp-api/docs/listing-workflow-migration-tutorial#submitting-inventory-data # attribute_actions: {fulfillment_availability: :replace} # For e.g. for creating new listing offers we might pass: # see: https://developer-docs.amazon.com/sp-api/docs/listing-workflow-migration-tutorial # attribute_actions: {condition_type: :replace, merchant_suggested_asin: :replace, purchasable_offer: :replace} # If attribute actions are not specified, we use the product-listing defaults: every schema # attribute set to :replace, minus offer/fulfillment (OFFER_ATTRIBUTES) and other_*_image_locator # attributes. Offers/inventory are submitted separately via price_advice / inventory_advice. @attribute_actions = attribute_actions&.transform_keys(&:to_sym)&.transform_values(&:to_sym) || self.class.default_product_attribute_actions(@amazon_schema.keys) # Until we refactor FBA into catalog_items, we need to pass this to generate the correct FBA logic for JSON feeds @fba = fba super(logger:) end |
Instance Attribute Details
#amazon_schema ⇒ Object (readonly)
Returns the value of attribute amazon_schema.
7 8 9 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 7 def amazon_schema @amazon_schema end |
#attribute_actions ⇒ Object (readonly)
Returns the value of attribute attribute_actions.
7 8 9 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 7 def attribute_actions @attribute_actions end |
#business_price_available ⇒ Object (readonly)
Returns the value of attribute business_price_available.
7 8 9 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 7 def business_price_available @business_price_available end |
#catalog_item ⇒ Object (readonly)
Returns the value of attribute catalog_item.
7 8 9 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 7 def catalog_item @catalog_item end |
#fba ⇒ Object (readonly)
Returns the value of attribute fba.
7 8 9 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 7 def fba @fba end |
#item ⇒ Object (readonly)
Returns the value of attribute item.
7 8 9 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 7 def item @item end |
#language_tag ⇒ Object (readonly)
Returns the value of attribute language_tag.
7 8 9 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 7 def language_tag @language_tag end |
#locale ⇒ Object (readonly)
Returns the value of attribute locale.
7 8 9 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 7 def locale @locale end |
#marketplace_country_iso ⇒ Object (readonly)
Returns the value of attribute marketplace_country_iso.
7 8 9 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 7 def marketplace_country_iso @marketplace_country_iso end |
#marketplace_id ⇒ Object (readonly)
Returns the value of attribute marketplace_id.
7 8 9 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 7 def marketplace_id @marketplace_id end |
#missing_attributes ⇒ Object (readonly)
Returns the value of attribute missing_attributes.
7 8 9 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 7 def missing_attributes @missing_attributes end |
#product_type ⇒ Object (readonly)
Returns the value of attribute product_type.
7 8 9 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 7 def product_type @product_type end |
#variation ⇒ Object (readonly)
Returns the value of attribute variation.
7 8 9 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 7 def variation @variation end |
Class Method Details
.default_product_attribute_actions(schema_keys) ⇒ Object
Default action set for a full product listing PUT: every schema attribute set to :replace,
minus OFFER_ATTRIBUTES and the other_*_image_locator attributes (only reliably settable via
Seller Central bulk upload, per Christian Billen's (cbillen@warmlyyours.com) email of 11/21/25
with subject 'Amazon patch/put').
26 27 28 29 30 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 26 def self.default_product_attribute_actions(schema_keys) schema_keys.reject do |k| OFFER_ATTRIBUTES.include?(k.to_sym) || (k.to_s.include?('other_') && k.to_s.include?('image_locator')) end.index_with { |_attribute| :replace } end |
Instance Method Details
#append_attribute(attributes_hash, attribute, include_nil: false) ⇒ Object
Appends an attribute to the given attributes hash based on the attribute name.
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 136 def append_attribute(attributes_hash, attribute, include_nil: false) attribute_builder = begin Edi::Amazon::JsonListingGenerator::Attributes::AttributeFactory.build(attribute, catalog_item:, variation:, language_tag:, enum_mapper:, marketplace_id:, fba:) rescue StandardError nil end return attributes_hash unless attribute_builder r = attribute_builder.build if r.nil? && !include_nil @missing_attributes << attribute logger.error "#{attribute_builder.class.name} returned nil" else attributes_hash[attribute] = r end attributes_hash end |
#build_attributes(include_nil: false) ⇒ Object
Builds a hash of attributes for a product listing.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 92 def build_attributes(include_nil: false) attributes_hash = {} @missing_attributes = [] # To make everything with locale, we will wrap into a mobility call Mobility.with_locale(locale) do @attribute_actions.each do |attribute, attribute_action| next if attribute_action == :skip include_nil = true if attribute_action.to_sym == :delete append_attribute(attributes_hash, attribute, include_nil:) end end attributes_hash end |
#enum_mapper ⇒ Object
86 87 88 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 86 def enum_mapper Edi::Amazon::EnumMapper.new(amazon_schema.schema) end |
#generate ⇒ Object
107 108 109 110 111 112 113 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 107 def generate GenerateResult.new( attributes_hash: build_attributes, product_data_hash: product_data_hash, missing_attributes: @missing_attributes ) end |
#get_patches ⇒ Object
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 115 def get_patches patches = generate.product_data_hash.values.flat_map do |locale_data| locale_data[:attributes].map do |attribute, value_arr| operation = attribute_actions[attribute] next if value_arr.blank? && operation.in?(%i[skip replace]) # Delete operation value value_arr = [{ marketplace_id: }] if operation == :delete { op: operation, path: "/attributes/#{attribute}", value: value_arr }.compact end end patches.compact.uniq # we might have the same attribute generated for two different locales that are not locale dependent end |
#product_data_hash ⇒ Object
154 155 156 157 158 159 160 161 |
# File 'app/services/edi/amazon/json_listing_generator/base_generator.rb', line 154 def product_data_hash { language_tag => { asin: @catalog_item.amazon_asin, attributes: build_attributes } } end |