solidus-returnly 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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
|