Skip to content

Commit 0ffc010

Browse files
committed
Change order adjuster to use adjustments
This way we can have a single source of truth for what's being discounted.
1 parent d6fc0a2 commit 0ffc010

File tree

14 files changed

+96
-62
lines changed

14 files changed

+96
-62
lines changed

promotions/app/models/concerns/solidus_promotions/discountable_amount.rb

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@
22

33
module SolidusPromotions
44
module DiscountableAmount
5-
def discountable_amount
6-
amount + current_discounts.sum(&:amount)
7-
end
8-
95
def current_discounts
106
@current_discounts ||= []
117
end
8+
deprecate current_discounts: :previous_lane_discounts, deprecator: Spree.deprecator
129

1310
def current_discounts=(args)
1411
@current_discounts = args
1512
end
13+
deprecate :current_discounts=, deprecator: Spree.deprecator
1614

1715
def reset_current_discounts
1816
@current_discounts = []
1917
end
18+
deprecate :reset_current_discounts=, deprecator: Spree.deprecator
2019
end
2120
end

promotions/app/models/concerns/solidus_promotions/discounted_amount.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ def initialize
2424
def discounted_amount
2525
amount + previous_lanes_discounts.sum(&:amount)
2626
end
27+
# The discountable amount is always equal to the discounted amount.
28+
alias_method :discountable_amount, :discounted_amount
2729

2830
# Returns discount objects from the current promotion lane.
2931
#

promotions/app/models/solidus_promotions/order_adjuster.rb

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,14 @@ def initialize(order, dry_run_promotion: nil)
1414
end
1515

1616
def call
17-
order.reset_current_discounts
18-
1917
return order unless SolidusPromotions::Promotion.order_activatable?(order)
2018

21-
discounted_order = DiscountOrder.new(order, promotions, dry_run: dry_run).call
22-
23-
PersistDiscountedOrder.new(discounted_order).call unless dry_run
19+
NullifyOrderDiscounts.new(order:).call
2420

25-
order.reset_current_discounts
21+
DiscountOrder.new(order, promotions, dry_run: dry_run).call
2622

2723
unless dry_run
28-
# Since automations might have added a line item, we need to recalculate
29-
# item total and item count here.
30-
line_items = order.line_items.reject(&:marked_for_destruction?)
31-
order.item_total = line_items.sum(&:amount)
32-
order.item_count = line_items.sum(&:quantity)
33-
order.promo_total = (line_items + order.shipments).sum(&:promo_total)
24+
order.save!
3425
end
3526
order
3627
end

promotions/app/models/solidus_promotions/order_adjuster/discount_order.rb

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,37 @@ def call
1515
return order if order.shipped?
1616

1717
SolidusPromotions::Promotion.ordered_lanes.each do |lane|
18-
lane_promotions = promotions.select { |promotion| promotion.lane == lane }
19-
lane_benefits = eligible_benefits_for_promotable(lane_promotions.flat_map(&:benefits), order)
20-
perform_order_benefits(lane_benefits, lane) unless dry_run
21-
line_item_discounts = adjust_line_items(lane_benefits)
22-
shipment_discounts = adjust_shipments(lane_benefits)
23-
shipping_rate_discounts = adjust_shipping_rates(lane_benefits)
24-
(line_item_discounts + shipment_discounts + shipping_rate_discounts).each do |item, chosen_discounts|
25-
item.current_discounts.concat(chosen_discounts)
18+
SolidusPromotions::PromotionLane.set(current_lane: lane) do
19+
lane_promotions = promotions.select { |promotion| promotion.lane == lane }
20+
lane_benefits = eligible_benefits_for_promotable(lane_promotions.flat_map(&:benefits), order)
21+
perform_order_benefits(lane_benefits, lane) unless dry_run
22+
adjust_line_items(lane_benefits)
23+
adjust_shipments(lane_benefits)
24+
adjust_shipping_rates(lane_benefits)
2625
end
2726
end
2827

28+
order.line_items.each do |line_item|
29+
line_item.adjustments.select { _1.amount.zero? }.each(&:mark_for_destruction)
30+
line_item.promo_total = line_item.adjustments.reject(&:marked_for_destruction?).sum(&:amount)
31+
line_item.adjustment_total = line_item.promo_total
32+
end
33+
34+
order.shipments.each do |shipment|
35+
shipment.adjustments.select { _1.amount.zero? }.each(&:mark_for_destruction)
36+
shipment.promo_total = shipment.adjustments.reject(&:marked_for_destruction?).sum(&:amount)
37+
shipment.shipping_rates.each do |shipping_rate|
38+
shipping_rate.discounts.select { _1.amount.zero? }.each(&:mark_for_destruction)
39+
end
40+
shipment.adjustment_total = shipment.promo_total
41+
end
42+
43+
line_items = order.line_items.reject(&:marked_for_destruction?)
44+
order.item_total = line_items.sum(&:amount)
45+
order.item_count = line_items.sum(&:quantity)
46+
order.promo_total = (line_items + order.shipments.reject(&:marked_for_destruction?)).sum(&:promo_total)
47+
order.adjustment_total = order.promo_total
48+
2949
order
3050
end
3151

