solidus-returnly 0.4.3 → 0.5.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +41 -31
- data/Rakefile +20 -1
- data/app/controllers/spree/api/returnly/api_controller.rb +2 -2
- data/app/controllers/spree/api/returnly/refunds_controller.rb +8 -8
- data/app/controllers/spree/api/returnly/version_controller.rb +2 -2
- data/app/models/spree/return_item_decorator.rb +14 -0
- data/config/routes.rb +3 -2
- data/lib/returnly.rb +4 -0
- data/lib/returnly/engine.rb +65 -0
- data/lib/{solidus/returnly → returnly}/factories.rb +0 -0
- data/lib/returnly/refund/amount_calculator.rb +21 -0
- data/lib/returnly/refund/return_item_restock_policy.rb +15 -0
- data/lib/returnly/refund_calculator.rb +91 -0
- data/lib/returnly/refund_presenter.rb +78 -0
- data/lib/returnly/refunder.rb +82 -0
- data/lib/returnly/refunds_configuration.rb +20 -0
- data/lib/returnly/version.rb +7 -0
- data/lib/solidus-returnly.rb +10 -10
- data/lib/spree-returnly.rb +12 -0
- metadata +78 -20
- data/lib/generators/solidus_returnly/install/install_generator.rb +0 -19
- data/lib/solidus/returnly/engine.rb +0 -67
- data/lib/solidus/returnly/refund/amount_calculator.rb +0 -23
- data/lib/solidus/returnly/refund/return_item_restock_policy.rb +0 -18
- data/lib/solidus/returnly/refund_calculator.rb +0 -87
- data/lib/solidus/returnly/refund_presenter.rb +0 -73
- data/lib/solidus/returnly/refunder.rb +0 -84
- data/lib/solidus/returnly/refunds_configuration.rb +0 -22
- data/lib/solidus/returnly/version.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 174cd758f9a9329da775abb30290df3a942f727f
|
4
|
+
data.tar.gz: c825cf7169dc8cc4b45d8c64248db506433a2b0f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 32530c1a9fae7cc15034e47ee6af6c5ba21204c86a0bf29499587ebcf389932f75bfa846a93dca38df553984bf0c7dd84dffcc94e16e261ac96529a2b8774964
|
7
|
+
data.tar.gz: cd2c85551f5f9fbd4210bd47c655f1551386fdc8cb115aad79bec8958594aed748c3364834fcad882ee44add7d2e7412366447eabcec9458e776e013444ad0a1
|
data/README.md
CHANGED
@@ -3,6 +3,19 @@ Solidus Returnly
|
|
3
3
|
|
4
4
|
This gem adds the required APIs to allow returnly obtain an estimate, process a return and apply a reimbursement
|
5
5
|
|
6
|
+
|
7
|
+
Spree/Solidus
|
8
|
+
-----
|
9
|
+
This gem can be installed on spree and solidus, to release a new version to both registries you need to run
|
10
|
+
`bash
|
11
|
+
$ rake both_releases
|
12
|
+
`
|
13
|
+
this will generate two packages, `solidus-returnly` and `spree-returnly`
|
14
|
+
|
15
|
+
Current Compat Versions:
|
16
|
+
- Solidus : `~>2.0.0`
|
17
|
+
- Spree : `~>3.0.1`
|
18
|
+
|
6
19
|
Installation
|
7
20
|
------------
|
8
21
|
|
@@ -63,15 +76,15 @@ API
|
|
63
76
|
|
64
77
|
To get an estimate of the return order and taxes
|
65
78
|
|
66
|
-
`POST /api/returnly/
|
79
|
+
`POST /api/returnly/orders/:order_number/refund_estimate`
|
67
80
|
|
68
81
|
Payload:
|
69
82
|
```json
|
70
83
|
{
|
71
|
-
"
|
84
|
+
"items": [
|
72
85
|
{
|
73
86
|
"order_line_item_id": "{spree order line item id}",
|
74
|
-
"
|
87
|
+
"units": 1
|
75
88
|
}
|
76
89
|
]
|
77
90
|
}
|
@@ -81,19 +94,18 @@ Response:
|
|
81
94
|
|
82
95
|
```json
|
83
96
|
{
|
84
|
-
"
|
85
|
-
"subtotal_amount": "{money}",
|
97
|
+
"product_amount": "{money}",
|
86
98
|
"tax_amount": "{money}",
|
87
99
|
"discount_amount": "{money}",
|
88
|
-
"
|
89
|
-
"
|
100
|
+
"total_refund_amount": "{money}",
|
101
|
+
"refundable_shipping_amount": "{money}",
|
102
|
+
"refundable_shipping_tax_amount": "{money}",
|
103
|
+
"max_refundable_amount": "{money}",
|
104
|
+
"refunds_by_payment_method": [
|
90
105
|
{
|
91
|
-
"
|
92
|
-
"
|
93
|
-
"
|
94
|
-
"subtotal_amount": "{money}",
|
95
|
-
"tax_amount": "{money}",
|
96
|
-
"discount_amount": "{money}",
|
106
|
+
"code": "Credit Card",
|
107
|
+
"amount": "{money}",
|
108
|
+
"original_transaction_id": 1
|
97
109
|
}
|
98
110
|
]
|
99
111
|
}
|
@@ -103,24 +115,23 @@ To process the return and apply the reimbursement**immediately**
|
|
103
115
|
you can pass the `restock` parameter on false to prevent the api
|
104
116
|
to immediately change the stock in the default warehouse
|
105
117
|
|
106
|
-
`POST /api/returnly/
|
118
|
+
`POST /api/returnly/orders/:order_number/refund`
|
107
119
|
|
108
120
|
Payload:
|
109
121
|
|
110
122
|
```json
|
111
123
|
{
|
112
|
-
"
|
124
|
+
"items": [
|
113
125
|
{
|
114
126
|
"order_line_item_id": "{x_order_line_item_id1}",
|
115
|
-
"
|
116
|
-
|
127
|
+
"units": 2,
|
128
|
+
"restock": true
|
129
|
+
}
|
117
130
|
],
|
118
|
-
"
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
"note": "comment text",
|
123
|
-
"restock": true
|
131
|
+
"notify_shopper": true,
|
132
|
+
"product_refund_amount": "{money}",
|
133
|
+
"shipping_refund_amount": "{money}",
|
134
|
+
"refund_note": "comment text"
|
124
135
|
}
|
125
136
|
```
|
126
137
|
|
@@ -129,22 +140,21 @@ Response:
|
|
129
140
|
```json
|
130
141
|
{
|
131
142
|
"refund_id": "{x_refund_id}",
|
132
|
-
"created_at": "{timestamp}",
|
133
|
-
"updated_at": "{timestamp}",
|
134
143
|
"user_id": "{optional merchant user ID}",
|
135
144
|
"line_items": [
|
136
145
|
{
|
137
146
|
"refund_line_item_id": "{x_refund_line_item_id1}",
|
138
147
|
"order_line_item_id": "{x_order_line_item_id1}",
|
139
|
-
"
|
148
|
+
"units": 2
|
140
149
|
},
|
141
150
|
],
|
142
|
-
"transactions": [
|
143
|
-
|
144
|
-
|
151
|
+
"transactions": [
|
152
|
+
{
|
153
|
+
"id": "{refund tx id}",
|
154
|
+
"amount": "{money}"
|
155
|
+
}
|
145
156
|
],
|
146
|
-
"
|
147
|
-
"restock": true
|
157
|
+
"refund_note": "comment text",
|
148
158
|
}
|
149
159
|
```
|
150
160
|
|
data/Rakefile
CHANGED
@@ -1,6 +1,16 @@
|
|
1
|
+
$:.push File.expand_path('../lib', __FILE__)
|
1
2
|
require 'bundler'
|
2
3
|
|
3
|
-
|
4
|
+
def load_library_env
|
5
|
+
lib_name = ENV['SPREE_BUILD'] ? 'spree-returnly' : 'solidus-returnly'
|
6
|
+
|
7
|
+
puts "Loading #{lib_name}"
|
8
|
+
|
9
|
+
Bundler::GemHelper.install_tasks name: lib_name
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
load_library_env
|
4
14
|
|
5
15
|
begin
|
6
16
|
require 'spree/testing_support/extension_rake'
|
@@ -20,6 +30,15 @@ task :first_run do
|
|
20
30
|
end
|
21
31
|
end
|
22
32
|
|
33
|
+
task :both_releases do
|
34
|
+
%w(spree-returnly solidus-returnly).each do |lib_name|
|
35
|
+
Bundler::GemHelper.install_tasks name: lib_name
|
36
|
+
Rake::Task[:release].invoke
|
37
|
+
end
|
38
|
+
|
39
|
+
load_library_env
|
40
|
+
end
|
41
|
+
|
23
42
|
desc 'Generates a dummy app for testing'
|
24
43
|
task :test_app do
|
25
44
|
ENV['LIB_NAME'] = 'solidus-returnly'
|
@@ -5,8 +5,8 @@ module Spree
|
|
5
5
|
before_filter :set_headers
|
6
6
|
|
7
7
|
def set_headers
|
8
|
-
response.headers['X-Returnly-Extension-Version'] =
|
9
|
-
response.headers['X-Returnly-Extension-Platform-Qualifier'] =
|
8
|
+
response.headers['X-Returnly-Extension-Version'] = ::Returnly::VERSION
|
9
|
+
response.headers['X-Returnly-Extension-Platform-Qualifier'] = ::Returnly.platform_version
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -2,7 +2,7 @@ module Spree
|
|
2
2
|
module Api
|
3
3
|
module Returnly
|
4
4
|
class RefundsController < ApiController
|
5
|
-
include
|
5
|
+
include ::Returnly::RefundsConfiguration
|
6
6
|
|
7
7
|
def estimate
|
8
8
|
authorize! :create, Order
|
@@ -14,23 +14,23 @@ module Spree
|
|
14
14
|
|
15
15
|
refunds = refunder_class.new order: order,
|
16
16
|
line_items: line_items_params,
|
17
|
-
|
18
|
-
|
17
|
+
product_refund_amount: product_refund_amount_param,
|
18
|
+
shipping_refund_amount: shipping_refund_amount_param
|
19
19
|
render json: refunds.proceed!
|
20
20
|
end
|
21
21
|
|
22
22
|
private
|
23
23
|
|
24
24
|
def line_items_params
|
25
|
-
params.require(:
|
25
|
+
params.require(:items)
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
29
|
-
params.require(:
|
28
|
+
def product_refund_amount_param
|
29
|
+
params.require(:product_refund_amount)
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
33
|
-
params.require(:
|
32
|
+
def shipping_refund_amount_param
|
33
|
+
params.require(:shipping_refund_amount)
|
34
34
|
end
|
35
35
|
|
36
36
|
def order
|
@@ -4,8 +4,8 @@ module Spree
|
|
4
4
|
class VersionController < ApiController
|
5
5
|
def index
|
6
6
|
render json: {
|
7
|
-
extension_version:
|
8
|
-
platform_version:
|
7
|
+
extension_version: ::Returnly::VERSION,
|
8
|
+
platform_version: ::Returnly.platform_version
|
9
9
|
}
|
10
10
|
end
|
11
11
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Spree::ReturnItem.class_eval do
|
2
|
+
unless ::Returnly.is_solidus?
|
3
|
+
attr_accessor :amount
|
4
|
+
|
5
|
+
def amount
|
6
|
+
self.pre_tax_amount + self.included_tax_total
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
def amount=(amount)
|
11
|
+
self.pre_tax_amount = amount - self.included_tax_total
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/config/routes.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
Spree::Core::Engine.routes.draw do
|
2
2
|
namespace :api, defaults: { format: 'json' } do
|
3
|
-
post '/returnly/
|
4
|
-
post '/returnly/
|
3
|
+
post '/returnly/orders/:order_id/refund_estimate', to: 'returnly/refunds#estimate'
|
4
|
+
post '/returnly/orders/:order_id/refund', to: 'returnly/refunds#create'
|
5
|
+
|
5
6
|
get '/returnly/version', to: 'returnly/version#index'
|
6
7
|
end
|
7
8
|
end
|
data/lib/returnly.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
module Returnly
|
2
|
+
class << self
|
3
|
+
mattr_accessor :return_item_amount_calculator,
|
4
|
+
:return_item_restock_policy,
|
5
|
+
:refunder,
|
6
|
+
:refund_calculator
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.configure(&block)
|
10
|
+
yield self if block
|
11
|
+
end
|
12
|
+
|
13
|
+
class Engine < Rails::Engine
|
14
|
+
require 'spree/core'
|
15
|
+
|
16
|
+
engine_name 'returnly'
|
17
|
+
|
18
|
+
config.autoload_paths += %W(#{config.root}/lib)
|
19
|
+
|
20
|
+
# use rspec for tests
|
21
|
+
config.generators do |g|
|
22
|
+
g.test_framework :rspec
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.activate
|
26
|
+
Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
|
27
|
+
Rails.configuration.cache_classes ? require(c) : load(c)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
config.to_prepare(&method(:activate).to_proc)
|
32
|
+
|
33
|
+
rake_tasks do
|
34
|
+
namespace :returnly do
|
35
|
+
require 'securerandom'
|
36
|
+
|
37
|
+
desc "Creates an returnly user and prints the generated API key"
|
38
|
+
task install_user: :environment do
|
39
|
+
|
40
|
+
returnly_email = 'api@returnly.com'
|
41
|
+
|
42
|
+
password = SecureRandom.hex(24)
|
43
|
+
|
44
|
+
if (user = Spree::User.find_by email: returnly_email)
|
45
|
+
puts "The Returnly User is already generated"
|
46
|
+
puts "The Api key is: #{user.spree_api_key}"
|
47
|
+
else
|
48
|
+
user = Spree::User.new email: returnly_email, password: password,
|
49
|
+
password_confirmation: password
|
50
|
+
|
51
|
+
user.generate_spree_api_key!
|
52
|
+
|
53
|
+
if user.save!
|
54
|
+
puts "****************************************************"
|
55
|
+
puts "Api key Generated #{user.spree_api_key}"
|
56
|
+
puts "Returnly User Password #{password}"
|
57
|
+
puts "Returnly User email #{returnly_email}"
|
58
|
+
puts "****************************************************"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
File without changes
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Returnly
|
2
|
+
module Refund
|
3
|
+
class AmountCalculator
|
4
|
+
attr_accessor :refund
|
5
|
+
|
6
|
+
def initialize(refund)
|
7
|
+
self.refund = refund
|
8
|
+
end
|
9
|
+
|
10
|
+
def return_item_refund_amount(return_item)
|
11
|
+
default_amount(return_item)
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
def default_amount(return_item)
|
16
|
+
refund.refund_amount_per_item -
|
17
|
+
Money.from_amount(return_item.total - return_item.pre_tax_amount)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Returnly
|
2
|
+
class RefundCalculator
|
3
|
+
attr_accessor :line_items, :order
|
4
|
+
|
5
|
+
def self.process(order, line_items)
|
6
|
+
RefundPresenter.present_estimate new(order, line_items)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(order, line_items)
|
10
|
+
self.line_items = line_items
|
11
|
+
self.order = order
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_tax(return_item)
|
15
|
+
percent_of_tax = (return_item.amount <= 0) ? 0 : return_item.amount /
|
16
|
+
Spree::ReturnItem.refund_amount_calculator.new.compute(return_item)
|
17
|
+
|
18
|
+
additional_tax_total = percent_of_tax * return_item.inventory_unit.additional_tax_total
|
19
|
+
included_tax_total = percent_of_tax * return_item.inventory_unit.included_tax_total
|
20
|
+
|
21
|
+
return_item.additional_tax_total = additional_tax_total
|
22
|
+
return_item.included_tax_total = included_tax_total
|
23
|
+
|
24
|
+
return_item
|
25
|
+
end
|
26
|
+
|
27
|
+
def shipping_tax
|
28
|
+
order.all_adjustments.where(source_type: 'Spree::TaxRate', adjustable_type: 'Spree::Shipment').sum(&:amount)
|
29
|
+
end
|
30
|
+
|
31
|
+
def line_items_return_items
|
32
|
+
found_return_items = {}
|
33
|
+
|
34
|
+
line_items.each do |line_item|
|
35
|
+
with_available_inventory_units line_item do |inventory_unit, quantity|
|
36
|
+
next unless quantity > 0
|
37
|
+
|
38
|
+
found_return_items[line_item[:order_line_item_id]] ||= []
|
39
|
+
return_item = create_return_item(inventory_unit, restock: line_item[:restock])
|
40
|
+
found_return_items[line_item[:order_line_item_id]] << set_tax(return_item)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
found_return_items
|
45
|
+
end
|
46
|
+
|
47
|
+
def line_item_inventory_unit(line_item)
|
48
|
+
returnable_inventory_units.select { |iu| iu.line_item_id == line_item[:order_line_item_id].to_i }
|
49
|
+
end
|
50
|
+
|
51
|
+
def line_item(id)
|
52
|
+
returnable_line_items.find { |i| i.id == id.to_i }
|
53
|
+
end
|
54
|
+
|
55
|
+
def returnable_inventory_units
|
56
|
+
@_inventory_units ||= order.inventory_units.includes(:line_item)
|
57
|
+
.where(line_item_id: requested_line_items)
|
58
|
+
.where('state is not "returned"')
|
59
|
+
end
|
60
|
+
|
61
|
+
def returnable_line_items
|
62
|
+
@_line_items ||= returnable_inventory_units.map(&:line_item)
|
63
|
+
end
|
64
|
+
|
65
|
+
def requested_line_items
|
66
|
+
line_items.map { |item| item[:order_line_item_id] }
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
protected
|
71
|
+
|
72
|
+
def create_return_item(inventory_unit, restock: false)
|
73
|
+
Spree::ReturnItem.new(
|
74
|
+
amount: inventory_unit.line_item.price,
|
75
|
+
acceptance_status: 'accepted',
|
76
|
+
inventory_unit_id: inventory_unit.id,
|
77
|
+
reception_status_event: 'receive',
|
78
|
+
resellable: restock
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
82
|
+
def with_available_inventory_units(line_item)
|
83
|
+
quantity = line_item[:units].to_i
|
84
|
+
|
85
|
+
available_inventory_units = line_item_inventory_unit(line_item).slice(0, quantity)
|
86
|
+
available_inventory_units.each do |inventory_unit|
|
87
|
+
yield inventory_unit, quantity
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Returnly
|
2
|
+
class RefundPresenter
|
3
|
+
|
4
|
+
def self.present_estimate(calculator)
|
5
|
+
total = Money.new 0
|
6
|
+
sub_total = Money.new 0
|
7
|
+
|
8
|
+
calculator.line_items_return_items.values.flatten.each do |return_item|
|
9
|
+
total += Money.from_amount return_item.total
|
10
|
+
sub_total += Money.from_amount return_item.pre_tax_amount
|
11
|
+
end
|
12
|
+
|
13
|
+
{
|
14
|
+
product_amount: sub_total.to_f,
|
15
|
+
tax_amount: (total - sub_total).to_f,
|
16
|
+
discount_amount: calculator.order.promo_total.to_f,
|
17
|
+
total_refund_amount: (total - calculator.order.promo_total).to_f,
|
18
|
+
refundable_shipping_amount: calculator.order.shipment_total.to_f,
|
19
|
+
refundable_shipping_tax_amount: calculator.shipping_tax.to_f,
|
20
|
+
max_refundable_amount: calculator.order.total.to_f,
|
21
|
+
refunds_by_payment_method: refunds_by_payment(calculator.order)
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.present_line_items(calculator)
|
26
|
+
calculator.line_items_return_items.values.map do |return_items|
|
27
|
+
line_item = return_items.first.inventory_unit.line_item
|
28
|
+
|
29
|
+
total_amount = 0.0
|
30
|
+
sub_total = 0.0
|
31
|
+
|
32
|
+
return_items.each do |return_item|
|
33
|
+
total_amount += return_item.total
|
34
|
+
sub_total += return_item.pre_tax_amount
|
35
|
+
end
|
36
|
+
|
37
|
+
{
|
38
|
+
order_line_item_id: line_item.id,
|
39
|
+
quantity: return_items.size,
|
40
|
+
total_amount: total_amount.to_f,
|
41
|
+
tax_amount: (total_amount - sub_total).to_f
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def self.present_refund(refunder)
|
48
|
+
customer_return = refunder.customer_return
|
49
|
+
|
50
|
+
{
|
51
|
+
refund_id: customer_return.number,
|
52
|
+
line_items: customer_return.return_items.group_by { |ri| ri.inventory_unit.line_item.id }.map do |_, return_items|
|
53
|
+
first_return_item = return_items.first
|
54
|
+
{
|
55
|
+
refund_line_item_id: first_return_item.id,
|
56
|
+
order_line_item_id: first_return_item.inventory_unit.line_item.id,
|
57
|
+
refunded_amount_per_item: first_return_item.amount.to_f,
|
58
|
+
units: return_items.size
|
59
|
+
}
|
60
|
+
end,
|
61
|
+
transactions: [
|
62
|
+
id: refunder.reimbursement.id,
|
63
|
+
amount: refunder.reimbursement.total
|
64
|
+
]
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
private_class_method def self.refunds_by_payment(order)
|
69
|
+
order.payments.each_with_object([]) do |payment, payments|
|
70
|
+
payments << {
|
71
|
+
code: payment.source_type.constantize.model_name.human,
|
72
|
+
amount: (order.item_total + order.adjustment_total).to_f,
|
73
|
+
original_transaction_id: ''
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Returnly
|
2
|
+
class Refunder
|
3
|
+
include Returnly::RefundsConfiguration
|
4
|
+
|
5
|
+
attr_accessor :order,
|
6
|
+
:line_items,
|
7
|
+
:product_refund_amount,
|
8
|
+
:shipping_refund_amount,
|
9
|
+
:customer_return,
|
10
|
+
:return_item_amount_calculator,
|
11
|
+
:return_item_restock_policy,
|
12
|
+
:refund_calculator
|
13
|
+
|
14
|
+
def initialize(order:, line_items:, product_refund_amount:, shipping_refund_amount:)
|
15
|
+
self.order = order
|
16
|
+
self.line_items = line_items
|
17
|
+
self.customer_return = Spree::CustomerReturn.new customer_return_params
|
18
|
+
self.product_refund_amount = product_refund_amount
|
19
|
+
self.shipping_refund_amount = shipping_refund_amount
|
20
|
+
|
21
|
+
configure
|
22
|
+
end
|
23
|
+
|
24
|
+
def process_return_items
|
25
|
+
each_return_item do |return_item|
|
26
|
+
return_item.amount = return_item_amount_calculator.return_item_refund_amount return_item
|
27
|
+
return_item.resellable = return_item_restock_policy.should_return_item? return_item
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def proceed!
|
32
|
+
process_return_items
|
33
|
+
|
34
|
+
if customer_return.save!
|
35
|
+
perform_reimbursement
|
36
|
+
RefundPresenter.present_refund(self)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def refund_available_amount
|
41
|
+
@available_amount ||= Money.from_amount(product_refund_amount.to_f + shipping_refund_amount.to_f)
|
42
|
+
end
|
43
|
+
|
44
|
+
def refund_amount_per_item
|
45
|
+
refund_available_amount / line_items.size
|
46
|
+
end
|
47
|
+
|
48
|
+
def reimbursement
|
49
|
+
@_reimbursement ||= Spree::Reimbursement.build_from_customer_return(customer_return)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def configure
|
55
|
+
self.return_item_amount_calculator = return_item_amount_calculator_class.new(self)
|
56
|
+
self.return_item_restock_policy = return_item_restock_policy_class.new(self)
|
57
|
+
self.refund_calculator = refund_calculator_class.new(order, line_items)
|
58
|
+
end
|
59
|
+
|
60
|
+
def perform_reimbursement
|
61
|
+
reimbursement.save!
|
62
|
+
reimbursement.perform!
|
63
|
+
end
|
64
|
+
|
65
|
+
def each_return_item
|
66
|
+
customer_return.return_items = refund_calculator.line_items_return_items.values.flatten
|
67
|
+
customer_return.return_items.each do |return_item|
|
68
|
+
yield return_item
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def customer_return_params
|
73
|
+
{
|
74
|
+
stock_location_id: stock_location_id
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def stock_location_id
|
79
|
+
order.shipments.last.stock_location.id
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Returnly
|
2
|
+
module RefundsConfiguration
|
3
|
+
def return_item_amount_calculator_class
|
4
|
+
Returnly.return_item_amount_calculator || Returnly::Refund::AmountCalculator
|
5
|
+
end
|
6
|
+
|
7
|
+
# return item qualifies to be restocked (after refund)
|
8
|
+
def return_item_restock_policy_class
|
9
|
+
Returnly.return_item_restock_policy || Returnly::Refund::ReturnItemRestockPolicy
|
10
|
+
end
|
11
|
+
|
12
|
+
def refunder_class
|
13
|
+
Returnly.refunder || Returnly::Refunder
|
14
|
+
end
|
15
|
+
|
16
|
+
def refund_calculator_class
|
17
|
+
Returnly.refund_calculator || Returnly::RefundCalculator
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/solidus-returnly.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
require '
|
1
|
+
require 'spree_core'
|
2
|
+
require 'returnly'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
4
|
+
module Returnly
|
5
|
+
def self.is_solidus?
|
6
|
+
true
|
7
|
+
end
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
require 'solidus/returnly/refund_calculator'
|
12
|
-
require 'solidus/returnly/refund_presenter'
|
9
|
+
def self.platform_version
|
10
|
+
Spree.solidus_version
|
11
|
+
end
|
12
|
+
end
|
metadata
CHANGED
@@ -1,57 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solidus-returnly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0.pre
|
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-08-
|
11
|
+
date: 2017-08-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: solidus_auth_devise
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: solidus
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
16
30
|
requirements:
|
17
31
|
- - "~>"
|
18
32
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
33
|
+
version: 2.0.0
|
20
34
|
type: :runtime
|
21
35
|
prerelease: false
|
22
36
|
version_requirements: !ruby/object:Gem::Requirement
|
23
37
|
requirements:
|
24
38
|
- - "~>"
|
25
39
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
40
|
+
version: 2.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 5.0.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 5.0.0
|
27
55
|
- !ruby/object:Gem::Dependency
|
28
56
|
name: solidus_core
|
29
57
|
requirement: !ruby/object:Gem::Requirement
|
30
58
|
requirements:
|
31
59
|
- - "~>"
|
32
60
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
61
|
+
version: 2.0.0
|
34
62
|
type: :runtime
|
35
63
|
prerelease: false
|
36
64
|
version_requirements: !ruby/object:Gem::Requirement
|
37
65
|
requirements:
|
38
66
|
- - "~>"
|
39
67
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
68
|
+
version: 2.0.0
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: solidus_api
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
44
72
|
requirements:
|
45
73
|
- - "~>"
|
46
74
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
75
|
+
version: 2.0.0
|
48
76
|
type: :runtime
|
49
77
|
prerelease: false
|
50
78
|
version_requirements: !ruby/object:Gem::Requirement
|
51
79
|
requirements:
|
52
80
|
- - "~>"
|
53
81
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
82
|
+
version: 2.0.0
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: capybara
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,6 +94,34 @@ dependencies:
|
|
66
94
|
- - ">="
|
67
95
|
- !ruby/object:Gem::Version
|
68
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: erubis
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: minitest
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
69
125
|
- !ruby/object:Gem::Dependency
|
70
126
|
name: awesome_print
|
71
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -274,19 +330,21 @@ files:
|
|
274
330
|
- app/controllers/spree/api/returnly/api_controller.rb
|
275
331
|
- app/controllers/spree/api/returnly/refunds_controller.rb
|
276
332
|
- app/controllers/spree/api/returnly/version_controller.rb
|
333
|
+
- app/models/spree/return_item_decorator.rb
|
277
334
|
- config/locales/en.yml
|
278
335
|
- config/routes.rb
|
279
|
-
- lib/
|
336
|
+
- lib/returnly.rb
|
337
|
+
- lib/returnly/engine.rb
|
338
|
+
- lib/returnly/factories.rb
|
339
|
+
- lib/returnly/refund/amount_calculator.rb
|
340
|
+
- lib/returnly/refund/return_item_restock_policy.rb
|
341
|
+
- lib/returnly/refund_calculator.rb
|
342
|
+
- lib/returnly/refund_presenter.rb
|
343
|
+
- lib/returnly/refunder.rb
|
344
|
+
- lib/returnly/refunds_configuration.rb
|
345
|
+
- lib/returnly/version.rb
|
280
346
|
- lib/solidus-returnly.rb
|
281
|
-
- lib/
|
282
|
-
- lib/solidus/returnly/factories.rb
|
283
|
-
- lib/solidus/returnly/refund/amount_calculator.rb
|
284
|
-
- lib/solidus/returnly/refund/return_item_restock_policy.rb
|
285
|
-
- lib/solidus/returnly/refund_calculator.rb
|
286
|
-
- lib/solidus/returnly/refund_presenter.rb
|
287
|
-
- lib/solidus/returnly/refunder.rb
|
288
|
-
- lib/solidus/returnly/refunds_configuration.rb
|
289
|
-
- lib/solidus/returnly/version.rb
|
347
|
+
- lib/spree-returnly.rb
|
290
348
|
homepage: https://github.com/returnly/solidus-returnly
|
291
349
|
licenses:
|
292
350
|
- MIT
|
@@ -302,9 +360,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
302
360
|
version: '0'
|
303
361
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
304
362
|
requirements:
|
305
|
-
- - "
|
363
|
+
- - ">"
|
306
364
|
- !ruby/object:Gem::Version
|
307
|
-
version:
|
365
|
+
version: 1.3.1
|
308
366
|
requirements: []
|
309
367
|
rubyforge_project:
|
310
368
|
rubygems_version: 2.6.11
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module SolidusReturnly
|
2
|
-
module Generators
|
3
|
-
class InstallGenerator < Rails::Generators::Base
|
4
|
-
class_option :auto_run_migrations, type: :boolean, default: false
|
5
|
-
|
6
|
-
def add_javascripts
|
7
|
-
end
|
8
|
-
|
9
|
-
def add_stylesheets
|
10
|
-
end
|
11
|
-
|
12
|
-
def add_migrations
|
13
|
-
end
|
14
|
-
|
15
|
-
def run_migrations
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
module Solidus
|
2
|
-
module Returnly
|
3
|
-
class << self
|
4
|
-
mattr_accessor :return_item_amount_calculator,
|
5
|
-
:return_item_restock_policy,
|
6
|
-
:refunder,
|
7
|
-
:refund_calculator
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.configure(&block)
|
11
|
-
yield self if block
|
12
|
-
end
|
13
|
-
|
14
|
-
class Engine < Rails::Engine
|
15
|
-
require 'spree/core'
|
16
|
-
|
17
|
-
engine_name 'returnly'
|
18
|
-
|
19
|
-
config.autoload_paths += %W(#{config.root}/lib)
|
20
|
-
|
21
|
-
# use rspec for tests
|
22
|
-
config.generators do |g|
|
23
|
-
g.test_framework :rspec
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.activate
|
27
|
-
Dir.glob(File.join(File.dirname(__FILE__), '../../app/**/*_decorator*.rb')) do |c|
|
28
|
-
Rails.configuration.cache_classes ? require(c) : load(c)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
config.to_prepare(&method(:activate).to_proc)
|
33
|
-
|
34
|
-
rake_tasks do
|
35
|
-
namespace :returnly do
|
36
|
-
require 'securerandom'
|
37
|
-
|
38
|
-
desc "Creates an returnly user and prints the generated API key"
|
39
|
-
task install_user: :environment do
|
40
|
-
|
41
|
-
returnly_email = 'api@returnly.com'
|
42
|
-
|
43
|
-
password = SecureRandom.hex(24)
|
44
|
-
|
45
|
-
if (user = Spree::User.find_by email: returnly_email)
|
46
|
-
puts "The Returnly User is already generated"
|
47
|
-
puts "The Api key is: #{user.spree_api_key}"
|
48
|
-
else
|
49
|
-
user = Spree::User.new email: returnly_email, password: password,
|
50
|
-
password_confirmation: password
|
51
|
-
|
52
|
-
api_key = user.generate_spree_api_key
|
53
|
-
|
54
|
-
if user.save!
|
55
|
-
puts "****************************************************"
|
56
|
-
puts "Api key Generated #{api_key}"
|
57
|
-
puts "Returnly User Password #{password}"
|
58
|
-
puts "Returnly User email #{returnly_email}"
|
59
|
-
puts "****************************************************"
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module Solidus
|
2
|
-
module Returnly
|
3
|
-
module Refund
|
4
|
-
class AmountCalculator
|
5
|
-
attr_accessor :refund
|
6
|
-
|
7
|
-
def initialize(refund)
|
8
|
-
self.refund = refund
|
9
|
-
end
|
10
|
-
|
11
|
-
def return_item_refund_amount(return_item)
|
12
|
-
default_amount(return_item)
|
13
|
-
end
|
14
|
-
|
15
|
-
protected
|
16
|
-
def default_amount(return_item)
|
17
|
-
refund.refund_amount_per_item -
|
18
|
-
Money.from_amount(return_item.total - return_item.pre_tax_amount)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module Solidus
|
2
|
-
module Returnly
|
3
|
-
module Refund
|
4
|
-
class ReturnItemRestockPolicy
|
5
|
-
attr_accessor :refund
|
6
|
-
|
7
|
-
def initialize(refund)
|
8
|
-
self.refund = refund
|
9
|
-
end
|
10
|
-
|
11
|
-
#
|
12
|
-
def should_return_item?(_)
|
13
|
-
refund.restock
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,87 +0,0 @@
|
|
1
|
-
module Solidus
|
2
|
-
module Returnly
|
3
|
-
class RefundCalculator
|
4
|
-
attr_accessor :line_items, :order
|
5
|
-
|
6
|
-
def self.process(order, line_items)
|
7
|
-
RefundPresenter.present_estimate new(order, line_items)
|
8
|
-
end
|
9
|
-
|
10
|
-
def initialize(order, line_items)
|
11
|
-
self.line_items = line_items
|
12
|
-
self.order = order
|
13
|
-
end
|
14
|
-
|
15
|
-
def set_tax(return_item)
|
16
|
-
percent_of_tax = (return_item.amount <= 0) ? 0 : return_item.amount /
|
17
|
-
Spree::ReturnItem.refund_amount_calculator.new.compute(return_item)
|
18
|
-
|
19
|
-
additional_tax_total = percent_of_tax * return_item.inventory_unit.additional_tax_total
|
20
|
-
included_tax_total = percent_of_tax * return_item.inventory_unit.included_tax_total
|
21
|
-
|
22
|
-
return_item.additional_tax_total = additional_tax_total
|
23
|
-
return_item.included_tax_total = included_tax_total
|
24
|
-
|
25
|
-
return_item
|
26
|
-
end
|
27
|
-
|
28
|
-
def line_items_return_items
|
29
|
-
found_return_items = {}
|
30
|
-
|
31
|
-
line_items.each do |line_item|
|
32
|
-
with_available_inventory_units line_item do |inventory_unit, quantity|
|
33
|
-
next unless quantity > 0
|
34
|
-
|
35
|
-
found_return_items[line_item[:order_line_item_id]] ||= []
|
36
|
-
return_item = create_return_item(inventory_unit)
|
37
|
-
found_return_items[line_item[:order_line_item_id]] << set_tax(return_item)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
found_return_items
|
42
|
-
end
|
43
|
-
|
44
|
-
def line_item_inventory_unit(line_item)
|
45
|
-
returnable_inventory_units.select { |iu| iu.line_item_id == line_item[:order_line_item_id].to_i }
|
46
|
-
end
|
47
|
-
|
48
|
-
def line_item(id)
|
49
|
-
returnable_line_items.find { |i| i.id == id.to_i }
|
50
|
-
end
|
51
|
-
|
52
|
-
def returnable_inventory_units
|
53
|
-
@_inventory_units ||= order.inventory_units.includes(:line_item)
|
54
|
-
.where(line_item_id: requested_line_items)
|
55
|
-
.where('state != ?', 'returned')
|
56
|
-
end
|
57
|
-
|
58
|
-
def returnable_line_items
|
59
|
-
@_line_items ||= returnable_inventory_units.map(&:line_item)
|
60
|
-
end
|
61
|
-
|
62
|
-
def requested_line_items
|
63
|
-
line_items.map { |item| item[:order_line_item_id] }
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
protected
|
68
|
-
|
69
|
-
def create_return_item(inventory_unit)
|
70
|
-
Spree::ReturnItem.new({ amount: inventory_unit.line_item.price,
|
71
|
-
acceptance_status: 'accepted',
|
72
|
-
inventory_unit_id: inventory_unit.id,
|
73
|
-
reception_status_event: 'receive'
|
74
|
-
})
|
75
|
-
end
|
76
|
-
|
77
|
-
def with_available_inventory_units(line_item)
|
78
|
-
quantity = line_item[:quantity].to_i
|
79
|
-
|
80
|
-
available_inventory_units = line_item_inventory_unit(line_item).slice(0, quantity)
|
81
|
-
available_inventory_units.each do |inventory_unit|
|
82
|
-
yield inventory_unit, quantity
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
@@ -1,73 +0,0 @@
|
|
1
|
-
module Solidus
|
2
|
-
module Returnly
|
3
|
-
class RefundPresenter
|
4
|
-
|
5
|
-
def self.present_estimate(calculator)
|
6
|
-
total = Money.new 0
|
7
|
-
sub_total = Money.new 0
|
8
|
-
|
9
|
-
calculator.line_items_return_items.values.flatten.each do |return_item|
|
10
|
-
total += Money.from_amount return_item.total
|
11
|
-
sub_total += Money.from_amount return_item.pre_tax_amount
|
12
|
-
end
|
13
|
-
|
14
|
-
{
|
15
|
-
total_amount: total.to_f,
|
16
|
-
subtotal_amount: sub_total.to_f,
|
17
|
-
tax_amount: (total - sub_total).to_f,
|
18
|
-
discount_amount: calculator.order.promo_total.to_f,
|
19
|
-
shipping_amount: calculator.order.shipment_total.to_f,
|
20
|
-
line_items: present_line_items(calculator)
|
21
|
-
}
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
|
-
def self.present_line_items(calculator)
|
26
|
-
calculator.line_items_return_items.values.map do |return_items|
|
27
|
-
line_item = return_items.first.inventory_unit.line_item
|
28
|
-
|
29
|
-
total_amount = 0.0
|
30
|
-
sub_total = 0.0
|
31
|
-
|
32
|
-
return_items.each do |return_item|
|
33
|
-
total_amount += return_item.total
|
34
|
-
sub_total += return_item.pre_tax_amount
|
35
|
-
end
|
36
|
-
|
37
|
-
{
|
38
|
-
order_line_item_id: line_item.id,
|
39
|
-
quantity: return_items.size,
|
40
|
-
total_amount: total_amount.to_f,
|
41
|
-
tax_amount: (total_amount - sub_total).to_f
|
42
|
-
}
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
|
47
|
-
def self.present_refund(refunder)
|
48
|
-
customer_return = refunder.customer_return
|
49
|
-
|
50
|
-
{
|
51
|
-
refund_id: customer_return.number,
|
52
|
-
created_at: customer_return.created_at,
|
53
|
-
updated_at: customer_return.updated_at,
|
54
|
-
line_items: customer_return.return_items.group_by{ |ri| ri.inventory_unit.line_item.id }.map do |_, return_items|
|
55
|
-
first_return_item = return_items.first
|
56
|
-
{
|
57
|
-
refund_line_item_id: first_return_item.id,
|
58
|
-
order_line_item_id: first_return_item.inventory_unit.line_item.id,
|
59
|
-
refunded_amount_per_item: first_return_item.amount.to_f,
|
60
|
-
total_refunded_per_line_item: return_items.sum(&:amount).to_f,
|
61
|
-
quantity: return_items.size
|
62
|
-
}
|
63
|
-
end,
|
64
|
-
transactions: [
|
65
|
-
id: refunder.reimbursement.id,
|
66
|
-
amount: refunder.reimbursement.total
|
67
|
-
],
|
68
|
-
restock: refunder.restock
|
69
|
-
}
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
@@ -1,84 +0,0 @@
|
|
1
|
-
module Solidus
|
2
|
-
module Returnly
|
3
|
-
class Refunder
|
4
|
-
include Solidus::Returnly::RefundsConfiguration
|
5
|
-
|
6
|
-
attr_accessor :order,
|
7
|
-
:line_items,
|
8
|
-
:restock,
|
9
|
-
:transactions,
|
10
|
-
:customer_return,
|
11
|
-
:return_item_amount_calculator,
|
12
|
-
:return_item_restock_policy,
|
13
|
-
:refund_calculator
|
14
|
-
|
15
|
-
def initialize(order:, line_items:, restock:, transactions:)
|
16
|
-
self.order = order
|
17
|
-
self.line_items = line_items
|
18
|
-
self.customer_return = Spree::CustomerReturn.new customer_return_params
|
19
|
-
self.transactions = transactions
|
20
|
-
self.restock = restock
|
21
|
-
|
22
|
-
configure
|
23
|
-
end
|
24
|
-
|
25
|
-
def process_return_items
|
26
|
-
each_return_item do |return_item|
|
27
|
-
return_item.amount = return_item_amount_calculator.return_item_refund_amount return_item
|
28
|
-
return_item.resellable = return_item_restock_policy.should_return_item? return_item
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def proceed!
|
33
|
-
process_return_items
|
34
|
-
|
35
|
-
if customer_return.save!
|
36
|
-
perform_reimbursement
|
37
|
-
RefundPresenter.present_refund(self)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def refund_available_amount
|
42
|
-
@available_amount ||= transactions.sum { |t| Money.from_amount(t[:amount].to_f) }
|
43
|
-
end
|
44
|
-
|
45
|
-
def refund_amount_per_item
|
46
|
-
refund_available_amount / line_items.size
|
47
|
-
end
|
48
|
-
|
49
|
-
def reimbursement
|
50
|
-
@_reimbursement ||= Spree::Reimbursement.build_from_customer_return(customer_return)
|
51
|
-
end
|
52
|
-
|
53
|
-
private
|
54
|
-
|
55
|
-
def configure
|
56
|
-
self.return_item_amount_calculator = return_item_amount_calculator_class.new(self)
|
57
|
-
self.return_item_restock_policy = return_item_restock_policy_class.new(self)
|
58
|
-
self.refund_calculator = refund_calculator_class.new(order, line_items)
|
59
|
-
end
|
60
|
-
|
61
|
-
def perform_reimbursement
|
62
|
-
reimbursement.save!
|
63
|
-
reimbursement.perform!
|
64
|
-
end
|
65
|
-
|
66
|
-
def each_return_item
|
67
|
-
customer_return.return_items = refund_calculator.line_items_return_items.values.flatten
|
68
|
-
customer_return.return_items.each do |return_item|
|
69
|
-
yield return_item
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def customer_return_params
|
74
|
-
{
|
75
|
-
stock_location_id: stock_location_id
|
76
|
-
}
|
77
|
-
end
|
78
|
-
|
79
|
-
def stock_location_id
|
80
|
-
order.shipments.last.stock_location.id
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module Solidus
|
2
|
-
module Returnly
|
3
|
-
module RefundsConfiguration
|
4
|
-
def return_item_amount_calculator_class
|
5
|
-
Solidus::Returnly.return_item_amount_calculator || Solidus::Returnly::Refund::AmountCalculator
|
6
|
-
end
|
7
|
-
|
8
|
-
# return item qualifies to be restocked (after refund)
|
9
|
-
def return_item_restock_policy_class
|
10
|
-
Solidus::Returnly.return_item_restock_policy || Solidus::Returnly::Refund::ReturnItemRestockPolicy
|
11
|
-
end
|
12
|
-
|
13
|
-
def refunder_class
|
14
|
-
Solidus::Returnly.refunder || Solidus::Returnly::Refunder
|
15
|
-
end
|
16
|
-
|
17
|
-
def refund_calculator_class
|
18
|
-
Solidus::Returnly.refund_calculator || Solidus::Returnly::RefundCalculator
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|