forked from solidusio/solidus
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor line item total calculations
While working on the in-memory updater in solidusio#5872, we found the need to change how item totals were being calculated, so that we could mark adjustments for destruction without actually destroying them, while still keeping tax adjustments intact. This change is completely backwards-compatible with the current OrderUpdater, so to reduce the scope of our PR, we wanted to make this change separately. Since the OrderUpdater is already very large, this helps reduce its responsibilities and makes it easier to test this behaviour. We don't see it as necessary to make this a configurable class, but this change leaves that option open in the future. Co-authored-by: Adam Mueller <[email protected]> Co-authored-by: Alistair Norman <[email protected]> Co-authored-by: Chris Todorov <[email protected]> Co-authored-by: Harmony Bouvier <[email protected]> Co-authored-by: Sofia Besenski <[email protected]> Co-authored-by: benjamin wil <[email protected]>
- Loading branch information
1 parent
3675af2
commit 9a82ff7
Showing
3 changed files
with
108 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# frozen_string_literal: true | ||
|
||
class Spree::ItemTotal | ||
def initialize(item) | ||
@item = item | ||
end | ||
|
||
def recalculate! | ||
tax_adjustments = item.adjustments.select { |adjustment| | ||
adjustment.tax? && !adjustment.marked_for_destruction? | ||
} | ||
|
||
# Included tax adjustments are those which are included in the price. | ||
# These ones should not affect the eventual total price. | ||
# | ||
# Additional tax adjustments are the opposite, affecting the final total. | ||
item.included_tax_total = tax_adjustments.select(&:included?).sum(&:amount) | ||
item.additional_tax_total = tax_adjustments.reject(&:included?).sum(&:amount) | ||
|
||
item.adjustment_total = item.adjustments.reject { |adjustment| | ||
adjustment.marked_for_destruction? || adjustment.included? | ||
}.sum(&:amount) | ||
end | ||
|
||
private | ||
|
||
attr_reader :item | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'rails_helper' | ||
|
||
RSpec.describe Spree::ItemTotal do | ||
describe "#recalculate!" do | ||
subject { described_class.new(item).recalculate! } | ||
|
||
let!(:item) { create :line_item, adjustments: } | ||
|
||
let(:tax_rate) { create(:tax_rate) } | ||
|
||
let(:arbitrary_adjustment) { create :adjustment, amount: 1, source: nil } | ||
let(:included_tax_adjustment) { create :adjustment, amount: 2, source: tax_rate, included: true } | ||
let(:additional_tax_adjustment) { create :adjustment, amount: 3, source: tax_rate, included: false } | ||
|
||
context "with multiple types of adjustments" do | ||
let(:marked_for_destruction_included_tax_adjustment) { create(:adjustment, amount: 5, source: tax_rate, included: true) } | ||
let(:marked_for_destruction_additional_tax_adjustment) { create(:adjustment, amount: 7, source: tax_rate, included: false) } | ||
|
||
let(:adjustments) { | ||
[ | ||
arbitrary_adjustment, | ||
included_tax_adjustment, | ||
additional_tax_adjustment, | ||
marked_for_destruction_included_tax_adjustment, | ||
marked_for_destruction_additional_tax_adjustment | ||
] | ||
} | ||
|
||
before do | ||
[marked_for_destruction_included_tax_adjustment, marked_for_destruction_additional_tax_adjustment] | ||
.each(&:mark_for_destruction) | ||
end | ||
|
||
it "updates item totals" do | ||
expect { | ||
subject | ||
}.to change(item, :adjustment_total).from(0).to(4). | ||
and change { item.included_tax_total }.from(0).to(2). | ||
and change { item.additional_tax_total }.from(0).to(3) | ||
end | ||
end | ||
|
||
context "with only an arbitrary adjustment" do | ||
let(:adjustments) { [arbitrary_adjustment] } | ||
|
||
it "updates the adjustment total" do | ||
expect { | ||
subject | ||
}.to change { item.adjustment_total }.from(0).to(1) | ||
end | ||
end | ||
|
||
context "with only tax adjustments" do | ||
let(:adjustments) { [included_tax_adjustment, additional_tax_adjustment] } | ||
|
||
it "updates the adjustment total" do | ||
expect { | ||
subject | ||
}.to change { item.adjustment_total }.from(0).to(3). | ||
and change { item.included_tax_total }.from(0).to(2). | ||
and change { item.additional_tax_total }.from(0).to(3) | ||
end | ||
end | ||
end | ||
end |