Skip to content

Commit 17d1ee5

Browse files
authored
Merge pull request #6315 from SuperGoodSoft/avoid-unnecessary-adjustment-persistence-in-tax-calculations
Avoid unnecessary adjustment persistence in tax calculations
2 parents 4671f9a + c2cd061 commit 17d1ee5

File tree

6 files changed

+89
-21
lines changed

6 files changed

+89
-21
lines changed

core/app/models/spree/line_item.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class LineItem < Spree::Base
1818

1919
has_one :product, through: :variant
2020

21-
has_many :adjustments, as: :adjustable, inverse_of: :adjustable, dependent: :destroy
21+
has_many :adjustments, as: :adjustable, inverse_of: :adjustable, dependent: :destroy, autosave: true
2222
has_many :inventory_units, inverse_of: :line_item
2323

2424
before_validation :normalize_quantity

core/app/models/spree/order.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def states
102102
has_many :cartons, -> { distinct }, through: :inventory_units
103103

104104
# Adjustments and promotions
105-
has_many :adjustments, -> { order(:created_at) }, as: :adjustable, inverse_of: :adjustable, dependent: :destroy
105+
has_many :adjustments, -> { order(:created_at) }, as: :adjustable, inverse_of: :adjustable, dependent: :destroy, autosave: true
106106
has_many :line_item_adjustments, through: :line_items, source: :adjustments
107107
has_many :shipment_adjustments, through: :shipments, source: :adjustments
108108
has_many :all_adjustments,

core/app/models/spree/order_taxation.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def update_adjustments(item, taxed_items)
5757

5858
# Remove any tax adjustments tied to rates which no longer match.
5959
unmatched_adjustments = tax_adjustments - active_adjustments
60-
item.adjustments.destroy(unmatched_adjustments)
60+
unmatched_adjustments.each(&:mark_for_destruction)
6161
end
6262

6363
# Update or create a new tax adjustment on an item.
@@ -77,7 +77,8 @@ def update_adjustment(item, tax_item)
7777
label: tax_item.label,
7878
included: tax_item.included_in_price
7979
)
80-
tax_adjustment.update!(amount: tax_item.amount)
80+
81+
tax_adjustment.amount = tax_item.amount
8182
tax_adjustment
8283
end
8384
end

core/app/models/spree/order_updater.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,12 @@ def update_adjustment_total
157157
recalculate_adjustments
158158

159159
all_items = line_items + shipments
160-
order_tax_adjustments = adjustments.select(&:tax?)
160+
# Ignore any adjustments that have been marked for destruction in our
161+
# calculations. They'll get removed when/if we persist the order.
162+
valid_adjustments = adjustments.reject(&:marked_for_destruction?)
163+
order_tax_adjustments = valid_adjustments.select(&:tax?)
161164

162-
order.adjustment_total = all_items.sum(&:adjustment_total) + adjustments.sum(&:amount)
165+
order.adjustment_total = all_items.sum(&:adjustment_total) + valid_adjustments.sum(&:amount)
163166
order.included_tax_total = all_items.sum(&:included_tax_total) + order_tax_adjustments.select(&:included?).sum(&:amount)
164167
order.additional_tax_total = all_items.sum(&:additional_tax_total) + order_tax_adjustments.reject(&:included?).sum(&:amount)
165168

core/spec/models/spree/order_taxation_spec.rb

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868

6969
it "creates a new tax adjustment", aggregate_failures: true do
7070
apply
71-
expect(line_item.adjustments.count).to eq 1
71+
expect(line_item.adjustments.size).to eq 1
7272

7373
tax_adjustment = line_item.adjustments.first
7474
expect(tax_adjustment.label).to eq "Tax!"
@@ -132,12 +132,11 @@
132132
)
133133
end
134134

135-
it "removes the tax adjustment" do
136-
expect {
137-
taxation.apply(new_taxes)
138-
}.to change {
139-
line_item.adjustments.count
140-
}.from(1).to(0)
135+
it "marks the tax adjustment for destruction" do
136+
order.save!
137+
taxation.apply(new_taxes)
138+
139+
expect(line_item.adjustments.first).to be_marked_for_destruction
141140
end
142141
end
143142

