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 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