flowcommerce_spree 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +91 -0
  4. data/Rakefile +33 -0
  5. data/SPREE_FLOW.md +134 -0
  6. data/app/assets/javascripts/flowcommerce_spree/application.js +13 -0
  7. data/app/assets/stylesheets/flowcommerce_spree/application.css +15 -0
  8. data/app/controllers/concerns/current_zone_loader_decorator.rb +49 -0
  9. data/app/controllers/flowcommerce_spree/webhooks_controller.rb +25 -0
  10. data/app/helpers/flowcommerce_spree/application_helper.rb +6 -0
  11. data/app/helpers/spree/admin/orders_helper_decorator.rb +17 -0
  12. data/app/helpers/spree/core/controller_helpers/flow_io_order_helper_decorator.rb +53 -0
  13. data/app/mailers/spree/spree_order_mailer_decorator.rb +24 -0
  14. data/app/models/flowcommerce_spree/settings.rb +8 -0
  15. data/app/models/spree/credit_card_decorator.rb +9 -0
  16. data/app/models/spree/flow_io_product_decorator.rb +91 -0
  17. data/app/models/spree/flow_io_variant_decorator.rb +205 -0
  18. data/app/models/spree/gateway/spree_flow_gateway.rb +116 -0
  19. data/app/models/spree/line_item_decorator.rb +15 -0
  20. data/app/models/spree/order_decorator.rb +179 -0
  21. data/app/models/spree/promotion_decorator.rb +10 -0
  22. data/app/models/spree/promotion_handler/coupon_decorator.rb +30 -0
  23. data/app/models/spree/spree_user_decorator.rb +15 -0
  24. data/app/models/spree/taxon_decorator.rb +37 -0
  25. data/app/models/spree/zone_decorator.rb +7 -0
  26. data/app/models/spree/zones/flow_io_product_zone_decorator.rb +55 -0
  27. data/app/services/flowcommerce_spree/import_experience_items.rb +76 -0
  28. data/app/services/flowcommerce_spree/import_experiences.rb +37 -0
  29. data/app/services/flowcommerce_spree/order_sync.rb +231 -0
  30. data/app/views/layouts/flowcommerce_spree/application.html.erb +14 -0
  31. data/app/views/spree/admin/payments/index.html.erb +28 -0
  32. data/app/views/spree/admin/promotions/edit.html.erb +57 -0
  33. data/app/views/spree/admin/shared/_order_summary.html.erb +44 -0
  34. data/app/views/spree/admin/shared/_order_summary_flow.html.erb +13 -0
  35. data/app/views/spree/order_mailer/confirm_email.html.erb +86 -0
  36. data/app/views/spree/order_mailer/confirm_email.text.erb +38 -0
  37. data/config/initializers/flowcommerce_spree.rb +7 -0
  38. data/config/routes.rb +5 -0
  39. data/db/migrate/20201021160159_add_type_and_meta_to_spree_zone.rb +23 -0
  40. data/db/migrate/20201021755957_add_meta_to_spree_tables.rb +17 -0
  41. data/db/migrate/20201022173210_add_zone_type_to_spree_zone_members.rb +24 -0
  42. data/db/migrate/20201022174252_add_kind_to_zone.rb +22 -0
  43. data/lib/flow/error.rb +73 -0
  44. data/lib/flow/pay_pal.rb +25 -0
  45. data/lib/flow/simple_gateway.rb +115 -0
  46. data/lib/flowcommerce_spree.rb +31 -0
  47. data/lib/flowcommerce_spree/api.rb +48 -0
  48. data/lib/flowcommerce_spree/engine.rb +27 -0
  49. data/lib/flowcommerce_spree/experience_service.rb +65 -0
  50. data/lib/flowcommerce_spree/logging_http_client.rb +43 -0
  51. data/lib/flowcommerce_spree/logging_http_handler.rb +15 -0
  52. data/lib/flowcommerce_spree/refresher.rb +81 -0
  53. data/lib/flowcommerce_spree/session.rb +71 -0
  54. data/lib/flowcommerce_spree/version.rb +5 -0
  55. data/lib/flowcommerce_spree/webhook_service.rb +98 -0
  56. data/lib/simple_csv_writer.rb +44 -0
  57. data/lib/tasks/flowcommerce_spree.rake +289 -0
  58. metadata +220 -0
