diff --git a/core/app/models/spree/calculator/default_tax.rb b/core/app/models/spree/calculator/default_tax.rb index 6090ee98be8..74f0c02714e 100644 --- a/core/app/models/spree/calculator/default_tax.rb +++ b/core/app/models/spree/calculator/default_tax.rb @@ -15,7 +15,7 @@ def compute_order(order) line_items_total = matched_line_items.sum(&:discounted_amount) if rate.included_in_price order_tax_amount = round_to_two_places(line_items_total - ( line_items_total / (1 + rate.amount) ) ) - refund_if_necessary(order_tax_amount, order.tax_zone) + refund_if_necessary(order_tax_amount, order.tax_address) else round_to_two_places(line_items_total * rate.amount) end @@ -48,20 +48,20 @@ def deduced_total_by_rate(item, rate) unrounded_net_amount = item.discounted_amount / (1 + sum_of_included_tax_rates(item)) refund_if_necessary( round_to_two_places(unrounded_net_amount * rate.amount), - item.order.tax_zone + item.order.tax_address ) end - def refund_if_necessary(amount, order_tax_zone) - if default_zone_or_zone_match?(order_tax_zone) + def refund_if_necessary(amount, order_tax_address) + if default_zone_or_zone_match?(order_tax_address) amount else amount * -1 end end - def default_zone_or_zone_match?(order_tax_zone) - Zone.default_tax.try!(:contains?, order_tax_zone) || rate.zone.contains?(order_tax_zone) + def default_zone_or_zone_match?(order_tax_address) + Zone.default_tax.try!(:include?, order_tax_address) || rate.zone.include?(order_tax_address) end end end diff --git a/core/app/models/spree/order.rb b/core/app/models/spree/order.rb index 52a4149ff2a..9ca000d7739 100644 --- a/core/app/models/spree/order.rb +++ b/core/app/models/spree/order.rb @@ -227,8 +227,10 @@ def backordered? # Returns the relevant zone (if any) to be used for taxation purposes. # Uses default tax zone unless there is a specific match def tax_zone - @tax_zone ||= Zone.match(tax_address) || Zone.default_tax + Zone.match(tax_address) || Zone.default_tax end + deprecate tax_zone: "Please use Spree::Order#tax_address instead.", + deprecator: Spree::Deprecation # Returns the address for taxation based on configuration def tax_address @@ -591,11 +593,6 @@ def can_approve? !approved? end - def reload(options = nil) - remove_instance_variable(:@tax_zone) if defined?(@tax_zone) - super - end - def quantity line_items.sum(:quantity) end diff --git a/core/app/models/spree/tax/item_adjuster.rb b/core/app/models/spree/tax/item_adjuster.rb index e686b9a4ac4..0ac66e17e19 100644 --- a/core/app/models/spree/tax/item_adjuster.rb +++ b/core/app/models/spree/tax/item_adjuster.rb @@ -16,9 +16,8 @@ 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] + @rates_for_order = options[:rates_for_order] @rates_for_default_zone = options[:rates_for_default_zone] - @order_tax_zone = options[:order_tax_zone] end # Deletes all existing tax adjustments and creates new adjustments for all @@ -26,11 +25,11 @@ def initialize(item, options = {}) # # @return [Array] newly created adjustments def adjust! - return unless order_tax_zone(order) + return unless order.tax_address.country_id item.adjustments.destroy(item.adjustments.select(&:tax?)) - rates_for_item(item).map { |rate| rate.adjust(order_tax_zone(order), item) } + rates_for_item(item).map { |rate| rate.adjust(nil, item) } end end end diff --git a/core/app/models/spree/tax/order_adjuster.rb b/core/app/models/spree/tax/order_adjuster.rb index eb79072e54b..7b49dfb6244 100644 --- a/core/app/models/spree/tax/order_adjuster.rb +++ b/core/app/models/spree/tax/order_adjuster.rb @@ -14,7 +14,7 @@ def initialize(order) # Creates tax adjustments for all taxable items (shipments and line items) # in the given order. def adjust! - return unless order_tax_zone(order) + return unless order.tax_address.country_id (order.line_items + order.shipments).each do |item| ItemAdjuster.new(item, order_wide_options).adjust! @@ -25,9 +25,8 @@ def adjust! def order_wide_options { - rates_for_order_zone: rates_for_order_zone(order), - rates_for_default_zone: rates_for_default_zone, - order_tax_zone: order_tax_zone(order), + rates_for_order: rates_for_order(order), + rates_for_default_zone: rates_for_default_zone } end end diff --git a/core/app/models/spree/tax/tax_helpers.rb b/core/app/models/spree/tax/tax_helpers.rb index a4e28f56426..1aff7591588 100644 --- a/core/app/models/spree/tax/tax_helpers.rb +++ b/core/app/models/spree/tax/tax_helpers.rb @@ -17,26 +17,22 @@ module TaxHelpers # # For further discussion, see https://github.com/spree/spree/issues/4397 and https://github.com/spree/spree/issues/4327. def applicable_rates(order) - order_zone_tax_categories = rates_for_order_zone(order).map(&:tax_category) + order_zone_tax_categories = rates_for_order(order).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(order) + default_rates_with_unmatched_tax_category).uniq + (rates_for_order(order) + default_rates_with_unmatched_tax_category).uniq end - def rates_for_order_zone(order) - @rates_for_order_zone ||= Spree::TaxRate.for_zone(order_tax_zone(order)) + def rates_for_order(order) + @rates_for_order ||= Spree::TaxRate.for_address(order.tax_address) end def rates_for_default_zone @rates_for_default_zone ||= Spree::TaxRate.for_zone(Spree::Zone.default_tax) end - def order_tax_zone(order) - @order_tax_zone ||= order.tax_zone - end - def sum_of_included_tax_rates(item) rates_for_item(item).map(&:amount).sum end diff --git a/core/app/models/spree/tax_rate.rb b/core/app/models/spree/tax_rate.rb index 31d0c7d64ed..93fd08e83f6 100644 --- a/core/app/models/spree/tax_rate.rb +++ b/core/app/models/spree/tax_rate.rb @@ -66,7 +66,7 @@ class TaxRate < Spree::Base scope :included_in_price, -> { where(included_in_price: true) } # Creates necessary tax adjustments for the order. - def adjust(order_tax_zone, item) + def adjust(_order_tax_zone, item) amount = compute_amount(item) return if amount == 0 diff --git a/core/spec/lib/spree/core/unreturned_item_charger_spec.rb b/core/spec/lib/spree/core/unreturned_item_charger_spec.rb index adb5b7cc383..1b9e307e8d1 100644 --- a/core/spec/lib/spree/core/unreturned_item_charger_spec.rb +++ b/core/spec/lib/spree/core/unreturned_item_charger_spec.rb @@ -49,7 +49,6 @@ context 'in tax zone' do let!(:tax_zone) { create(:zone, countries: [ship_address.country]) } let!(:tax_rate) { create(:tax_rate, zone: tax_zone, tax_category: original_variant.tax_category) } - before { tax_zone.update_attributes!(default_tax: true) } it "applies tax" do exchange_order = exchange_shipment.order diff --git a/core/spec/lib/tasks/exchanges_spec.rb b/core/spec/lib/tasks/exchanges_spec.rb index 01d02398f9a..7b2ceda29af 100644 --- a/core/spec/lib/tasks/exchanges_spec.rb +++ b/core/spec/lib/tasks/exchanges_spec.rb @@ -27,7 +27,8 @@ let(:return_item_1) { build(:exchange_return_item, inventory_unit: order.inventory_units.first) } let(:return_item_2) { build(:exchange_return_item, inventory_unit: order.inventory_units.last) } let!(:rma) { create(:return_authorization, order: order, return_items: [return_item_1, return_item_2]) } - let!(:tax_rate) { create(:tax_rate, zone: order.tax_zone, tax_category: return_item_2.exchange_variant.tax_category) } + let(:zone) { create(:zone, countries: [order.tax_address.country])} + let!(:tax_rate) { create(:tax_rate, zone: zone, tax_category: return_item_2.exchange_variant.tax_category) } before do rma.save! Spree::Shipment.last.ship! @@ -44,7 +45,8 @@ let(:return_item_1) { build(:exchange_return_item, inventory_unit: order.inventory_units.first) } let(:return_item_2) { build(:exchange_return_item, inventory_unit: order.inventory_units.last) } let!(:rma) { create(:return_authorization, order: order, return_items: [return_item_1, return_item_2]) } - let!(:tax_rate) { create(:tax_rate, zone: order.tax_zone, tax_category: return_item_2.exchange_variant.tax_category) } + let(:zone) { create(:zone, countries: [order.tax_address.country])} + let!(:tax_rate) { create(:tax_rate, zone: zone, tax_category: return_item_2.exchange_variant.tax_category) } before do rma.save! diff --git a/core/spec/models/spree/order/checkout_spec.rb b/core/spec/models/spree/order/checkout_spec.rb index 824b6175ccf..4b6db7399cc 100644 --- a/core/spec/models/spree/order/checkout_spec.rb +++ b/core/spec/models/spree/order/checkout_spec.rb @@ -183,7 +183,8 @@ def assert_state_changed(order, from, to) end it "recalculates tax and updates totals" do - create(:tax_rate, tax_category: line_item.tax_category, amount: 0.05, zone: order.tax_zone) + zone = create(:zone, countries: [order.tax_address.country]) + create(:tax_rate, tax_category: line_item.tax_category, amount: 0.05, zone: zone) order.next! expect(order).to have_attributes( adjustment_total: 0.5, diff --git a/core/spec/models/spree/order/tax_spec.rb b/core/spec/models/spree/order/tax_spec.rb index dea0df1abe5..fee9451886d 100644 --- a/core/spec/models/spree/order/tax_spec.rb +++ b/core/spec/models/spree/order/tax_spec.rb @@ -12,7 +12,9 @@ module Spree context "when no zones exist" do it "should return nil" do - expect(order.tax_zone).to be_nil + Spree::Deprecation.silence do + expect(order.tax_zone).to be_nil + end end end @@ -22,7 +24,9 @@ module Spree it "should calculate using ship_address" do expect(Spree::Zone).to receive(:match).at_least(:once).with(ship_address) expect(Spree::Zone).not_to receive(:match).with(bill_address) - order.tax_zone + Spree::Deprecation.silence do + order.tax_zone + end end end @@ -32,7 +36,9 @@ module Spree it "should calculate using bill_address" do expect(Spree::Zone).to receive(:match).at_least(:once).with(bill_address) expect(Spree::Zone).not_to receive(:match).with(ship_address) - order.tax_zone + Spree::Deprecation.silence do + order.tax_zone + end end end @@ -46,7 +52,9 @@ module Spree before { allow(Spree::Zone).to receive_messages(match: zone) } it "should return the matching zone" do - expect(order.tax_zone).to eq(zone) + Spree::Deprecation.silence do + expect(order.tax_zone).to eq(zone) + end end end @@ -54,7 +62,9 @@ module Spree before { allow(Spree::Zone).to receive_messages(match: nil) } it "should return the default tax zone" do - expect(order.tax_zone).to eq(@default_zone) + Spree::Deprecation.silence do + expect(order.tax_zone).to eq(@default_zone) + end end end end @@ -66,7 +76,9 @@ module Spree before { allow(Spree::Zone).to receive_messages(match: zone) } it "should return the matching zone" do - expect(order.tax_zone).to eq(zone) + Spree::Deprecation.silence do + expect(order.tax_zone).to eq(zone) + end end end @@ -74,10 +86,13 @@ module Spree before { allow(Spree::Zone).to receive_messages(match: nil) } it "should return nil" do - expect(order.tax_zone).to be_nil + Spree::Deprecation.silence do + expect(order.tax_zone).to be_nil + end end end end + end end end diff --git a/core/spec/models/spree/order_contents_spec.rb b/core/spec/models/spree/order_contents_spec.rb index ef2da601e80..ee872e63afe 100644 --- a/core/spec/models/spree/order_contents_spec.rb +++ b/core/spec/models/spree/order_contents_spec.rb @@ -103,9 +103,9 @@ create(:tax_rate, zone: zone, tax_category: variant.tax_category) end - context 'when the order has a tax zone' do + context 'when the order has a taxable address' do before do - expect(order.tax_zone).to be_present + expect(order.tax_address.country_id).to be_present end it 'creates a tax adjustment' do @@ -115,10 +115,10 @@ end end - context 'when the order does not have a tax zone' do + context 'when the order does not have a taxable address' do before do order.update_attributes!(ship_address: nil, bill_address: nil) - expect(order.tax_zone).to be_nil + expect(order.tax_address.country_id).to be_nil end it 'creates a tax adjustment' do diff --git a/core/spec/models/spree/promotion_handler/coupon_spec.rb b/core/spec/models/spree/promotion_handler/coupon_spec.rb index 0cf9db3d019..b861bec4313 100644 --- a/core/spec/models/spree/promotion_handler/coupon_spec.rb +++ b/core/spec/models/spree/promotion_handler/coupon_spec.rb @@ -252,57 +252,59 @@ def expect_adjustment_creation(adjustable:, promotion:, promotion_code:nil) context "for an order with taxable line items" do let(:store) { create(:store) } + let(:order) { create(:order, store: store) } + let(:tax_category) { create(:tax_category, name: "Taxable Foo") } + let(:zone) { create(:zone, :with_country) } + let!(:tax_rate) { create(:tax_rate, amount: 0.1, tax_category: tax_category, zone: zone )} + before(:each) do - @country = create(:country) - @zone = create(:zone, name: "Country Zone", default_tax: true, zone_members: []) - @zone.zone_members.create(zoneable: @country) - @category = Spree::TaxCategory.create name: "Taxable Foo" - @rate1 = Spree::TaxRate.create( - amount: 0.10, - calculator: Spree::Calculator::DefaultTax.create, - tax_category: @category, - zone: @zone - ) - - @order = Spree::Order.create!(store: store) - allow(@order).to receive_messages coupon_code: "10off" + expect(order).to receive(:tax_address).at_least(:once).and_return(Spree::Tax::TaxLocation.new(country: zone.countries.first)) end + context "and the product price is less than promo discount" do before(:each) do + expect(order).to receive(:coupon_code).at_least(:once).and_return("10off") + 3.times do |_i| - taxable = create(:product, tax_category: @category, price: 9.0) - @order.contents.add(taxable.master, 1) + taxable = create(:product, tax_category: tax_category, price: 9.0) + order.contents.add(taxable.master, 1) end end + it "successfully applies the promo" do # 3 * (9 + 0.9) - expect(@order.total).to eq(29.7) - coupon = Coupon.new(@order) + expect(order.total).to eq(29.7) + coupon = Coupon.new(order) coupon.apply expect(coupon.success).to be_present # 3 * ((9 - [9,10].min) + 0) - expect(@order.reload.total).to eq(0) - expect(@order.additional_tax_total).to eq(0) + expect(order.reload.total).to eq(0) + expect(order.additional_tax_total).to eq(0) end end + context "and the product price is greater than promo discount" do before(:each) do + expect(order).to receive(:coupon_code).at_least(:once).and_return("10off") + 3.times do |_i| - taxable = create(:product, tax_category: @category, price: 11.0) - @order.contents.add(taxable.master, 2) + taxable = create(:product, tax_category: tax_category, price: 11.0) + order.contents.add(taxable.master, 2) end end + it "successfully applies the promo" do # 3 * (22 + 2.2) - expect(@order.total.to_f).to eq(72.6) - coupon = Coupon.new(@order) + expect(order.total.to_f).to eq(72.6) + coupon = Coupon.new(order) coupon.apply expect(coupon.success).to be_present # 3 * ( (22 - 10) + 1.2) - expect(@order.reload.total).to eq(39.6) - expect(@order.additional_tax_total).to eq(3.6) + expect(order.reload.total).to eq(39.6) + expect(order.additional_tax_total).to eq(3.6) end end + context "and multiple quantity per line item" do before(:each) do twnty_off = create(:promotion, name: "promo", code: "20off") @@ -310,22 +312,23 @@ def expect_adjustment_creation(adjustable:, promotion:, promotion_code:nil) Promotion::Actions::CreateItemAdjustments.create(promotion: twnty_off, calculator: twnty_off_calc) - allow(@order).to receive(:coupon_code).and_call_original - allow(@order).to receive_messages coupon_code: "20off" + expect(order).to receive(:coupon_code).at_least(:once).and_return("20off") + 3.times do |_i| - taxable = create(:product, tax_category: @category, price: 10.0) - @order.contents.add(taxable.master, 2) + taxable = create(:product, tax_category: tax_category, price: 10.0) + order.contents.add(taxable.master, 2) end end + it "successfully applies the promo" do # 3 * ((2 * 10) + 2.0) - expect(@order.total.to_f).to eq(66) - coupon = Coupon.new(@order) + expect(order.total.to_f).to eq(66) + coupon = Coupon.new(order) coupon.apply expect(coupon.success).to be_present # 0 - expect(@order.reload.total).to eq(0) - expect(@order.additional_tax_total).to eq(0) + expect(order.reload.total).to eq(0) + expect(order.additional_tax_total).to eq(0) end end end diff --git a/core/spec/models/spree/shipping_rate_spec.rb b/core/spec/models/spree/shipping_rate_spec.rb index 52521198bca..d02bc3c83ff 100644 --- a/core/spec/models/spree/shipping_rate_spec.rb +++ b/core/spec/models/spree/shipping_rate_spec.rb @@ -141,7 +141,9 @@ end it "shows correct tax amount" do - expect(shipping_rate.display_price.to_s).to eq("$10.00 (+ $1.00 Sales Tax, + $0.50 Other Sales Tax)") + expect(shipping_rate.display_price.to_s).to match(/\$10.00 \(.*, .*\)/) + expect(shipping_rate.display_price.to_s).to include("+ $1.00 Sales Tax") + expect(shipping_rate.display_price.to_s).to include("+ $0.50 Other Sales Tax") end context "when cost is zero" do diff --git a/core/spec/models/spree/stock/estimator_spec.rb b/core/spec/models/spree/stock/estimator_spec.rb index a1b9939d8bb..5bc5e2932fd 100644 --- a/core/spec/models/spree/stock/estimator_spec.rb +++ b/core/spec/models/spree/stock/estimator_spec.rb @@ -140,7 +140,9 @@ module Stock end context "includes tax adjustments if applicable" do - let!(:tax_rate) { create(:tax_rate, zone: order.tax_zone) } + let(:zone) { create(:zone, countries: [order.tax_address.country])} + + let!(:tax_rate) { create(:tax_rate, zone: zone) } before do shipping_method.update!(tax_category: tax_rate.tax_category) diff --git a/core/spec/models/spree/tax/item_adjuster_spec.rb b/core/spec/models/spree/tax/item_adjuster_spec.rb index 1f58f9f1dfe..419e1a9da34 100644 --- a/core/spec/models/spree/tax/item_adjuster_spec.rb +++ b/core/spec/models/spree/tax/item_adjuster_spec.rb @@ -5,10 +5,6 @@ let(:order) { create(:order) } 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) @@ -21,14 +17,13 @@ describe '#adjust!' do before do - expect(order).to receive(:tax_zone).and_return(tax_zone) + expect(order).to receive(:tax_address).at_least(:once).and_return(address) end context 'when the order has no tax zone' do - let(:tax_zone) { nil } + let(:address) { Spree::Tax::TaxLocation.new } before do - allow(order).to receive(:tax_zone).and_return(nil) adjuster.adjust! end @@ -37,13 +32,12 @@ end end - context 'when the order has a tax zone' do + context 'when the order has an address thats taxable' do let(:item) { build_stubbed :line_item, order: order } - let(:tax_zone) { build_stubbed(:zone, :with_country) } + let(:address) { order.tax_address } before do - 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([]) + expect(Spree::TaxRate).to receive(:for_address).with(order.tax_address).and_return(rates_for_order_zone) end context 'when there are no matching rates' do diff --git a/core/spec/models/spree/tax/order_adjuster_spec.rb b/core/spec/models/spree/tax/order_adjuster_spec.rb index 8cfd7b84f85..e9cd63b2f9a 100644 --- a/core/spec/models/spree/tax/order_adjuster_spec.rb +++ b/core/spec/models/spree/tax/order_adjuster_spec.rb @@ -12,32 +12,28 @@ 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(:rates_for_default_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([]) + expect(Spree::TaxRate).to receive(:for_address).with(order.tax_address).and_return(rates_for_order_zone) 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, - rates_for_default_zone: [], - order_tax_zone: zone, + rates_for_order: rates_for_order_zone, + rates_for_default_zone: rates_for_default_zone ).and_return(item_adjuster) expect(Spree::Tax::ItemAdjuster).to receive(:new). with( line_items.second, - rates_for_order_zone: rates_for_order_zone, - rates_for_default_zone: [], - order_tax_zone: zone, + rates_for_order: rates_for_order_zone, + rates_for_default_zone: rates_for_default_zone ).and_return(item_adjuster) expect(item_adjuster).to receive(:adjust!).twice diff --git a/core/spec/models/spree/tax_rate_spec.rb b/core/spec/models/spree/tax_rate_spec.rb index 4ca8440591c..6b6f41aa6dd 100644 --- a/core/spec/models/spree/tax_rate_spec.rb +++ b/core/spec/models/spree/tax_rate_spec.rb @@ -152,7 +152,7 @@ describe 'adjustments' do before do - tax_rate.adjust(order.tax_zone, item) + tax_rate.adjust(nil, item) end let(:adjustment_label) { item.adjustments.tax.first.label }