huginn_bigcommerce_product_agent 1.12.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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