diff --git a/app/models/exchange.rb b/app/models/exchange.rb index 0f8b472443..ce698c1cd0 100644 --- a/app/models/exchange.rb +++ b/app/models/exchange.rb @@ -35,6 +35,10 @@ class Exchange < ActiveRecord::Base receiver == order_cycle.coordinator end + def role + incoming? ? 'supplier' : 'distributor' + end + def to_h(core=false) h = attributes.merge({ 'variant_ids' => variant_ids.sort, 'enterprise_fee_ids' => enterprise_fee_ids.sort }) h.reject! { |k| %w(id order_cycle_id created_at updated_at).include? k } if core diff --git a/app/models/order_cycle.rb b/app/models/order_cycle.rb index d710befc10..1dbdbbed18 100644 --- a/app/models/order_cycle.rb +++ b/app/models/order_cycle.rb @@ -1,3 +1,5 @@ +require 'open_food_network/enterprise_fee_applicator' + class OrderCycle < ActiveRecord::Base belongs_to :coordinator, :class_name => 'Enterprise' has_and_belongs_to_many :coordinator_fees, :class_name => 'EnterpriseFee', :join_table => 'coordinator_fees' @@ -144,12 +146,12 @@ class OrderCycle < ActiveRecord::Base # -- Fees def fees_for(variant, distributor) - enterprise_fees_for(variant, distributor).sum do |fee| + enterprise_fees_for(variant, distributor).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) - fee[:enterprise_fee].compute_amount(line_item) + applicator.enterprise_fee.compute_amount(line_item) end end @@ -157,7 +159,7 @@ class OrderCycle < ActiveRecord::Base variant = line_item.variant distributor = line_item.order.distributor - enterprise_fees_for(variant, distributor).each { |fee| create_adjustment_for_fee line_item, fee[:enterprise_fee], fee[:label], fee[:role] } + enterprise_fees_for(variant, distributor).each { |applicator| applicator.create_line_item_adjustment(line_item) } end private @@ -168,31 +170,17 @@ class OrderCycle < ActiveRecord::Base exchanges_carrying(variant, distributor).each do |exchange| exchange.enterprise_fees.each do |enterprise_fee| - role = exchange.incoming? ? 'supplier' : 'distributor' - fees << {enterprise_fee: enterprise_fee, - label: adjustment_label_for(variant, enterprise_fee, role), - role: role} + fees << OpenFoodNetwork::EnterpriseFeeApplicator.new(enterprise_fee, variant, exchange.role) end end coordinator_fees.each do |enterprise_fee| - fees << {enterprise_fee: enterprise_fee, - label: adjustment_label_for(variant, enterprise_fee, 'coordinator'), - role: 'coordinator'} + fees << OpenFoodNetwork::EnterpriseFeeApplicator.new(enterprise_fee, variant, 'coordinator') end fees end - def create_adjustment_for_fee(line_item, enterprise_fee, label, role) - a = enterprise_fee.create_locked_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 adjustment_label_for(variant, enterprise_fee, role) - "#{variant.product.name} - #{enterprise_fee.fee_type} fee by #{role} #{enterprise_fee.enterprise.name}" - end - def exchanges_carrying(variant, distributor) exchanges.to_enterprises([coordinator, distributor]).with_variant(variant) end diff --git a/lib/open_food_network/enterprise_fee_applicator.rb b/lib/open_food_network/enterprise_fee_applicator.rb new file mode 100644 index 0000000000..c2b3001bca --- /dev/null +++ b/lib/open_food_network/enterprise_fee_applicator.rb @@ -0,0 +1,16 @@ +module OpenFoodNetwork + class EnterpriseFeeApplicator < Struct.new(:enterprise_fee, :variant, :role) + def create_line_item_adjustment(line_item) + a = enterprise_fee.create_locked_adjustment(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 + + + private + + def adjustment_label + "#{variant.product.name} - #{enterprise_fee.fee_type} fee by #{role} #{enterprise_fee.enterprise.name}" + end + end +end + diff --git a/spec/lib/open_food_network/enterprise_fee_applicator_spec.rb b/spec/lib/open_food_network/enterprise_fee_applicator_spec.rb new file mode 100644 index 0000000000..345eae845c --- /dev/null +++ b/spec/lib/open_food_network/enterprise_fee_applicator_spec.rb @@ -0,0 +1,37 @@ +require 'open_food_network/enterprise_fee_applicator' + +module OpenFoodNetwork + describe EnterpriseFeeApplicator do + it "creates an adjustment for a line item" do + line_item = create(:line_item) + enterprise_fee = create(:enterprise_fee) + product = create(:simple_product) + + efa = EnterpriseFeeApplicator.new enterprise_fee, product.master, 'role' + efa.stub(:adjustment_label) { 'label' } + efa.create_line_item_adjustment line_item + + adjustment = Spree::Adjustment.last + adjustment.label.should == 'label' + adjustment.adjustable.should == line_item.order + adjustment.source.should == line_item + adjustment.originator.should == enterprise_fee + adjustment.should be_mandatory + + md = adjustment.metadata + md.enterprise.should == enterprise_fee.enterprise + md.fee_name.should == enterprise_fee.name + md.fee_type.should == enterprise_fee.fee_type + md.enterprise_role.should == 'role' + end + + it "makes adjustment labels" do + variant = double(:variant, product: double(:product, name: 'Bananas')) + enterprise_fee = double(:enterprise_fee, fee_type: 'packing', enterprise: double(:enterprise, name: 'Ballantyne')) + + efa = EnterpriseFeeApplicator.new enterprise_fee, variant, 'distributor' + + efa.send(:adjustment_label).should == "Bananas - packing fee by distributor Ballantyne" + end + end +end diff --git a/spec/models/exchange_spec.rb b/spec/models/exchange_spec.rb index f4ebfc2d8a..df26d20ac0 100644 --- a/spec/models/exchange_spec.rb +++ b/spec/models/exchange_spec.rb @@ -62,6 +62,20 @@ describe Exchange do end end + describe "reporting its role" do + it "returns 'supplier' when it is an incoming exchange" do + e = Exchange.new + e.stub(:incoming?) { true } + e.role.should == 'supplier' + end + + it "returns 'distributor' when it is an outgoing exchange" do + e = Exchange.new + e.stub(:incoming?) { false } + e.role.should == 'distributor' + end + end + describe "scopes" do let(:supplier) { create(:supplier_enterprise) } let(:coordinator) { create(:distributor_enterprise) } diff --git a/spec/models/order_cycle_spec.rb b/spec/models/order_cycle_spec.rb index bd8d835d91..36480ca74b 100644 --- a/spec/models/order_cycle_spec.rb +++ b/spec/models/order_cycle_spec.rb @@ -348,9 +348,9 @@ describe OrderCycle do let(:line_item) { double(:line_item, variant: variant, order: order) } it "creates adjustment for each fee" do - fee = {enterprise_fee: 'ef', label: 'label', role: 'role'} - oc.should_receive(:enterprise_fees_for).with(variant, distributor) { [fee] } - oc.should_receive(:create_adjustment_for_fee).with(line_item, 'ef', 'label', 'role') + applicator = double(:enterprise_fee_applicator) + applicator.should_receive(:create_line_item_adjustment).with(line_item) + oc.should_receive(:enterprise_fees_for).with(variant, distributor) { [applicator] } oc.send(:create_adjustments_for, line_item) end @@ -360,44 +360,16 @@ describe OrderCycle do ef1 = double(:enterprise_fee) ef2 = double(:enterprise_fee) ef3 = double(:enterprise_fee) - incoming_exchange = double(:exchange, enterprise_fees: [ef1], incoming?: true) - outgoing_exchange = double(:exchange, enterprise_fees: [ef2], incoming?: false) + incoming_exchange = double(:exchange, enterprise_fees: [ef1], role: 'supplier') + outgoing_exchange = double(:exchange, enterprise_fees: [ef2], role: 'distributor') oc.stub(:exchanges_carrying) { [incoming_exchange, outgoing_exchange] } oc.stub(:coordinator_fees) { [ef3] } - oc.stub(:adjustment_label_for) { 'label' } oc.send(:enterprise_fees_for, line_item.variant, distributor).should == - [{enterprise_fee: ef1, label: 'label', role: 'supplier'}, - {enterprise_fee: ef2, label: 'label', role: 'distributor'}, - {enterprise_fee: ef3, label: 'label', role: 'coordinator'}] - end - - it "creates an adjustment for a fee" do - line_item = create(:line_item) - enterprise_fee = create(:enterprise_fee) - - oc.send(:create_adjustment_for_fee, line_item, enterprise_fee, 'label', 'role') - - adjustment = Spree::Adjustment.last - adjustment.label.should == 'label' - adjustment.adjustable.should == line_item.order - adjustment.source.should == line_item - adjustment.originator.should == enterprise_fee - adjustment.should be_mandatory - - md = adjustment.metadata - md.enterprise.should == enterprise_fee.enterprise - md.fee_name.should == enterprise_fee.name - md.fee_type.should == enterprise_fee.fee_type - md.enterprise_role.should == 'role' - end - - it "makes adjustment labels" do - variant = double(:variant, product: double(:product, name: 'Bananas')) - enterprise_fee = double(:enterprise_fee, fee_type: 'packing', enterprise: double(:enterprise, name: 'Ballantyne')) - - oc.send(:adjustment_label_for, variant, enterprise_fee, 'distributor').should == "Bananas - packing fee by distributor Ballantyne" + [OpenFoodNetwork::EnterpriseFeeApplicator.new(ef1, line_item.variant, 'supplier'), + OpenFoodNetwork::EnterpriseFeeApplicator.new(ef2, line_item.variant, 'distributor'), + OpenFoodNetwork::EnterpriseFeeApplicator.new(ef3, line_item.variant, 'coordinator')] end end