solidus-returnly 0.4.3 → 0.5.0.pre
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/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
|