mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-27 01:43:22 +00:00
Record the tax included in per-order EnterpriseFees
This commit is contained in:
@@ -2,12 +2,16 @@ module OpenFoodNetwork
|
||||
class EnterpriseFeeApplicator < Struct.new(:enterprise_fee, :variant, :role)
|
||||
def create_line_item_adjustment(line_item)
|
||||
a = enterprise_fee.create_locked_adjustment(line_item_adjustment_label, line_item.order, line_item, true)
|
||||
|
||||
AdjustmentMetadata.create! adjustment: a, enterprise: enterprise_fee.enterprise, fee_name: enterprise_fee.name, fee_type: enterprise_fee.fee_type, enterprise_role: role
|
||||
end
|
||||
|
||||
def create_order_adjustment(order)
|
||||
a = enterprise_fee.create_locked_adjustment(order_adjustment_label, order, order, true)
|
||||
|
||||
AdjustmentMetadata.create! adjustment: a, enterprise: enterprise_fee.enterprise, fee_name: enterprise_fee.name, fee_type: enterprise_fee.fee_type, enterprise_role: role
|
||||
|
||||
a.set_absolute_included_tax! adjustment_tax(order, a)
|
||||
end
|
||||
|
||||
|
||||
@@ -24,6 +28,46 @@ module OpenFoodNetwork
|
||||
def base_adjustment_label
|
||||
"#{enterprise_fee.fee_type} fee by #{role} #{enterprise_fee.enterprise.name}"
|
||||
end
|
||||
|
||||
def adjustment_tax(order, adjustment)
|
||||
enterprise_fee.tax_category.tax_rates.match(order).sum do |rate|
|
||||
compute_tax rate, adjustment.amount
|
||||
end
|
||||
end
|
||||
|
||||
# Apply a TaxRate to a particular amount. TaxRates normally compute against
|
||||
# LineItems or Orders, so we mock out a line item here to fit the interface
|
||||
# that our calculator (usually DefaultTax) expects.
|
||||
def compute_tax(tax_rate, amount)
|
||||
product = OpenStruct.new tax_category: tax_rate.tax_category
|
||||
line_item = Spree::LineItem.new quantity: 1
|
||||
line_item.define_singleton_method(:product) { product }
|
||||
line_item.define_singleton_method(:price) { amount }
|
||||
|
||||
# The enterprise fee adjustments for which we're calculating tax are always inclusive of
|
||||
# tax. However, there's nothing to stop an admin from setting one up with a tax rate
|
||||
# that's marked as not inclusive of tax, and that would result in the DefaultTax
|
||||
# calculator generating a slightly incorrect value. Therefore, we treat the tax
|
||||
# rate as inclusive of tax for the calculations below, regardless of its original
|
||||
# setting.
|
||||
with_tax_included_in_price(tax_rate) do
|
||||
tax_rate.calculator.compute line_item
|
||||
end
|
||||
end
|
||||
|
||||
def with_tax_included_in_price(tax_rate)
|
||||
old_included_in_price = tax_rate.included_in_price
|
||||
|
||||
tax_rate.included_in_price = true
|
||||
tax_rate.calculator.calculable.included_in_price = true
|
||||
|
||||
result = yield
|
||||
|
||||
tax_rate.included_in_price = old_included_in_price
|
||||
tax_rate.calculator.calculable.included_in_price = old_included_in_price
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -65,4 +65,33 @@ module OpenFoodNetwork
|
||||
efa.send(:order_adjustment_label).should == "Whole order - packing fee by distributor Ballantyne"
|
||||
end
|
||||
end
|
||||
|
||||
describe "ensuring that tax rate is marked as tax included_in_price" do
|
||||
let(:efa) { EnterpriseFeeApplicator.new nil, nil, nil }
|
||||
let(:tax_rate) { create(:tax_rate, included_in_price: false, calculator: Spree::Calculator::DefaultTax.new) }
|
||||
|
||||
it "sets included_in_price to true" do
|
||||
efa.send(:with_tax_included_in_price, tax_rate) do
|
||||
tax_rate.included_in_price.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
it "sets the included_in_price value accessible to the calculator to true" do
|
||||
efa.send(:with_tax_included_in_price, tax_rate) do
|
||||
tax_rate.calculator.calculable.included_in_price.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
it "passes through the return value of the block" do
|
||||
efa.send(:with_tax_included_in_price, tax_rate) do
|
||||
'asdf'
|
||||
end.should == 'asdf'
|
||||
end
|
||||
|
||||
it "restores both values to their original afterwards" do
|
||||
efa.send(:with_tax_included_in_price, tax_rate) {}
|
||||
tax_rate.included_in_price.should be_false
|
||||
tax_rate.calculator.calculable.included_in_price.should be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -79,6 +79,57 @@ module Spree
|
||||
end
|
||||
end
|
||||
|
||||
describe "EnterpriseFee adjustments" do
|
||||
let!(:zone) { create(:zone, default_tax: true) }
|
||||
let!(:zone_member) { ZoneMember.create!(zone: zone, zoneable: Country.find_by_name('Australia')) }
|
||||
let(:tax_rate) { create(:tax_rate, included_in_price: true, calculator: Calculator::DefaultTax.new, zone: zone, amount: 0.1) }
|
||||
let(:tax_category) { create(:tax_category, tax_rates: [tax_rate]) }
|
||||
let(:tax_category_untaxed) { create(:tax_category) }
|
||||
|
||||
let(:coordinator) { create(:distributor_enterprise) }
|
||||
let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, tax_category: tax_category, calculator: Calculator::FlatRate.new(preferred_amount: 50.0)) }
|
||||
let(:order_cycle) { create(:simple_order_cycle, coordinator: coordinator, coordinator_fees: [enterprise_fee], distributors: [coordinator]) }
|
||||
let!(:order) { create(:order, order_cycle: order_cycle, distributor: coordinator) }
|
||||
let!(:line_item) { create(:line_item, order: order) }
|
||||
let(:adjustment) { order.adjustments(:reload).enterprise_fee.first }
|
||||
|
||||
before do
|
||||
order.update_distribution_charge!
|
||||
end
|
||||
|
||||
context "when enterprise fees are taxed" 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
|
||||
|
||||
adjustment.included_tax.should == 4.55
|
||||
end
|
||||
|
||||
context "when the tax rate does not include the tax in the price" do
|
||||
before do
|
||||
tax_rate.update_attribute :included_in_price, false
|
||||
order.update_distribution_charge!
|
||||
end
|
||||
|
||||
it "treats it as inclusive anyway" do
|
||||
adjustment.included_tax.should == 4.55
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when enterprise fees have no tax" do
|
||||
before do
|
||||
enterprise_fee.tax_category = tax_category_untaxed
|
||||
enterprise_fee.save!
|
||||
order.update_distribution_charge!
|
||||
end
|
||||
|
||||
it "records no tax as charged" do
|
||||
adjustment.included_tax.should == 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "setting the included tax by tax rate" do
|
||||
let(:adjustment) { Adjustment.new label: 'foo', amount: 50 }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user