From 8c41a6c9097cd3d4476d83afe914bdbda801f024 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 31 Jul 2014 10:09:46 +1000 Subject: [PATCH] Calculate fee breakdown --- app/models/spree/variant_decorator.rb | 4 ++++ app/serializers/api/variant_serializer.rb | 7 ++---- .../enterprise_fee_calculator.rb | 23 +++++++++++++++---- .../enterprise_fee_calculator_spec.rb | 17 +++++++++++++- spec/models/spree/variant_spec.rb | 14 +++++++++++ 5 files changed, 54 insertions(+), 11 deletions(-) diff --git a/app/models/spree/variant_decorator.rb b/app/models/spree/variant_decorator.rb index 1ad2dd75d0..7d4f178488 100644 --- a/app/models/spree/variant_decorator.rb +++ b/app/models/spree/variant_decorator.rb @@ -48,6 +48,10 @@ Spree::Variant.class_eval do OpenFoodNetwork::EnterpriseFeeCalculator.new(distributor, order_cycle).fees_for self end + def fees_by_type_for(distributor, order_cycle) + OpenFoodNetwork::EnterpriseFeeCalculator.new(distributor, order_cycle).fees_by_type_for self + end + # Copied and modified from Spree::Variant def options_text diff --git a/app/serializers/api/variant_serializer.rb b/app/serializers/api/variant_serializer.rb index 74bc19e65c..e03f1e0ec8 100644 --- a/app/serializers/api/variant_serializer.rb +++ b/app/serializers/api/variant_serializer.rb @@ -7,13 +7,10 @@ class Api::VariantSerializer < ActiveModel::Serializer end def base_price - 1.00 + object.price end def fees - {admin: 1.23, sales: 4.56, packing: 7.89, transport: 0.12} + object.fees_by_type_for(options[:current_distributor], options[:current_order_cycle]) end end - - -# price_without_fees / price diff --git a/lib/open_food_network/enterprise_fee_calculator.rb b/lib/open_food_network/enterprise_fee_calculator.rb index bbd220cfad..2d76d8d280 100644 --- a/lib/open_food_network/enterprise_fee_calculator.rb +++ b/lib/open_food_network/enterprise_fee_calculator.rb @@ -10,14 +10,19 @@ module OpenFoodNetwork def fees_for(variant) per_item_enterprise_fee_applicators_for(variant).sum do |applicator| - # Spree's Calculator interface accepts Orders or LineItems, - # so we meet that interface with a struct. - # Amount is faked, this is a method on LineItem - line_item = OpenStruct.new variant: variant, quantity: 1, amount: variant.price - applicator.enterprise_fee.compute_amount(line_item) + calculate_fee_for variant, applicator end end + def fees_by_type_for(variant) + per_item_enterprise_fee_applicators_for(variant).inject({}) do |fees, applicator| + fees[applicator.enterprise_fee.fee_type.to_sym] ||= 0 + fees[applicator.enterprise_fee.fee_type.to_sym] += calculate_fee_for variant, applicator + fees + end + end + + def create_line_item_adjustments_for(line_item) variant = line_item.variant @distributor = line_item.order.distributor @@ -40,6 +45,14 @@ module OpenFoodNetwork private + def calculate_fee_for(variant, applicator) + # Spree's Calculator interface accepts Orders or LineItems, + # so we meet that interface with a struct. + # Amount is faked, this is a method on LineItem + line_item = OpenStruct.new variant: variant, quantity: 1, amount: variant.price + applicator.enterprise_fee.compute_amount(line_item) + end + def per_item_enterprise_fee_applicators_for(variant) fees = [] diff --git a/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb b/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb index 697bb3c702..21c4848fda 100644 --- a/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb +++ b/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb @@ -8,7 +8,7 @@ module OpenFoodNetwork let(:order_cycle) { create(:simple_order_cycle) } let(:product) { create(:simple_product, price: 10.00) } - describe "calculating fees for a variant via a particular distribution" do + describe "calculating fees for a variant" do it "sums all the per-item fees for the variant in the specified hub + order cycle" do enterprise_fee1 = create(:enterprise_fee, amount: 20) enterprise_fee2 = create(:enterprise_fee, amount: 3) @@ -32,6 +32,21 @@ module OpenFoodNetwork end end + describe "calculating fees by type" do + let!(:ef_admin) { create(:enterprise_fee, fee_type: 'admin', amount: 1.23) } + let!(:ef_sales) { create(:enterprise_fee, fee_type: 'sales', amount: 4.56) } + let!(:ef_packing) { create(:enterprise_fee, fee_type: 'packing', amount: 7.89) } + let!(:ef_transport) { create(:enterprise_fee, fee_type: 'transport', amount: 0.12) } + let!(:exchange) { create(:exchange, order_cycle: order_cycle, + sender: coordinator, receiver: distributor, incoming: false, + enterprise_fees: [ef_admin, ef_sales, ef_packing, ef_transport], + variants: [product.master]) } + + it "returns a breakdown of fees" do + EnterpriseFeeCalculator.new(distributor, order_cycle).fees_by_type_for(product.master).should == {admin: 1.23, sales: 4.56, packing: 7.89, transport: 0.12} + end + end + describe "creating adjustments" do let(:order) { create(:order, distributor: distributor, order_cycle: order_cycle) } let!(:line_item) { create(:line_item, order: order, variant: product.master) } diff --git a/spec/models/spree/variant_spec.rb b/spec/models/spree/variant_spec.rb index d1d833664a..7fb160ce3f 100644 --- a/spec/models/spree/variant_spec.rb +++ b/spec/models/spree/variant_spec.rb @@ -94,6 +94,20 @@ module Spree end + describe "calculating fees broken down by fee type" do + it "delegates to EnterpriseFeeCalculator" do + distributor = double(:distributor) + order_cycle = double(:order_cycle) + variant = Variant.new + fees = double(:fees) + + OpenFoodNetwork::EnterpriseFeeCalculator.any_instance.should_receive(:fees_by_type_for).with(variant) { fees } + + variant.fees_by_type_for(distributor, order_cycle).should == fees + end + end + + context "when the product has variants" do let!(:product) { create(:simple_product) } let!(:variant) { create(:variant, product: product) }