solidus-returnly 0.0.1 → 0.2.0
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 +4 -4
- data/LICENSE +23 -18
- data/README.md +13 -7
- data/Rakefile +1 -1
- data/app/controllers/spree/api/returnly/api_controller.rb +14 -0
- data/app/controllers/spree/api/returnly/refunds_controller.rb +42 -0
- data/app/controllers/spree/api/returnly/version_controller.rb +13 -0
- data/config/routes.rb +3 -2
- data/lib/generators/solidus_returnly/install/install_generator.rb +11 -0
- data/lib/solidus-returnly.rb +5 -0
- data/lib/solidus/returnly/calculator.rb +102 -0
- data/lib/solidus/returnly/engine.rb +56 -0
- data/lib/{solidus_returnly → solidus/returnly}/factories.rb +1 -1
- data/lib/solidus/returnly/refunds.rb +84 -0
- data/lib/solidus/returnly/version.rb +5 -0
- metadata +11 -9
- data/app/controllers/spree/api/refunds_controller.rb +0 -40
- data/lib/solidus/returnly.rb +0 -5
- data/lib/solidus_returnly/calculator.rb +0 -98
- data/lib/solidus_returnly/engine.rb +0 -53
- data/lib/solidus_returnly/refunds.rb +0 -81
- data/lib/solidus_returnly/version.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2655c6ac9fa6c07fec8b5ab27a213bdb73a326ee
|
4
|
+
data.tar.gz: d8503946bcf7f9c1d03e6bf06354ee8c1dbbf165
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 759e8a79160f9d73fa6a1f5ccc9e8e83b6a58bc588b36e74c42faf9acc7fd5d9d8da3c027a1bdf92662833905357d8430448e80aa59d83297be0ee32481a034a
|
7
|
+
data.tar.gz: d2424d70d40a0e06d8791b380d9a79f62aed777d4d2bc87163de7359cef2ab6c3babb548b4a6e5384a941c5199aa5f5f1b80a5a8bd1bb41b4af6d6ea6826b5f3
|
data/LICENSE
CHANGED
@@ -1,21 +1,26 @@
|
|
1
|
-
|
1
|
+
Copyright (c) 2017 [name of plugin creator]
|
2
|
+
All rights reserved.
|
2
3
|
|
3
|
-
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
in
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
* Neither the name Spree nor the names of its contributors may be used to
|
13
|
+
endorse or promote products derived from this software without specific
|
14
|
+
prior written permission.
|
11
15
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
THE
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
17
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
18
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
19
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
20
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
21
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
22
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
23
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
24
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
25
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
26
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
Solidus Returnly
|
2
2
|
===============
|
3
3
|
|
4
|
-
This gem adds the required
|
4
|
+
This gem adds the required APIs to allow returnly obtain an estimate, process a return and apply a reimbursement
|
5
|
+
|
6
|
+
|
7
|
+
KNOW ISSUES
|
8
|
+
-----------
|
9
|
+
* Currently the restock feature only supports the order shipping warehouse
|
10
|
+
* The API user should have the right to create an order there is no an special permission yet for this api
|
5
11
|
|
6
12
|
Installation
|
7
13
|
------------
|
@@ -9,7 +15,7 @@ Installation
|
|
9
15
|
Add solidus_returnly to your Gemfile:
|
10
16
|
|
11
17
|
```ruby
|
12
|
-
gem '
|
18
|
+
gem 'solidus_returnly'
|
13
19
|
```
|
14
20
|
|
15
21
|
Bundle your dependencies and run the installation generator:
|
@@ -33,7 +39,7 @@ When testing your applications integration with this extension you may use it's
|
|
33
39
|
Simply add this require statement to your spec_helper:
|
34
40
|
|
35
41
|
```ruby
|
36
|
-
require '
|
42
|
+
require 'solidus/returnly/factories'
|
37
43
|
```
|
38
44
|
|
39
45
|
Solidus/Spree Sandbox
|
@@ -63,7 +69,7 @@ API
|
|
63
69
|
|
64
70
|
To get an estimate of the return order and taxes
|
65
71
|
|
66
|
-
`POST /api/
|
72
|
+
`POST /api/returnly/refunds/:order_number/estimate`
|
67
73
|
|
68
74
|
Payload:
|
69
75
|
```json
|
@@ -103,7 +109,7 @@ To process the return and apply the reimbursement**immediately**
|
|
103
109
|
you can pass the `restock` parameter on false to prevent the api
|
104
110
|
to immediately change the stock in the default warehouse
|
105
111
|
|
106
|
-
`POST /api/
|
112
|
+
`POST /api/returnly/refunds/:order_number`
|
107
113
|
|
108
114
|
Payload:
|
109
115
|
|
@@ -124,7 +130,7 @@ Payload:
|
|
124
130
|
}
|
125
131
|
```
|
126
132
|
|
127
|
-
|
133
|
+
Response:
|
128
134
|
|
129
135
|
```json
|
130
136
|
{
|
@@ -149,4 +155,4 @@ Responce:
|
|
149
155
|
```
|
150
156
|
|
151
157
|
|
152
|
-
Copyright (c) 2017 Returnly Technologies, Inc
|
158
|
+
Copyright (c) 2017 Returnly Technologies, Inc, released under the New BSD License
|
data/Rakefile
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
module Spree
|
2
|
+
module Api
|
3
|
+
module Returnly
|
4
|
+
class ApiController < Spree::Api::BaseController
|
5
|
+
before_filter :set_headers
|
6
|
+
|
7
|
+
def set_headers
|
8
|
+
response.headers['X-Returnly-Extension-Version'] = Solidus::Returnly::VERSION
|
9
|
+
response.headers['X-Returnly-Extension-Platform-Qualifier'] = Spree.solidus_version
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Spree
|
2
|
+
module Api
|
3
|
+
module Returnly
|
4
|
+
class RefundsController < ApiController
|
5
|
+
|
6
|
+
def estimate
|
7
|
+
authorize! :create, Order
|
8
|
+
render json: Solidus::Returnly::Calculator.process(order, line_items_params)
|
9
|
+
end
|
10
|
+
|
11
|
+
def create
|
12
|
+
authorize! :create, Order
|
13
|
+
|
14
|
+
refunds = Solidus::Returnly::Refunds.new order: order,
|
15
|
+
line_items: line_items_params,
|
16
|
+
restock: refund_restock_param,
|
17
|
+
transactions: transactions_params
|
18
|
+
render json: refunds.proceed!
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def line_items_params
|
24
|
+
params.require(:line_items)
|
25
|
+
end
|
26
|
+
|
27
|
+
def transactions_params
|
28
|
+
params.require(:transactions)
|
29
|
+
end
|
30
|
+
|
31
|
+
def refund_restock_param
|
32
|
+
params.require(:restock) == 'true'
|
33
|
+
end
|
34
|
+
|
35
|
+
def order
|
36
|
+
@order ||= Spree::Order.find_by(number: params[:order_id])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
data/config/routes.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
Spree::Core::Engine.routes.draw do
|
2
2
|
namespace :api, defaults: { format: 'json' } do
|
3
|
-
post '/
|
4
|
-
post '/
|
3
|
+
post '/returnly/refunds/:order_id/estimate', to: 'returnly/refunds#estimate'
|
4
|
+
post '/returnly/refunds/:order_id', to: 'returnly/refunds#create'
|
5
|
+
get '/returnly/version', to: 'returnly/version#index'
|
5
6
|
end
|
6
7
|
end
|
@@ -4,15 +4,26 @@ module SolidusReturnly
|
|
4
4
|
class_option :auto_run_migrations, type: :boolean, default: false
|
5
5
|
|
6
6
|
def add_javascripts
|
7
|
+
append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/frontend/solidus_returnly\n"
|
8
|
+
append_file 'vendor/assets/javascripts/spree/backend/all.js', "//= require spree/backend/solidus_returnly\n"
|
7
9
|
end
|
8
10
|
|
9
11
|
def add_stylesheets
|
12
|
+
inject_into_file 'vendor/assets/stylesheets/spree/frontend/all.css', " *= require spree/frontend/solidus_returnly\n", before: /\*\//, verbose: true
|
13
|
+
inject_into_file 'vendor/assets/stylesheets/spree/backend/all.css', " *= require spree/backend/solidus_returnly\n", before: /\*\//, verbose: true
|
10
14
|
end
|
11
15
|
|
12
16
|
def add_migrations
|
17
|
+
run 'bundle exec rake railties:install:migrations FROM=solidus_returnly'
|
13
18
|
end
|
14
19
|
|
15
20
|
def run_migrations
|
21
|
+
run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]'))
|
22
|
+
if run_migrations
|
23
|
+
run 'bundle exec rake db:migrate'
|
24
|
+
else
|
25
|
+
puts 'Skipping rake db:migrate, don\'t forget to run it!'
|
26
|
+
end
|
16
27
|
end
|
17
28
|
end
|
18
29
|
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Solidus
|
2
|
+
module Returnly
|
3
|
+
class Calculator
|
4
|
+
attr_accessor :line_items, :order
|
5
|
+
|
6
|
+
def self.process(order, line_items)
|
7
|
+
new(order, line_items).calculated_estimate
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(order, line_items)
|
11
|
+
self.line_items = line_items
|
12
|
+
self.order = order
|
13
|
+
end
|
14
|
+
|
15
|
+
def calculated_estimate
|
16
|
+
total = line_items_return_items.values.sum {|iu| iu.sum(&:pre_tax_amount)}
|
17
|
+
|
18
|
+
tax_amount = returnable_inventory_units.sum do |inventory_unit|
|
19
|
+
calculate_tax inventory_unit
|
20
|
+
end
|
21
|
+
|
22
|
+
{
|
23
|
+
total_amount: total,
|
24
|
+
subtotal_amount: total - tax_amount,
|
25
|
+
tax_amount: tax_amount,
|
26
|
+
discount_amount: order.promo_total,
|
27
|
+
shipping_amount: order.shipment_total,
|
28
|
+
line_items: present_line_items
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def present_line_items
|
33
|
+
line_items_return_items.map do |line_item_id, inventory_units|
|
34
|
+
line_item = line_item(line_item_id)
|
35
|
+
|
36
|
+
{
|
37
|
+
order_line_item_id: line_item.id,
|
38
|
+
quantity: inventory_units.size,
|
39
|
+
total_amount: inventory_units.sum(&:amount),
|
40
|
+
tax_amount: line_item.included_tax_total,
|
41
|
+
discount_amount: line_item.adjustment_total,
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def calculate_tax(inventory_unit)
|
48
|
+
return_item = Spree::ReturnItem.from_inventory_unit(inventory_unit)
|
49
|
+
(return_item.amount <= 0) ? 0 : return_item.amount /
|
50
|
+
Spree::ReturnItem.refund_amount_calculator.new.compute(return_item)
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def line_items_return_items
|
55
|
+
found_return_items = {}
|
56
|
+
|
57
|
+
self.line_items.each do |line_item|
|
58
|
+
quantity = line_item[:quantity].to_i
|
59
|
+
|
60
|
+
if quantity > 0
|
61
|
+
available_inventory_units = line_item_inventory_unit(line_item).slice(0, quantity)
|
62
|
+
|
63
|
+
available_inventory_units.each do |inventory_unit|
|
64
|
+
found_return_items[line_item[:order_line_item_id]] ||= []
|
65
|
+
found_return_items[line_item[:order_line_item_id]] << Spree::ReturnItem.new({amount: inventory_unit.line_item.price,
|
66
|
+
acceptance_status: 'accepted',
|
67
|
+
inventory_unit_id: inventory_unit.id,
|
68
|
+
reception_status_event: 'receive'
|
69
|
+
})
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
found_return_items
|
75
|
+
end
|
76
|
+
|
77
|
+
def line_item_inventory_unit(line_item)
|
78
|
+
returnable_inventory_units.select {|iu| iu.line_item_id == line_item[:order_line_item_id].to_i}
|
79
|
+
end
|
80
|
+
|
81
|
+
def line_item(id)
|
82
|
+
returnable_line_items.select {|i| i.id == id.to_i}.first
|
83
|
+
end
|
84
|
+
|
85
|
+
def returnable_inventory_units
|
86
|
+
@_inventory_units ||= order.inventory_units.includes(:line_item)
|
87
|
+
.where(line_item_id: requested_line_items)
|
88
|
+
.where('state is not "returned"')
|
89
|
+
end
|
90
|
+
|
91
|
+
def returnable_line_items
|
92
|
+
@_line_items ||= returnable_inventory_units.map(&:line_item)
|
93
|
+
end
|
94
|
+
|
95
|
+
def requested_line_items
|
96
|
+
line_items.map {|item| item[:order_line_item_id]}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Solidus
|
2
|
+
module Returnly
|
3
|
+
class Engine < Rails::Engine
|
4
|
+
require 'spree/core'
|
5
|
+
|
6
|
+
engine_name 'returnly'
|
7
|
+
|
8
|
+
config.autoload_paths += %W(#{config.root}/lib)
|
9
|
+
|
10
|
+
# use rspec for tests
|
11
|
+
config.generators do |g|
|
12
|
+
g.test_framework :rspec
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.activate
|
16
|
+
Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
|
17
|
+
Rails.configuration.cache_classes ? require(c) : load(c)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
config.to_prepare(&method(:activate).to_proc)
|
22
|
+
|
23
|
+
rake_tasks do
|
24
|
+
namespace :returnly do
|
25
|
+
require 'securerandom'
|
26
|
+
|
27
|
+
desc "Creates an returnly user and prints the generated API key"
|
28
|
+
task install_user: :environment do
|
29
|
+
returnly_email = 'api@returnly.coim'
|
30
|
+
|
31
|
+
password = SecureRandom.hex(24)
|
32
|
+
|
33
|
+
if (user = Spree::User.find_by email: returnly_email)
|
34
|
+
puts "The Returnly User is already generated"
|
35
|
+
puts "The Api key is: #{user.spree_api_key}"
|
36
|
+
else
|
37
|
+
user = Spree::User.new email: returnly_email, password: password,
|
38
|
+
password_confirmation: password
|
39
|
+
|
40
|
+
api_key = user.generate_spree_api_key
|
41
|
+
|
42
|
+
if user.save!
|
43
|
+
puts "****************************************************"
|
44
|
+
puts "Api key Generated #{api_key}"
|
45
|
+
puts "Returnly User Password #{password}"
|
46
|
+
puts "Returnly User email #{returnly_email}"
|
47
|
+
puts "****************************************************"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -2,5 +2,5 @@ FactoryGirl.define do
|
|
2
2
|
# Define your Spree extensions Factories within this file to enable applications, and other extensions to use and override them.
|
3
3
|
#
|
4
4
|
# Example adding this to your spec_helper will load these Factories for use:
|
5
|
-
# require '
|
5
|
+
# require 'returnly/factories'
|
6
6
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Solidus
|
2
|
+
module Returnly
|
3
|
+
class Refunds
|
4
|
+
attr_accessor :calculator, :order, :line_items, :restock, :transactions
|
5
|
+
|
6
|
+
def initialize(order:, line_items:, restock: true, transactions:)
|
7
|
+
self.order = order
|
8
|
+
self.line_items = line_items
|
9
|
+
self.calculator = Calculator.new order, line_items
|
10
|
+
self.restock = restock
|
11
|
+
self.transactions = transactions
|
12
|
+
end
|
13
|
+
|
14
|
+
def restock_return(customer_return)
|
15
|
+
customer_return.return_items.each do |item|
|
16
|
+
customer_return.stock_location.restock(item.inventory_unit.variant, 1, customer_return)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def proceed!
|
21
|
+
customer_return = Spree::CustomerReturn.new customer_return_params
|
22
|
+
customer_return.return_items = calculator.line_items_return_items.values.flatten
|
23
|
+
|
24
|
+
customer_return.return_items.each do |return_item|
|
25
|
+
return_item.amount = refund_amount_per_item
|
26
|
+
end
|
27
|
+
|
28
|
+
if customer_return.save!
|
29
|
+
reimbursement = perform_reimbursement(customer_return)
|
30
|
+
restock_return(customer_return) if self.restock
|
31
|
+
|
32
|
+
processed_customer_return(customer_return, reimbursement)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def processed_customer_return(customer_return, reimbursement)
|
37
|
+
{
|
38
|
+
refund_id: customer_return.number,
|
39
|
+
created_at: customer_return.created_at,
|
40
|
+
updated_at: customer_return.updated_at,
|
41
|
+
line_items: customer_return.return_items.map {|ri|
|
42
|
+
{
|
43
|
+
refund_line_item_id: ri.id,
|
44
|
+
order_line_item_id: ri.inventory_unit.line_item.id,
|
45
|
+
quantity: 1
|
46
|
+
}
|
47
|
+
},
|
48
|
+
transactions: [
|
49
|
+
id: reimbursement.id,
|
50
|
+
amount: reimbursement.total
|
51
|
+
],
|
52
|
+
note: "comment text",
|
53
|
+
restock: true
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
def perform_reimbursement(customer_return)
|
58
|
+
reimbursement = Spree::Reimbursement.build_from_customer_return(customer_return)
|
59
|
+
reimbursement.save!
|
60
|
+
reimbursement.perform!
|
61
|
+
reimbursement
|
62
|
+
end
|
63
|
+
|
64
|
+
def customer_return_params
|
65
|
+
{
|
66
|
+
stock_location_id: stock_location_id,
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def stock_location_id
|
71
|
+
order.shipments.last.stock_location.id
|
72
|
+
end
|
73
|
+
|
74
|
+
def refund_available_amount
|
75
|
+
@available_amount ||= self.transactions.sum {|t| Money.from_amount(t[:amount].to_f)}
|
76
|
+
end
|
77
|
+
|
78
|
+
def refund_amount_per_item
|
79
|
+
refund_available_amount / line_items.size
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solidus-returnly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Returnly Technologies, Inc
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: solidus
|
@@ -243,16 +243,18 @@ files:
|
|
243
243
|
- LICENSE
|
244
244
|
- README.md
|
245
245
|
- Rakefile
|
246
|
-
- app/controllers/spree/api/
|
246
|
+
- app/controllers/spree/api/returnly/api_controller.rb
|
247
|
+
- app/controllers/spree/api/returnly/refunds_controller.rb
|
248
|
+
- app/controllers/spree/api/returnly/version_controller.rb
|
247
249
|
- config/locales/en.yml
|
248
250
|
- config/routes.rb
|
249
251
|
- lib/generators/solidus_returnly/install/install_generator.rb
|
250
|
-
- lib/solidus
|
251
|
-
- lib/
|
252
|
-
- lib/
|
253
|
-
- lib/
|
254
|
-
- lib/
|
255
|
-
- lib/
|
252
|
+
- lib/solidus-returnly.rb
|
253
|
+
- lib/solidus/returnly/calculator.rb
|
254
|
+
- lib/solidus/returnly/engine.rb
|
255
|
+
- lib/solidus/returnly/factories.rb
|
256
|
+
- lib/solidus/returnly/refunds.rb
|
257
|
+
- lib/solidus/returnly/version.rb
|
256
258
|
homepage: https://github.com/returnly/solidus-returnly
|
257
259
|
licenses:
|
258
260
|
- MIT
|
@@ -1,40 +0,0 @@
|
|
1
|
-
module Spree
|
2
|
-
module Api
|
3
|
-
class RefundsController < Spree::Api::BaseController
|
4
|
-
|
5
|
-
def estimate
|
6
|
-
authorize! :create, Order
|
7
|
-
render json: SolidusReturnly::Calculator.process(order, line_items_params)
|
8
|
-
end
|
9
|
-
|
10
|
-
def create
|
11
|
-
authorize! :create, Order
|
12
|
-
|
13
|
-
refunds = SolidusReturnly::Refunds.new order: order,
|
14
|
-
line_items: line_items_params,
|
15
|
-
restock: refund_restock_param,
|
16
|
-
transactions: transactions_params
|
17
|
-
render json: refunds.proceed!
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def line_items_params
|
23
|
-
params.require(:line_items)
|
24
|
-
end
|
25
|
-
|
26
|
-
def transactions_params
|
27
|
-
params.require(:transactions)
|
28
|
-
end
|
29
|
-
|
30
|
-
def refund_restock_param
|
31
|
-
params.require(:restock) == 'true'
|
32
|
-
end
|
33
|
-
|
34
|
-
def order
|
35
|
-
@order ||= Spree::Order.find_by(number: params[:order_id])
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
data/lib/solidus/returnly.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
module SolidusReturnly
|
2
|
-
class Calculator
|
3
|
-
attr_accessor :line_items, :order
|
4
|
-
|
5
|
-
def self.process(order, line_items)
|
6
|
-
new(order, line_items).calculated_estimate
|
7
|
-
end
|
8
|
-
|
9
|
-
def initialize(order, line_items)
|
10
|
-
self.line_items = line_items
|
11
|
-
self.order = order
|
12
|
-
end
|
13
|
-
|
14
|
-
def calculated_estimate
|
15
|
-
total = line_items_return_items.values.sum{|iu| iu.sum(&:pre_tax_amount) }
|
16
|
-
|
17
|
-
tax_amount = returnable_inventory_units.sum do |inventory_unit|
|
18
|
-
calculate_tax inventory_unit
|
19
|
-
end
|
20
|
-
|
21
|
-
{
|
22
|
-
total_amount: total,
|
23
|
-
subtotal_amount: total - tax_amount,
|
24
|
-
tax_amount: tax_amount,
|
25
|
-
discount_amount: order.promo_total,
|
26
|
-
shipping_amount: order.shipment_total,
|
27
|
-
line_items: present_line_items
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
def present_line_items
|
32
|
-
line_items_return_items.map do| line_item_id, inventory_units|
|
33
|
-
line_item = line_item(line_item_id)
|
34
|
-
|
35
|
-
{
|
36
|
-
order_line_item_id: line_item.id,
|
37
|
-
quantity: inventory_units.size,
|
38
|
-
total_amount: inventory_units.sum(&:amount),
|
39
|
-
tax_amount: line_item.included_tax_total,
|
40
|
-
discount_amount: line_item.adjustment_total,
|
41
|
-
}
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
|
46
|
-
def calculate_tax(inventory_unit)
|
47
|
-
return_item = Spree::ReturnItem.from_inventory_unit(inventory_unit)
|
48
|
-
(return_item.amount <= 0) ? 0 : return_item.amount /
|
49
|
-
Spree::ReturnItem.refund_amount_calculator.new.compute(return_item)
|
50
|
-
end
|
51
|
-
|
52
|
-
|
53
|
-
def line_items_return_items
|
54
|
-
found_return_items = {}
|
55
|
-
|
56
|
-
self.line_items.each do |line_item|
|
57
|
-
quantity = line_item[:quantity].to_i
|
58
|
-
|
59
|
-
if quantity > 0
|
60
|
-
available_inventory_units = line_item_inventory_unit(line_item).slice(0, quantity)
|
61
|
-
|
62
|
-
available_inventory_units.each do |inventory_unit|
|
63
|
-
found_return_items[line_item[:order_line_item_id]] ||= []
|
64
|
-
found_return_items[line_item[:order_line_item_id]] << Spree::ReturnItem.new({amount: inventory_unit.line_item.price,
|
65
|
-
acceptance_status: 'accepted',
|
66
|
-
inventory_unit_id: inventory_unit.id,
|
67
|
-
reception_status_event: 'receive'
|
68
|
-
})
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
found_return_items
|
74
|
-
end
|
75
|
-
|
76
|
-
def line_item_inventory_unit(line_item)
|
77
|
-
returnable_inventory_units.select{|iu| iu.line_item_id == line_item[:order_line_item_id].to_i }
|
78
|
-
end
|
79
|
-
|
80
|
-
def line_item(id)
|
81
|
-
returnable_line_items.select{|i| i.id == id.to_i }.first
|
82
|
-
end
|
83
|
-
|
84
|
-
def returnable_inventory_units
|
85
|
-
@_inventory_units ||= order.inventory_units.includes(:line_item)
|
86
|
-
.where(line_item_id: requested_line_items)
|
87
|
-
.where('state is not "returned"')
|
88
|
-
end
|
89
|
-
|
90
|
-
def returnable_line_items
|
91
|
-
@_line_items ||= returnable_inventory_units.map(&:line_item)
|
92
|
-
end
|
93
|
-
|
94
|
-
def requested_line_items
|
95
|
-
line_items.map { |item| item[:order_line_item_id] }
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
module SolidusReturnly
|
2
|
-
class Engine < Rails::Engine
|
3
|
-
require 'spree/core'
|
4
|
-
|
5
|
-
engine_name 'solidus_returnly'
|
6
|
-
|
7
|
-
config.autoload_paths += %W(#{config.root}/lib)
|
8
|
-
|
9
|
-
# use rspec for tests
|
10
|
-
config.generators do |g|
|
11
|
-
g.test_framework :rspec
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.activate
|
15
|
-
Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
|
16
|
-
Rails.configuration.cache_classes ? require(c) : load(c)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
config.to_prepare(&method(:activate).to_proc)
|
21
|
-
|
22
|
-
rake_tasks do
|
23
|
-
namespace :returnly do
|
24
|
-
require 'securerandom'
|
25
|
-
|
26
|
-
desc "Creates an returnly user and prints the generated API key"
|
27
|
-
task install_user: :environment do
|
28
|
-
returnly_email = 'api@returnly.coim'
|
29
|
-
|
30
|
-
password = SecureRandom.hex(24)
|
31
|
-
|
32
|
-
if (user = Spree::User.find_by email: returnly_email)
|
33
|
-
puts "The Returnly User is already generated"
|
34
|
-
puts "The Api key is: #{user.spree_api_key}"
|
35
|
-
else
|
36
|
-
user = Spree::User.new email: returnly_email, password: password,
|
37
|
-
password_confirmation: password
|
38
|
-
|
39
|
-
api_key = user.generate_spree_api_key
|
40
|
-
|
41
|
-
if user.save!
|
42
|
-
puts "****************************************************"
|
43
|
-
puts "Api key Generated #{api_key}"
|
44
|
-
puts "Returnly User Password #{password}"
|
45
|
-
puts "Returnly User email #{returnly_email}"
|
46
|
-
puts "****************************************************"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
module SolidusReturnly
|
2
|
-
class Refunds
|
3
|
-
attr_accessor :calculator, :order, :line_items, :restock, :transactions
|
4
|
-
|
5
|
-
def initialize(order:, line_items:, restock: true, transactions:)
|
6
|
-
self.order = order
|
7
|
-
self.line_items = line_items
|
8
|
-
self.calculator = Calculator.new order, line_items
|
9
|
-
self.restock = restock
|
10
|
-
self.transactions = transactions
|
11
|
-
end
|
12
|
-
|
13
|
-
def restock_return(customer_return)
|
14
|
-
customer_return.return_items.each do | item |
|
15
|
-
customer_return.stock_location.restock(item.inventory_unit.variant, 1, customer_return)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def proceed!
|
20
|
-
customer_return = Spree::CustomerReturn.new customer_return_params
|
21
|
-
customer_return.return_items = calculator.line_items_return_items.values.flatten
|
22
|
-
|
23
|
-
customer_return.return_items.each do |return_item|
|
24
|
-
return_item.amount = refund_amount_per_item
|
25
|
-
end
|
26
|
-
|
27
|
-
if customer_return.save!
|
28
|
-
reimbursement = perform_reimbursement(customer_return)
|
29
|
-
restock_return(customer_return) if self.restock
|
30
|
-
|
31
|
-
processed_customer_return(customer_return, reimbursement)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def processed_customer_return(customer_return, reimbursement)
|
36
|
-
{
|
37
|
-
refund_id: customer_return.number,
|
38
|
-
created_at: customer_return.created_at,
|
39
|
-
updated_at: customer_return.updated_at,
|
40
|
-
line_items: customer_return.return_items.map { |ri|
|
41
|
-
{
|
42
|
-
refund_line_item_id: ri.id,
|
43
|
-
order_line_item_id: ri.inventory_unit.line_item.id,
|
44
|
-
quantity: 1
|
45
|
-
}
|
46
|
-
},
|
47
|
-
transactions: [
|
48
|
-
id: reimbursement.id,
|
49
|
-
amount: reimbursement.total
|
50
|
-
],
|
51
|
-
note: "comment text",
|
52
|
-
restock: true
|
53
|
-
}
|
54
|
-
end
|
55
|
-
|
56
|
-
def perform_reimbursement(customer_return)
|
57
|
-
reimbursement = Spree::Reimbursement.build_from_customer_return(customer_return)
|
58
|
-
reimbursement.save!
|
59
|
-
reimbursement.perform!
|
60
|
-
reimbursement
|
61
|
-
end
|
62
|
-
|
63
|
-
def customer_return_params
|
64
|
-
{
|
65
|
-
stock_location_id: stock_location_id,
|
66
|
-
}
|
67
|
-
end
|
68
|
-
|
69
|
-
def stock_location_id
|
70
|
-
order.shipments.last.stock_location.id
|
71
|
-
end
|
72
|
-
|
73
|
-
def refund_available_amount
|
74
|
-
@available_amount ||= self.transactions.sum{|t| Money.from_amount(t[:amount].to_f) }
|
75
|
-
end
|
76
|
-
|
77
|
-
def refund_amount_per_item
|
78
|
-
refund_available_amount / line_items.size
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|