huginn_bigcommerce_product_agent 1.9.0 → 1.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/client/meta_field.rb +5 -1
- data/lib/client/product.rb +7 -0
- data/lib/client/product_option.rb +6 -2
- data/lib/huginn_bigcommerce_product_agent/bigcommerce_product_agent.rb +51 -18
- data/lib/mapper/product_mapper.rb +20 -2
- data/lib/mapper/variant_mapper.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75db6b836de4031aa33df47c393b0db0b59f99813fa96e98ee15ec10b39b8f91
|
4
|
+
data.tar.gz: d5c2bcc87f0fd3f95e489aa651f06297b07225398edfb6dfc8869c976f63caf7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96cc182ce0413cbb9843e4ab435d47ca85540e0025a9cb60579a200f37a3c9c299df0583b20454a83adf23f516e917f75e75942b555245761e21918af79d76b4
|
7
|
+
data.tar.gz: 463354a063899f6cb03c253cf65b692ecb2258525e04ce107320f41e03ea6ee4251eda5c8bd4147596a9d6a2fdb90e1e85837b13aa7a05936e7f026d763e22fd
|
data/lib/client/meta_field.rb
CHANGED
@@ -42,7 +42,11 @@ module BigcommerceProductAgent
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def delete(product_id, meta_field_id)
|
45
|
-
|
45
|
+
begin
|
46
|
+
client.delete(uri(product_id: product_id, meta_field_id: meta_field_id))
|
47
|
+
rescue Faraday::Error::ClientError => e
|
48
|
+
raise e, "\n#{e.message}\nFailed to delete meta_field with id = #{meta_field_id}\nfor product with id = #{product_id}\n", e.backtrace
|
49
|
+
end
|
46
50
|
end
|
47
51
|
end
|
48
52
|
end
|
data/lib/client/product.rb
CHANGED
@@ -33,8 +33,12 @@ module BigcommerceProductAgent
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def create(product_id, option)
|
36
|
-
|
37
|
-
|
36
|
+
begin
|
37
|
+
response = client.post(uri(product_id: product_id), option.to_json)
|
38
|
+
return response.body['data']
|
39
|
+
rescue Faraday::Error::ClientError => e
|
40
|
+
raise e, "\n#{e.message}\nFailed to upsert product_option = #{option.to_json}\nfor product with id = #{product_id}\n", e.backtrace
|
41
|
+
end
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|
@@ -100,36 +100,48 @@ module Agents
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
-
# 1.
|
104
|
-
#
|
105
|
-
#
|
103
|
+
# 1. Upsert the core product (Wrapper Product)
|
104
|
+
# - NOTE: This initial upsert intentionally disables the product.
|
105
|
+
# Doing so prevents content hiccups with variants particularly
|
106
|
+
# for products going off sale.
|
107
|
+
# 2. Upsert option & option_values (BigCommerce Variants)
|
108
|
+
# 3. Delete old option_values
|
106
109
|
# - NOTE: deleting an option_value also deletes the variant
|
107
110
|
# associated with the option_value
|
108
|
-
# 4.
|
111
|
+
# 4. Upsert variants
|
109
112
|
# - NOTE: because deleting option values deletes variants
|
110
113
|
# we need to fetch the variants AFTER deletion has occurred.
|
111
114
|
# - NOTE: by deleting variants in #3 if option_values on an
|
112
115
|
# existing variant changes over time, we're effectively deleting
|
113
116
|
# and then re-adding the variant. Could get weird.
|
117
|
+
# 5. Re-enable the updated product
|
118
|
+
# - NOTE: If the product no longer has any variants, it will remain
|
119
|
+
# disabled as it can no longer be purchased.
|
114
120
|
def handle_variants(event)
|
115
121
|
product = event.payload
|
116
122
|
|
117
123
|
split = get_mapper(:ProductMapper).split_digital_and_physical(
|
118
|
-
|
119
|
-
|
124
|
+
product,
|
125
|
+
interpolated['custom_fields_map']
|
120
126
|
)
|
121
127
|
physical = split[:physical]
|
122
128
|
digital = split[:digital]
|
123
129
|
|
130
|
+
base_sku = product['additionalProperty'].find { |p|
|
131
|
+
p['propertyID'] == 'baseSku'
|
132
|
+
}['value']
|
133
|
+
|
124
134
|
wrapper_skus = {
|
125
|
-
|
126
|
-
|
135
|
+
# Use the provided base_sku if it exists -- otherwise, infer the SKU from the variant list
|
136
|
+
physical: base_sku ? "#{base_sku}-P" : get_mapper(:ProductMapper).get_wrapper_sku(physical),
|
137
|
+
digital: base_sku ? "#{base_sku}-D" : get_mapper(:ProductMapper).get_wrapper_sku(digital),
|
127
138
|
}
|
128
139
|
|
129
140
|
bc_products = @product.get_by_skus(
|
130
141
|
wrapper_skus.map {|k,v| v},
|
131
142
|
%w[custom_fields options]
|
132
143
|
)
|
144
|
+
|
133
145
|
#save skus
|
134
146
|
digital_skus = []
|
135
147
|
physical_skus = []
|
@@ -149,15 +161,13 @@ module Agents
|
|
149
161
|
product['name'] = "#{product['name']} (Digital)"
|
150
162
|
end
|
151
163
|
|
152
|
-
#
|
153
|
-
#
|
164
|
+
# BigCommerce requires that product names be unique. In some cases, (like book titles from multiple sources),
|
165
|
+
# this may be hard to enforce. In those cases, the product SKUs should still be unique, so we append the SKU
|
166
|
+
# to the product title with a `|~` separator. We then set the `page_title` to the original product name so
|
167
|
+
# users don't see system values.
|
154
168
|
if boolify(options['should_disambiguate'])
|
155
169
|
product['page_title'] = product['name']
|
156
|
-
product['name'] += " |~ " +
|
157
|
-
m['additionalProperty'].find { |p|
|
158
|
-
p['propertyID'] == 'option'
|
159
|
-
}['value']
|
160
|
-
}.join(", ")
|
170
|
+
product['name'] += " |~ " + (is_digital ? wrapper_skus[:digital] : wrapper_skus[:physical])
|
161
171
|
end
|
162
172
|
|
163
173
|
wrapper_sku = wrapper_skus[type]
|
@@ -166,6 +176,8 @@ module Agents
|
|
166
176
|
bc_option = !bc_product.nil? ? bc_product['options'].select {|opt| opt['display_name'] === variant_option_name}.first : nil
|
167
177
|
|
168
178
|
search_skus = is_digital ? physical_skus : digital_skus
|
179
|
+
|
180
|
+
|
169
181
|
# ##############################
|
170
182
|
# 1. update wrapper product
|
171
183
|
# ##############################
|
@@ -204,7 +216,7 @@ module Agents
|
|
204
216
|
# ##############################
|
205
217
|
variant_skus = get_mapper(:ProductMapper).get_product_skus(product)
|
206
218
|
bc_variants = @product_variant.index(product_id)
|
207
|
-
mapped_variants = product['model'].map do |variant|
|
219
|
+
mapped_variants = product['model'].select { |m| m['isAvailableForPurchase'] }.map do |variant|
|
208
220
|
bc_variant = bc_variants.select {|v| v['sku'] === variant['sku']}.first
|
209
221
|
opt = get_mapper(:ProductMapper).get_option(variant)
|
210
222
|
bc_option_value = bc_option['option_values'].select {|ov| ov['label'] == opt}.first
|
@@ -221,7 +233,15 @@ module Agents
|
|
221
233
|
)
|
222
234
|
end
|
223
235
|
|
224
|
-
|
236
|
+
|
237
|
+
unless (mapped_variants.blank?)
|
238
|
+
bc_product['variants'] = @variant.upsert(mapped_variants)
|
239
|
+
|
240
|
+
# ##############################
|
241
|
+
# 5. Re-enable the updated product
|
242
|
+
# ##############################
|
243
|
+
@product.enable(product_id)
|
244
|
+
end
|
225
245
|
end
|
226
246
|
|
227
247
|
bc_physical = bc_products[wrapper_skus[:physical]]
|
@@ -329,6 +349,11 @@ module Agents
|
|
329
349
|
clean_up_modifier_values(modifier_updates[:delete])
|
330
350
|
meta_fields = update_meta_fields(meta_fields_upsert, meta_fields_delete)
|
331
351
|
|
352
|
+
if product['is_visible']
|
353
|
+
# If the product should be enabled, re-enable it
|
354
|
+
@product.enable(result[:product]['id'])
|
355
|
+
end
|
356
|
+
|
332
357
|
product['meta_fields'] = meta_fields
|
333
358
|
product['modifiers'] = modifier_updates[:upsert]
|
334
359
|
create_event payload: {
|
@@ -385,6 +410,12 @@ module Agents
|
|
385
410
|
is_digital,
|
386
411
|
)
|
387
412
|
|
413
|
+
payload[:is_visible] = false
|
414
|
+
# NOTE: Products are intentionally upserted as disabled so that users
|
415
|
+
# don't see an incomplete listing (particularly when leveraging variants)
|
416
|
+
# The variant and option_list methods will re-enable products after the
|
417
|
+
# upsert is complete.
|
418
|
+
|
388
419
|
bc_product = @product.upsert(payload, {
|
389
420
|
include: %w[custom_fields variants options].join(',')
|
390
421
|
})
|
@@ -427,7 +458,9 @@ module Agents
|
|
427
458
|
end
|
428
459
|
|
429
460
|
delete_fields.each do |field|
|
430
|
-
|
461
|
+
if field[:resource_id] && field[:id]
|
462
|
+
@meta_field.delete(field[:resource_id], field[:id])
|
463
|
+
end
|
431
464
|
end
|
432
465
|
|
433
466
|
meta_fields
|
@@ -63,7 +63,7 @@ module BigcommerceProductAgent
|
|
63
63
|
variant = self.get_variant_by_sku(sku, product)
|
64
64
|
payload = self.map(product, variant, additional_data, is_digital, sku)
|
65
65
|
payload[:id] = product_id unless product_id.nil?
|
66
|
-
payload[:sku] =
|
66
|
+
payload[:sku] = sku
|
67
67
|
|
68
68
|
return payload
|
69
69
|
end
|
@@ -76,7 +76,9 @@ module BigcommerceProductAgent
|
|
76
76
|
map = {}
|
77
77
|
|
78
78
|
product['model'].each do |model|
|
79
|
-
|
79
|
+
if model['isAvailableForPurchase']
|
80
|
+
map[model['sku']] = self.get_option(model)
|
81
|
+
end
|
80
82
|
end
|
81
83
|
|
82
84
|
return map
|
@@ -109,6 +111,7 @@ module BigcommerceProductAgent
|
|
109
111
|
clone = Marshal.load(Marshal.dump(product))
|
110
112
|
clone['model'] = digitals
|
111
113
|
clone['sku'] = clone['model'].select {|m| m['isDefault'] = true}.first['sku']
|
114
|
+
clone['categories'] = self.get_categories_after_split(clone, clone['categories'])
|
112
115
|
self.merge_additional_properties(clone, field_map)
|
113
116
|
result[:digital] = clone
|
114
117
|
end
|
@@ -119,6 +122,7 @@ module BigcommerceProductAgent
|
|
119
122
|
clone = Marshal.load(Marshal.dump(product))
|
120
123
|
clone['model'] = physicals
|
121
124
|
clone['sku'] = clone['model'].select {|m| m['isDefault'] = true}.first['sku']
|
125
|
+
clone['categories'] = self.get_categories_after_split(clone, clone['categories'])
|
122
126
|
self.merge_additional_properties(clone, field_map)
|
123
127
|
result[:physical] = clone
|
124
128
|
end
|
@@ -140,6 +144,20 @@ module BigcommerceProductAgent
|
|
140
144
|
return categories
|
141
145
|
end
|
142
146
|
|
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
|
+
|
143
161
|
def self.get_option(variant)
|
144
162
|
if variant['encodingFormat']
|
145
163
|
return variant['encodingFormat']
|
@@ -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.
|
4
|
+
version: 1.12.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
|
+
date: 2020-11-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|