huginn_bigcommerce_product_agent 1.10.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,41 +2,49 @@ module BigcommerceProductAgent
2
2
  module Mapper
3
3
  class CustomFieldMapper
4
4
 
5
- def self.map(field_map, product, bc_product)
5
+ def self.map(field_map, raw_product, bc_product, current_custom_fields, namespace)
6
6
  fields = {
7
7
  upsert: [],
8
8
  delete: [],
9
9
  }
10
10
 
11
- existing_fields = {}
11
+ to_delete = {}
12
12
 
13
- if bc_product
14
- bc_product['custom_fields'].each do |cf|
13
+ if bc_product && current_custom_fields
14
+ current_custom_fields.each do |cf|
15
15
  cf['product_id'] = bc_product['id']
16
- existing_fields[cf['name'].to_s] = cf
16
+
17
+ # Initially assume that a field should be deleted.
18
+ to_delete[cf['name'].to_s] = cf
17
19
  end
18
20
  end
19
21
 
20
22
  if field_map && field_map['additionalProperty']
21
- field_map['additionalProperty'].each do |key, val|
22
- field = self.from_additional_property(product, existing_fields, key, val)
23
- fields[:upsert].push(field) unless field.nil?
23
+ field_map['additionalProperty'].each do |from_key, to_key|
24
+ field = self.from_additional_property(raw_product, to_delete, from_key, to_key)
25
+ if field
26
+ field['product_id'] = bc_product['id'] unless bc_product.nil?
27
+ fields[:upsert].push(field)
28
+ end
24
29
  end
25
30
  end
26
31
 
27
32
  if field_map
28
- field_map.each do |key, val|
29
- if key == 'additionalProperty'
33
+ field_map.each do |from_key, to_key|
34
+ if from_key == 'additionalProperty'
30
35
  next
31
36
  end
32
37
 
33
- field = self.from_property(product, existing_fields, key, val)
34
- fields[:upsert].push(field) unless field.nil?
38
+ field = self.from_property(raw_product, to_delete, from_key, to_key)
39
+ if field
40
+ field['product_id'] = bc_product['id'] unless bc_product.nil?
41
+ fields[:upsert].push(field)
42
+ end
35
43
  end
36
44
  end
37
45
 
38
46
  # return values that need deleted
39
- fields[:delete] = existing_fields.values
47
+ fields[:delete] = to_delete.values
40
48
  return fields
41
49
  end
42
50
 
@@ -57,34 +65,34 @@ module BigcommerceProductAgent
57
65
 
58
66
  private
59
67
 
60
- def self.from_property(product, existing_fields, from_key, to_key)
61
- if !product[from_key].nil?
68
+ def self.from_property(raw_product, fields_to_delete, from_key, to_key)
69
+ if !raw_product[from_key].nil?
62
70
  field = {
63
71
  name: to_key,
64
- value: product[from_key].to_s
72
+ value: raw_product[from_key].to_s
65
73
  }
66
74
 
67
- if existing_fields[to_key]
68
- field[:id] = existing_fields[to_key]['id']
69
- existing_fields.delete(to_key)
75
+ if fields_to_delete[to_key]
76
+ field[:id] = fields_to_delete[to_key]['id']
77
+ fields_to_delete.delete(to_key)
70
78
  end
71
79
 
72
80
  return field
73
81
  end
74
82
  end
75
83
 
76
- def self.from_additional_property(product, existing_fields, from_key, to_key)
84
+ def self.from_additional_property(raw_product, fields_to_delete, from_key, to_key)
77
85
  # date published
78
- item = product['additionalProperty'].select {|p| p['propertyID'] == from_key}.first
86
+ item = raw_product['additionalProperty'].select {|p| p['propertyID'] == from_key}.first
79
87
  if !item.nil?
80
88
  field = {
81
89
  name: to_key,
82
90
  value: item['value'].to_s
83
91
  }
84
92
 