@@ -49,16 +69,16 @@ def adjust_line_items(benefits)
4969
next unless line_item.variant.product.promotionable?
5070

5171
discounts = generate_discounts(benefits, line_item)
52-
chosen_item_discounts = SolidusPromotions.config.discount_chooser_class.new(discounts).call
53-
[line_item, chosen_item_discounts]
72+
chosen_discounts = SolidusPromotions.config.discount_chooser_class.new(discounts).call
73+
(line_item.current_lane_discounts - chosen_discounts).each(&:mark_for_destruction)
5474
end
5575
end
5676

5777
def adjust_shipments(benefits)
5878
order.shipments.map do |shipment|
5979
discounts = generate_discounts(benefits, shipment)
60-
chosen_item_discounts = SolidusPromotions.config.discount_chooser_class.new(discounts).call
61-
[shipment, chosen_item_discounts]
80+
chosen_discounts = SolidusPromotions.config.discount_chooser_class.new(discounts).call
81+
(shipment.current_lane_discounts - chosen_discounts).each(&:mark_for_destruction)
6282
end
6383
end
6484

@@ -67,8 +87,8 @@ def adjust_shipping_rates(benefits)
6787
next unless rate.cost
6888

6989
discounts = generate_discounts(benefits, rate)
70-
chosen_item_discounts = SolidusPromotions.config.discount_chooser_class.new(discounts).call
71-
[rate, chosen_item_discounts]
90+
chosen_discounts = SolidusPromotions.config.discount_chooser_class.new(discounts).call
91+
(rate.current_lane_discounts - chosen_discounts).each(&:mark_for_destruction)
7292
end
7393
end
7494

promotions/app/models/solidus_promotions/shipping_rate_discount.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ class ShippingRateDiscount < Spree::Base
55
belongs_to :shipping_rate, inverse_of: :discounts, class_name: "Spree::ShippingRate"
66
belongs_to :benefit, inverse_of: :shipping_rate_discounts
77

8+
alias_method :source, :benefit
9+
810
extend Spree::DisplayMoney
911
money_methods :amount
1012
end

promotions/spec/models/solidus_promotions/benefit_spec.rb

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,14 @@ def compute_line_item(_line_item, _options) = 1
141141

142142
subject { benefit.discount(discountable, extra_data: "foo") }
143143

144+
around do |example|
145+
SolidusPromotions::PromotionLane.set(current_lane: promotion.lane) do
146+
example.run
147+
end
148+
end
149+
144150
it "passes the option on to the calculator" do
145-
expect(calculator).to receive(:compute_line_item).with(discountable, extra_data: "foo").and_return(1)
151+
expect(calculator).to receive(:compute_line_item).with(discountable, extra_data: "foo").and_call_original
146152
subject
147153
end
148154
end

promotions/spec/models/solidus_promotions/benefits/adjust_line_item_quantity_groups_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121
let(:quantity) { 1 }
2222
let(:promotion) { create(:solidus_promotion, apply_automatically: true) }
2323

24+
around do |example|
25+
SolidusPromotions::PromotionLane.set(current_lane: promotion.lane) do
26+
example.run
27+
end
28+
end
29+
2430
describe "#compute_amount" do
2531
subject { action.compute_amount(line_item) }
2632

promotions/spec/models/solidus_promotions/benefits/create_discounted_item_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010
let(:promotion) { create(:solidus_promotion) }
1111
let(:goodie) { create(:variant) }
1212

13+
around do |example|
14+
SolidusPromotions::PromotionLane.set(current_lane: promotion.lane) do
15+
example.run
16+
end
17+
end
18+
1319
describe "#can_discount?" do
1420
let(:benefit) { described_class.new }
1521
let(:discountable) { Spree::Order.new }

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616
end
1717

1818
context "with a shipment" do
19-
let(:item) { build(:shipment, cost: 29) }
19+
let(:item) { build(:shipment, order:, cost: 29) }
2020

2121
it { is_expected.to eq(4.35) }
2222
end
2323

2424
context "with a shipping rate" do
25-
let(:item) { build(:shipping_rate, cost: 38) }
25+
let(:shipment) { build(:shipment, order:, cost: 29) }
26+
let(:item) { build(:shipping_rate, shipment:, cost: 38) }
2627

2728
it { is_expected.to eq(5.70) }
2829
end

promotions/spec/models/solidus_promotions/order_adjuster/discount_order_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
subject { described_class.new(order, promotions).call }
1111

1212
it "returns the order unmodified" do
13-
expect(order).not_to receive(:reset_current_discounts)
1413
expect(subject).to eq(order)
14+
expect(order.changes).to be_empty
1515
end
1616
end
1717

0 commit comments

Comments
 (0)