@@ -0,0 +1,289 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'flowcommerce'
4
+ require 'digest/sha1'
5
+ require 'colorize'
6
+
7
+ namespace :flowcommerce_spree do
8
+ logger = FlowcommerceSpree.logger
9
+ client = FlowcommerceSpree.client(logger: logger)
10
+ refresher = FlowcommerceSpree::Refresher.new(logger: logger)
11
+
12
+ desc 'Listing and possible invocation of all the Flow tasks'
13
+ task :list_tasks do |t|
14
+ task_list = `rake -T | grep flowcommerce_spree`.split($RS)
15
+ @exit = false
16
+ logger.info "Running task: #{t}"
17
+
18
+ loop do
19
+ puts 'Flowcommerce tasks:'
20
+ task_list.each_with_index do |task, index|
21
+ puts format(" %3d. #{task}", (index + 1))
22
+ end
23
+
24
+ print "\nType the task number to be invoked: "
25
+ task_number = $stdin.gets.to_i
26
+
27
+ if (1..task_list.size).cover?(task_number)
28
+ selected_task_name = task_list[task_number - 1].to_s.split(/\s+/)[1]
29
+ logger.info "\nRunning: #{selected_task_name}"
30
+ Rake::Task[selected_task_name].invoke
31
+ puts
32
+ else
33
+ puts "Unknown task number: #{task_number}".red, ''
34
+ end
35
+
36
+ break if @exit
37
+ end
38
+ end
39
+
40
+ # uploads catalog to Flow API using local Spree database
41
+ desc 'Upload catalog'
42
+ task upload_catalog: :environment do |t|
43
+ update_sum = 0
44
+ total_sum = 0
45
+ current_page = 0
46
+ variants = []
47
+
48
+ while current_page == 0 || !variants.empty?
49
+ current_page += 1
50
+ variants = Spree::Variant.order('updated_at desc').page(current_page).per(100).all
51
+
52
+ variants.each do |variant|
53
+ total_sum += 1
54
+ result = variant.sync_product_to_flow
55
+
56
+ # skip if sync not needed
57
+ next $stdout.print "\nVariant #{variant.sku} is synced, no need to update".green unless result
58
+
59
+ if result.is_a?(Hash) && result[:error]
60
+ $stdout.print "\nError uploading #{variant.sku}. Reason: #{result[:error]}".red
61
+ else
62
+ update_sum += 1
63
+ $stdout.print "\n#{variant.sku}: #{variant.product.name} (#{variant.price} #{variant.cost_currency})"
64
+ end
65
+ end
66
+ end
67
+
68
+ needed_update = (update_sum == 0 ? 'none' : update_sum).to_s.green
69
+ puts "\nFor total of #{total_sum.to_s.blue} products, #{needed_update} needed update"
70
+ t.reenable
71
+ end
72
+
73
+ desc 'Check if ENV vars, center and tier per experience is set'
74
+ task check: :environment do |t|
75
+ logger.info 'Environment check'
76
+ required_env_vars = %w[FLOW_TOKEN FLOW_ORGANIZATION FLOW_BASE_COUNTRY]
77
+ required_env_vars.each { |el| logger.info " ENV: #{el} - #{ENV[el].present? ? 'present'.green : 'MISSING'.red} " }
78
+ organization = FlowcommerceSpree::ORGANIZATION
79
+
80
+ logger.info 'Experiences:'
81
+ logger.info " Getting experiences for flow org: #{organization}"
82
+ experiences = client.experiences.get(organization)
83
+ logger.info " Got %d experiences - #{experiences.map(&:country).join(', ')}".green % experiences.length
84
+
85
+ # create default experience unless one exists
86
+ logger.info 'Centers:'
87
+ center_name = 'default'
88
+ current_centers = client.centers.get(organization).map(&:key)
89
+ if current_centers.include?(center_name)
90
+ logger.info " Default center: #{'present'.green}"
91
+ else
92
+ FlowcommerceSpree::Api.run(
93
+ :put, "/:organization/centers/#{center_name}", {},
94
+ 'key': center_name,
95
+ 'address': { 'contact': { 'name': { 'first': 'Kinto',
96
+ 'last': 'Doe' },
97
+ 'company': organization,
98
+ 'email': 'dcone@test.flow.io',
99
+ 'phone': '1-555-444-0001' },
100
+ 'location': { 'streets': ['88 East Broad Street'],
101
+ 'city': 'Columbus',
102
+ 'province': 'OH',
103
+ 'postal': '43215',
104
+ 'country': FlowcommerceSpree::BASE_COUNTRY } },
105
+ 'packaging': [{ 'dimensions': { 'packaging': { 'depth': { 'value': '9', 'units': 'inch' },
106
+ 'length': { 'value': '13', 'units': 'inch' },
107
+ 'weight': { 'value': '1', 'units': 'pound' },
108
+ 'width': { 'value': '3', 'units': 'inch' } } },
109
+ 'name': 'Big Box',
110
+ 'number': 'box1' }],
111
+ 'name': 'Spree Test',
112
+ 'services': [{ 'service': 'dhl-express-worldwide' },
113
+ { 'service': 'landmark-global' }],
114
+ 'schedule': { 'holiday': 'us_bank_holidays',
115
+ 'exception': [{ 'type': 'closed',
116
+ 'datetime_range': { 'from': '2016-05-05T18:30:00.000Z',
117
+ 'to': '2016-05-06T18:30:00.000Z' } }],
118
+ 'calendar': 'weekdays',
119
+ 'cutoff': '16:30' },
120
+ 'timezone': 'US/Eastern'
121
+ )
122
+ logger.info " Default center: #{'created'.blue} (run again)"
123
+ end
124
+
125
+ logger.info 'Tiers:'
126
+ experiences.each do |exp|
127
+ exp_tiers = client.tiers.get(FlowcommerceSpree::ORGANIZATION, experience: exp.key)
128
+ count = exp_tiers.length
129
+ count_desc = count == 0 ? '0 (error!)'.red : count.to_s.green
130
+ exp_services = exp_tiers.inject([]) { |total, tier| total.push(*tier.services.map(&:id)) }
131
+ services_str = if exp_services.empty?
132
+ 'and no delivery services defined!'.red
133
+ else
134
+ "with #{exp_services.length.to_s.green} delivery services defined (#{exp_services.join(', ')})"
135
+ end
136
+ logger.info " Experience #{exp.key.yellow} has #{count_desc} delivery tiers defined, #{services_str}"
137
+ end
138
+
139
+ logger.info 'Database fields (flow_data):'
140
+ [Spree::CreditCard, Spree::Product, Spree::Variant, Spree::Order, Spree::Promotion].each do |klass|
141
+ state = klass.new.respond_to?(:flow_data) ? 'exists'.green : 'not present (run DB migrations)'.red
142
+ logger.info " #{klass.to_s.ljust(18)} - #{state}"
143
+ end
144
+
145
+ logger.info 'Default store URL:'
146
+ url = Spree::Store.find_by(default: true).url
147
+ logger.info " Spree::Store.find_by(default:true).url == \"#{url.blue}\" (ensure this is valid and right URL)"
148
+
149
+ # rate cards check
150
+ ratecard_estimates_path = '/:organization/ratecard_estimates/summaries'
151
+ origins = []
152
+ errors = []
153
+ client.ratecards.get(FlowcommerceSpree::ORGANIZATION).each do |rc|
154
+ rc.origination_zones.each do |oz|
155
+ data = FlowcommerceSpree::Api.run(
156
+ :post, ratecard_estimates_path, {}, origin: oz.country, destination: origins.last || 'USA'
157
+ )
158
+
159
+ if data.is_a?(Hash) && data['code'] == 'generic_error'
160
+ errors << { origin: oz.country, messages: data['messages'] }
161
+ next
162
+ elsif data.is_a?(Array) && !data.empty?
163
+ origins << oz.country
164
+ else
165
+ errors << { origin: oz.country, messages: ['Unknown error'] }
166
+ end
167
+ end
168
+ end
169
+
170
+ unless origins.empty?
171
+ logger.info "\nRate cards set, OK:".green
172
+ origins.each_with_index do |origin, index|
173
+ logger.info format(" %3d. #{origin}", (index + 1))
174
+ end
175
+ end
176
+
177
+ unless errors.empty?
178
+ logger.info "\nRate cards errors:".red
179
+ errors.each_with_index do |err, index|
180
+ logger.info format(" %3d. Origin = #{err[:origin]}, errors:", (index + 1))
181
+ err[:messages].each do |m|
182
+ logger.info " #{m}".red
183
+ end
184
+ end
185
+ end
186
+ t.reenable
187
+ end
188
+
189
+ desc 'Sync experiences and localized product catalog items from Flow.io'
190
+ task sync_localized_items: :environment do |t|
191
+ next t.reenable unless refresher.needs_refresh?
192
+
193
+ logger.info 'Sync needed, running ...'.yellow
194
+
195
+ FlowcommerceSpree::ImportExperiences.run(with_items: true, client: client, refresher: refresher)
196
+
197
+ t.reenable
198
+ end
199
+
200
+ desc 'Force sync (no timeout) experiences and localized product catalog items from Flow.io'
201
+ task sync_localized_items_forced: :environment do |t|
202
+ next t.reenable if refresher.in_progress?
203
+
204
+ FlowcommerceSpree::ImportExperiences.run(with_items: true, client: client, refresher: refresher)
205
+
206
+ t.reenable
207
+ end
208
+
209
+ # checks existence of every item in local product catalog - remove product from flow unless exists locally
210
+ desc 'Remove unused items from flow catalog'
211
+ task clean_flow_catalog: :environment do |t|
212
+ page_size = 100
213
+ offset = 0
214
+ items = []
215
+ promises = []
216
+ thread_pool = Concurrent::FixedThreadPool.new(5)
217
+
218
+ while offset == 0 || items.length == 100
219
+ items = FlowcommerceSpree::Api.run :get, '/:organization/catalog/items', limit: page_size, offset: offset
220
+ offset += page_size
221
+
222
+ items.each do |item|
223
+ sku = item['number']
224
+
225
+ next if Spree::Variant.exists?(sku: sku)
226
+
227
+ promises << Concurrent::Promises.future_on(thread_pool, sku) do |number|
228
+ FlowcommerceSpree::Api.run :delete, "/:organization/catalog/items/#{number}"
229
+ $stdout.puts "Removed item: #{number.red}"
230
+ end
231
+ end
232
+ end
233
+
234
+ Concurrent::Promises.zip(*promises).value!
235
+ thread_pool.shutdown
236
+ thread_pool.wait_for_termination
237
+ t.reenable
238
+ end
239
+
240
+ # remove all the products from flow.io
241
+ desc 'Purge Product Catalog on flow.io'
242
+ task purge_catalog: :environment do |t|
243
+ page_size = 100
244
+ offset = 0
245
+ items = []
246
+ promises = []
247
+ thread_pool = Concurrent::FixedThreadPool.new(5)
248
+
249
+ while offset == 0 || items.length == 100
250
+ items = FlowcommerceSpree::Api.run :get, '/:organization/catalog/items', limit: page_size, offset: offset
251
+ offset += page_size
252
+
253
+ items.each do |item|
254
+ variant_sku = item['number']
255
+ promises << Concurrent::Promises.future_on(thread_pool, variant_sku) do |sku|
256
+ FlowcommerceSpree::Api.run :delete, "/:organization/catalog/items/#{sku}"
257
+ $stdout.puts "Removed item: #{sku.red}"
258
+ end
259
+ v = Spree::Variant.find_by(sku: variant_sku)
260
+ v.flow_data.delete('last_sync_sh1')
261
+ v.update_column(:meta, v.meta.to_json)
262
+ end
263
+ end
264
+
265
+ Concurrent::Promises.zip(*promises).value!
266
+ thread_pool.shutdown
267
+ thread_pool.wait_for_termination
268
+ t.reenable
269
+ end
270
+
271
+ desc 'Purge flow_data from all the Variants in the DB'
272
+ task purge_flow_data: :environment do |t|
273
+ record_counter = 0
274
+ Spree::Variant.where("meta->>'flow_data' IS NOT NULL").each do |v|
275
+ v.truncate_flow_data
276
+ record_counter += 1
277
+ print '.'
278
+ $stdout.flush
279
+ end
280
+ logger.info "\nTruncated flow_data on #{record_counter} records"
281
+
282
+ t.reenable
283
+ end
284
+
285
+ desc 'Exit list_tasks'
286
+ task exit: :environment do
287
+ @exit = true
288
+ end
289
+ end
metadata ADDED
@@ -0,0 +1,220 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flowcommerce_spree
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Aurel Branzeanu
8
+ - Sebastian De Luca
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2021-02-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: colorize
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: concurrent-ruby
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.0'
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: 1.1.7
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - "~>"
43
+ - !ruby/object:Gem::Version
44
+ version: '1.0'
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 1.1.7
48
+ - !ruby/object:Gem::Dependency
49
+ name: flowcommerce
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: flowcommerce-reference
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ type: :runtime
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ - !ruby/object:Gem::Dependency
77
+ name: oj
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ - !ruby/object:Gem::Dependency
91
+ name: pg
92
+ requirement: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.21'
97
+ type: :runtime
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.21'
104
+ - !ruby/object:Gem::Dependency
105
+ name: spree_backend
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 2.3.0
111
+ type: :runtime
112
+ prerelease: false
113
+ version_requirements: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 2.3.0
118
+ - !ruby/object:Gem::Dependency
119
+ name: github_changelog_generator
120
+ requirement: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ type: :development
126
+ prerelease: false
127
+ version_requirements: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ description: Integration of popular Rails/Spree store framework with e-commerce Flow
133
+ API
134
+ email:
135
+ - a.branzeanu@datarockets.com
136
+ - sebastian.deluca@mejuri.com
137
+ executables: []
138
+ extensions: []
139
+ extra_rdoc_files: []
140
+ files:
141
+ - MIT-LICENSE
142
+ - README.md
143
+ - Rakefile
144
+ - SPREE_FLOW.md
145
+ - app/assets/javascripts/flowcommerce_spree/application.js
146
+ - app/assets/stylesheets/flowcommerce_spree/application.css
147
+ - app/controllers/concerns/current_zone_loader_decorator.rb
148
+ - app/controllers/flowcommerce_spree/webhooks_controller.rb
149
+ - app/helpers/flowcommerce_spree/application_helper.rb
150
+ - app/helpers/spree/admin/orders_helper_decorator.rb
151
+ - app/helpers/spree/core/controller_helpers/flow_io_order_helper_decorator.rb
152
+ - app/mailers/spree/spree_order_mailer_decorator.rb
153
+ - app/models/flowcommerce_spree/settings.rb
154
+ - app/models/spree/credit_card_decorator.rb
155
+ - app/models/spree/flow_io_product_decorator.rb
156
+ - app/models/spree/flow_io_variant_decorator.rb
157
+ - app/models/spree/gateway/spree_flow_gateway.rb
158
+ - app/models/spree/line_item_decorator.rb
159
+ - app/models/spree/order_decorator.rb
160
+ - app/models/spree/promotion_decorator.rb
161
+ - app/models/spree/promotion_handler/coupon_decorator.rb
162
+ - app/models/spree/spree_user_decorator.rb
163
+ - app/models/spree/taxon_decorator.rb
164
+ - app/models/spree/zone_decorator.rb
165
+ - app/models/spree/zones/flow_io_product_zone_decorator.rb
166
+ - app/services/flowcommerce_spree/import_experience_items.rb
167
+ - app/services/flowcommerce_spree/import_experiences.rb
168
+ - app/services/flowcommerce_spree/order_sync.rb
169
+ - app/views/layouts/flowcommerce_spree/application.html.erb
170
+ - app/views/spree/admin/payments/index.html.erb
171
+ - app/views/spree/admin/promotions/edit.html.erb
172
+ - app/views/spree/admin/shared/_order_summary.html.erb
173
+ - app/views/spree/admin/shared/_order_summary_flow.html.erb
174
+ - app/views/spree/order_mailer/confirm_email.html.erb
175
+ - app/views/spree/order_mailer/confirm_email.text.erb
176
+ - config/initializers/flowcommerce_spree.rb
177
+ - config/routes.rb
178
+ - db/migrate/20201021160159_add_type_and_meta_to_spree_zone.rb
179
+ - db/migrate/20201021755957_add_meta_to_spree_tables.rb
180
+ - db/migrate/20201022173210_add_zone_type_to_spree_zone_members.rb
181
+ - db/migrate/20201022174252_add_kind_to_zone.rb
182
+ - lib/flow/error.rb
183
+ - lib/flow/pay_pal.rb
184
+ - lib/flow/simple_gateway.rb
185
+ - lib/flowcommerce_spree.rb
186
+ - lib/flowcommerce_spree/api.rb
187
+ - lib/flowcommerce_spree/engine.rb
188
+ - lib/flowcommerce_spree/experience_service.rb
189
+ - lib/flowcommerce_spree/logging_http_client.rb
190
+ - lib/flowcommerce_spree/logging_http_handler.rb
191
+ - lib/flowcommerce_spree/refresher.rb
192
+ - lib/flowcommerce_spree/session.rb
193
+ - lib/flowcommerce_spree/version.rb
194
+ - lib/flowcommerce_spree/webhook_service.rb
195
+ - lib/simple_csv_writer.rb
196
+ - lib/tasks/flowcommerce_spree.rake
197
+ homepage: https://github.com/mejuri-inc/flowcommerce_spree
198
+ licenses:
199
+ - MIT
200
+ metadata: {}
201
+ post_install_message:
202
+ rdoc_options: []
203
+ require_paths:
204
+ - lib
205
+ required_ruby_version: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - "~>"
208
+ - !ruby/object:Gem::Version
209
+ version: 2.3.0
210
+ required_rubygems_version: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
215
+ requirements: []
216
+ rubygems_version: 3.0.8
217
+ signing_key:
218
+ specification_version: 4
219
+ summary: Integration of Spree with Flow API
220
+ test_files: []