@@ -174,7 +173,7 @@
174173
end
175174

176175
it "creates a new tax adjustment", aggregate_failures: true do
177-
expect(order.adjustments.count).to eq 1
176+
expect(order.adjustments.size).to eq 1
178177

179178
tax_adjustment = order.adjustments.first
180179
expect(tax_adjustment.label).to eq "Order Tax!"

core/spec/models/spree/order_updater_spec.rb

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,28 +69,39 @@ module Spree
6969
end
7070

7171
describe 'tax recalculation' do
72-
let!(:ship_address) { create(:address) }
73-
let!(:tax_zone) { create(:global_zone) } # will include the above address
74-
let!(:tax_rate) { create(:tax_rate, zone: tax_zone, tax_categories: [tax_category]) }
72+
let(:tax_category) { create(:tax_category) }
73+
let(:ship_address) { create(:address, state: new_york) }
74+
let(:new_york) { create(:state, state_code: "NY") }
75+
let(:tax_zone) { create(:zone, states: [new_york]) }
76+
77+
let!(:tax_rate) do
78+
create(
79+
:tax_rate,
80+
name: "New York Sales Tax",
81+
tax_categories: [tax_category],
82+
zone: tax_zone,
83+
included_in_price: false,
84+
amount: 0.1
85+
)
86+
end
7587

7688
let(:order) do
7789
create(
7890
:order_with_line_items,
79-
line_items_attributes: [{ price: 10, variant: }],
80-
ship_address:,
91+
line_items_attributes: [{ price: 10, variant: variant }],
92+
ship_address: ship_address,
8193
)
8294
end
8395
let(:line_item) { order.line_items[0] }
8496

8597
let(:variant) { create(:variant, tax_category:) }
86-
let(:tax_category) { create(:tax_category) }
8798

8899
context 'when the item quantity has changed' do
89100
before do
90101
line_item.update!(quantity: 2)
91102
end
92103

93-
it 'updates the promotion amount' do
104+
it 'updates the additional_tax_total' do
94105
expect {
95106
order.recalculate
96107
}.to change {
@@ -99,6 +110,60 @@ module Spree
99110
end
100111
end
101112

113+
context 'when the address has changed to a different state' do
114+
let(:new_shipping_address) { create(:address) }
115+
116+
before do
117+
order.ship_address = new_shipping_address
118+
end
119+
120+
it 'removes the old taxes' do
121+
expect {
122+
order.recalculate
123+
}.to change {
124+
order.all_adjustments.tax.count
125+
}.from(1).to(0)
126+
127+
expect(order.additional_tax_total).to eq 0
128+
expect(order.adjustment_total).to eq 0
129+
end
130+
end
131+
132+
context "with an order-level tax adjustment" do
133+
let(:colorado) { create(:state, state_code: "CO") }
134+
let(:colorado_tax_zone) { create(:zone, states: [colorado]) }
135+
let(:ship_address) { create(:address, state: colorado) }
136+
137+
let!(:colorado_delivery_fee) do
138+
create(
139+
:tax_rate,
140+
amount: 0.27,
141+
calculator: Spree::Calculator::FlatFee.new,
142+
level: "order",
143+
name: "Colorado Delivery Fee",
144+
tax_categories: [tax_category],
145+
zone: colorado_tax_zone
146+
)
147+
end
148+
149+
before { order.recalculate }
150+
151+
it "updates the order-level tax adjustment" do
152+
expect {
153+
order.ship_address = create(:address)
154+
order.recalculate
155+
}.to change { order.additional_tax_total }.from(0.27).to(0).
156+
and change { order.adjustment_total }.from(0.27).to(0)
157+
end
158+
159+
it "deletes the order-level tax adjustments when it persists the order" do
160+
expect {
161+
order.ship_address = create(:address)
162+
order.recalculate
163+
}.to change { order.all_adjustments.count }.from(1).to(0)
164+
end
165+
end
166+
102167
context 'with a custom tax_calculator_class' do
103168
let(:custom_calculator_class) { double }
104169
let(:custom_calculator_instance) { double }

0 commit comments

Comments
 (0)