Class: Edi::Wayfair::ListingGenerator::Attributes::BaseAttribute

Inherits:
Object
  • Object
show all
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"]
}

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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(catalog_item:, wayfair_schema: nil, taxonomy_attribute_id: nil) ⇒ BaseAttribute

Returns a new instance of BaseAttribute.



40
41
42
43
44
45
46
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 40

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
  @taxonomy_attribute_id = taxonomy_attribute_id || self.class.taxonomy_attribute_id
  @attribute_definition = @wayfair_schema&.find_attribute(@taxonomy_attribute_id)
end

Instance Attribute Details

#attribute_definitionObject (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_itemObject (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

#itemObject (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_idObject (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_schemaObject (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_nameObject

Class method to get the attribute name from class name



112
113
114
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 112

def self.attribute_name
  name.demodulize.underscore
end

.set_taxonomy_attribute_id(id) ⇒ Object



107
108
109
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 107

def self.set_taxonomy_attribute_id(id)
  @taxonomy_attribute_id = id.to_s
end

.taxonomy_attribute_idObject

Class method to define the taxonomy attribute ID



103
104
105
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 103

def self.taxonomy_attribute_id
  @taxonomy_attribute_id
end

Instance Method Details

#attribute_titleObject

Get the attribute title from schema



70
71
72
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 70

def attribute_title
  attribute_definition&.dig('title')
end

#buildHash?

Build the attribute payload for Wayfair API

Returns:

  • (Hash, nil)

    The attribute hash or nil if no value



50
51
52
53
54
55
56
57
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 50

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) ⇒ Object (protected)



118
119
120
121
122
123
124
125
126
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 118

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 (has schema, is applicable, etc.)

Returns:

  • (Boolean)


65
66
67
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 65

def can_build?
  wayfair_schema.present? && taxonomy_attribute_id.present?
end

#custom_values_allowed?Boolean

Check if custom values are allowed

Returns:

  • (Boolean)


85
86
87
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 85

def custom_values_allowed?
  attribute_definition&.dig('valueFormat', 'canValueBeCustomized') == true
end

#datatypeObject

Get the datatype (SINGLE_CHOICE, MULTI_CHOICE, DECIMAL, BOOLEAN, STRING, etc.)



75
76
77
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 75

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



129
130
131
132
133
134
135
136
137
138
139
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 129

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) ⇒ Object (protected)

Format a boolean value



154
155
156
157
158
159
160
161
162
163
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 154

def format_boolean(val)
  case val
  when true, 'true', 1, '1', 'yes', 'Yes'
    'Yes'
  when false, 'false', 0, '0', 'no', 'No'
    'No'
  else
    nil
  end
end

#format_decimal(val) ⇒ Object (protected)

Format a decimal value (Wayfair expects strings for decimals)



147
148
149
150
151
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 147

def format_decimal(val)
  return nil if val.nil?

  val.to_f.round(2).to_s
end

#map_unit(unit) ⇒ Object (protected)

Map a Ruby unit to Wayfair unit



142
143
144
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 142

def map_unit(unit)
  UNIT_MAPPINGS[unit] || unit
end

#possible_valuesObject

Get possible values for this attribute



90
91
92
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 90

def possible_values
  wayfair_schema&.possible_values_for(taxonomy_attribute_id) || []
end

#requirementObject

Get the requirement level (REQUIRED, RECOMMENDED, OPTIONAL)



80
81
82
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 80

def requirement
  attribute_definition&.dig('requirement')
end

#valid_value?(val) ⇒ Boolean

Validate a value against possible values

Returns:

  • (Boolean)


95
96
97
98
99
100
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 95

def valid_value?(val)
  return true if custom_values_allowed?
  return true if possible_values.empty?

  possible_values.include?(val.to_s)
end

#valueObject

Override in subclasses to provide the value

Raises:

  • (NotImplementedError)


60
61
62
# File 'app/services/edi/wayfair/listing_generator/attributes/base_attribute.rb', line 60

def value
  raise NotImplementedError, "#{self.class.name} must implement #value"
end