Skip to content

Commit 1492e01

Browse files
committed
FlexiRate: Allow calculating prices
This turned out to be rather complicated.
1 parent 934b851 commit 1492e01

File tree

3 files changed

+214
-15
lines changed

3 files changed

+214
-15
lines changed

promotions/app/models/solidus_promotions/calculators/flexi_rate.rb

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,33 @@ class FlexiRate < Spree::Calculator
5151
# line_item.quantity # => 5
5252
# calculator.compute_line_item(line_item) # => 15.0 (10 + 5, limited to 2 items)
5353
def compute_line_item(line_item)
54-
items_count = line_item.quantity
55-
items_count = [items_count, preferred_max_items].min unless preferred_max_items.zero?
54+
compute_for_quantity(line_item.quantity)
55+
end
56+
57+
def compute_price(price, options = {})
58+
order = options[:order]
59+
desired_quantity = options[:quantity] || 0
60+
return Spree::ZERO if desired_quantity.zero?
61+
62+
already_ordered_quantity = if order
63+
order.line_items.detect do |line_item|
64+
line_item.variant == price.variant
65+
end&.quantity || 0
66+
else
67+
0
68+
end
69+
possible_discount = compute_for_quantity(already_ordered_quantity + desired_quantity)
70+
existing_discount = compute_for_quantity(already_ordered_quantity)
71+
round_to_currency(
72+
(possible_discount - existing_discount) / desired_quantity,
73+
price.currency
74+
)
75+
end
76+
77+
private
78+
79+
def compute_for_quantity(quantity)
80+
items_count = preferred_max_items.zero? ? quantity : [quantity, preferred_max_items].min
5681

5782
return Spree::ZERO if items_count.zero?
5883

promotions/lib/solidus_promotions/configuration.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ def shipment_conditions=(conditions)
127127
],
128128
"SolidusPromotions::Benefits::AdvertisePrice" => [
129129
"SolidusPromotions::Calculators::Percent",
130-
"SolidusPromotions::Calculators::FlatRate"
130+
"SolidusPromotions::Calculators::FlatRate",
131+
"SolidusPromotions::Calculators::FlexiRate"
131132
]
132133
}
133134

promotions/spec/models/solidus_promotions/calculators/flexi_rate_spec.rb

Lines changed: 185 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,20 @@
1010
preferred_max_items: max_items
1111
)
1212
end
13-
let(:line_item) do
14-
mock_model(
15-
Spree::LineItem, quantity: quantity
16-
)
17-
end
13+
1814
let(:first_item) { 0 }
1915
let(:additional_item) { 0 }
2016
let(:max_items) { 0 }
2117

22-
let(:line_item) do
23-
mock_model(
24-
Spree::LineItem, quantity: quantity
25-
)
26-
end
27-
2818
it_behaves_like "a promotion calculator"
2919

30-
context "compute" do
20+
context "compute_line_item" do
21+
let(:line_item) do
22+
mock_model(
23+
Spree::LineItem, quantity: quantity
24+
)
25+
end
26+
3127
subject { calculator.compute(line_item) }
3228

3329
context "with all amounts 0" do
@@ -176,6 +172,183 @@
176172
end
177173
end
178174

