diff --git a/core/app/models/spree/line_item.rb b/core/app/models/spree/line_item.rb index 2b0b815c631..13ad17e54bd 100644 --- a/core/app/models/spree/line_item.rb +++ b/core/app/models/spree/line_item.rb @@ -173,7 +173,7 @@ def recalculate_adjustments end def update_tax_charge - Spree::TaxRate.adjust(order.tax_zone, [self]) + Spree::Tax::ItemAdjuster.new(self).adjust! end def ensure_proper_currency diff --git a/core/app/models/spree/order.rb b/core/app/models/spree/order.rb index 8ee9d9b17e1..0fab7786483 100644 --- a/core/app/models/spree/order.rb +++ b/core/app/models/spree/order.rb @@ -321,10 +321,7 @@ def line_item_options_match(line_item, options) # Creates new tax charges if there are any applicable rates. If prices already # include taxes then price adjustments are created instead. def create_tax_charge! - # We want to only look up the applicable tax zone once and pass it to TaxRate calculation to avoid duplicated lookups. - order_tax_zone = tax_zone - Spree::TaxRate.adjust(order_tax_zone, line_items) - Spree::TaxRate.adjust(order_tax_zone, shipments) if shipments.any? + Spree::Tax::OrderAdjuster.new(self).adjust! end def outstanding_balance diff --git a/core/app/models/spree/tax/item_adjuster.rb b/core/app/models/spree/tax/item_adjuster.rb new file mode 100644 index 00000000000..5431d9a863e --- /dev/null +++ b/core/app/models/spree/tax/item_adjuster.rb @@ -0,0 +1,42 @@ +module Spree + module Tax + # Adjust a single taxable item (line item or shipment) + class ItemAdjuster + attr_reader :item, :order + + include TaxHelpers + + # @param [Spree::LineItem,Spree::Shipment] item to adjust + # @param [Hash] options like already known tax rates for the order's zone + def initialize(item, options = {}) + @item = item + @order = @item.order + # set instance variable so `TaxRate.match` is only called when necessary + @rates_for_order_zone = options[:rates_for_order_zone] + end + + # Deletes all existing tax adjustments and creates new adjustments for all + # (geographically and category-wise) applicable tax rates. + # + # Creating the adjustments will also run the ItemAdjustments class and + # persist all taxation and promotion totals on the item. + # + # @return [Array] newly created adjustments + def adjust! + return unless order_tax_zone + # Using .destroy_all to make sure callbacks fire + item.adjustments.tax.destroy_all + + TaxRate.store_pre_tax_amount(item, rates_for_item) + + rates_for_item.map { |rate| rate.adjust(order_tax_zone, item) } + end + + private + + def rates_for_item + @rates_for_item ||= applicable_rates.select { |rate| rate.tax_category == item.tax_category } + end + end + end +end diff --git a/core/app/models/spree/tax/order_adjuster.rb b/core/app/models/spree/tax/order_adjuster.rb new file mode 100644 index 00000000000..1a9cc5a9e30 --- /dev/null +++ b/core/app/models/spree/tax/order_adjuster.rb @@ -0,0 +1,25 @@ +module Spree + module Tax + # Add tax adjustments to all line items and shipments in an order + class OrderAdjuster + attr_reader :order + + include TaxHelpers + + # @param [Spree::Order] order to be adjusted + def initialize(order) + @order = order + end + + # Creates tax adjustments for all taxable items (shipments and line items) + # in the given order. + def adjust! + return unless order_tax_zone + + (order.line_items + order.shipments).each do |item| + ItemAdjuster.new(item, rates_for_order_zone: applicable_rates).adjust! + end + end + end + end +end diff --git a/core/app/models/spree/tax/tax_helpers.rb b/core/app/models/spree/tax/tax_helpers.rb new file mode 100644 index 00000000000..7e8985a999e --- /dev/null +++ b/core/app/models/spree/tax/tax_helpers.rb @@ -0,0 +1,41 @@ +module Spree + module Tax + module TaxHelpers + private + + # Imagine with me this scenario: + # You are living in Spain and you have a store which ships to France. + # Spain is therefore your default tax rate. + # When you ship to Spain, you want the Spanish rate to apply. + # When you ship to France, you want the French rate to apply. + # + # Normally, Spree would notice that you have two potentially applicable + # tax rates for one particular item. + # When you ship to Spain, only the Spanish one will apply. + # When you ship to France, you'll see a Spanish refund AND a French tax. + # This little bit of code at the end stops the Spanish refund from appearing. + # + # For further discussion, see https://github.com/spree/spree/issues/4397 and https://github.com/spree/spree/issues/4327. + def applicable_rates + order_zone_tax_categories = rates_for_order_zone.map(&:tax_category) + default_rates_with_unmatched_tax_category = rates_for_default_zone.to_a.delete_if do |default_rate| + order_zone_tax_categories.include?(default_rate.tax_category) + end + + (rates_for_order_zone + default_rates_with_unmatched_tax_category).uniq + end + + def rates_for_order_zone + @rates_for_order_zone ||= Spree::TaxRate.for_zone(order_tax_zone) + end + + def rates_for_default_zone + @rates_for_default_zone ||= Spree::TaxRate.for_zone(Spree::Zone.default_tax) + end + + def order_tax_zone + @order_tax_zone ||= order.tax_zone + end + end + end +end diff --git a/core/app/models/spree/tax_rate.rb b/core/app/models/spree/tax_rate.rb index 116fbb3fefb..c287e1f3689 100644 --- a/core/app/models/spree/tax_rate.rb +++ b/core/app/models/spree/tax_rate.rb @@ -27,9 +27,7 @@ class TaxRate < Spree::Base validates :tax_category_id, presence: true validates_with DefaultTaxZoneValidator - scope :by_zone, ->(zone) { where(zone_id: zone) } - - # Finds geographically matching tax rates for an order's tax zone. + # Finds geographically matching tax rates for a tax zone. # We do not know if they are/aren't applicable until we attempt to apply these rates to # the items contained within the Order itself. # For instance, if a rate passes the criteria outlined in this method, @@ -69,33 +67,20 @@ class TaxRate < Spree::Base # Under no circumstances should negative adjustments be applied for the Spanish tax rates. # # Those rates should never come into play at all and only the French rates should apply. - def self.match(order_tax_zone) - return [] unless order_tax_zone - all_rates = includes(zone: { zone_members: :zoneable }).load - - rates_for_order_zone = all_rates.select { |rate| rate.zone.contains?(order_tax_zone) } - rates_for_default_zone = all_rates.select(&:default_vat?) - - # Imagine with me this scenario: - # You are living in Spain and you have a store which ships to France. - # Spain is therefore your default tax rate. - # When you ship to Spain, you want the Spanish rate to apply. - # When you ship to France, you want the French rate to apply. - # - # Normally, Spree would notice that you have two potentially applicable - # tax rates for one particular item. - # When you ship to Spain, only the Spanish one will apply. - # When you ship to France, you'll see a Spanish refund AND a French tax. - # This little bit of code at the end stops the Spanish refund from appearing. - # - # For further discussion, see https://github.com/spree/spree/issues/4397 and https://github.com/spree/spree/issues/4327. - - order_zone_tax_categories = rates_for_order_zone.map(&:tax_category) - rates_for_default_zone.delete_if do |default_rate| - order_zone_tax_categories.include?(default_rate.tax_category) - end + scope :for_zone, ->(zone) { where(zone_id: Spree::Zone.with_shared_members(zone).pluck(:id)) } + scope :included_in_price, -> { where(included_in_price: true) } - (rates_for_order_zone + rates_for_default_zone).uniq + # Create tax adjustments for some items that have the same tax zone. + # + # @deprecated Please use Spree::Tax::OrderAdjuster or Spree::Tax::ItemAdjuster instead. + # + # @param [Spree::Zone] order_tax_zone is the smalles applicable zone to the order's tax address + # @param [Array] items to be adjusted + def self.adjust(order_tax_zone, items) + ActiveSupport::Deprecation.warn("Please use Spree::Tax::OrderAdjuster or Spree::Tax::ItemAdjuster instead", caller) + items.map do |item| + Spree::Tax::ItemAdjuster.new(item, rates_for_order_zone: for_zone(order_tax_zone)).adjust! + end end # Pre-tax amounts must be stored so that we can calculate @@ -115,29 +100,6 @@ def self.store_pre_tax_amount(item, rates) item.update_column(:pre_tax_amount, pre_tax_amount.round(2)) end - # This method is best described by the documentation on .match - def self.adjust(order_tax_zone, items) - rates = match(order_tax_zone) - tax_categories = rates.map(&:tax_category) - relevant_items, non_relevant_items = items.partition { |item| tax_categories.include?(item.tax_category) } - unless relevant_items.empty? - Spree::Adjustment.where(adjustable: relevant_items).tax.destroy_all # using destroy_all to ensure adjustment destroy callback fires. - end - relevant_items.each do |item| - relevant_rates = rates.select { |rate| rate.tax_category == item.tax_category } - store_pre_tax_amount(item, relevant_rates) - relevant_rates.each do |rate| - rate.adjust(order_tax_zone, item) - end - end - non_relevant_items.each do |item| - if item.adjustments.tax.present? - item.adjustments.tax.destroy_all # using destroy_all to ensure adjustment destroy callback fires. - item.update_columns pre_tax_amount: 0 - end - end - end - # Creates necessary tax adjustments for the order. def adjust(order_tax_zone, item) amount = compute_amount(item) @@ -172,10 +134,6 @@ def default_zone_or_zone_match?(order_tax_zone) Zone.default_tax.try!(:contains?, order_tax_zone) || zone.contains?(order_tax_zone) end - def default_vat? - included_in_price && zone.contains?(Spree::Zone.default_tax) - end - private def create_label diff --git a/core/app/models/spree/zone.rb b/core/app/models/spree/zone.rb index 4df41080e0c..96735ff702a 100644 --- a/core/app/models/spree/zone.rb +++ b/core/app/models/spree/zone.rb @@ -58,6 +58,8 @@ def self.match(address) # current zone, if it's a state zone. If the passed-in zone has members, it # will also be in the result set. def self.with_shared_members(zone) + return none unless zone + states_and_state_country_ids = zone.states.pluck(:id, :country_id).to_a state_ids = states_and_state_country_ids.map(&:first) state_country_ids = states_and_state_country_ids.map(&:second) diff --git a/core/spec/models/spree/order/state_machine_spec.rb b/core/spec/models/spree/order/state_machine_spec.rb index aaf3fb76667..e7b7a9323fd 100644 --- a/core/spec/models/spree/order/state_machine_spec.rb +++ b/core/spec/models/spree/order/state_machine_spec.rb @@ -43,7 +43,7 @@ end it "adjusts tax rates when transitioning to delivery" do - expect(Spree::TaxRate).to receive(:adjust).once.with(order.tax_zone, order.line_items) + expect(Spree::Tax::OrderAdjuster).to receive(:new).once.with(order).and_call_original order.next! end end diff --git a/core/spec/models/spree/reimbursement_spec.rb b/core/spec/models/spree/reimbursement_spec.rb index b21612d209e..a7a582f56b9 100644 --- a/core/spec/models/spree/reimbursement_spec.rb +++ b/core/spec/models/spree/reimbursement_spec.rb @@ -49,7 +49,7 @@ let!(:adjustments) { [] } # placeholder to ensure it gets run prior the "before" at this level let!(:tax_rate) { nil } - let!(:tax_zone) { create :zone, default_tax: true } + let!(:tax_zone) { create :zone, :with_country, default_tax: true } let(:shipping_method) { create :shipping_method, zones: [tax_zone] } let(:variant) { create :variant } let(:order) { create(:order_with_line_items, state: 'payment', line_items_attributes: [{ variant: variant, price: line_items_price }], shipment_cost: 0, shipping_method: shipping_method) } diff --git a/core/spec/models/spree/reimbursement_tax_calculator_spec.rb b/core/spec/models/spree/reimbursement_tax_calculator_spec.rb index 2ce2c78c5b5..c49e4ab99d4 100644 --- a/core/spec/models/spree/reimbursement_tax_calculator_spec.rb +++ b/core/spec/models/spree/reimbursement_tax_calculator_spec.rb @@ -24,7 +24,7 @@ context 'with additional tax' do let!(:tax_rate) { create(:tax_rate, name: "Sales Tax", amount: 0.10, included_in_price: false, zone: tax_zone) } - let(:tax_zone) { create(:zone, default_tax: true) } + let(:tax_zone) { create(:zone, :with_country, default_tax: true) } it 'sets additional_tax_total on the return items' do subject @@ -37,13 +37,13 @@ context 'with included tax' do let!(:tax_rate) { create(:tax_rate, name: "VAT Tax", amount: 0.1, included_in_price: true, zone: tax_zone) } - let(:tax_zone) { create(:zone, default_tax: true) } + let(:tax_zone) { create(:zone, :with_country, default_tax: true) } it 'sets included_tax_total on the return items' do subject return_item.reload - expect(return_item.included_tax_total).to be < 0 + expect(return_item.included_tax_total).to be > 0 expect(return_item.included_tax_total).to eq line_item.included_tax_total end end diff --git a/core/spec/models/spree/tax/item_adjuster_spec.rb b/core/spec/models/spree/tax/item_adjuster_spec.rb new file mode 100644 index 00000000000..bc613178e19 --- /dev/null +++ b/core/spec/models/spree/tax/item_adjuster_spec.rb @@ -0,0 +1,76 @@ +require 'spec_helper' + +RSpec.describe Spree::Tax::ItemAdjuster do + subject(:adjuster) { described_class.new(item) } + let(:order) { Spree::Order.new } + let(:item) { Spree::LineItem.new(order: order) } + + before do + allow(order).to receive(:tax_zone) { build(:zone) } + end + + describe 'initialization' do + it 'sets order to item order' do + expect(adjuster.order).to eq(item.order) + end + + it 'sets adjustable' do + expect(adjuster.item).to eq(item) + end + end + + describe '#adjust!' do + before do + expect(order).to receive(:tax_zone).and_return(tax_zone) + end + + context 'when the order has no tax zone' do + let(:tax_zone) { nil } + + before do + allow(order).to receive(:tax_zone).and_return(nil) + adjuster.adjust! + end + + it 'returns nil early' do + expect(adjuster.adjust!).to be_nil + end + end + + context 'when the order has a tax zone' do + let(:item) { build_stubbed :line_item, order: order } + let(:tax_zone) { build_stubbed(:zone, :with_country) } + + before do + expect(item).to receive(:update_column) + + expect(Spree::TaxRate).to receive(:for_zone).with(tax_zone).and_return(rates_for_order_zone) + expect(Spree::TaxRate).to receive(:for_zone).with(Spree::Zone.default_tax).and_return([]) + end + + context 'when there are no matching rates' do + let(:rates_for_order_zone) { [] } + + it 'returns no adjustments' do + expect(adjuster.adjust!).to eq([]) + end + end + + context 'when there are matching rates for the zone' do + context 'and all rates have the same tax category as the item' do + let(:item_tax_category) { build_stubbed(:tax_category) } + let(:rate_1) { create :tax_rate, tax_category: item_tax_category } + let(:rate_2) { create :tax_rate } + let(:rates_for_order_zone) { [rate_1, rate_2] } + + before { allow(item).to receive(:tax_category).and_return(item_tax_category) } + + it 'creates an adjustment for every matching rate' do + expect(rate_1).to receive_message_chain(:adjustments, :create!) + expect(adjuster.adjust!.length).to eq(1) + end + end + end + end + end +end diff --git a/core/spec/models/spree/tax/order_adjuster_spec.rb b/core/spec/models/spree/tax/order_adjuster_spec.rb new file mode 100644 index 00000000000..378d0540bd2 --- /dev/null +++ b/core/spec/models/spree/tax/order_adjuster_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +RSpec.describe Spree::Tax::OrderAdjuster do + subject(:adjuster) { described_class.new(order) } + + describe 'initialization' do + let(:order) { Spree::Order.new } + + it 'sets order to adjustable' do + expect(adjuster.order).to eq(order) + end + end + + describe '#adjust!' do + let(:zone) { build_stubbed(:zone) } + let(:line_items) { build_stubbed_list(:line_item, 2) } + let(:order) { build_stubbed(:order, line_items: line_items) } + let(:rates_for_order_zone) { [] } + let(:item_adjuster) { Spree::Tax::ItemAdjuster.new(line_items.first) } + + before do + expect(order).to receive(:tax_zone).at_least(:once).and_return(zone) + expect(Spree::TaxRate).to receive(:for_zone).with(zone).and_return(rates_for_order_zone) + expect(Spree::TaxRate).to receive(:for_zone).with(Spree::Zone.default_tax).and_return([]) + end + + it 'calls the item adjuster with all line items' do + expect(Spree::Tax::ItemAdjuster).to receive(:new).with(line_items.first, rates_for_order_zone: rates_for_order_zone).and_return(item_adjuster) + expect(Spree::Tax::ItemAdjuster).to receive(:new).with(line_items.second, rates_for_order_zone: rates_for_order_zone).and_return(item_adjuster) + + expect(item_adjuster).to receive(:adjust!).twice + adjuster.adjust! + end + end +end diff --git a/core/spec/models/spree/tax_rate_spec.rb b/core/spec/models/spree/tax_rate_spec.rb index c65289dfe70..d0ad1c0f09f 100644 --- a/core/spec/models/spree/tax_rate_spec.rb +++ b/core/spec/models/spree/tax_rate_spec.rb @@ -1,107 +1,68 @@ require 'spec_helper' describe Spree::TaxRate, type: :model do - context "match" do - let(:order) { create(:order) } - let(:country) { create(:country) } - let(:tax_category) { create(:tax_category) } - let(:calculator) { Spree::Calculator::FlatRate.new } - - it "should return an empty array when tax_zone is nil" do - allow(order).to receive_messages tax_zone: nil - expect(Spree::TaxRate.match(order.tax_zone)).to eq([]) + context ".for_zone" do + subject(:rates_for_zone) { Spree::TaxRate.for_zone(zone) } + + context "when zone is nil" do + let(:zone) { nil } + + it "should return an empty array" do + expect(subject).to eq([]) + end end context "when no rate zones match the tax zone" do - before do - Spree::TaxRate.create(amount: 1, zone: create(:zone)) - end + let(:rate_zone) { create(:zone, :with_country) } + let!(:rate) { create :tax_rate, zone: rate_zone } context "when there is no default tax zone" do - before do - @zone = create(:zone, name: "Country Zone", default_tax: false, zone_members: []) - @zone.zone_members.create(zoneable: country) - end + context "and the zone has no shared members with the rate zone" do + let(:zone) { create(:zone, :with_country) } - it "should return an empty array" do - allow(order).to receive_messages tax_zone: @zone - expect(Spree::TaxRate.match(order.tax_zone)).to eq([]) + it "should return an empty array" do + expect(subject).to eq([]) + end end - it "should return the rate that matches the rate zone" do - rate = Spree::TaxRate.create( - amount: 1, - zone: @zone, - tax_category: tax_category, - calculator: calculator - ) + context "and the zone has shared members with the rate zone" do + let(:zone) { create(:zone, countries: rate_zone.countries) } - allow(order).to receive_messages tax_zone: @zone - expect(Spree::TaxRate.match(order.tax_zone)).to eq([rate]) + it "should return the rate that matches the rate zone" do + expect(subject).to eq([rate]) + end end - it "should return all rates that match the rate zone" do - rate1 = Spree::TaxRate.create( - amount: 1, - zone: @zone, - tax_category: tax_category, - calculator: calculator - ) - - rate2 = Spree::TaxRate.create( - amount: 2, - zone: @zone, - tax_category: tax_category, - calculator: Spree::Calculator::FlatRate.new - ) - - allow(order).to receive_messages tax_zone: @zone - expect(Spree::TaxRate.match(order.tax_zone)).to match_array([rate1, rate2]) + context "there is many rates that match the zone" do + let!(:rate2) { create :tax_rate, zone: rate_zone } + let(:zone) { create(:zone, countries: rate_zone.countries) } + + it "should return all rates that match the rate zone" do + expect(subject).to match_array([rate, rate2]) + end end context "when the tax_zone is contained within a rate zone" do - before do - sub_zone = create(:zone, name: "State Zone", zone_members: []) - sub_zone.zone_members.create(zoneable: create(:state, country: country)) - allow(order).to receive_messages tax_zone: sub_zone - @rate = Spree::TaxRate.create( - amount: 1, - zone: @zone, - tax_category: tax_category, - calculator: calculator - ) - end + let(:country1) { create :country } + let(:country2) { create :country } + let(:rate_zone) { create(:zone, countries: [country1, country2]) } + let(:zone) { create(:zone, countries: [country1]) } it "should return the rate zone" do - expect(Spree::TaxRate.match(order.tax_zone)).to eq([@rate]) + expect(subject).to eq([rate]) end end end context "when there is a default tax zone" do - before do - @zone = create(:zone, name: "Country Zone", default_tax: true, zone_members: []) - @zone.zone_members.create(zoneable: country) - end - + let(:default_zone) { create(:zone, :with_country, default_tax: true) } let(:included_in_price) { false } let!(:rate) do - Spree::TaxRate.create(amount: 1, - zone: @zone, - tax_category: tax_category, - calculator: calculator, - included_in_price: included_in_price) + create(:tax_rate, zone: default_zone, included_in_price: included_in_price) end - subject { Spree::TaxRate.match(order.tax_zone) } - - context "when the order has the same tax zone" do - before do - allow(order).to receive_messages tax_zone: @zone - allow(order).to receive_messages tax_address: tax_address - end - - let(:tax_address) { stub_model(Spree::Address) } + context "when the zone is the default zone" do + let(:zone) { default_zone } context "when the tax is not a VAT" do it { is_expected.to eq([rate]) } @@ -109,102 +70,45 @@ context "when the tax is a VAT" do let(:included_in_price) { true } + it { is_expected.to eq([rate]) } end end - context "when the order has a different tax zone" do - before do - allow(order).to receive_messages tax_zone: create(:zone, name: "Other Zone") - allow(order).to receive_messages tax_address: tax_address - end + context "when the zone is outside the default zone" do + let(:zone) { create(:zone, :with_country) } - context "when the order has a tax_address" do - let(:tax_address) { stub_model(Spree::Address) } - - context "when the tax is a VAT" do - let(:included_in_price) { true } - # The rate should match in this instance because: - # 1) It's the default rate (and as such, a negative adjustment should apply) - it { is_expected.to eq([rate]) } - end - - context "when the tax is not VAT" do - it "returns no tax rate" do - expect(subject).to be_empty - end - end - end - - context "when the order does not have a tax_address" do - let(:tax_address) { nil } - - context "when the tax is a VAT" do - let(:included_in_price) { true } - # The rate should match in this instance because: - # 1) The order has no tax address by this stage - # 2) With no tax address, it has no tax zone - # 3) Therefore, we assume the default tax zone - # 4) This default zone has a default tax rate. - it { is_expected.to eq([rate]) } - end - - context "when the tax is not a VAT" do - it { is_expected.to be_empty } - end - end + it { is_expected.to be_empty } end end end end context ".adjust" do - let(:order) { stub_model(Spree::Order) } - let(:tax_category_1) { stub_model(Spree::TaxCategory) } - let(:tax_category_2) { stub_model(Spree::TaxCategory) } - let(:rate_1) { stub_model(Spree::TaxRate, tax_category: tax_category_1) } - let(:rate_2) { stub_model(Spree::TaxRate, tax_category: tax_category_2) } + let(:zone) { stub_model(Spree::Zone) } context "with line items" do - let(:line_item) do - stub_model(Spree::LineItem, - price: 10.0, - quantity: 1, - tax_category: tax_category_1, - variant: stub_model(Spree::Variant) - ) - end + let(:line_item) { stub_model(Spree::LineItem) } - let(:line_items) { [line_item] } - - before do - allow(Spree::TaxRate).to receive_messages match: [rate_1, rate_2] - end - - it "should only apply adjustments for matching rates" do - expect(rate_1).to receive(:adjust) - expect(rate_2).not_to receive(:adjust) - Spree::TaxRate.adjust(order.tax_zone, line_items) + it 'should emit a deprecation warning and call the item adjuster' do + expect(ActiveSupport::Deprecation).to receive(:warn) + expect(Spree::Tax::ItemAdjuster).to receive_message_chain(:new, :adjust!) + Spree::TaxRate.adjust(zone, [line_item]) end end context "with shipments" do - let(:shipments) { [stub_model(Spree::Shipment, cost: 10.0, tax_category: tax_category_1)] } + let(:shipment) { stub_model(Spree::Shipment) } - before do - allow(Spree::TaxRate).to receive_messages match: [rate_1, rate_2] - end - - it "should apply adjustments for matching rates" do - expect(rate_1).to receive(:adjust) - expect(rate_2).not_to receive(:adjust) - Spree::TaxRate.adjust(order.tax_zone, shipments) + it 'should emit a deprecation warning and call the item adjuster' do + expect(ActiveSupport::Deprecation).to receive(:warn) + expect(Spree::Tax::ItemAdjuster).to receive_message_chain(:new, :adjust!) + Spree::TaxRate.adjust(zone, [shipment]) end end end - # While the above test is nice and fast - let me tell you a story or two here. - context ".adjust" do + context "Taxation system integration tests" do let(:order) { create :order } let(:book_product) { create :product, price: 20, name: "Book", tax_category: books_category } let(:download_product) { create :product, price: 10, name: "Download", tax_category: digital_category } @@ -265,7 +169,7 @@ before do allow(order).to receive(:tax_zone) { tax_zone } order.contents.add(variant) - Spree::TaxRate.adjust(order.tax_zone, order.line_items) + Spree::Tax::OrderAdjuster.new(order).adjust! end let(:line_item) { order.line_items.first } @@ -525,7 +429,7 @@ before do allow(order).to receive(:tax_zone) { tax_zone } order.contents.add(variant) - Spree::TaxRate.adjust(order.tax_zone, order.line_items) + Spree::Tax::OrderAdjuster.new(order).adjust! end let(:line_item) { order.line_items.first } diff --git a/core/spec/models/spree/zone_spec.rb b/core/spec/models/spree/zone_spec.rb index 36b13c718f6..8cc4f0a5829 100644 --- a/core/spec/models/spree/zone_spec.rb +++ b/core/spec/models/spree/zone_spec.rb @@ -348,6 +348,14 @@ end end + context 'when passing nil' do + let!(:zone) { nil } + + it 'will return an empty set' do + expect(subject).to eq([]) + end + end + context "finding potential matches for a country zone" do let!(:zone) do create(:zone).tap do |z|