solidus-returnly 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/spree/api/returnly/refunds_controller.rb +7 -5
- data/lib/solidus/returnly/engine.rb +11 -0
- data/lib/solidus/returnly/refund/amount_calculator.rb +17 -0
- data/lib/solidus/returnly/refund/return_item_restock_policy.rb +18 -0
- data/lib/solidus/returnly/{calculator.rb → refund_calculator.rb} +25 -54
- data/lib/solidus/returnly/refund_presenter.rb +73 -0
- data/lib/solidus/returnly/refunder.rb +84 -0
- data/lib/solidus/returnly/refunds_configuration.rb +22 -0
- data/lib/solidus/returnly/version.rb +1 -1
- data/lib/solidus-returnly.rb +4 -2
- metadata +22 -4
- data/lib/solidus/returnly/refunds.rb +0 -79
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c766335abec60d67ec8b8cdd47f0f625298ccfc9
|
4
|
+
data.tar.gz: f10c5c2093ca06bba6968c36f95631805207fded
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 716c5b3aa3d8e4021f7df14f7bd8405b8fcee690324ce7b2c91f04a20b3d43e9620f0ed79761f870fd6f50f49a374d6bffdc8b01ab2aa284076437e587d5d7f9
|
7
|
+
data.tar.gz: 0dea426fb3dc4a023113a43506d9524326678234c807c6da8e3e9b5719194afe01019843d1f92a35d288617825f88a862df7577e2a66673f3d33f359f72f4d6b
|
@@ -2,18 +2,20 @@ module Spree
|
|
2
2
|
module Api
|
3
3
|
module Returnly
|
4
4
|
class RefundsController < ApiController
|
5
|
+
include Solidus::Returnly::RefundsConfiguration
|
6
|
+
|
5
7
|
def estimate
|
6
8
|
authorize! :create, Order
|
7
|
-
render json:
|
9
|
+
render json: refund_calculator_class.process(order, line_items_params)
|
8
10
|
end
|
9
11
|
|
10
12
|
def create
|
11
13
|
authorize! :create, Order
|
12
14
|
|
13
|
-
refunds =
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
refunds = refunder_class.new order: order,
|
16
|
+
line_items: line_items_params,
|
17
|
+
restock: refund_restock_param,
|
18
|
+
transactions: transactions_params
|
17
19
|
render json: refunds.proceed!
|
18
20
|
end
|
19
21
|
|
@@ -1,5 +1,16 @@
|
|
1
1
|
module Solidus
|
2
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
|
+
|
3
14
|
class Engine < Rails::Engine
|
4
15
|
require 'spree/core'
|
5
16
|
|
@@ -0,0 +1,17 @@
|
|
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
|
+
refund.refund_amount_per_item - Money.from_amount(return_item.total - return_item.pre_tax_amount)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
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,10 +1,10 @@
|
|
1
1
|
module Solidus
|
2
2
|
module Returnly
|
3
|
-
class
|
3
|
+
class RefundCalculator
|
4
4
|
attr_accessor :line_items, :order
|
5
5
|
|
6
6
|
def self.process(order, line_items)
|
7
|
-
new(order, line_items)
|
7
|
+
RefundPresenter.present_estimate new(order, line_items)
|
8
8
|
end
|
9
9
|
|
10
10
|
def initialize(order, line_items)
|
@@ -12,46 +12,6 @@ module Solidus
|
|
12
12
|
self.order = order
|
13
13
|
end
|
14
14
|
|
15
|
-
def calculated_estimate
|
16
|
-
total = 0.0
|
17
|
-
sub_total = 0.0
|
18
|
-
|
19
|
-
line_items_return_items.values.flatten.each do |return_item|
|
20
|
-
total += return_item.total
|
21
|
-
sub_total += return_item.pre_tax_amount
|
22
|
-
end
|
23
|
-
|
24
|
-
{
|
25
|
-
total_amount: total,
|
26
|
-
subtotal_amount: sub_total,
|
27
|
-
tax_amount: total - sub_total,
|
28
|
-
discount_amount: order.promo_total,
|
29
|
-
shipping_amount: order.shipment_total,
|
30
|
-
line_items: present_line_items
|
31
|
-
}
|
32
|
-
end
|
33
|
-
|
34
|
-
def present_line_items
|
35
|
-
line_items_return_items.values.map do |return_items|
|
36
|
-
line_item = return_items.first.inventory_unit.line_item
|
37
|
-
|
38
|
-
total_amount = 0.0
|
39
|
-
sub_total = 0.0
|
40
|
-
|
41
|
-
return_items.each do |return_item|
|
42
|
-
total_amount += return_item.total
|
43
|
-
sub_total += return_item.pre_tax_amount
|
44
|
-
end
|
45
|
-
|
46
|
-
{
|
47
|
-
order_line_item_id: line_item.id,
|
48
|
-
quantity: return_items.size,
|
49
|
-
total_amount: total_amount,
|
50
|
-
tax_amount: total_amount - sub_total
|
51
|
-
}
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
15
|
def set_tax(return_item)
|
56
16
|
percent_of_tax = (return_item.amount <= 0) ? 0 : return_item.amount /
|
57
17
|
Spree::ReturnItem.refund_amount_calculator.new.compute(return_item)
|
@@ -69,20 +29,11 @@ module Solidus
|
|
69
29
|
found_return_items = {}
|
70
30
|
|
71
31
|
line_items.each do |line_item|
|
72
|
-
|
32
|
+
with_available_inventory_units line_item do |inventory_unit, quantity|
|
33
|
+
next unless quantity > 0
|
73
34
|
|
74
|
-
next unless quantity > 0
|
75
|
-
available_inventory_units = line_item_inventory_unit(line_item).slice(0, quantity)
|
76
|
-
|
77
|
-
available_inventory_units.each do |inventory_unit|
|
78
35
|
found_return_items[line_item[:order_line_item_id]] ||= []
|
79
|
-
|
80
|
-
return_item = Spree::ReturnItem.new({ amount: inventory_unit.line_item.price,
|
81
|
-
acceptance_status: 'accepted',
|
82
|
-
inventory_unit_id: inventory_unit.id,
|
83
|
-
reception_status_event: 'receive'
|
84
|
-
})
|
85
|
-
|
36
|
+
return_item = create_return_item(inventory_unit)
|
86
37
|
found_return_items[line_item[:order_line_item_id]] << set_tax(return_item)
|
87
38
|
end
|
88
39
|
end
|
@@ -111,6 +62,26 @@ module Solidus
|
|
111
62
|
def requested_line_items
|
112
63
|
line_items.map { |item| item[:order_line_item_id] }
|
113
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
|
114
85
|
end
|
115
86
|
end
|
116
87
|
end
|
@@ -0,0 +1,73 @@
|
|
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
|
@@ -0,0 +1,84 @@
|
|
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
|
@@ -0,0 +1,22 @@
|
|
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
|
data/lib/solidus-returnly.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'solidus_core'
|
2
2
|
|
3
3
|
require 'solidus/returnly/engine'
|
4
|
-
require 'solidus/returnly/
|
5
|
-
|
4
|
+
require 'solidus/returnly/refunds_configuration'
|
5
|
+
|
6
|
+
require 'solidus/returnly/refunder'
|
7
|
+
require 'solidus/returnly/refund_calculator'
|
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.
|
4
|
+
version: 0.4.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-
|
11
|
+
date: 2017-06-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: solidus
|
@@ -248,6 +248,20 @@ dependencies:
|
|
248
248
|
- - ">="
|
249
249
|
- !ruby/object:Gem::Version
|
250
250
|
version: '0'
|
251
|
+
- !ruby/object:Gem::Dependency
|
252
|
+
name: yard
|
253
|
+
requirement: !ruby/object:Gem::Requirement
|
254
|
+
requirements:
|
255
|
+
- - ">="
|
256
|
+
- !ruby/object:Gem::Version
|
257
|
+
version: '0'
|
258
|
+
type: :development
|
259
|
+
prerelease: false
|
260
|
+
version_requirements: !ruby/object:Gem::Requirement
|
261
|
+
requirements:
|
262
|
+
- - ">="
|
263
|
+
- !ruby/object:Gem::Version
|
264
|
+
version: '0'
|
251
265
|
description: Solidus API extensions for returnly
|
252
266
|
email: support@returnly.com
|
253
267
|
executables: []
|
@@ -264,10 +278,14 @@ files:
|
|
264
278
|
- config/routes.rb
|
265
279
|
- lib/generators/solidus_returnly/install/install_generator.rb
|
266
280
|
- lib/solidus-returnly.rb
|
267
|
-
- lib/solidus/returnly/calculator.rb
|
268
281
|
- lib/solidus/returnly/engine.rb
|
269
282
|
- lib/solidus/returnly/factories.rb
|
270
|
-
- lib/solidus/returnly/
|
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
|
271
289
|
- lib/solidus/returnly/version.rb
|
272
290
|
homepage: https://github.com/returnly/solidus-returnly
|
273
291
|
licenses:
|
@@ -1,79 +0,0 @@
|
|
1
|
-
module Solidus
|
2
|
-
module Returnly
|
3
|
-
class Refunds
|
4
|
-
attr_accessor :calculator, :order, :line_items, :restock, :transactions, :customer_return
|
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
|
-
self.customer_return = Spree::CustomerReturn.new customer_return_params
|
13
|
-
end
|
14
|
-
|
15
|
-
def proceed!
|
16
|
-
customer_return.return_items = calculator.line_items_return_items.values.flatten
|
17
|
-
|
18
|
-
customer_return.return_items.each do |return_item|
|
19
|
-
return_item.amount = refund_amount_per_item - Money.from_amount(return_item.total - return_item.pre_tax_amount)
|
20
|
-
return_item.resellable = restock
|
21
|
-
end
|
22
|
-
|
23
|
-
if customer_return.save!
|
24
|
-
perform_reimbursement
|
25
|
-
processed_customer_return(customer_return, reimbursement)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def processed_customer_return(customer_return, reimbursement)
|
30
|
-
{
|
31
|
-
refund_id: customer_return.number,
|
32
|
-
created_at: customer_return.created_at,
|
33
|
-
updated_at: customer_return.updated_at,
|
34
|
-
line_items: customer_return.return_items.group_by{ |ri| ri.inventory_unit.line_item.id }.map {|_, return_items|
|
35
|
-
{
|
36
|
-
refund_line_item_id: return_items.first.id,
|
37
|
-
order_line_item_id: return_items.first.inventory_unit.line_item.id,
|
38
|
-
refunded_amount_per_item: return_items.first.amount.to_f,
|
39
|
-
total_refunded_per_line_item: return_items.sum(&:amount).to_f,
|
40
|
-
quantity: return_items.size
|
41
|
-
}
|
42
|
-
},
|
43
|
-
transactions: [
|
44
|
-
id: reimbursement.id,
|
45
|
-
amount: reimbursement.total
|
46
|
-
],
|
47
|
-
restock: restock
|
48
|
-
}
|
49
|
-
end
|
50
|
-
|
51
|
-
def perform_reimbursement
|
52
|
-
reimbursement.save!
|
53
|
-
reimbursement.perform!
|
54
|
-
end
|
55
|
-
|
56
|
-
def reimbursement
|
57
|
-
@_reimbursement ||= Spree::Reimbursement.build_from_customer_return(customer_return)
|
58
|
-
end
|
59
|
-
|
60
|
-
def customer_return_params
|
61
|
-
{
|
62
|
-
stock_location_id: stock_location_id
|
63
|
-
}
|
64
|
-
end
|
65
|
-
|
66
|
-
def stock_location_id
|
67
|
-
order.shipments.last.stock_location.id
|
68
|
-
end
|
69
|
-
|
70
|
-
def refund_available_amount
|
71
|
-
@available_amount ||= transactions.sum { |t| Money.from_amount(t[:amount].to_f) }
|
72
|
-
end
|
73
|
-
|
74
|
-
def refund_amount_per_item
|
75
|
-
refund_available_amount / line_items.size
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|