Class: Edi::Wayfair::ListingGenerator::Attributes::BaseAttribute
- Inherits:
-
Object
- Object
- Edi::Wayfair::ListingGenerator::Attributes::BaseAttribute
- Defined in:
- app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb
Overview
Base class for Wayfair attribute mappers
Maps internal product data to Wayfair's taxonomy attribute format
Wayfair attribute format:
{
taxonomyAttributeId: "218029",
value: "Electric"
}
For multi-value attributes:
{
taxonomyAttributeId: "218029",
values: ["Electric", "Infrared"]
}
Direct Known Subclasses
AirFlowType, Amperage, Assembly, BtuOutput, FuelType, HazardClasses, HazardousMaterialDangerousGoods, HazardousMaterialWeight, HeatingElement, Material, MaximumTemperature, OverallDepthFrontToBack, OverallHeightTopToBottom, OverallWidthSideToSide, PackingGroup, PlugIn, UnOrIdNumber, UniformPackagingAndLabelingRegulationsUplrCompliant, Wattage, WayfairComplianceVerifiedProgram
Constant Summary collapse
- UNIT_MAPPINGS =
Unit conversions for Wayfair
{ 'in' => 'inches', 'ft' => 'feet', 'cm' => 'centimeters', 'm' => 'meters', 'mm' => 'millimeters', 'lb' => 'pounds', 'lbs' => 'pounds', 'kg' => 'kilograms', 'oz' => 'ounces', 'g' => 'grams', 'W' => 'watts', 'V' => 'volts', 'A' => 'amps', 'degF' => 'fahrenheit', 'degC' => 'celsius' }.with_indifferent_access.freeze
Class Attribute Summary collapse
-
.taxonomy_attribute_id ⇒ Object
readonly
Legacy/fallback taxonomy attribute id.
Instance Attribute Summary collapse
-
#attribute_definition ⇒ Object
readonly
Returns the value of attribute attribute_definition.
-
#catalog_item ⇒ Object
readonly
Returns the value of attribute catalog_item.
-
#item ⇒ Object
readonly
Returns the value of attribute item.
-
#taxonomy_attribute_id ⇒ Object
readonly
Returns the value of attribute taxonomy_attribute_id.
-
#wayfair_schema ⇒ Object
readonly
Returns the value of attribute wayfair_schema.
Class Method Summary collapse
-
.attribute_name ⇒ String
Class method to get the attribute name from class name.
-
.schema_titles ⇒ Array<String>
The schema attribute title(s) this mapper satisfies.
-
.set_schema_titles(*titles) ⇒ Array<String>
Declare the schema attribute title(s) this mapper satisfies.
-
.set_taxonomy_attribute_id(id) ⇒ String
Set the legacy/fallback taxonomy attribute ID for this mapper class.
Instance Method Summary collapse
-
#attribute_title ⇒ String?
Get the attribute title from schema.
-
#build ⇒ Hash?
Build the attribute payload for Wayfair API.
-
#build_attribute_hash(val) ⇒ Hash
protected
Build the Wayfair API payload hash for a resolved value, keyed on datatype.
-
#can_build? ⇒ Boolean
Check if this attribute can be built.
-
#custom_values_allowed? ⇒ Boolean
Check if custom values are allowed.
-
#datatype ⇒ String?
Get the datatype (SINGLE_CHOICE, MULTI_CHOICE, DECIMAL, BOOLEAN, STRING, etc.).
-
#fetch_value(attribute, output_unit: nil) ⇒ Object?
protected
Fetch a value from item specs or catalog_item/item attributes.
-
#format_boolean(val) ⇒ String?
protected
Format a boolean value.
-
#format_decimal(val) ⇒ String?
protected
Format a decimal value (Wayfair expects strings for decimals).
-
#initialize(catalog_item:, wayfair_schema: nil, taxonomy_attribute_id: nil) ⇒ BaseAttribute
constructor
Initialize the mapper, resolving the live schema attribute it targets.
-
#map_unit(unit) ⇒ String
protected
Map a Ruby unit to Wayfair unit.
-
#possible_values ⇒ Array<String>
Get possible values for this attribute.
-
#requirement ⇒ String?
Get the requirement level (REQUIRED, RECOMMENDED, OPTIONAL).
-
#valid_value?(val) ⇒ Boolean
Validate a value against possible values.
-
#value ⇒ Object?
Override in subclasses to provide the value.
Constructor Details
#initialize(catalog_item:, wayfair_schema: nil, taxonomy_attribute_id: nil) ⇒ BaseAttribute
Initialize the mapper, resolving the live schema attribute it targets.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 46 def initialize(catalog_item:, wayfair_schema: nil, taxonomy_attribute_id: nil) @catalog_item = catalog_item @item = catalog_item.item @wayfair_schema = wayfair_schema || catalog_item.wayfair_pull_taxonomy_schema # Resolve the schema attribute this mapper targets from the LIVE schema (by # title), not a hardcoded taxonomy id — the same concept carries a different # id per Wayfair class (Wattage is 895 on space heaters but 383497 on # Underfloor Heating / class 7441). The hardcoded id is only a fallback. # When the resolved attribute isn't part of this class's schema the mapper # won't build (see #can_build?), so we never send a heater attribute on a # floor-heating listing — Wayfair rejects those as "invalid attribute". @attribute_definition = resolve_attribute_definition(taxonomy_attribute_id) @taxonomy_attribute_id = attribute_definition&.dig('taxonomyAttributeId')&.to_s.presence || taxonomy_attribute_id&.to_s || self.class.taxonomy_attribute_id end |
Class Attribute Details
.taxonomy_attribute_id ⇒ Object (readonly)
Legacy/fallback taxonomy attribute id. Used only when the live schema has
no attribute matching schema_titles — title resolution is preferred so
the per-class id is always correct.
135 136 137 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 135 def taxonomy_attribute_id @taxonomy_attribute_id end |
Instance Attribute Details
#attribute_definition ⇒ Object (readonly)
Returns the value of attribute attribute_definition.
38 39 40 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 38 def attribute_definition @attribute_definition end |
#catalog_item ⇒ Object (readonly)
Returns the value of attribute catalog_item.
38 39 40 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 38 def catalog_item @catalog_item end |
#item ⇒ Object (readonly)
Returns the value of attribute item.
38 39 40 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 38 def item @item end |
#taxonomy_attribute_id ⇒ Object (readonly)
Returns the value of attribute taxonomy_attribute_id.
38 39 40 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 38 def taxonomy_attribute_id @taxonomy_attribute_id end |
#wayfair_schema ⇒ Object (readonly)
Returns the value of attribute wayfair_schema.
38 39 40 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 38 def wayfair_schema @wayfair_schema end |
Class Method Details
.attribute_name ⇒ String
Class method to get the attribute name from class name
165 166 167 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 165 def self.attribute_name name.demodulize.underscore end |
.schema_titles ⇒ Array<String>
The schema attribute title(s) this mapper satisfies. Defaults to the
humanized class name (MaximumTemperature -> "Maximum Temperature") which,
combined with the punctuation-insensitive match, already covers titles like
"BTU Output" and "Plug-In".
159 160 161 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 159 def self.schema_titles @schema_titles || [name.demodulize.titleize] end |
.set_schema_titles(*titles) ⇒ Array<String>
Declare the schema attribute title(s) this mapper satisfies. The live schema
is searched for an attribute whose title matches one of these
(case/punctuation-insensitive) to resolve the per-class taxonomy id.
150 151 152 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 150 def self.set_schema_titles(*titles) @schema_titles = titles.flatten.map(&:to_s) end |
.set_taxonomy_attribute_id(id) ⇒ String
Set the legacy/fallback taxonomy attribute ID for this mapper class.
141 142 143 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 141 def self.set_taxonomy_attribute_id(id) @taxonomy_attribute_id = id.to_s end |
Instance Method Details
#attribute_title ⇒ String?
Get the attribute title from schema
92 93 94 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 92 def attribute_title attribute_definition&.dig('title') end |
#build ⇒ Hash?
Build the attribute payload for Wayfair API
65 66 67 68 69 70 71 72 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 65 def build return nil unless can_build? v = value return nil if v.nil? || (v.respond_to?(:blank?) && v.blank?) build_attribute_hash(v) end |
#build_attribute_hash(val) ⇒ Hash (protected)
Build the Wayfair API payload hash for a resolved value, keyed on datatype.
174 175 176 177 178 179 180 181 182 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 174 def build_attribute_hash(val) case datatype when 'MULTI_CHOICE' values = val.is_a?(Array) ? val : [val] { taxonomyAttributeId: taxonomy_attribute_id, values: values.map(&:to_s) } else { taxonomyAttributeId: taxonomy_attribute_id, value: val.to_s } end end |
#can_build? ⇒ Boolean
Check if this attribute can be built. Requires the resolved attribute to be
part of THIS class's schema (attribute_definition.present?) — a mapper
whose attribute isn't in the class schema never builds, which is what keeps
heater attributes off floor-heating listings.
86 87 88 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 86 def can_build? wayfair_schema.present? && attribute_definition.present? end |
#custom_values_allowed? ⇒ Boolean
Check if custom values are allowed
110 111 112 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 110 def custom_values_allowed? attribute_definition&.dig('valueFormat', 'canValueBeCustomized') == true end |
#datatype ⇒ String?
Get the datatype (SINGLE_CHOICE, MULTI_CHOICE, DECIMAL, BOOLEAN, STRING, etc.)
98 99 100 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 98 def datatype attribute_definition&.dig('valueFormat', 'datatype') end |
#fetch_value(attribute, output_unit: nil) ⇒ Object? (protected)
Fetch a value from item specs or catalog_item/item attributes
188 189 190 191 192 193 194 195 196 197 198 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 188 def fetch_value(attribute, output_unit: nil) # Try spec first (with wayfair_ prefix) v = item.spec_value(:"wayfair_#{attribute}", output_unit:) if item.respond_to?(:spec_value) v ||= item.spec_value(attribute, output_unit:) if item.respond_to?(:spec_value) # Fall back to direct attributes v ||= catalog_item.send(attribute) if catalog_item.respond_to?(attribute) v ||= item.send(attribute) if item.respond_to?(attribute) v end |
#format_boolean(val) ⇒ String? (protected)
Format a boolean value
219 220 221 222 223 224 225 226 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 219 def format_boolean(val) case val when true, 'true', 1, '1', 'yes', 'Yes' 'Yes' when false, 'false', 0, '0', 'no', 'No' 'No' end end |
#format_decimal(val) ⇒ String? (protected)
Format a decimal value (Wayfair expects strings for decimals)
210 211 212 213 214 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 210 def format_decimal(val) return nil if val.nil? val.to_f.round(2).to_s end |
#map_unit(unit) ⇒ String (protected)
Map a Ruby unit to Wayfair unit
203 204 205 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 203 def map_unit(unit) UNIT_MAPPINGS[unit] || unit end |
#possible_values ⇒ Array<String>
Get possible values for this attribute
116 117 118 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 116 def possible_values wayfair_schema&.possible_values_for(taxonomy_attribute_id) || [] end |
#requirement ⇒ String?
Get the requirement level (REQUIRED, RECOMMENDED, OPTIONAL)
104 105 106 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 104 def requirement attribute_definition&.dig('requirement') end |
#valid_value?(val) ⇒ Boolean
Validate a value against possible values
123 124 125 126 127 128 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 123 def valid_value?(val) return true if custom_values_allowed? return true if possible_values.empty? possible_values.include?(val.to_s) end |
#value ⇒ Object?
Override in subclasses to provide the value
77 78 79 |
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 77 def value raise NotImplementedError, "#{self.class.name} must implement #value" end |