85
- if existing_fields[to_key]
86
- field[:id] = existing_fields[to_key]['id']
87
- existing_fields.delete(to_key)
93
+ if fields_to_delete[to_key]
94
+ field[:id] = fields_to_delete[to_key]['id']
95
+ fields_to_delete.delete(to_key)
88
96
  end
89
97
 
90
98
  return field
@@ -2,7 +2,7 @@ module BigcommerceProductAgent
2
2
  module Mapper
3
3
  class MetaFieldMapper
4
4
 
5
- def self.map(field_map, product, bc_product, meta_fields, namespace)
5
+ def self.map(field_map, raw_product, bc_product, current_meta_fields, namespace)
6
6
  fields = {
7
7
  upsert: [],
8
8
  delete: [],
@@ -11,8 +11,8 @@ module BigcommerceProductAgent
11
11
  existing_fields = {}
12
12
 
13
13
  if bc_product
14
- meta_fields.each do |mf|
15
-
14
+ current_meta_fields.each do |mf|
15
+ mf['resource_id'] = bc_product['id']
16
16
  unless mf['namespace'] != namespace
17
17
  # Only delete meta fields managed by this sync
18
18
  existing_fields[mf['key'].to_s] = mf
@@ -22,7 +22,7 @@ module BigcommerceProductAgent
22
22
 
23
23
  if field_map && field_map['additionalProperty']
24
24
  field_map['additionalProperty'].each do |key, val|
25
- field = self.from_additional_property(product, existing_fields, key, val, namespace, bc_product)
25
+ field = self.from_additional_property(raw_product, existing_fields, key, val, namespace, bc_product)
26
26
  fields[:upsert].push(field) unless field.nil?
27
27
  end
28
28
  end
@@ -33,7 +33,7 @@ module BigcommerceProductAgent
33
33
  next
34
34
  end
35
35
 
36
- field = self.from_property(product, existing_fields, key, val, namespace, bc_product)
36
+ field = self.from_property(raw_product, existing_fields, key, val, namespace, bc_product)
37
37
  fields[:upsert].push(field) unless field.nil?
38
38
  end
39
39
  end
@@ -45,15 +45,15 @@ module BigcommerceProductAgent
45
45
 
46
46
  private
47
47
 
48
- def self.from_property(product, existing_fields, from_key, to_key, namespace, bc_product)
48
+ def self.from_property(raw_product, existing_fields, from_key, to_key, namespace, bc_product)
49
49
 
50
- if !product[from_key].nil?
50
+ if !raw_product[from_key].nil?
51
51
  field = {
52
52
  namespace: namespace,
53
53
  permission_set: 'write',
54
54
  resource_type: 'product',
55
55
  key: to_key,
56
- value: product[from_key]
56
+ value: raw_product[from_key]
57
57
  }
58
58
 
59
59
  if bc_product
@@ -69,9 +69,9 @@ module BigcommerceProductAgent
69
69
  end
70
70
  end
71
71
 
72
- def self.from_additional_property(product, existing_fields, from_key, to_key, namespace, bc_product)
72
+ def self.from_additional_property(raw_product, existing_fields, from_key, to_key, namespace, bc_product)
73
73
 
74
- item = product['additionalProperty'].select {|p| p['propertyID'] == from_key}.first
74
+ item = raw_product['additionalProperty'].select {|p| p['propertyID'] == from_key}.first
75
75
  if !item.nil?
76
76
 
77
77
  field = {
@@ -2,130 +2,42 @@ module BigcommerceProductAgent
2
2
  module Mapper
3
3
  class ProductMapper
4
4
 
5
- def self.map(product, variant, additional_data = {}, is_digital = false, default_sku='')
5
+ def self.map_payload(product, additional_data = {}, track_inventory = true, default_sku = '')
6
6
  name = product['name']
7
+ isDigital = product['isDigital'].to_s == 'true'
7
8
 
8
- if variant
9
- # variants inherit from and override parent product info
10
- name = "#{name} (#{self.get_option(variant)})"
11
- product = product.merge(variant)
12
- else
13
- # wrapper product
14
- default_variant = self.get_variant_by_sku(product['sku'], product)
15
- if default_variant
16
- # pull up some properties from default variant (since bc doesn't display them otherwise)
17
- product = {
18
- "weight" => default_variant['weight'],
19
- "width" => default_variant['width'],
20
- "depth" => default_variant['depth'],
21
- "height" => default_variant['height'],
22
- "releaseDate" => default_variant['releaseDate'],
23
- "datePublished" => default_variant['datePublished'],
24
- "availability" => self.get_availability_offer(product, default_variant),
25
- }.merge(product)
26
- end
27
- end
9
+ track_inventory = self.get_availability(product) == 'preorder' ? false : track_inventory
28
10
 
29
11
  result = {
30
- name: name,
31
- sku: product ? product['sku'] : default_sku,
32
- is_default: product['isDefault'],
33
- type: product['isDigital'] == true || is_digital ? 'digital' : 'physical',
34
- description: product['description'] || '',
35
- price: product['offers'] && product['offers'][0] ? product['offers'][0]['price'] : '0',
36
- categories: self.get_categories(product),
37
- availability: self.get_availability(product),
38
- weight: product['weight'] ? product['weight']['value'] : '0',
39
- width: product['width'] ? product['width']['value'] : '0',
40
- depth: product['depth'] ? product['depth']['value'] : '0',
41
- height: product['height'] ? product['height']['value'] : '0',
42
- meta_keywords: self.meta_keywords(product),
43
- meta_description: self.meta_description(product) || '',
44
- search_keywords: self.get_search_keywords(additional_data.delete(:additional_search_terms), product),
45
- is_visible: variant ? false : true,
46
- preorder_release_date: product['releaseDate'] && product['releaseDate'].to_datetime ? product['releaseDate'].to_datetime.strftime("%FT%T%:z") : nil,
47
- preorder_message: self.get_availability(product) == 'preorder' ? product['availability'] : '',
48
- is_preorder_only: self.get_availability(product) == 'preorder' ? true : false,
49
- page_title: product['page_title'] || '',
12
+ availability: self.get_availability(product),
13
+ categories: self.get_categories(product),
14
+ depth: product['depth'] ? product['depth']['value'] : '0',
15
+ description: product['description'] || '',
16
+ height: product['height'] ? product['height']['value'] : '0',
17
+ is_default: product['isDefault'],
18
+ is_preorder_only: self.get_availability(product) == 'preorder' ? true : false,
19
+ is_visible: true,
20
+ meta_description: self.meta_description(product) || '',
21
+ meta_keywords: self.meta_keywords(product),
22
+ name: name,
23
+ page_title: product['page_title'] || '',
24
+ preorder_message: self.get_availability(product) == 'preorder' ? product['offers'][0]['availability'] : '',
25
+ preorder_release_date: product['releaseDate'] && product['releaseDate'].to_datetime ? product['releaseDate'].to_datetime.strftime("%FT%T%:z") : nil,
26
+ price: product['offers'] && product['offers'][0] ? product['offers'][0]['price'] : '0',
27
+ retail_price: product['offers'] && product['offers'][0] ? product['offers'][0]['price'] : '0',
28
+ search_keywords: self.get_search_keywords(additional_data.delete(:additional_search_terms), product),
29
+ sku: product ? product['sku'] : default_sku,
30
+ type: isDigital ? 'digital' : 'physical',
31
+ weight: product['weight'] ? product['weight']['value'] : '0',
32
+ width: product['width'] ? product['width']['value'] : '0',
33
+ inventory_tracking: isDigital || !track_inventory ? 'none' : 'product',
50
34
  }
51
- result[:upc] = product['gtin12'] if product['gtin12']
35
+ result[:upc] = product['isbn'] ? product['isbn'] : product['gtin12']
36
+ result[:gtin] = product['gtin12'] if product['gtin12']
52
37
 
53
38
  result.merge(additional_data)
54
39
  end
55
40
 
56
- def self.get_wrapper_sku(product)
57
- if product
58
- "#{product['sku']}-W"
59
- end
60
- end
61
-
62
- def self.payload(sku, product, product_id = nil, additional_data = {}, is_digital = false)
63
- variant = self.get_variant_by_sku(sku, product)
64
- payload = self.map(product, variant, additional_data, is_digital, sku)
65
- payload[:id] = product_id unless product_id.nil?
66
- payload[:sku] = self.get_wrapper_sku(product)
67
-
68
- return payload
69
- end
70
-
71
- def self.get_product_skus(product)
72
- product['model'].map { |model| model['sku'] }
73
- end
74
-
75
- def self.get_sku_option_label_map(product)
76
- map = {}
77
-
78
- product['model'].each do |model|
79
- map[model['sku']] = self.get_option(model)
80
- end
81
-
82
- return map
83
- end
84
-
85
- def self.get_is_default(product)
86
- map = {}
87
-
88
- product['model'].each do |model|
89
- map[model['sku']] = model["isDefault"]
90
- end
91
-
92
- return map
93
- end
94
-
95
- def self.has_digital_variants?(product)
96
- product['model'].any? {|m| m['isDigital'] == true}
97
- end
98
-
99
- def self.has_physical_variants?(product)
100
- product['model'].any? {|m| m['isDigital'] != true}
101
- end
102
-
103
- def self.split_digital_and_physical(product, field_map)
104
- result = {}
105
-
106
- digitals = product['model'].select {|m| m['isDigital'] == true}
107
-
108
- if digitals.length > 0
109
- clone = Marshal.load(Marshal.dump(product))
110
- clone['model'] = digitals
111
- clone['sku'] = clone['model'].select {|m| m['isDefault'] = true}.first['sku']
112
- self.merge_additional_properties(clone, field_map)
113
- result[:digital] = clone
114
- end
115
-
116
- physicals = product['model'].select {|m| m['isDigital'] != true}
117
-
118
- if physicals.length > 0
119
- clone = Marshal.load(Marshal.dump(product))
120
- clone['model'] = physicals
121
- clone['sku'] = clone['model'].select {|m| m['isDefault'] = true}.first['sku']
122
- self.merge_additional_properties(clone, field_map)
123
- result[:physical] = clone
124
- end
125
-
126
- return result
127
- end
128
-
129
41
  private
130
42
 
131
43
  def self.get_categories(product)
@@ -140,17 +52,6 @@ module BigcommerceProductAgent
140
52
  return categories
141
53
  end
142
54
 
143
- def self.get_option(variant)
144
- if variant['encodingFormat']
145
- return variant['encodingFormat']
146
- elsif variant['bookFormat']
147
- parts = variant['bookFormat'].split('/')
148
- return parts[parts.length - 1]
149
- else
150
- return self.get_additional_property_value(variant, 'option')
151
- end
152
- end
153
-
154
55
  def self.meta_description(product)
155
56
  return self.get_additional_property_value(product, 'meta_description', '')
156
57
  end
@@ -158,7 +59,7 @@ module BigcommerceProductAgent
158
59
  def self.meta_keywords(product)
159
60
  meta_keywords = []
160
61
 
161
- product['keywords'].split(',') unless product['keywords'].nil?
62
+ meta_keywords = product['keywords'].split(',') unless product['keywords'].nil?
162
63
 
163
64
  return meta_keywords
164
65
  end
@@ -174,52 +75,23 @@ module BigcommerceProductAgent
174
75
  return value
175
76
  end
176
77
 
177
- def self.get_variant_by_sku(sku, product)
178
- product['model'].select {|m| m['sku'] == sku}.first
179
- end
180
-
181
- def self.merge_additional_properties(clone, field_map)
182
- defaultVariant = clone['model'].select { |v| v['isDefault'] }.first
183
- if defaultVariant['isDefault'] && defaultVariant['additionalProperty']
184
- unless field_map.nil? || field_map['additionalProperty'].nil?
185
- field_map['additionalProperty'].each do |field, key|
186
- prop = defaultVariant['additionalProperty'].select { |prop| prop['propertyID'] == field[key] }.first
187
- clone['additionalProperty'].push(prop) unless prop.nil?
188
- end
189
- end
190
- end
191
- end
192
-
193
78
  # get a list of search keywords for the products
194
79
  def self.get_search_keywords(additional_search_terms, product)
195
- return (self.meta_keywords(product) + additional_search_terms.split(",")).join(",")
196
- end
80
+ search_keywords = self.meta_keywords(product)
81
+ search_keywords << product['isbn'] if product['isbn'].present?
82
+ if (additional_search_terms && !additional_search_terms.empty?)
83
+ search_keywords.concat(additional_search_terms)
84
+ end
197
85
 
198
- def self.get_availability(product)
199
- if product['datePublished'] && product['datePublished'].to_datetime && product['datePublished'].to_datetime < DateTime.now
200
- return 'available'
201
- else
202
- if product['releaseDate'] && product['releaseDate'].to_datetime
203
- if product['releaseDate'].to_datetime > DateTime.now
204
- return 'preorder'
205
- else
206
- return 'available'
207
- end
208
- else
209
- return 'disabled'
210
- end
211
- end
86
+ return search_keywords.uniq.join(",")
212
87
  end
213
88
 
214
- def self.get_availability_offer(product, variant)
215
- if product['offers'] && product['offers'][0]
216
- return product['offers'][0]['availability']
89
+ def self.get_availability(product)
90
+ if product['productAvailability'] == 'not available'
91
+ return 'disabled'
217
92
  else
218
- if variant['offers'] && variant['offers'][0]
219
- return variant['offers'][0]['availability']
220
- end
93
+ return product['productAvailability']
221
94
  end
222
- return ''
223
95
  end
224
96
  end
225
97
  end
@@ -9,7 +9,7 @@ module BigcommerceProductAgent
9
9
  price: variant['offers'] && variant['offers'][0] ? variant['offers'][0]['price'] : '0',
10
10
  cost_price: nil,
11
11
  sale_price: nil,
12
- retail_price: nil,
12
+ retail_price: variant['offers'] && variant['offers'][0] ? variant['offers'][0]['price'] : nil,
13
13
  weight: variant['weight'] ? variant['weight']['value'] : '0',
14
14
  width: variant['width'] ? variant['width']['value'] : '0',
15
15
  depth: variant['depth'] ? variant['depth']['value'] : '0',
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: huginn_bigcommerce_product_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.1
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jacob Spizziri
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-21 00:00:00.000000000 Z
11
+ date: 2021-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -63,18 +63,12 @@ files:
63
63
  - lib/abstract_client.rb
64
64
  - lib/client/custom_field.rb
65
65
  - lib/client/meta_field.rb
66
- - lib/client/modifier.rb
67
- - lib/client/modifier_value.rb
68
66
  - lib/client/product.rb
69
- - lib/client/product_option.rb
70
- - lib/client/product_option_value.rb
71
- - lib/client/product_variant.rb
72
- - lib/client/variant.rb
73
67
  - lib/huginn_bigcommerce_product_agent.rb
68
+ - lib/huginn_bigcommerce_product_agent/big_commerce_product_error.rb
74
69
  - lib/huginn_bigcommerce_product_agent/bigcommerce_product_agent.rb
75
70
  - lib/mapper/custom_field_mapper.rb
76
71
  - lib/mapper/meta_field_mapper.rb
77
- - lib/mapper/modifier_mapper.rb
78
72
  - lib/mapper/option_mapper.rb
79
73
  - lib/mapper/option_value_mapper.rb
80
74
  - lib/mapper/product_mapper.rb