-
-
Notifications
You must be signed in to change notification settings - Fork 708
/
enterprise_fee_calculator.rb
147 lines (117 loc) · 4.87 KB
/
enterprise_fee_calculator.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# frozen_string_literal: true
require 'open_food_network/enterprise_fee_applicator'
module OpenFoodNetwork
class EnterpriseFeeCalculator
def initialize(distributor = nil, order_cycle = nil)
@distributor = distributor
@order_cycle = order_cycle
end
def indexed_fees_for(variant)
load_enterprise_fees unless @indexed_enterprise_fees
indexed_enterprise_fees_for(variant).sum do |enterprise_fee|
calculate_fee_for variant, enterprise_fee
end
end
def indexed_fees_by_type_for(variant)
load_enterprise_fees unless @indexed_enterprise_fees
indexed_enterprise_fees_for(variant).each_with_object({}) do |enterprise_fee, fees|
fees[enterprise_fee.fee_type.to_sym] ||= 0
fees[enterprise_fee.fee_type.to_sym] += calculate_fee_for variant, enterprise_fee
end.select { |_fee_type, amount| amount > 0 }
end
def fees_for(variant)
per_item_enterprise_fee_applicators_for(variant).sum do |applicator|
calculate_fee_for variant, applicator.enterprise_fee
end
end
def fees_by_type_for(variant)
per_item_enterprise_fee_applicators_for(variant).each_with_object({}) do |applicator, fees|
fees[applicator.enterprise_fee.fee_type.to_sym] ||= 0
fees[applicator.enterprise_fee.fee_type.to_sym] +=
calculate_fee_for variant, applicator.enterprise_fee
end.select { |_fee_type, amount| amount > 0 }
end
def fees_name_by_type_for(variant)
per_item_enterprise_fee_applicators_for(variant).each_with_object({}) do |applicator, fees|
fees[applicator.enterprise_fee.fee_type.to_sym] = applicator.enterprise_fee.name
end
end
def create_line_item_adjustments_for(line_item)
variant = line_item.variant
per_item_enterprise_fee_applicators_for(variant).each do |applicator|
applicator.create_line_item_adjustment(line_item)
end
end
def create_order_adjustments_for(order)
per_order_enterprise_fee_applicators_for(order).each do |applicator|
applicator.create_order_adjustment(order)
end
end
def per_item_enterprise_fee_applicators_for(variant)
fees = []
return [] unless @order_cycle && @distributor
@order_cycle.exchanges_carrying(variant, @distributor).each do |exchange|
exchange.enterprise_fees.per_item.each do |enterprise_fee|
fees << OpenFoodNetwork::EnterpriseFeeApplicator.new(enterprise_fee, variant,
exchange.role)
end
end
@order_cycle.coordinator_fees.per_item.each do |enterprise_fee|
fees << OpenFoodNetwork::EnterpriseFeeApplicator.new(enterprise_fee, variant, 'coordinator')
end
fees
end
def per_order_enterprise_fee_applicators_for(order)
fees = []
return fees unless @order_cycle && order.distributor
@order_cycle.exchanges_supplying(order).each do |exchange|
exchange.enterprise_fees.per_order.each do |enterprise_fee|
fees << OpenFoodNetwork::EnterpriseFeeApplicator.new(enterprise_fee, nil, exchange.role)
end
end
@order_cycle.coordinator_fees.per_order.each do |enterprise_fee|
fees << OpenFoodNetwork::EnterpriseFeeApplicator.new(enterprise_fee, nil, 'coordinator')
end
fees
end
private
def load_enterprise_fees
@indexed_enterprise_fees = {}
exchange_fees = per_item_enterprise_fees_with_exchange_details
load_exchange_fees exchange_fees
load_coordinator_fees
end
def per_item_enterprise_fees_with_exchange_details
EnterpriseFee.
per_item.
joins(exchanges: :exchange_variants).
where(exchanges: { order_cycle_id: @order_cycle.id }).
merge(Exchange.supplying_to(@distributor)).
select('enterprise_fees.*, exchange_variants.variant_id AS variant_id')
end
def load_exchange_fees(exchange_fees)
exchange_fees.each do |enterprise_fee|
@indexed_enterprise_fees[enterprise_fee.variant_id.to_i] ||= []
@indexed_enterprise_fees[enterprise_fee.variant_id.to_i] << enterprise_fee
end
end
def load_coordinator_fees
@order_cycle.coordinator_fees.per_item.each do |enterprise_fee|
@order_cycle.variants.map(&:id).each do |variant_id|
@indexed_enterprise_fees[variant_id] ||= []
@indexed_enterprise_fees[variant_id] << enterprise_fee
end
end
end
def indexed_enterprise_fees_for(variant)
@indexed_enterprise_fees[variant.id] || []
end
def calculate_fee_for(variant, enterprise_fee)
# Spree's Calculator interface accepts Orders or LineItems,
# so we meet that interface with a struct.
line_item = OpenStruct.new variant:, quantity: 1, price: variant.price,
amount: variant.price
enterprise_fee.compute_amount(line_item)
end
end
end