Files
openfoodnetwork/spec/models/spree/adjustment_spec.rb
Matt-Yorkley 0247386f82 Delete dead code Spree::Order#price_adjustments
This method returns the same thing as the Spree::Order#line_items_adjustments scope, but in a slightly less useful format (an array instead of a relation). The method's name is also totally inaccurate, as currently the only adjustments that appear on line items are tax adjustments for inclusive tax rates, which by definition have no effect on the price whatsoever...
2021-01-23 00:05:56 +00:00

465 lines
18 KiB
Ruby

# frozen_string_literal: true
require 'spec_helper'
module Spree
describe Adjustment do
let(:order) { build(:order) }
let(:adjustment) { Spree::Adjustment.create(label: "Adjustment", amount: 5) }
describe "scopes" do
let!(:arbitrary_adjustment) { create(:adjustment, source: nil, label: "Arbitrary") }
let!(:return_authorization_adjustment) { create(:adjustment, source: create(:return_authorization)) }
it "returns return_authorization adjustments" do
expect(Spree::Adjustment.return_authorization.to_a).to eq [return_authorization_adjustment]
end
end
context "#update!" do
context "when originator present" do
let(:originator) { double("originator", update_adjustment: nil) }
before do
allow(originator).to receive_messages update_amount: true
allow(adjustment).to receive_messages originator: originator, label: 'adjustment', amount: 0
end
it "should do nothing when closed" do
adjustment.close
expect(originator).not_to receive(:update_adjustment)
adjustment.update!
end
it "should do nothing when finalized" do
adjustment.finalize
expect(originator).not_to receive(:update_adjustment)
adjustment.update!
end
it "should set the eligibility" do
expect(adjustment).to receive(:set_eligibility)
adjustment.update!
end
it "should ask the originator to update_adjustment" do
expect(originator).to receive(:update_adjustment)
adjustment.update!
end
end
it "should do nothing when originator is nil" do
allow(adjustment).to receive_messages originator: nil
expect(adjustment).not_to receive(:amount=)
adjustment.update!
end
end
context "#eligible? after #set_eligibility" do
context "when amount is 0" do
before { adjustment.amount = 0 }
it "should be eligible if mandatory?" do
adjustment.mandatory = true
adjustment.set_eligibility
expect(adjustment).to be_eligible
end
it "should not be eligible unless mandatory?" do
adjustment.mandatory = false
adjustment.set_eligibility
expect(adjustment).to_not be_eligible
end
end
context "when amount is greater than 0" do
before { adjustment.amount = 25.00 }
it "should be eligible if mandatory?" do
adjustment.mandatory = true
adjustment.set_eligibility
expect(adjustment).to be_eligible
end
end
end
context "#save" do
it "should call order#update!" do
adjustment = Spree::Adjustment.new(
adjustable: order,
amount: 10,
label: "Foo"
)
expect(order).to receive(:update!)
adjustment.save
end
end
context "adjustment state" do
let(:adjustment) { create(:adjustment, state: 'open') }
context "#immutable?" do
it "is true when adjustment state isn't open" do
adjustment.state = "closed"
expect(adjustment).to be_immutable
adjustment.state = "finalized"
expect(adjustment).to be_immutable
end
it "is false when adjustment state is open" do
adjustment.state = "open"
expect(adjustment).to_not be_immutable
end
end
context "#finalized?" do
it "is true when adjustment state is finalized" do
adjustment.state = "finalized"
expect(adjustment).to be_finalized
end
it "is false when adjustment state isn't finalized" do
adjustment.state = "closed"
expect(adjustment).to_not be_finalized
adjustment.state = "open"
expect(adjustment).to_not be_finalized
end
end
end
context "#display_amount" do
before { adjustment.amount = 10.55 }
context "with display_currency set to true" do
before { Spree::Config[:display_currency] = true }
it "shows the currency" do
expect(adjustment.display_amount.to_s).to eq "$10.55 #{Spree::Config[:currency]}"
end
end
context "with display_currency set to false" do
before { Spree::Config[:display_currency] = false }
it "does not include the currency" do
expect(adjustment.display_amount.to_s).to eq "$10.55"
end
end
context "with currency set to JPY" do
context "when adjustable is set to an order" do
before do
allow(order).to receive(:currency) { 'JPY' }
adjustment.adjustable = order
end
it "displays in JPY" do
expect(adjustment.display_amount.to_s).to eq "¥11"
end
end
context "when adjustable is nil" do
it "displays in the default currency" do
expect(adjustment.display_amount.to_s).to eq "$10.55"
end
end
end
end
context '#currency' do
it 'returns the globally configured currency' do
expect(adjustment.currency).to eq Spree::Config[:currency]
end
end
it "has metadata" do
adjustment = create(:adjustment, metadata: create(:adjustment_metadata))
expect(adjustment.metadata).to be
end
describe "querying included tax" do
let!(:adjustment_with_tax) { create(:adjustment, included_tax: 123) }
let!(:adjustment_without_tax) { create(:adjustment, included_tax: 0) }
describe "finding adjustments with and without tax included" do
it "finds adjustments with tax" do
expect(Adjustment.with_tax).to include adjustment_with_tax
expect(Adjustment.with_tax).not_to include adjustment_without_tax
end
it "finds adjustments without tax" do
expect(Adjustment.without_tax).to include adjustment_without_tax
expect(Adjustment.without_tax).not_to include adjustment_with_tax
end
end
describe "checking if an adjustment includes tax" do
it "returns true when it has > 0 tax" do
expect(adjustment_with_tax).to have_tax
end
it "returns false when it has 0 tax" do
expect(adjustment_without_tax).not_to have_tax
end
end
end
describe "recording included tax" do
describe "TaxRate adjustments" do
let!(:zone) { create(:zone_with_member) }
let!(:order) { create(:order, bill_address: create(:address)) }
let!(:line_item) { create(:line_item, order: order) }
let(:tax_rate) { create(:tax_rate, included_in_price: true, calculator: ::Calculator::FlatRate.new(preferred_amount: 0.1)) }
let(:adjustment) { line_item.adjustments(:reload).first }
before do
order.reload
tax_rate.adjust(order)
end
it "has 100% tax included" do
expect(adjustment.amount).to be > 0
expect(adjustment.included_tax).to eq(adjustment.amount)
end
it "does not crash when order data has been updated previously" do
order.line_item_adjustments.first.destroy
tax_rate.adjust(order)
end
end
describe "Shipment adjustments" do
let(:hub) { create(:distributor_enterprise, charges_sales_tax: true) }
let(:order) { create(:order, distributor: hub) }
let(:line_item) { create(:line_item, order: order) }
let(:shipping_method) { create(:shipping_method_with, :flat_rate) }
let(:shipment) { create(:shipment_with, :shipping_method, shipping_method: shipping_method, order: order) }
describe "the shipping charge" do
it "is the adjustment amount" do
order.shipments = [shipment]
expect(order.adjustments.first.amount).to eq(50)
end
end
describe "when tax on shipping is disabled" do
before do
allow(Config).to receive(:shipment_inc_vat).and_return(false)
end
it "records 0% tax on shipment adjustments" do
allow(Config).to receive(:shipping_tax_rate).and_return(0)
order.shipments = [shipment]
expect(order.adjustments.first.included_tax).to eq(0)
end
it "records 0% tax on shipments when a rate is set but shipment_inc_vat is false" do
allow(Config).to receive(:shipping_tax_rate).and_return(0.25)
order.shipments = [shipment]
expect(order.adjustments.first.included_tax).to eq(0)
end
end
describe "when tax on shipping is enabled" do
before do
allow(Config).to receive(:shipment_inc_vat).and_return(true)
end
it "takes the shipment adjustment tax included from the system setting" do
allow(Config).to receive(:shipping_tax_rate).and_return(0.25)
order.shipments = [shipment]
# Finding the tax included in an amount that's already inclusive of tax:
# total - ( total / (1 + rate) )
# 50 - ( 50 / (1 + 0.25) )
# = 10
expect(order.adjustments.first.included_tax).to eq(10.00)
end
it "records 0% tax on shipments when shipping_tax_rate is not set" do
allow(Config).to receive(:shipping_tax_rate).and_return(0)
order.shipments = [shipment]
expect(order.adjustments.first.included_tax).to eq(0)
end
it "records 0% tax on shipments when the distributor does not charge sales tax" do
order.distributor.update! charges_sales_tax: false
order.shipments = [shipment]
expect(order.adjustments.first.included_tax).to eq(0)
end
end
end
describe "EnterpriseFee adjustments" do
let(:zone) { create(:zone_with_member) }
let(:fee_tax_rate) { create(:tax_rate, included_in_price: true, calculator: ::Calculator::DefaultTax.new, zone: zone, amount: 0.1) }
let(:fee_tax_category) { create(:tax_category, tax_rates: [fee_tax_rate]) }
let(:coordinator) { create(:distributor_enterprise, charges_sales_tax: true) }
let(:variant) { create(:variant, product: create(:product, tax_category: nil)) }
let(:order_cycle) { create(:simple_order_cycle, coordinator: coordinator, coordinator_fees: [enterprise_fee], distributors: [coordinator], variants: [variant]) }
let(:line_item) { create(:line_item, variant: variant) }
let(:order) { create(:order, line_items: [line_item], order_cycle: order_cycle, distributor: coordinator) }
let(:adjustment) { order.adjustments(:reload).enterprise_fee.first }
context "when enterprise fees have a fixed tax_category" do
before do
order.reload.update_distribution_charge!
end
context "when enterprise fees are taxed per-order" do
let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, tax_category: fee_tax_category, calculator: ::Calculator::FlatRate.new(preferred_amount: 50.0)) }
describe "when the tax rate includes the tax in the price" do
it "records the tax on the enterprise fee adjustments" do
# The fee is $50, tax is 10%, and the fee is inclusive of tax
# Therefore, the included tax should be 0.1/1.1 * 50 = $4.55
expect(adjustment.included_tax).to eq(4.55)
end
end
describe "when the tax rate does not include the tax in the price" do
before do
fee_tax_rate.update_attribute :included_in_price, false
order.reload.create_tax_charge! # Updating line_item or order has the same effect
order.update_distribution_charge!
end
it "records the tax on TaxRate adjustment on the order" do
expect(adjustment.included_tax).to eq(0)
expect(order.adjustments.tax.first.amount).to eq(5.0)
end
end
describe "when enterprise fees have no tax" do
before do
enterprise_fee.tax_category = nil
enterprise_fee.save!
order.update_distribution_charge!
end
it "records no tax as charged" do
expect(adjustment.included_tax).to eq(0)
end
end
end
context "when enterprise fees are taxed per-item" do
let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, tax_category: fee_tax_category, calculator: ::Calculator::PerItem.new(preferred_amount: 50.0)) }
describe "when the tax rate includes the tax in the price" do
it "records the tax on the enterprise fee adjustments" do
expect(adjustment.included_tax).to eq(4.55)
end
end
describe "when the tax rate does not include the tax in the price" do
before do
fee_tax_rate.update_attribute :included_in_price, false
order.reload.create_tax_charge! # Updating line_item or order has the same effect
order.update_distribution_charge!
end
it "records the tax on TaxRate adjustment on the order" do
expect(adjustment.included_tax).to eq(0)
expect(order.adjustments.tax.first.amount).to eq(5.0)
end
end
end
end
context "when enterprise fees inherit their tax_category from the product they are applied to" do
let(:product_tax_rate) {
create(:tax_rate, included_in_price: true, calculator: ::Calculator::DefaultTax.new, zone: zone, amount: 0.2)
}
let(:product_tax_category) { create(:tax_category, tax_rates: [product_tax_rate]) }
before do
variant.product.update_attribute(:tax_category_id, product_tax_category.id)
order.create_tax_charge! # Updating line_item or order has the same effect
order.update_distribution_charge!
end
context "when enterprise fees are taxed per-order" do
let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, inherits_tax_category: true, calculator: ::Calculator::FlatRate.new(preferred_amount: 50.0)) }
describe "when the tax rate includes the tax in the price" do
it "records no tax on the enterprise fee adjustments" do
# EnterpriseFee tax category is nil and inheritance only applies to per item fees
# so tax on the enterprise_fee adjustment will be 0
# Tax on line item is: 0.2/1.2 x $10 = $1.67
expect(adjustment.included_tax).to eq(0.0)
expect(line_item.adjustments.first.included_tax).to eq(1.67)
end
end
describe "when the tax rate does not include the tax in the price" do
before do
product_tax_rate.update_attribute :included_in_price, false
order.reload.create_tax_charge! # Updating line_item or order has the same effect
order.reload.update_distribution_charge!
end
it "records the no tax on TaxRate adjustment on the order" do
# EnterpriseFee tax category is nil and inheritance only applies to per item fees
# so total tax on the order is only that which applies to the line_item itself
# ie. $10 x 0.2 = $2.0
expect(adjustment.included_tax).to eq(0)
expect(order.adjustments.tax.first.amount).to eq(2.0)
end
end
end
context "when enterprise fees are taxed per-item" do
let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, inherits_tax_category: true, calculator: ::Calculator::PerItem.new(preferred_amount: 50.0)) }
describe "when the tax rate includes the tax in the price" do
it "records the tax on the enterprise fee adjustments" do
# Applying product tax rate of 0.2 to enterprise fee of $50
# gives tax on fee of 0.2/1.2 x $50 = $8.33
# Tax on line item is: 0.2/1.2 x $10 = $1.67
expect(adjustment.included_tax).to eq(8.33)
expect(line_item.adjustments.first.included_tax).to eq(1.67)
end
end
describe "when the tax rate does not include the tax in the price" do
before do
product_tax_rate.update_attribute :included_in_price, false
order.reload.create_tax_charge! # Updating line_item or order has the same effect
order.update_distribution_charge!
end
it "records the tax on TaxRate adjustment on the order" do
# EnterpriseFee inherits tax_category from product so total tax on
# the order is that which applies to the line item itself, plus the
# same rate applied to the fee of $50. ie. ($10 + $50) x 0.2 = $12.0
expect(adjustment.included_tax).to eq(0)
expect(order.adjustments.tax.first.amount).to eq(12.0)
end
end
end
end
end
describe "setting the included tax by tax rate" do
let(:adjustment) { Adjustment.new label: 'foo', amount: 50 }
it "sets it, rounding to two decimal places" do
adjustment.set_included_tax! 0.25
expect(adjustment.included_tax).to eq(10.00)
end
end
end
context "extends LocalizedNumber" do
it_behaves_like "a model using the LocalizedNumber module", [:amount]
end
end
end