Files
openfoodnetwork/spec/models/spree/tax_rate_spec.rb

419 lines
15 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
module Spree
describe TaxRate do
describe "#match" do
let!(:zone) { create(:zone_with_member) }
let!(:order) { create(:order, distributor: hub, bill_address: create(:address)) }
let!(:tax_rate) {
create(:tax_rate, included_in_price: true,
calculator: ::Calculator::FlatRate.new(preferred_amount: 0.1), zone: zone)
}
describe "when the order's hub charges sales tax" do
let(:hub) { create(:distributor_enterprise, charges_sales_tax: true) }
it "selects all tax rates" do
expect(TaxRate.match(order)).to eq([tax_rate])
end
end
describe "when the order's hub does not charge sales tax" do
let(:hub) { create(:distributor_enterprise, charges_sales_tax: false) }
it "selects no tax rates" do
expect(TaxRate.match(order)).to be_empty
end
end
describe "when the order does not have a hub" do
let!(:order) { create(:order, distributor: nil, bill_address: create(:address)) }
it "selects all tax rates" do
expect(TaxRate.match(order)).to eq([tax_rate])
end
end
end
context "original Spree::TaxRate specs" do
context "match" do
let(:order) { create(:order) }
let(:country) { create(:country) }
let(:tax_category) { create(:tax_category) }
let(:calculator) { ::Calculator::FlatRate.new }
it "should return an empty array when tax_zone is nil" do
allow(order).to receive(:tax_zone) { nil }
expect(Spree::TaxRate.match(order)).to eq []
end
context "when no rate zones match the tax zone" do
before do
Spree::TaxRate.create(amount: 1, zone: create(:zone))
end
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
it "should return an empty array" do
order.stub tax_zone: @zone
expect(Spree::TaxRate.match(order)).to eq []
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
)
order.stub tax_zone: @zone
expect(Spree::TaxRate.match(order)).to eq [rate]
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: ::Calculator::FlatRate.new
)
order.stub tax_zone: @zone
expect(Spree::TaxRate.match(order)).to eq [rate1, rate2]
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))
order.stub tax_zone: sub_zone
@rate = Spree::TaxRate.create(
amount: 1,
zone: @zone,
tax_category: tax_category,
calculator: calculator
)
end
it "should return the rate zone" do
expect(Spree::TaxRate.match(order)).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(: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)
end
subject { Spree::TaxRate.match(order) }
context "when the order has the same tax zone" do
before do
order.stub tax_zone: @zone
order.stub billing_address: tax_address
end
let(:tax_address) { build_stubbed(:address) }
context "when the tax is not a VAT" do
it { is_expected.to eq [rate] }
end
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
let(:other_zone) { create(:zone, name: "Other Zone") }
before do
allow(order).to receive(:tax_zone) { other_zone }
allow(order).to receive(:billing_address) { tax_address }
end
context "when the order has a tax_address" do
let(:tax_address) { build_stubbed(: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
end
end
end
end
context "adjust" do
let(:order) { create(:order) }
let(:tax_category_1) { build_stubbed(:tax_category) }
let(:tax_category_2) { build_stubbed(:tax_category) }
let(:rate_1) { build_stubbed(:tax_rate, tax_category: tax_category_1) }
let(:rate_2) { build_stubbed(:tax_rate, tax_category: tax_category_2) }
let(:line_items) { [build_stubbed(:line_item)] }
context "with line items" do
let(:line_item) { build_stubbed(:line_item, tax_category: tax_category_1) }
let(:line_items) { [line_item] }
before do
allow(Spree::TaxRate).to receive(:match) { [rate_1, rate_2] }
end
it "should apply adjustments for two tax rates to the order" do
expect(rate_1).to receive(:adjust)
expect(rate_2).to_not receive(:adjust)
Spree::TaxRate.adjust(order, line_items)
end
end
context "with shipments" do
let(:shipment) { build_stubbed(:shipment, order: order) }
let(:shipments) { [shipment] }
before do
allow(shipment).to receive(:tax_category) { tax_category_1 }
allow(Spree::TaxRate).to receive(:match) { [rate_1, rate_2] }
end
it "should apply adjustments for two tax rates to the order" do
expect(rate_1).to receive(:adjust)
expect(rate_2).to_not receive(:adjust)
Spree::TaxRate.adjust(order, shipments)
end
end
end
context "default" do
let(:tax_category) { create(:tax_category) }
let(:country) { create(:country) }
let(:calculator) { ::Calculator::FlatRate.new }
context "when there is no default tax_category" do
before { tax_category.is_default = false }
it "should return 0" do
expect(Spree::TaxRate.default).to eq 0
end
end
context "when there is a default tax_category" do
before { tax_category.update_column :is_default, true }
context "when the default category has tax rates in the default tax zone" do
before(:each) do
allow(DefaultCountry).to receive(:id) { country.id }
@zone = create(:zone, name: "Country Zone", default_tax: true)
@zone.zone_members.create(zoneable: country)
rate = Spree::TaxRate.create(
amount: 1,
zone: @zone,
tax_category: tax_category,
calculator: calculator
)
end
it "should return the correct tax_rate" do
expect(Spree::TaxRate.default.to_f).to eq 1.0
end
end
context "when the default category has no tax rates in the default tax zone" do
it "should return 0" do
expect(Spree::TaxRate.default).to eq 0
end
end
end
end
context "#adjust" do
before 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")
@category2 = Spree::TaxCategory.create(name: "Non Taxable")
@rate1 = Spree::TaxRate.create(
amount: 0.10,
calculator: ::Calculator::DefaultTax.new,
tax_category: @category,
zone: @zone
)
@rate2 = Spree::TaxRate.create(
amount: 0.05,
calculator: ::Calculator::DefaultTax.new,
tax_category: @category,
zone: @zone
)
@order = Spree::Order.create!
@taxable = create(:product, tax_category: @category)
@nontaxable = create(:product, tax_category: @category2)
end
context "not taxable line item " do
let!(:line_item) { @order.contents.add(@nontaxable.variants.first, 1) }
it "should not create a tax adjustment" do
Spree::TaxRate.adjust(@order, @order.line_items)
expect(line_item.adjustments.tax.charge.count).to eq 0
end
it "should not create a refund" do
Spree::TaxRate.adjust(@order, @order.line_items)
expect(line_item.adjustments.credit.count).to eq 0
end
end
context "taxable line item" do
let!(:line_item) { @order.contents.add(@taxable.variants.first, 1) }
before do
@rate1.update_column(:included_in_price, true)
@rate2.update_column(:included_in_price, true)
end
context "when price includes tax" do
context "when zone is contained by default tax zone" do
it "should create two adjustments, one for each tax rate" do
Spree::TaxRate.adjust(@order, @order.line_items)
expect(line_item.adjustments.count).to eq 2
end
it "should not create a tax refund" do
Spree::TaxRate.adjust(@order, @order.line_items)
expect(line_item.adjustments.credit.count).to eq 0
end
end
context "when order's zone is neither the default zone, or included in the default zone, but matches the rate's zone" do
before do
# With no zone members, this zone will not contain anything
@zone.zone_members.delete_all
end
it "should create an adjustment" do
Spree::TaxRate.adjust(@order, @order.line_items)
expect(line_item.adjustments.charge.count).to eq 2
end
it "should not create a tax refund for each tax rate" do
Spree::TaxRate.adjust(@order, @order.line_items)
expect(line_item.adjustments.credit.count).to eq 0
end
end
end
context "when order's zone does not match default zone, is not included in the default zone, AND does not match the rate's zone" do
before do
@new_zone = create(:zone, name: "New Zone", default_tax: false)
@new_country = create(:country, name: "New Country")
@new_zone.zone_members.create(zoneable: @new_country)
@new_state = create(:state, country: @new_country)
@order.ship_address = create(:address, country: @new_country, state: @new_state)
@order.save
end
it "should not create positive adjustments" do
Spree::TaxRate.adjust(@order, @order.line_items)
expect(line_item.adjustments.charge.count).to eq 0
end
it "should create a tax refund for each tax rate" do
Spree::TaxRate.adjust(@order, @order.line_items)
expect(line_item.adjustments.credit.count).to eq 2
end
end
context "when price does not include tax" do
before do
allow(@order).to receive(:tax_zone) { @zone }
[@rate1, @rate2].each do |rate|
rate.included_in_price = false
rate.zone = @zone
rate.save
end
end
it "should not delete adjustments for complete order when taxrate is deleted" do
@order.update_column :completed_at, Time.now
@rate1.destroy!
@rate2.destroy!
expect(line_item.adjustments.count).to eq 2
end
it "should create adjustments" do
expect(line_item.adjustments.count).to eq 2
end
it "should not create a tax refund" do
expect(line_item.adjustments.credit.count).to eq 0
end
it "should remove adjustments when tax_zone is removed" do
Spree::TaxRate.adjust(@order, @order.line_items)
expect(line_item.adjustments.count).to eq 2
allow(@order).to receive(:tax_zone) { nil }
Spree::TaxRate.adjust(@order, @order.line_items)
expect(line_item.adjustments.count).to eq 0
end
end
end
end
end
end
end