spree_channable 0.0.18.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.rspec +3 -0
- data/.rubocop.yml +24 -0
- data/.travis.yml +35 -0
- data/Appraisals +27 -0
- data/Gemfile +17 -0
- data/LICENSE +29 -0
- data/README.md +56 -0
- data/Rakefile +21 -0
- data/app/assets/javascripts/spree/backend/spree_channable.js +2 -0
- data/app/assets/javascripts/spree/frontend/spree_channable.js +2 -0
- data/app/assets/stylesheets/spree/backend/spree_channable.css +4 -0
- data/app/assets/stylesheets/spree/frontend/spree_channable.css +4 -0
- data/app/controllers/spree/admin/channable_settings_controller.rb +14 -0
- data/app/controllers/spree/api/v1/channable_controller.rb +21 -0
- data/app/jobs/application_job.rb +7 -0
- data/app/jobs/spree_channable/order_import_job.rb +37 -0
- data/app/jobs/spree_channable/return_import_job.rb +36 -0
- data/app/models/channable_setting.rb +10 -0
- data/app/models/spree/order_decorator.rb +127 -0
- data/app/models/spree/product_decorator.rb +118 -0
- data/app/models/spree/reimbursement_decorator.rb +39 -0
- data/app/models/spree/shipment_decorator.rb +28 -0
- data/app/models/spree/shipment_handler_decorator.rb +11 -0
- data/app/models/spree/variant_decorator.rb +78 -0
- data/app/overrides/add_settings_to_admin_configurator.rb +32 -0
- data/app/overrides/order_index.rb +13 -0
- data/app/views/spree/admin/channable_settings/_form.html.erb +105 -0
- data/app/views/spree/admin/channable_settings/edit.html.erb +1 -0
- data/app/views/spree/admin/channable_settings/new.html.erb +1 -0
- data/app/views/spree/admin/orders/_index_channable_state_override.html.erb +7 -0
- data/app/views/spree/admin/orders/_index_channable_state_override_head.html.erb +1 -0
- data/bin/rails +8 -0
- data/config/locales/en.yml +5 -0
- data/config/routes.rb +18 -0
- data/db/migrate/20190710092345_create_channable_settings.rb +16 -0
- data/db/migrate/20190710103701_add_settings_to_settings_table.rb +9 -0
- data/db/migrate/20190710115409_add_order_columns.rb +9 -0
- data/db/migrate/20190711122425_set_order_connection_defaults.rb +5 -0
- data/db/migrate/20190711123402_add_channable_fields_to_shipping_methods.rb +8 -0
- data/db/migrate/20190711140015_add_payment_method_for_channable.rb +7 -0
- data/db/migrate/20190711145940_add_order_import_settings.rb +9 -0
- data/db/migrate/20190717120144_add_channable_id_to_return_authorisations.rb +5 -0
- data/gemfiles/spree_3_2.gemfile +10 -0
- data/gemfiles/spree_3_5.gemfile +10 -0
- data/gemfiles/spree_3_7.gemfile +10 -0
- data/gemfiles/spree_master.gemfile +10 -0
- data/lib/channable/client.rb +42 -0
- data/lib/channable/response.rb +15 -0
- data/lib/generators/spree_channable/install/install_generator.rb +20 -0
- data/lib/spree_channable/engine.rb +20 -0
- data/lib/spree_channable/factories.rb +6 -0
- data/lib/spree_channable/order_importer.rb +280 -0
- data/lib/spree_channable/return_importer.rb +63 -0
- data/lib/spree_channable/version.rb +18 -0
- data/lib/spree_channable.rb +36 -0
- data/spec/fixtures/invalid_channable_order.json +117 -0
- data/spec/fixtures/valid_channable_order.json +117 -0
- data/spree_channable.gemspec +50 -0
- metadata +451 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: cc45055d9e1bef626d21f196471a45402d5c220cc05d0db9f7488630addc54a6
|
4
|
+
data.tar.gz: 0ef0d52b27cce58f5fe3edbc8fac265163b517ae4354c671513689d0dbe8ee3b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c83193ff3364edc06054c6ecea2fe661c6d30de3af8f01aa4f95998b72d99dbcab4a633bce31c6736104519992a8443bd67696f7f38fce81f3e044b7913f717f
|
7
|
+
data.tar.gz: 43dac314d47fb2fdd16374b6a6ace86df645655accb6e63d9e20c1241b36b9fca52fac39fda740276a7ad3abd81d3437ed69ecd6b77f040e70069d8ebc09c2a6
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
\#*
|
2
|
+
*~
|
3
|
+
.#*
|
4
|
+
.DS_Store
|
5
|
+
.idea
|
6
|
+
.localeapp/locales
|
7
|
+
.project
|
8
|
+
.vscode
|
9
|
+
coverage
|
10
|
+
default
|
11
|
+
Gemfile.lock
|
12
|
+
tmp
|
13
|
+
nbproject
|
14
|
+
pkg
|
15
|
+
*.sw?
|
16
|
+
spec/dummy
|
17
|
+
.rvmrc
|
18
|
+
.sass-cache
|
19
|
+
public/spree
|
20
|
+
.ruby-version
|
21
|
+
.ruby-gemset
|
22
|
+
gemfiles/*.gemfile.lock
|
23
|
+
*.gem
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
AllCops:
|
2
|
+
DisplayCopNames: true
|
3
|
+
TargetRubyVersion: 2.3
|
4
|
+
Include:
|
5
|
+
- '**/Gemfile'
|
6
|
+
- '**/Rakefile'
|
7
|
+
- '**/Appraisals'
|
8
|
+
Exclude:
|
9
|
+
- 'spec/dummy/**/*'
|
10
|
+
- 'lib/generators/**/*'
|
11
|
+
|
12
|
+
Rails:
|
13
|
+
Enabled: true
|
14
|
+
|
15
|
+
Metrics/LineLength:
|
16
|
+
Max: 150
|
17
|
+
|
18
|
+
# DISABLED
|
19
|
+
|
20
|
+
Style/Documentation:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Style/FrozenStringLiteralComment:
|
24
|
+
Enabled: false
|
data/.travis.yml
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
sudo: required
|
2
|
+
dist: trusty
|
3
|
+
|
4
|
+
language: ruby
|
5
|
+
|
6
|
+
env:
|
7
|
+
- DB=postgres
|
8
|
+
- DB=mysql
|
9
|
+
|
10
|
+
gemfile:
|
11
|
+
- gemfiles/spree_3_2.gemfile
|
12
|
+
- gemfiles/spree_3_5.gemfile
|
13
|
+
- gemfiles/spree_3_7.gemfile
|
14
|
+
- gemfiles/spree_master.gemfile
|
15
|
+
|
16
|
+
script:
|
17
|
+
- bundle exec rake test_app
|
18
|
+
- bundle exec rake spec
|
19
|
+
|
20
|
+
rvm:
|
21
|
+
- 2.5.1
|
22
|
+
- 2.4.2
|
23
|
+
|
24
|
+
matrix:
|
25
|
+
allow_failures:
|
26
|
+
- gemfile: gemfiles/spree_master.gemfile
|
27
|
+
|
28
|
+
before_install:
|
29
|
+
- mysql -u root -e "GRANT ALL ON *.* TO 'travis'@'%';"
|
30
|
+
- wget -N https://chromedriver.storage.googleapis.com/2.35/chromedriver_linux64.zip -P ~/
|
31
|
+
- unzip ~/chromedriver_linux64.zip -d ~/
|
32
|
+
- rm ~/chromedriver_linux64.zip
|
33
|
+
- sudo mv -f ~/chromedriver /usr/local/share/
|
34
|
+
- sudo chmod +x /usr/local/share/chromedriver
|
35
|
+
- sudo ln -s /usr/local/share/chromedriver /usr/local/bin/chromedriver
|
data/Appraisals
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
appraise 'spree-3-2' do
|
2
|
+
gem 'spree_core', '~> 3.2.0'
|
3
|
+
gem 'spree_backend', '~> 3.2.0'
|
4
|
+
gem 'spree_auth_devise', '~> 3.4.0'
|
5
|
+
gem 'rails-controller-testing'
|
6
|
+
end
|
7
|
+
|
8
|
+
appraise 'spree-3-5' do
|
9
|
+
gem 'spree_core', '~> 3.5.0'
|
10
|
+
gem 'spree_backend', '~> 3.5.0'
|
11
|
+
gem 'spree_auth_devise', '~> 3.4.0'
|
12
|
+
gem 'rails-controller-testing'
|
13
|
+
end
|
14
|
+
|
15
|
+
appraise 'spree-3-7' do
|
16
|
+
gem 'spree_core', '~> 3.7.0'
|
17
|
+
gem 'spree_backend', '~> 3.7.0'
|
18
|
+
gem 'spree_auth_devise', '~> 3.5.0'
|
19
|
+
gem 'rails-controller-testing'
|
20
|
+
end
|
21
|
+
|
22
|
+
appraise 'spree-master' do
|
23
|
+
gem 'spree_core', github: 'spree/spree', branch: 'master'
|
24
|
+
gem 'spree_backend', github: 'spree/spree', branch: 'master'
|
25
|
+
gem 'spree_auth_devise', github: 'spree/spree_auth_devise', branch: 'master'
|
26
|
+
gem 'rails-controller-testing'
|
27
|
+
end
|
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
git_source(:github) do |repo_name|
|
4
|
+
repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?('/')
|
5
|
+
"https://github.com/#{repo_name}.git"
|
6
|
+
end
|
7
|
+
|
8
|
+
gem 'spree_core', github: 'spree/spree', branch: 'master'
|
9
|
+
gem 'spree_backend', github: 'spree/spree', branch: 'master'
|
10
|
+
# Provides basic authentication functionality for testing parts of your engine
|
11
|
+
gem 'spree_auth_devise', github: 'spree/spree_auth_devise', branch: 'master'
|
12
|
+
gem 'rails-controller-testing'
|
13
|
+
|
14
|
+
gem 'rubocop', require: false
|
15
|
+
gem 'rubocop-rspec', require: false
|
16
|
+
|
17
|
+
gemspec
|
data/LICENSE
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
BSD 3-Clause License
|
2
|
+
|
3
|
+
Copyright (c) 2019, Fabian Oudhaarlem
|
4
|
+
All rights reserved.
|
5
|
+
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
8
|
+
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
10
|
+
list of conditions and the following disclaimer.
|
11
|
+
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
14
|
+
and/or other materials provided with the distribution.
|
15
|
+
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
17
|
+
contributors may be used to endorse or promote products derived from
|
18
|
+
this software without specific prior written permission.
|
19
|
+
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# SpreeChannable
|
2
|
+
|
3
|
+
Channable offers many ways to transform a product feed to many marketplace formats. On top channable offers an order connection to accept incoming orders from connected marketplaces. This gem connects your spree store to the channable platform. The feeds are configurable and can be directly loaded into channable.
|
4
|
+
The order connection can be enabled by channable on request and can be easily configured through the spree admin panel.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
1. Add this extension to your Gemfile with this line:
|
9
|
+
```ruby
|
10
|
+
gem 'spree_channable', github: 'Oldharlem/spree_channable'
|
11
|
+
```
|
12
|
+
|
13
|
+
2. Install the gem using Bundler:
|
14
|
+
```ruby
|
15
|
+
bundle install
|
16
|
+
```
|
17
|
+
|
18
|
+
3. Copy & run migrations
|
19
|
+
```ruby
|
20
|
+
bundle exec rails g spree_channable:install
|
21
|
+
```
|
22
|
+
|
23
|
+
4. Schedule order imports
|
24
|
+
|
25
|
+
Schedule the `SpreeChannable::OrderImportJob.perform_later` to run every `SpreeChannable.configuration.polling_interval` minutes. This script will pull all orders placed `SpreeChannable.configuration.polling_interval` minutes ago. Please configure the integration through the channable settings under spree configurations before running the script.
|
26
|
+
|
27
|
+
5. Restart your server
|
28
|
+
|
29
|
+
If your server was running, restart it so that it can find the assets properly.
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
## Testing
|
34
|
+
|
35
|
+
First bundle your dependencies, then run `rake`. `rake` will default to building the dummy app if it does not exist, then it will run specs. The dummy app can be regenerated by using `rake test_app`.
|
36
|
+
|
37
|
+
```shell
|
38
|
+
bundle
|
39
|
+
bundle exec rake
|
40
|
+
```
|
41
|
+
|
42
|
+
When testing your applications integration with this extension you may use it's factories.
|
43
|
+
Simply add this require statement to your spec_helper:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
require 'spree_channable/factories'
|
47
|
+
```
|
48
|
+
|
49
|
+
|
50
|
+
## Contributing
|
51
|
+
|
52
|
+
If you'd like to contribute, please take a look at the
|
53
|
+
[instructions](CONTRIBUTING.md) for installing dependencies and crafting a good
|
54
|
+
pull request.
|
55
|
+
|
56
|
+
Copyright (c) 2019 Fabian Oudhaarlem, released under the New BSD License
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'spree/testing_support/extension_rake'
|
6
|
+
|
7
|
+
RSpec::Core::RakeTask.new
|
8
|
+
|
9
|
+
task :default do
|
10
|
+
if Dir['spec/dummy'].empty?
|
11
|
+
Rake::Task[:test_app].invoke
|
12
|
+
Dir.chdir('../../')
|
13
|
+
end
|
14
|
+
Rake::Task[:spec].invoke
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Generates a dummy app for testing'
|
18
|
+
task :test_app do
|
19
|
+
ENV['LIB_NAME'] = 'spree_channable'
|
20
|
+
Rake::Task['extension:test_app'].invoke
|
21
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Spree
|
2
|
+
module Admin
|
3
|
+
class ChannableSettingsController < ResourceController
|
4
|
+
def index
|
5
|
+
path = model_class.last ? edit_admin_channable_setting_path(model_class.last.id) : new_admin_channable_setting_path
|
6
|
+
redirect_to path
|
7
|
+
end
|
8
|
+
|
9
|
+
def model_class
|
10
|
+
@model_class ||= ::ChannableSetting
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Spree::Api::V1::ChannableController < Spree::Api::BaseController
|
2
|
+
|
3
|
+
before_action :get_products, only: [:variant_feed, :product_feed]
|
4
|
+
|
5
|
+
def variant_feed
|
6
|
+
headers["Content-Type"] = 'application/atom+xml; charset=utf-8'
|
7
|
+
render plain: Spree::Product.to_channable_variant_xml(@products)
|
8
|
+
end
|
9
|
+
|
10
|
+
def product_feed
|
11
|
+
headers["Content-Type"] = 'application/atom+xml; charset=utf-8'
|
12
|
+
render plain: Spree::Product.to_channable_product_xml(@products)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def get_products
|
18
|
+
@products = Spree::Product.active.includes([:option_types, :taxons, product_properties: :property, variants: [{option_values: :option_type}, :default_price, :images], master: [{option_values: :option_type}, :default_price, :images]])
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
class ApplicationJob < ActiveJob::Base
|
2
|
+
# Automatically retry jobs that encountered a deadlock
|
3
|
+
# retry_on ActiveRecord::Deadlocked
|
4
|
+
|
5
|
+
# Most jobs are safe to ignore if the underlying records are no longer available
|
6
|
+
# discard_on ActiveJob::DeserializationError
|
7
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module SpreeChannable
|
2
|
+
class OrderImportJob < ApplicationJob
|
3
|
+
queue_as :default
|
4
|
+
|
5
|
+
def perform(*args)
|
6
|
+
return unless ::SpreeChannable.configuration.active?
|
7
|
+
|
8
|
+
@client = ::Channable::Client.new
|
9
|
+
channable_orders = get_orders
|
10
|
+
channable_orders.each &method(:persist_order)
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_orders
|
14
|
+
limit = 100
|
15
|
+
orders = []
|
16
|
+
loop do
|
17
|
+
order_data = client.get_orders(offset: orders.size, limit: limit, start_date: (SpreeChannable.configuration.polling_interval * 2).minutes.ago)
|
18
|
+
order_data.data.orders.each {|order| orders << order} if order_data.data.orders.any?
|
19
|
+
|
20
|
+
break if order_data.data.total < limit || (!order_data.success && order_data.response.code != 429)
|
21
|
+
end
|
22
|
+
orders
|
23
|
+
end
|
24
|
+
|
25
|
+
def persist_order(channable_order)
|
26
|
+
return if Spree::Order.exists?(channable_order_id: channable_order.id)
|
27
|
+
begin
|
28
|
+
order_attributes = Spree::Order.channable_to_order_params(channable_order)
|
29
|
+
SpreeChannable::OrderImporter.import(nil, order_attributes)
|
30
|
+
rescue StandardError => e
|
31
|
+
Rails.logger.warn "[CHANNABLE] Failed to import order #{channable_order.id}. #{e}"
|
32
|
+
@client.cancellation_update(channable_order.id)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module SpreeChannable
|
2
|
+
class ReturnImportJob < ApplicationJob
|
3
|
+
queue_as :default
|
4
|
+
|
5
|
+
def perform(*args)
|
6
|
+
return unless ::SpreeChannable.configuration.active?
|
7
|
+
|
8
|
+
@client = ::Channable::Client.new
|
9
|
+
channable_returns = get_returns
|
10
|
+
channable_returns.each &method(:persist_return)
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_returns
|
14
|
+
limit = 100
|
15
|
+
returns = []
|
16
|
+
loop do
|
17
|
+
return_data = @client.get_returns(offset: returns.size, limit: limit, start_date: (SpreeChannable.configuration.polling_interval * 2).minutes.ago)
|
18
|
+
return_data.data.returns.each {|return_data| returns << return_data} if return_data.data.returns.any?
|
19
|
+
|
20
|
+
break if return_data.data.total < limit || (!return_data.success && return_data.response.code != 429)
|
21
|
+
end
|
22
|
+
returns
|
23
|
+
end
|
24
|
+
|
25
|
+
def persist_return(channable_return)
|
26
|
+
return if Spree::ReturnAuthorization.exists?(channable_return_id: channable_return.channable_id)
|
27
|
+
begin
|
28
|
+
SpreeChannable::ReturnImporter.import(channable_return)
|
29
|
+
rescue StandardError => e
|
30
|
+
Rails.logger.warn "[CHANNABLE] Failed to import return #{channable_return.channable_id}. #{e}"
|
31
|
+
@client.return_update(channable_return.channable_id, {status: 'cancelled'}.to_json)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class ChannableSetting < ActiveRecord::Base
|
2
|
+
|
3
|
+
belongs_to :stock_location, foreign_key: 'spree_stock_location_id', class_name: 'Spree::StockLocation'
|
4
|
+
belongs_to :payment_method, foreign_key: 'spree_payment_method_id', class_name: 'Spree::PaymentMethod'
|
5
|
+
|
6
|
+
PRODUCT_CONDITIONS = ['New', 'Used']
|
7
|
+
|
8
|
+
validates_inclusion_of :product_condition, in: PRODUCT_CONDITIONS
|
9
|
+
|
10
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module Spree
|
2
|
+
module SpreeChannable
|
3
|
+
module OrderDecorator
|
4
|
+
|
5
|
+
def channable_client
|
6
|
+
@channable_client ||= ::Channable::Client.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def deliver_order_confirmation_email
|
10
|
+
unless is_channable_order?
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def send_cancel_email
|
16
|
+
unless is_channable_order?
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def is_channable_order?
|
22
|
+
channable_order_id.present?
|
23
|
+
end
|
24
|
+
|
25
|
+
def cancel_channable_order
|
26
|
+
return unless is_channable_order?
|
27
|
+
|
28
|
+
channable_client.cancellation_update(channable_order_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.prepended(base)
|
32
|
+
base.state_machine.after_transition to: :cancelled, do: :cancel_channable_order
|
33
|
+
|
34
|
+
class << base
|
35
|
+
|
36
|
+
def channable_to_order_params(channable_order)
|
37
|
+
order_params = {}
|
38
|
+
|
39
|
+
order_params[:channable_order_id] = channable_order.id
|
40
|
+
order_params[:channable_channel_order_id] = channable_order.channel_id
|
41
|
+
order_params[:channable_channel_name] = channable_order.channel_name
|
42
|
+
order_params[:completed_at] = DateTime.parse(channable_order.created)
|
43
|
+
order_params[:email] = channable_order.data.shipping.email
|
44
|
+
|
45
|
+
order_params[:bill_address_attributes] = build_address(channable_order.data.billing)
|
46
|
+
order_params[:ship_address_attributes] = build_address(channable_order.data.shipping)
|
47
|
+
|
48
|
+
order_params[:shipments_attributes] = build_shipments_attributes(channable_order)
|
49
|
+
order_params[:payments_attributes] = build_payments_attributes(channable_order)
|
50
|
+
order_params[:line_items_attributes] = build_line_items_attributes(channable_order)
|
51
|
+
|
52
|
+
order_params
|
53
|
+
end
|
54
|
+
|
55
|
+
def build_address(address_params)
|
56
|
+
{
|
57
|
+
firstname: address_params.first_name,
|
58
|
+
lastname: address_params.last_name,
|
59
|
+
address1: address_params.street,
|
60
|
+
address2: [address_params.house_number, address_params.house_number_ext].join(' '),
|
61
|
+
city: address_params.city,
|
62
|
+
zipcode: address_params.zip_code,
|
63
|
+
phone: '0612345678',
|
64
|
+
country: {
|
65
|
+
'iso' => address_params.country_code
|
66
|
+
}
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def build_shipments_attributes(channable_order)
|
71
|
+
[
|
72
|
+
{
|
73
|
+
tracking: nil,
|
74
|
+
stock_location: ::SpreeChannable.configuration.stock_location,
|
75
|
+
shipping_method: channable_order.channel_name,
|
76
|
+
inventory_units: channable_order.data.products.flat_map do |item|
|
77
|
+
variant = Spree::Variant.active.find_by_sku!(item.ean)
|
78
|
+
item.quantity.times.map do
|
79
|
+
{
|
80
|
+
variant_id: variant.id
|
81
|
+
}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
}
|
85
|
+
]
|
86
|
+
end
|
87
|
+
|
88
|
+
def build_payments_attributes(channable_order)
|
89
|
+
[
|
90
|
+
{
|
91
|
+
amount: channable_order.data.price.total.to_f,
|
92
|
+
state: 'completed',
|
93
|
+
payment_method: ::SpreeChannable.configuration.payment_method
|
94
|
+
}
|
95
|
+
]
|
96
|
+
end
|
97
|
+
|
98
|
+
def build_line_items_attributes(channable_order)
|
99
|
+
channable_order.data.products.map do |item|
|
100
|
+
variant = Spree::Variant.active.find_by_sku!(item.ean)
|
101
|
+
{
|
102
|
+
variant_id: variant.id,
|
103
|
+
quantity: item.quantity,
|
104
|
+
price: item.price.to_f
|
105
|
+
}
|
106
|
+
end.compact
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
def build_adjustments_attributes(channable_order)
|
111
|
+
raise 'Not implemented'
|
112
|
+
[
|
113
|
+
{
|
114
|
+
label: 'Channable Discount',
|
115
|
+
amount: -(channable_order['discount'].abs.to_f)
|
116
|
+
}
|
117
|
+
]
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
Spree::Order.prepend(Spree::SpreeChannable::OrderDecorator)
|
127
|
+
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'parallel'
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module SpreeChannable
|
5
|
+
module ProductDecorator
|
6
|
+
def self.prepended(base)
|
7
|
+
class << base
|
8
|
+
|
9
|
+
def to_channable_variant_xml(products)
|
10
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
11
|
+
xml.feed(xmlns: 'http://www.w3.org/2005/Atom') do
|
12
|
+
xml.title 'Channable variant feed'
|
13
|
+
xml.link(rel: 'self', href: ::SpreeChannable.configuration.host)
|
14
|
+
xml.updated DateTime.now.strftime('%Y-%m-%dT%H:%M:%S%z')
|
15
|
+
|
16
|
+
Parallel.map(products) {|product| product.to_channable_variant_xml}.each do |products_xml|
|
17
|
+
products_xml.each do |variant_xml|
|
18
|
+
xml.parent << Nokogiri::XML(variant_xml).at('product')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
builder.to_xml
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_channable_product_xml(products)
|
29
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
30
|
+
xml.feed(xmlns: 'http://www.w3.org/2005/Atom') do
|
31
|
+
xml.title 'Channable product feed'
|
32
|
+
xml.link(rel: 'self', href: ::SpreeChannable.configuration.host)
|
33
|
+
xml.updated DateTime.now.strftime('%Y-%m-%dT%H:%M:%S%z')
|
34
|
+
|
35
|
+
xml.products do
|
36
|
+
Parallel.map(products) {|product| product.to_channable_product_xml}.each do |product_xml|
|
37
|
+
xml.parent << Nokogiri::XML(product_xml).at('product')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
builder.to_xml
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def to_channable_variant_xml
|
51
|
+
variants.active.map do |variant|
|
52
|
+
variant.to_channable_feed_entry
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_channable_product_xml
|
57
|
+
Nokogiri::XML::Builder.new do |xml|
|
58
|
+
xml.product do
|
59
|
+
xml.id id
|
60
|
+
xml.title "#{name}"
|
61
|
+
xml.description ActionController::Base.helpers.strip_tags(normalized_description)
|
62
|
+
xml.link URI.join(::SpreeChannable.configuration.host, "/#{::SpreeChannable.configuration.url_prefix}/" + slug).to_s
|
63
|
+
(xml.image_link URI.join(::SpreeChannable.configuration.image_host, images.first.attachment.url(:large)).to_s) if images.any?
|
64
|
+
xml.condition property('product_condition') || ::SpreeChannable.configuration.product_condition
|
65
|
+
|
66
|
+
xml.price price
|
67
|
+
|
68
|
+
xml.brand property('brand') || ::SpreeChannable.configuration.brand
|
69
|
+
|
70
|
+
xml.categories do
|
71
|
+
taxons.each do |taxon|
|
72
|
+
xml.category taxon.self_and_ancestors.collect(&:name).join('|')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
xml.currency Spree::Config.currency
|
77
|
+
xml.locale I18n.default_locale
|
78
|
+
|
79
|
+
# Property fields
|
80
|
+
|
81
|
+
xml.gender property('gender') || 'Not set'
|
82
|
+
xml.delivery_period property('delivery_period') || ::SpreeChannable.configuration.delivery_period
|
83
|
+
xml.material property('material') || 'Not set'
|
84
|
+
|
85
|
+
xml.variants do
|
86
|
+
variants.each do |variant|
|
87
|
+
xml.variant do
|
88
|
+
xml.id variant.id
|
89
|
+
xml.product_id id
|
90
|
+
xml.options_text variant.options_text
|
91
|
+
(xml.image_link URI.join(::SpreeChannable.configuration.image_host, variant.get_images.first.attachment.url(:large)).to_s) unless variant.get_images.empty?
|
92
|
+
|
93
|
+
xml.availability variant.can_supply?
|
94
|
+
xml.stock variant.total_on_hand
|
95
|
+
xml.price variant.price
|
96
|
+
xml.sale_price variant.respond_to?(:sale_price) ? (variant.sale_price || variant.price) : variant.price
|
97
|
+
|
98
|
+
xml.sku variant.sku
|
99
|
+
|
100
|
+
xml.currency Spree::Config.currency
|
101
|
+
xml.locale I18n.default_locale
|
102
|
+
|
103
|
+
variant.option_values.each do |option_value|
|
104
|
+
xml.send(option_value.option_type.name, option_value.presentation)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end.to_xml
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
Spree::Product.prepend(Spree::SpreeChannable::ProductDecorator)
|