huginn_bigcommerce_product_agent 1.0.1
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.
- checksums.yaml +7 -0
- data/lib/abstract_client.rb +80 -0
- data/lib/client/custom_field.rb +11 -0
- data/lib/client/modifier.rb +35 -0
- data/lib/client/modifier_value.rb +11 -0
- data/lib/client/product.rb +46 -0
- data/lib/huginn_bigcommerce_product_agent.rb +15 -0
- data/lib/huginn_bigcommerce_product_agent/bigcommerce_product_agent.rb +166 -0
- data/lib/mapper/custom_field_mapper.rb +81 -0
- data/lib/mapper/modifier_mapper.rb +83 -0
- data/lib/mapper/product_mapper.rb +114 -0
- data/spec/bigcommerce_product_agent_spec.rb +13 -0
- metadata +98 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7c7ba2d9c033ac9bcb4e6b918e5061e4a24aefc5969df512976bcb40ba9dff99
|
4
|
+
data.tar.gz: 27ba376c8ae1c70e19e0f0412e742899885aa42946ec4ceec22a3efcac96b409
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dcd14b6b838f97586e9b7d039ef6620074d56cb76cf90623edfc4ddd2b6826e9ad4c675f5fd68c36d393f8933dc86d440372727c13171330f276a5116adb7df1
|
7
|
+
data.tar.gz: 0f73c946976ad3b633635e32c79e823a1a36e57cee63708aac667bbcb86726c6a3761549021636d45cbfaee146baa23c05f584ba38003adf5990e0fe4db78dcb
|
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
module BigcommerceProductAgent
|
3
|
+
module Client
|
4
|
+
class AbstractClient
|
5
|
+
@client = nil
|
6
|
+
@uri_base = ''
|
7
|
+
|
8
|
+
def initialize(
|
9
|
+
store_hash,
|
10
|
+
client_id,
|
11
|
+
access_token,
|
12
|
+
params = {
|
13
|
+
endpoint: 'https://api.bigcommerce.com',
|
14
|
+
api_version: 'v3',
|
15
|
+
}
|
16
|
+
)
|
17
|
+
@headers = {
|
18
|
+
'X-Auth-Client' => client_id,
|
19
|
+
'X-Auth-Token' => access_token,
|
20
|
+
'Content-Type' => 'application/json',
|
21
|
+
'Accept' => 'application/json'
|
22
|
+
}
|
23
|
+
@store_hash = store_hash
|
24
|
+
@endpoint = params[:endpoint]
|
25
|
+
@api_version = params[:api_version]
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.uri_base
|
29
|
+
@uri_base
|
30
|
+
end
|
31
|
+
|
32
|
+
def uri_base
|
33
|
+
self.class.uri_base
|
34
|
+
end
|
35
|
+
|
36
|
+
def client
|
37
|
+
if !@client
|
38
|
+
@client = Faraday.new({ url: @endpoint, headers: @headers }) do |conn|
|
39
|
+
conn.use Faraday::Response::RaiseError
|
40
|
+
conn.response :logger, nil, { headers: true, bodies: true }
|
41
|
+
conn.response :json, :content_type => 'application/json'
|
42
|
+
conn.adapter Faraday.default_adapter
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
return @client
|
47
|
+
end
|
48
|
+
|
49
|
+
def uri(params = {})
|
50
|
+
u = "/stores/#{@store_hash}/#{@api_version}/#{uri_base}"
|
51
|
+
|
52
|
+
params.each do |key,val|
|
53
|
+
u = u.gsub(":#{key.to_s}", val.to_s)
|
54
|
+
end
|
55
|
+
|
56
|
+
# remove params that weren't provided
|
57
|
+
u = u.gsub(/(\/\:[^\/]+)/, '')
|
58
|
+
|
59
|
+
return u
|
60
|
+
end
|
61
|
+
|
62
|
+
def index(params = {})
|
63
|
+
response = client.get(uri, params)
|
64
|
+
return response.body['data']
|
65
|
+
end
|
66
|
+
|
67
|
+
def create(payload)
|
68
|
+
raise "not implemented yet."
|
69
|
+
end
|
70
|
+
|
71
|
+
def update(payload)
|
72
|
+
raise "not implemented yet."
|
73
|
+
end
|
74
|
+
|
75
|
+
def upsert(payload)
|
76
|
+
raise "not implemented yet."
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module BigcommerceProductAgent
|
2
|
+
module Client
|
3
|
+
class CustomField < AbstractClient
|
4
|
+
@uri_base = 'catalog/products/:product_id/custom-fields/:custom_field_id'
|
5
|
+
|
6
|
+
def delete(product_id, custom_field_id)
|
7
|
+
client.delete(uri(product_id: product_id, custom_field_id: custom_field_id))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module BigcommerceProductAgent
|
2
|
+
module Client
|
3
|
+
class Modifier < AbstractClient
|
4
|
+
@uri_base = 'catalog/products/:product_id/modifiers/:modifier_id'
|
5
|
+
|
6
|
+
def delete(product_id, modifier_id)
|
7
|
+
client.delete(uri(product_id: product_id, modifier_id: modifier_id))
|
8
|
+
end
|
9
|
+
|
10
|
+
def upsert(product_id, modifier)
|
11
|
+
begin
|
12
|
+
if modifier[:id] || modifier['id']
|
13
|
+
modifier['id'] = modifier[:id] unless modifier[:id].nil?
|
14
|
+
return update(product_id, modifier)
|
15
|
+
else
|
16
|
+
return create(product_id, modifier)
|
17
|
+
end
|
18
|
+
rescue Faraday::Error::ClientError => e
|
19
|
+
puts e.inspect
|
20
|
+
raise e
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def update(product_id, modifier)
|
25
|
+
response = client.put(uri(product_id: product_id, modifier_id: modifier['id']), modifier.to_json)
|
26
|
+
return response.body['data']
|
27
|
+
end
|
28
|
+
|
29
|
+
def create(product_id, modifier)
|
30
|
+
response = client.post(uri(product_id: product_id), modifier.to_json)
|
31
|
+
return response.body['data']
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module BigcommerceProductAgent
|
2
|
+
module Client
|
3
|
+
class ModifierValue < AbstractClient
|
4
|
+
@uri_base = 'catalog/products/:product_id/modifiers/:modifier_id/values/:value_id'
|
5
|
+
|
6
|
+
def delete(product_id, modifier_id, value_id)
|
7
|
+
client.delete(uri(product_id: product_id, modifier_id: modifier_id, value_id: value_id))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module BigcommerceProductAgent
|
2
|
+
module Client
|
3
|
+
class Product < AbstractClient
|
4
|
+
@uri_base = 'catalog/products/:product_id'
|
5
|
+
|
6
|
+
def update(id, payload)
|
7
|
+
response = client.put(uri(product_id: id), { data: payload }.to_json)
|
8
|
+
return response.body['data']
|
9
|
+
end
|
10
|
+
|
11
|
+
def create(payload)
|
12
|
+
response = client.post(uri, payload.to_json)
|
13
|
+
return response.body['data']
|
14
|
+
end
|
15
|
+
|
16
|
+
def upsert(payload)
|
17
|
+
begin
|
18
|
+
if payload['id']
|
19
|
+
return update(payload['id'], payload)
|
20
|
+
else
|
21
|
+
return create(payload)
|
22
|
+
end
|
23
|
+
rescue Faraday::Error::ClientError => e
|
24
|
+
puts e.inspect
|
25
|
+
raise e
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_by_skus(skus, include = %w[custom_fields modifiers])
|
30
|
+
products = index({
|
31
|
+
'sku:in': skus.join(','),
|
32
|
+
include: include.join(','),
|
33
|
+
})
|
34
|
+
|
35
|
+
map = {}
|
36
|
+
|
37
|
+
products.each do |product|
|
38
|
+
map[product['sku']] = product
|
39
|
+
end
|
40
|
+
|
41
|
+
map
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'huginn_agent'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
# load clients
|
5
|
+
HuginnAgent.load 'abstract_client'
|
6
|
+
Dir[File.join(__dir__, 'client', '*.rb')].each do |file|
|
7
|
+
HuginnAgent.load file
|
8
|
+
end
|
9
|
+
|
10
|
+
# load mappers
|
11
|
+
Dir[File.join(__dir__, 'mapper', '*.rb')].each do |file|
|
12
|
+
HuginnAgent.load file
|
13
|
+
end
|
14
|
+
|
15
|
+
HuginnAgent.register 'huginn_bigcommerce_product_agent/bigcommerce_product_agent'
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Agents
|
6
|
+
class BigcommerceProductAgent < Agent
|
7
|
+
|
8
|
+
include WebRequestConcern
|
9
|
+
|
10
|
+
can_dry_run!
|
11
|
+
default_schedule 'never'
|
12
|
+
|
13
|
+
description <<-MD
|
14
|
+
Takes a generic product interface && upserts that product in BigCommerce.
|
15
|
+
MD
|
16
|
+
|
17
|
+
def default_options
|
18
|
+
{
|
19
|
+
'store_hash' => '',
|
20
|
+
'client_id' => '',
|
21
|
+
'access_token' => '',
|
22
|
+
'custom_fields_map' => {},
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate_options
|
27
|
+
unless options['store_hash'].present?
|
28
|
+
errors.add(:base, 'store_hash is a required field')
|
29
|
+
end
|
30
|
+
|
31
|
+
unless options['client_id'].present?
|
32
|
+
errors.add(:base, 'client_id is a required field')
|
33
|
+
end
|
34
|
+
|
35
|
+
unless options['access_token'].present?
|
36
|
+
errors.add(:base, 'access_token is a required field')
|
37
|
+
end
|
38
|
+
|
39
|
+
unless options['custom_fields_map'].is_a?(Hash)
|
40
|
+
errors.add(:base, "if provided, custom_fields_map must be a hash")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def working?
|
45
|
+
received_event_without_error?
|
46
|
+
end
|
47
|
+
|
48
|
+
def check
|
49
|
+
initialize_clients()
|
50
|
+
handle interpolated['payload'].presence || {}
|
51
|
+
end
|
52
|
+
|
53
|
+
def receive(incoming_events)
|
54
|
+
initialize_clients()
|
55
|
+
incoming_events.each do |event|
|
56
|
+
handle(event)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def handle(event)
|
61
|
+
product = event.payload
|
62
|
+
|
63
|
+
skus = ::BigcommerceProductAgent::Mapper::ProductMapper.get_product_skus(product)
|
64
|
+
wrapper_sku = ::BigcommerceProductAgent::Mapper::ProductMapper.get_wrapper_sku(product)
|
65
|
+
all_skus = [].push(*skus).push(wrapper_sku)
|
66
|
+
bc_products = @product.get_by_skus(all_skus)
|
67
|
+
|
68
|
+
# upsert child products
|
69
|
+
bc_children = []
|
70
|
+
custom_fields_delete = []
|
71
|
+
skus.each do |sku|
|
72
|
+
bc_product = bc_products[sku]
|
73
|
+
result = upsert(sku, product, bc_product)
|
74
|
+
custom_fields_delete += result[:custom_fields_delete]
|
75
|
+
bc_children.push(result[:product])
|
76
|
+
end
|
77
|
+
|
78
|
+
# upsert wrapper
|
79
|
+
bc_wrapper_product = bc_products[wrapper_sku]
|
80
|
+
result = upsert(wrapper_sku, product, bc_wrapper_product)
|
81
|
+
custom_fields_delete += result[:custom_fields_delete]
|
82
|
+
|
83
|
+
# update modifier
|
84
|
+
sku_option_map = ::BigcommerceProductAgent::Mapper::ProductMapper.get_sku_option_label_map(product)
|
85
|
+
modifier_updates = ::BigcommerceProductAgent::Mapper::ModifierMapper.map(
|
86
|
+
bc_wrapper_product,
|
87
|
+
bc_children,
|
88
|
+
sku_option_map
|
89
|
+
)
|
90
|
+
@modifier.upsert(result[:product]['id'], modifier_updates[:upsert])
|
91
|
+
|
92
|
+
clean_up_custom_fields(custom_fields_delete)
|
93
|
+
clean_up_modifier_values(modifier_updates[:delete])
|
94
|
+
|
95
|
+
product['modifiers'] = modifier_updates[:upsert]
|
96
|
+
create_event payload: {
|
97
|
+
product: product,
|
98
|
+
parent: result[:product],
|
99
|
+
children: bc_children,
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def initialize_clients
|
106
|
+
@product = ::BigcommerceProductAgent::Client::Product.new(
|
107
|
+
interpolated['store_hash'],
|
108
|
+
interpolated['client_id'],
|
109
|
+
interpolated['access_token']
|
110
|
+
)
|
111
|
+
|
112
|
+
@custom_field = ::BigcommerceProductAgent::Client::CustomField.new(
|
113
|
+
interpolated['store_hash'],
|
114
|
+
interpolated['client_id'],
|
115
|
+
interpolated['access_token']
|
116
|
+
)
|
117
|
+
|
118
|
+
@modifier = ::BigcommerceProductAgent::Client::Modifier.new(
|
119
|
+
interpolated['store_hash'],
|
120
|
+
interpolated['client_id'],
|
121
|
+
interpolated['access_token']
|
122
|
+
)
|
123
|
+
|
124
|
+
@modifier_value = ::BigcommerceProductAgent::Client::ModifierValue.new(
|
125
|
+
interpolated['store_hash'],
|
126
|
+
interpolated['client_id'],
|
127
|
+
interpolated['access_token']
|
128
|
+
)
|
129
|
+
end
|
130
|
+
|
131
|
+
def upsert(sku, product, bc_product = nil)
|
132
|
+
custom_fields_updates = ::BigcommerceProductAgent::Mapper::CustomFieldMapper.map(
|
133
|
+
interpolated['custom_fields_map'],
|
134
|
+
product,
|
135
|
+
bc_product
|
136
|
+
)
|
137
|
+
|
138
|
+
product_id = bc_product['id'] unless bc_product.nil?
|
139
|
+
payload = ::BigcommerceProductAgent::Mapper::ProductMapper.payload(
|
140
|
+
sku,
|
141
|
+
product,
|
142
|
+
product_id,
|
143
|
+
{ custom_fields: custom_fields_updates[:upsert] }
|
144
|
+
)
|
145
|
+
|
146
|
+
bc_product = @product.upsert(payload)
|
147
|
+
|
148
|
+
return {
|
149
|
+
product: bc_product,
|
150
|
+
custom_fields_delete: custom_fields_updates[:delete],
|
151
|
+
}
|
152
|
+
end
|
153
|
+
|
154
|
+
def clean_up_custom_fields(custom_fields)
|
155
|
+
custom_fields.each do |field|
|
156
|
+
@custom_field.delete(field['product_id'], field['id'])
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def clean_up_modifier_values(modifier_values)
|
161
|
+
modifier_values.each do |field|
|
162
|
+
@modifier_value.delete(field[:product_id], field[:modifier_id], field[:value_id])
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module BigcommerceProductAgent
|
2
|
+
module Mapper
|
3
|
+
class CustomFieldMapper
|
4
|
+
|
5
|
+
def self.map(field_map, product, bc_product)
|
6
|
+
fields = {
|
7
|
+
upsert: [],
|
8
|
+
delete: [],
|
9
|
+
}
|
10
|
+
|
11
|
+
existing_fields = {}
|
12
|
+
|
13
|
+
if bc_product
|
14
|
+
bc_product['custom_fields'].each do |cf|
|
15
|
+
cf['product_id'] = bc_product['id']
|
16
|
+
existing_fields[cf['name'].to_s] = cf
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
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?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
if field_map
|
28
|
+
field_map.each do |key, val|
|
29
|
+
if key == 'additionalProperty'
|
30
|
+
next
|
31
|
+
end
|
32
|
+
|
33
|
+
field = self.from_property(product, existing_fields, key, val)
|
34
|
+
fields[:upsert].push(field) unless field.nil?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# return values that need deleted
|
39
|
+
fields[:delete] = existing_fields.values
|
40
|
+
return fields
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def self.from_property(product, existing_fields, from_key, to_key)
|
46
|
+
if !product[from_key].nil?
|
47
|
+
field = {
|
48
|
+
name: to_key,
|
49
|
+
value: product[from_key]
|
50
|
+
}
|
51
|
+
|
52
|
+
if existing_fields[to_key]
|
53
|
+
field[:id] = existing_fields[to_key]['id']
|
54
|
+
existing_fields.delete(to_key)
|
55
|
+
end
|
56
|
+
|
57
|
+
return field
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.from_additional_property(product, existing_fields, from_key, to_key)
|
62
|
+
# date published
|
63
|
+
item = product['additionalProperty'].select {|p| p['propertyID'] == from_key}.first
|
64
|
+
if !item.nil?
|
65
|
+
field = {
|
66
|
+
name: to_key,
|
67
|
+
value: item['value']
|
68
|
+
}
|
69
|
+
|
70
|
+
if existing_fields[to_key]
|
71
|
+
field[:id] = existing_fields[to_key]['id']
|
72
|
+
existing_fields.delete(to_key)
|
73
|
+
end
|
74
|
+
|
75
|
+
return field
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module BigcommerceProductAgent
|
2
|
+
module Mapper
|
3
|
+
class ModifierMapper
|
4
|
+
|
5
|
+
def self.map(bc_product, bc_children, sku_option_map)
|
6
|
+
modifier = {
|
7
|
+
display_name: 'Option',
|
8
|
+
type: 'product_list',
|
9
|
+
required: true,
|
10
|
+
sort_order: 1,
|
11
|
+
config: {
|
12
|
+
product_list_adjusts_inventory: true,
|
13
|
+
product_list_adjusts_pricing: true,
|
14
|
+
product_list_shipping_calc: 'none'
|
15
|
+
},
|
16
|
+
option_values: []
|
17
|
+
}
|
18
|
+
|
19
|
+
existing_modifier = nil
|
20
|
+
existing_option_ids = []
|
21
|
+
if bc_product && !bc_product['modifiers'].nil?
|
22
|
+
existing_modifier = bc_product['modifiers'].select {|m| m['display_name'] == modifier[:display_name]}.first
|
23
|
+
modifier[:product_id] = bc_product['id']
|
24
|
+
|
25
|
+
if !existing_modifier.nil?
|
26
|
+
modifier[:id] = existing_modifier['id']
|
27
|
+
existing_option_ids = existing_modifier['option_values'].map {|value| value['id']}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
bc_children.each do |child|
|
32
|
+
existing_option = nil
|
33
|
+
if existing_modifier
|
34
|
+
existing_option = existing_modifier['option_values'].select do |val|
|
35
|
+
val['value_data'] && val['value_data']['product_id'] == child['id']
|
36
|
+
end.first
|
37
|
+
end
|
38
|
+
|
39
|
+
option = {
|
40
|
+
label: sku_option_map[child['sku']],
|
41
|
+
sort_order: 0,
|
42
|
+
value_data: {
|
43
|
+
product_id: child['id']
|
44
|
+
},
|
45
|
+
is_default: false,
|
46
|
+
adjusters: {
|
47
|
+
price: nil,
|
48
|
+
weight: nil,
|
49
|
+
image_url: '',
|
50
|
+
purchasing_disabled: {
|
51
|
+
status: false,
|
52
|
+
message: ''
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
if existing_option
|
58
|
+
option[:id] = existing_option['id']
|
59
|
+
option[:option_id] = existing_option['option_id']
|
60
|
+
existing_option_ids.delete(existing_option['id'])
|
61
|
+
end
|
62
|
+
|
63
|
+
modifier[:option_values].push(option)
|
64
|
+
end
|
65
|
+
|
66
|
+
# any left over option value should be removed
|
67
|
+
modifier_values_delete = existing_option_ids.map do |id|
|
68
|
+
{
|
69
|
+
product_id: bc_product['id'],
|
70
|
+
modifier_id: existing_modifier['id'],
|
71
|
+
value_id: id
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
return {
|
76
|
+
upsert: modifier,
|
77
|
+
delete: modifier_values_delete
|
78
|
+
}
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module BigcommerceProductAgent
|
2
|
+
module Mapper
|
3
|
+
class ProductMapper
|
4
|
+
|
5
|
+
def self.map(product, variant, additional_data = {})
|
6
|
+
product = {
|
7
|
+
name: variant.nil? ? product['name'] : "#{product['name']} (#{self.get_option(variant)})",
|
8
|
+
sku: variant ? variant['sku'] : self.get_wrapper_sku(product),
|
9
|
+
type: variant && variant['isDigital'] == true ? 'digital' : 'physical',
|
10
|
+
description: product['description'],
|
11
|
+
price: variant && variant['offers'] && variant['offers'][0] ? variant['offers'][0]['price'] : '0',
|
12
|
+
categories: self.get_categories(product),
|
13
|
+
available: 'available',
|
14
|
+
weight: variant && variant['weight'] ? variant['weight']['value'] : '0',
|
15
|
+
width: variant && variant['width'] ? variant['width']['value'] : '0',
|
16
|
+
depth: variant && variant['depth'] ? variant['depth']['value'] : '0',
|
17
|
+
height: variant && variant['height'] ? variant['height']['value'] : '0',
|
18
|
+
meta_keywords: self.meta_keywords(product),
|
19
|
+
meta_description: self.meta_description(product),
|
20
|
+
search_keywords: self.meta_keywords(product).join(','),
|
21
|
+
is_visible: variant.nil? ? true : false,
|
22
|
+
}.merge(additional_data)
|
23
|
+
|
24
|
+
|
25
|
+
upc = variant ? variant['gtin12'] : product['gtin12']
|
26
|
+
|
27
|
+
if upc
|
28
|
+
product[:upc] = upc
|
29
|
+
end
|
30
|
+
|
31
|
+
return product
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.get_wrapper_sku(product)
|
35
|
+
"#{product['sku']}-W"
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.payload(sku, product, product_id = nil, additional_data = {})
|
39
|
+
variant = self.get_variant_by_sku(sku, product)
|
40
|
+
payload = self.map(product, variant, additional_data)
|
41
|
+
payload['id'] = product_id unless product_id.nil?
|
42
|
+
|
43
|
+
return payload
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.get_product_skus(product)
|
47
|
+
product['model'].map { |model| model['sku'] }
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.get_sku_option_label_map(product)
|
51
|
+
map = {}
|
52
|
+
|
53
|
+
product['model'].each do |model|
|
54
|
+
map[model['sku']] = self.get_option(model)
|
55
|
+
end
|
56
|
+
|
57
|
+
return map
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def self.get_categories(product)
|
63
|
+
categories = []
|
64
|
+
|
65
|
+
if product['categories']
|
66
|
+
categories = product['categories'].map do |category|
|
67
|
+
category['identifier'].to_i
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
return categories
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.get_option(variant)
|
75
|
+
if variant['encodingFormat']
|
76
|
+
return variant['encodingFormat']
|
77
|
+
elsif variant['bookFormat']
|
78
|
+
parts = variant['bookFormat'].split('/')
|
79
|
+
return parts[parts.length - 1]
|
80
|
+
else
|
81
|
+
return self.get_additional_property_value(variant, 'option')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.meta_description(product)
|
86
|
+
return self.get_additional_property_value(product, 'meta_description', '')
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.meta_keywords(product)
|
90
|
+
meta_keywords = []
|
91
|
+
|
92
|
+
product['keywords'].split(',') unless product['keywords'].nil?
|
93
|
+
|
94
|
+
return meta_keywords
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.get_additional_property_value(product, name, default = nil)
|
98
|
+
value = default
|
99
|
+
|
100
|
+
return value if product['additionalProperty'].nil?
|
101
|
+
|
102
|
+
idx = product['additionalProperty'].index {|item| item['propertyID'] == name}
|
103
|
+
value = product['additionalProperty'][idx]['value'] unless idx.nil?
|
104
|
+
|
105
|
+
return value
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.get_variant_by_sku(sku, product)
|
109
|
+
product['model'].select {|m| m['sku'] == sku}.first
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# require 'rails_helper'
|
2
|
+
# require 'huginn_agent/spec_helper'
|
3
|
+
#
|
4
|
+
# describe Agents::BigcommerceProductAgent do
|
5
|
+
# before(:each) do
|
6
|
+
# @valid_options = Agents::BigcommerceProductAgent.new.default_options
|
7
|
+
# @checker = Agents::BigcommerceProductAgent.new(:name => "BigcommerceProductAgent", :options => @valid_options)
|
8
|
+
# @checker.user = users(:bob)
|
9
|
+
# @checker.save!
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# pending "add specs here"
|
13
|
+
# end
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: huginn_bigcommerce_product_agent
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jacob Spizziri
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-03-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: huginn_agent
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Agent that takes a generic product interface and upserts that product
|
56
|
+
in BigCommerce.
|
57
|
+
email:
|
58
|
+
- jspizziri@weare5stones.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- lib/abstract_client.rb
|
64
|
+
- lib/client/custom_field.rb
|
65
|
+
- lib/client/modifier.rb
|
66
|
+
- lib/client/modifier_value.rb
|
67
|
+
- lib/client/product.rb
|
68
|
+
- lib/huginn_bigcommerce_product_agent.rb
|
69
|
+
- lib/huginn_bigcommerce_product_agent/bigcommerce_product_agent.rb
|
70
|
+
- lib/mapper/custom_field_mapper.rb
|
71
|
+
- lib/mapper/modifier_mapper.rb
|
72
|
+
- lib/mapper/product_mapper.rb
|
73
|
+
- spec/bigcommerce_product_agent_spec.rb
|
74
|
+
homepage: https://github.com/5-stones/huginn_bigcommerce_product_agent
|
75
|
+
licenses: []
|
76
|
+
metadata: {}
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
requirements: []
|
92
|
+
rubygems_version: 3.0.3
|
93
|
+
signing_key:
|
94
|
+
specification_version: 4
|
95
|
+
summary: Agent that takes a generic product interface and upserts that product in
|
96
|
+
BigCommerce.
|
97
|
+
test_files:
|
98
|
+
- spec/bigcommerce_product_agent_spec.rb
|