175+
context "compute_price" do
176+
let(:variant) { mock_model(Spree::Variant) }
177+
let(:price) { mock_model(Spree::Price, amount: 12, variant: variant, currency: "USD") }
178+
let(:order) { mock_model(Spree::Order, line_items: [line_item]) }
179+
let(:line_item_quantity) { 0 }
180+
let(:line_item) do
181+
mock_model(
182+
Spree::LineItem,
183+
quantity: line_item_quantity,
184+
variant: variant
185+
)
186+
end
187+
188+
subject { calculator.compute(price, { order: order, quantity: quantity }) }
189+
190+
context "with no order given" do
191+
let(:order) { nil }
192+
193+
context "when first_item and additional_item have values" do
194+
let(:first_item) { 1.13 }
195+
let(:additional_item) { 2.11 }
196+
197+
context "with quantity 2" do
198+
let(:quantity) { 2 }
199+
200+
it { is_expected.to eq(1.62) }
201+
end
202+
end
203+
end
204+
205+
context "if nothing is in the cart" do
206+
let(:line_item_quantity) { 0 }
207+
208+
context "when first_item and additional_items have values" do
209+
let(:first_item) { 1.13 }
210+
let(:additional_item) { 2.11 }
211+
212+
context "with quantity 0" do
213+
let(:quantity) { 0 }
214+
215+
it { is_expected.to eq 0 }
216+
end
217+
218+
context "with quantity 1" do
219+
let(:quantity) { 1 }
220+
221+
it { is_expected.to eq 1.13 }
222+
end
223+
224+
context "with quantity 2" do
225+
let(:quantity) { 2 }
226+
227+
it { is_expected.to eq 1.62 }
228+
end
229+
230+
context "with quantity 10" do
231+
let(:quantity) { 3 }
232+
233+
it { is_expected.to eq 1.78 }
234+
end
235+
236+
context "with quantity 10" do
237+
let(:quantity) { 10 }
238+
239+
it { is_expected.to eq 2.01 }
240+
end
241+
242+
context "with max_items 5" do
243+
let(:max_items) { 5 }
244+
245+
context "with quantity 0" do
246+
let(:quantity) { 0 }
247+
248+
it { is_expected.to eq 0 }
249+
end
250+
251+
context "with quantity 1" do
252+
let(:quantity) { 1 }
253+
254+
it { is_expected.to eq 1.13 }
255+
end
256+
257+
context "with quantity 2" do
258+
let(:quantity) { 2 }
259+
260+
it { is_expected.to eq 1.62 }
261+
end
262+
263+
context "with quantity 5" do
264+
let(:quantity) { 5 }
265+
266+
it { is_expected.to eq 1.91 }
267+
end
268+
269+
context "with quantity 10" do
270+
let(:quantity) { 10 }
271+
272+
it { is_expected.to eq 0.96 }
273+
end
274+
end
275+
end
276+
end
277+
278+
context "with items already in the cart" do
279+
let(:line_item_quantity) { 2 }
280+
281+
context "when first_item and additional_items have values" do
282+
let(:first_item) { 1.13 }
283+
let(:additional_item) { 2.11 }
284+
285+
context "with quantity 0" do
286+
let(:quantity) { 0 }
287+
288+
it { is_expected.to eq 0 }
289+
end
290+
291+
context "with quantity 1" do
292+
let(:quantity) { 1 }
293+
294+
it { is_expected.to eq 2.11 }
295+
end
296+
297+
context "with quantity 2" do
298+
let(:quantity) { 2 }
299+
300+
it { is_expected.to eq 2.11 }
301+
end
302+
303+
context "with quantity 10" do
304+
let(:quantity) { 3 }
305+
306+
it { is_expected.to eq 2.11 }
307+
end
308+
309+
context "with quantity 10" do
310+
let(:quantity) { 10 }
311+
312+
it { is_expected.to eq 2.11 }
313+
end
314+
315+
context "with max_items 5" do
316+
let(:max_items) { 5 }
317+
318+
context "with quantity 0" do
319+
let(:quantity) { 0 }
320+
321+
it { is_expected.to eq 0 }
322+
end
323+
324+
context "with quantity 1" do
325+
let(:quantity) { 1 }
326+
327+
it { is_expected.to eq 2.11 }
328+
end
329+
330+
context "with quantity 2" do
331+
let(:quantity) { 2 }
332+
333+
it { is_expected.to eq 2.11 }
334+
end
335+
336+
context "with quantity 5" do
337+
let(:quantity) { 5 }
338+
339+
it { is_expected.to eq 1.27 }
340+
end
341+
342+
context "with quantity 10" do
343+
let(:quantity) { 10 }
344+
345+
it { is_expected.to eq 0.63 }
346+
end
347+
end
348+
end
349+
end
350+
end
351+
179352
it "allows creation of new object with all the attributes" do
180353
attributes = { preferred_first_item: 1, preferred_additional_item: 1, preferred_max_items: 1 }
181354
calculator = described_class.new(attributes)

0 commit comments

Comments
 (0)