From 137003c671278c1d2495dfe47228cf04babe01de Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 22 Jan 2016 15:31:59 +1100 Subject: [PATCH] Correct calculation of tax on EnterpriseFees with TaxRates where included_in_price=false --- .../spree/calculator/default_tax_decorator.rb | 39 +++++++++++++++++++ .../enterprise_fee_applicator.rb | 2 +- spec/models/spree/adjustment_spec.rb | 35 +++++++++++++---- 3 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 app/models/spree/calculator/default_tax_decorator.rb diff --git a/app/models/spree/calculator/default_tax_decorator.rb b/app/models/spree/calculator/default_tax_decorator.rb new file mode 100644 index 0000000000..e55cfc5536 --- /dev/null +++ b/app/models/spree/calculator/default_tax_decorator.rb @@ -0,0 +1,39 @@ +require 'open_food_network/enterprise_fee_calculator' + +Spree::Calculator::DefaultTax.class_eval do + + private + + # Override this method to enable calculation of tax for + # enterprise fees with tax rates where included_in_price = false + def compute_order(order) + matched_line_items = order.line_items.select do |line_item| + line_item.product.tax_category == rate.tax_category + end + + line_items_total = matched_line_items.sum(&:total) + + # Added this line + calculator = OpenFoodNetwork::EnterpriseFeeCalculator.new(order.distributor, order.order_cycle) + + # Added this block, finds relevant fees for each line_item, calculates the tax on them, and returns the total tax + per_item_fees_total = order.line_items.sum do |line_item| + calculator.send(:per_item_enterprise_fee_applicators_for, line_item.variant) + .select { |applicator| applicator.enterprise_fee.tax_category == rate.tax_category } + .sum { |applicator| applicator.enterprise_fee.compute_amount(line_item) } + end + + # Added this block, finds relevant fees for whole order, calculates the tax on them, and returns the total tax + per_order_fees_total = calculator.send(:per_order_enterprise_fee_applicators_for, order) + .select { |applicator| applicator.enterprise_fee.tax_category == rate.tax_category } + .sum { |applicator| applicator.enterprise_fee.compute_amount(order) } + + # round_to_two_places(line_items_total * rate.amount) # Removed this line + + # Added this block + [line_items_total, per_item_fees_total, per_order_fees_total].sum do |total| + round_to_two_places(total * rate.amount) + end + end + +end diff --git a/lib/open_food_network/enterprise_fee_applicator.rb b/lib/open_food_network/enterprise_fee_applicator.rb index 4962bc148e..26b1397193 100644 --- a/lib/open_food_network/enterprise_fee_applicator.rb +++ b/lib/open_food_network/enterprise_fee_applicator.rb @@ -34,7 +34,7 @@ module OpenFoodNetwork def adjustment_tax(order, adjustment) tax_rates = enterprise_fee.tax_category ? enterprise_fee.tax_category.tax_rates.match(order) : [] - tax_rates.sum do |rate| + tax_rates.select(&:included_in_price).sum do |rate| rate.compute_tax adjustment.amount end end diff --git a/spec/models/spree/adjustment_spec.rb b/spec/models/spree/adjustment_spec.rb index 512e720f54..cd49e3893a 100644 --- a/spec/models/spree/adjustment_spec.rb +++ b/spec/models/spree/adjustment_spec.rb @@ -137,21 +137,25 @@ module Spree context "when enterprise fees are taxed per-order" do let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, tax_category: tax_category, calculator: Calculator::FlatRate.new(preferred_amount: 50.0)) } - 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 + 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 - adjustment.included_tax.should == 4.55 + adjustment.included_tax.should == 4.55 + end end describe "when the tax rate does not include the tax in the price" do before do tax_rate.update_attribute :included_in_price, false + order.create_tax_charge! # Updating line_item or order has the same effect order.update_distribution_charge! end - it "treats it as inclusive anyway" do - adjustment.included_tax.should == 4.55 + it "records the tax on TaxRate adjustment on the order" do + adjustment.included_tax.should == 0 + order.adjustments.tax.first.amount.should == 5.0 end end @@ -172,8 +176,23 @@ module Spree context "when enterprise fees are taxed per-item" do let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, tax_category: tax_category, calculator: Calculator::PerItem.new(preferred_amount: 50.0)) } - it "records the tax on the enterprise fee adjustments" do - adjustment.included_tax.should == 4.55 + describe "when the tax rate includes the tax in the price" do + it "records the tax on the enterprise fee adjustments" do + adjustment.included_tax.should == 4.55 + end + end + + describe "when the tax rate does not include the tax in the price" do + before do + tax_rate.update_attribute :included_in_price, false + order.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 + adjustment.included_tax.should == 0 + order.adjustments.tax.first.amount.should == 5.0 + end end end end