solidus-returnly 0.0.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|