huginn_bigcommerce_product_agent 1.12.0 → 2.0.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,134 +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] = sku
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
- if model['isAvailableForPurchase']
80
- map[model['sku']] = self.get_option(model)
81
- end
82
- end
83
-
84
- return map
85
- end
86
-
87
- def self.get_is_default(product)
88
- map = {}
89
-
90
- product['model'].each do |model|
91
- map[model['sku']] = model["isDefault"]
92
- end
93
-
94
- return map
95
- end
96
-
97
- def self.has_digital_variants?(product)
98
- product['model'].any? {|m| m['isDigital'] == true}
99
- end
100
-
101
- def self.has_physical_variants?(product)
102
- product['model'].any? {|m| m['isDigital'] != true}
103
- end
104
-
105
- def self.split_digital_and_physical(product, field_map)
106
- result = {}
107
-
108
- digitals = product['model'].select {|m| m['isDigital'] == true}
109
-
110
- if digitals.length > 0
111
- clone = Marshal.load(Marshal.dump(product))
112
- clone['model'] = digitals
113
- clone['sku'] = clone['model'].select {|m| m['isDefault'] = true}.first['sku']
114
- clone['categories'] = self.get_categories_after_split(clone, clone['categories'])
115
- self.merge_additional_properties(clone, field_map)
116
- result[:digital] = clone
117
- end
118
-
119
- physicals = product['model'].select {|m| m['isDigital'] != true}
120
-
121
- if physicals.length > 0
122
- clone = Marshal.load(Marshal.dump(product))
123
- clone['model'] = physicals
124
- clone['sku'] = clone['model'].select {|m| m['isDefault'] = true}.first['sku']
125
- clone['categories'] = self.get_categories_after_split(clone, clone['categories'])
126
- self.merge_additional_properties(clone, field_map)
127
- result[:physical] = clone
128
- end
129
-
130
- return result
131
- end
132
-
133
41
  private
134
42
 
135
43
  def self.get_categories(product)
@@ -144,31 +52,6 @@ module BigcommerceProductAgent
144
52
  return categories
145
53
  end
146
54
 
147
- def self.get_categories_after_split(product, categories)
148
- # categories equal shared categories between digital and physical products
149
-
150
- if product['model'].select { |c| c['categories']}
151
- product['model'].each do |variant|
152
- variant['categories'].map do |category|
153
- categories.push(category)
154
- end
155
- end
156
- end
157
-
158
- return categories
159
- end
160
-
161
- def self.get_option(variant)
162
- if variant['encodingFormat']
163
- return variant['encodingFormat']
164
- elsif variant['bookFormat']
165
- parts = variant['bookFormat'].split('/')
166
- return parts[parts.length - 1]
167
- else
168
- return self.get_additional_property_value(variant, 'option')
169
- end
170
- end
171
-
172
55
  def self.meta_description(product)
173
56
  return self.get_additional_property_value(product, 'meta_description', '')
174
57
  end
@@ -176,7 +59,7 @@ module BigcommerceProductAgent
176
59
  def self.meta_keywords(product)
177
60
  meta_keywords = []
178
61
 
179
- product['keywords'].split(',') unless product['keywords'].nil?
62
+ meta_keywords = product['keywords'].split(',') unless product['keywords'].nil?
180
63
 
181
64
  return meta_keywords
182
65
  end
@@ -192,52 +75,23 @@ module BigcommerceProductAgent
192
75
  return value
193
76
  end
194
77
 
195
- def self.get_variant_by_sku(sku, product)
196
- product['model'].select {|m| m['sku'] == sku}.first
197
- end
198
-
199
- def self.merge_additional_properties(clone, field_map)
200
- defaultVariant = clone['model'].select { |v| v['isDefault'] }.first
201
- if defaultVariant['isDefault'] && defaultVariant['additionalProperty']
202
- unless field_map.nil? || field_map['additionalProperty'].nil?
203
- field_map['additionalProperty'].each do |field, key|
204
- prop = defaultVariant['additionalProperty'].select { |prop| prop['propertyID'] == field[key] }.first
205
- clone['additionalProperty'].push(prop) unless prop.nil?
206
- end
207
- end
208
- end
209
- end
210
-
211
78
  # get a list of search keywords for the products
212
79
  def self.get_search_keywords(additional_search_terms, product)
213
- return (self.meta_keywords(product) + additional_search_terms.split(",")).join(",")
214
- 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
215
85
 
216
- def self.get_availability(product)
217
- if product['datePublished'] && product['datePublished'].to_datetime && product['datePublished'].to_datetime < DateTime.now
218
- return 'available'
219
- else
220
- if product['releaseDate'] && product['releaseDate'].to_datetime
221
- if product['releaseDate'].to_datetime > DateTime.now
222
- return 'preorder'
223
- else
224
- return 'available'
225
- end
226
- else
227
- return 'disabled'
228
- end
229
- end
86
+ return search_keywords.uniq.join(",")
230
87
  end
231
88
 
232
- def self.get_availability_offer(product, variant)
233
- if product['offers'] && product['offers'][0]
234
- return product['offers'][0]['availability']
89
+ def self.get_availability(product)
90
+ if product['productAvailability'] == 'not available'
91
+ return 'disabled'
235
92
  else
236
- if variant['offers'] && variant['offers'][0]
237
- return variant['offers'][0]['availability']
238
- end
93
+ return product['productAvailability']
239
94
  end
240
- return ''
241
95
  end
242
96
  end
243
97
  end
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.12.0
4
+ version: 2.0.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-11-06 00:00:00.000000000 Z
11
+ date: 2021-03-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -63,18 +63,11 @@ 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
74
68
  - lib/huginn_bigcommerce_product_agent/bigcommerce_product_agent.rb
75
69
  - lib/mapper/custom_field_mapper.rb
76
70
  - lib/mapper/meta_field_mapper.rb
77
- - lib/mapper/modifier_mapper.rb
78
71
  - lib/mapper/option_mapper.rb
79
72
  - lib/mapper/option_value_mapper.rb
80
73
  - lib/mapper/product_mapper.rb