diff --git a/app/models/exchange.rb b/app/models/exchange.rb index 66a5894c1e..0fb27b7af5 100644 --- a/app/models/exchange.rb +++ b/app/models/exchange.rb @@ -15,10 +15,11 @@ class Exchange < ActiveRecord::Base accepts_nested_attributes_for :variants - scope :incoming, joins(:order_cycle).where('exchanges.receiver_id = order_cycles.coordinator_id') - scope :outgoing, joins(:order_cycle).where('exchanges.sender_id = order_cycles.coordinator_id') + scope :incoming, where(incoming: true) + scope :outgoing, where(incoming: false) scope :from_enterprises, lambda { |enterprises| where('exchanges.sender_id IN (?)', enterprises) } scope :to_enterprises, lambda { |enterprises| where('exchanges.receiver_id IN (?)', enterprises) } + scope :supplying_to, lambda { |distributor| where('exchanges.incoming OR exchanges.receiver_id = ?', distributor) } scope :with_variant, lambda { |variant| joins(:exchange_variants).where('exchange_variants.variant_id = ?', variant) } scope :with_any_variant, lambda { |variants| joins(:exchange_variants).where('exchange_variants.variant_id IN (?)', variants).select('DISTINCT exchanges.*') } scope :with_product, lambda { |product| joins(:exchange_variants).where('exchange_variants.variant_id IN (?)', product.variants_including_master) } @@ -32,10 +33,6 @@ class Exchange < ActiveRecord::Base exchange end - def incoming? - receiver == order_cycle.coordinator - end - def role incoming? ? 'supplier' : 'distributor' end diff --git a/app/models/order_cycle.rb b/app/models/order_cycle.rb index a6707d9220..1b85055dc3 100644 --- a/app/models/order_cycle.rb +++ b/app/models/order_cycle.rb @@ -78,11 +78,11 @@ class OrderCycle < ActiveRecord::Base end def suppliers - self.exchanges.where(:receiver_id => self.coordinator).map(&:sender).uniq + self.exchanges.incoming.map(&:sender).uniq end def distributors - self.exchanges.where(:sender_id => self.coordinator).map(&:receiver).uniq + self.exchanges.outgoing.map(&:receiver).uniq end def variants @@ -90,7 +90,7 @@ class OrderCycle < ActiveRecord::Base end def distributed_variants - self.exchanges.where(:sender_id => self.coordinator).map(&:variants).flatten.uniq + self.exchanges.outgoing.map(&:variants).flatten.uniq end def variants_distributed_by(distributor) @@ -239,11 +239,10 @@ class OrderCycle < ActiveRecord::Base end def exchanges_carrying(variant, distributor) - exchanges.to_enterprises([coordinator, distributor]).with_variant(variant) + exchanges.supplying_to(distributor).with_variant(variant) end def exchanges_supplying(order) - variants = order.line_items.map(&:variant) - exchanges.to_enterprises([coordinator, order.distributor]).with_any_variant(variants) + exchanges.supplying_to(order.distributor).with_any_variant(order.variants) end end diff --git a/db/migrate/20140324025840_add_incoming_to_exchanges.rb b/db/migrate/20140324025840_add_incoming_to_exchanges.rb new file mode 100644 index 0000000000..37df0a48db --- /dev/null +++ b/db/migrate/20140324025840_add_incoming_to_exchanges.rb @@ -0,0 +1,25 @@ +class AddIncomingToExchanges < ActiveRecord::Migration + class Exchange < ActiveRecord::Base + belongs_to :order_cycle + belongs_to :receiver, :class_name => 'Enterprise' + + def incoming? + receiver == order_cycle.coordinator + end + end + + + def up + add_column :exchanges, :incoming, :boolean, null: false, default: false + + # Initialise based on whether the exchange is going to or coming + # from the order cycle coordinator + Exchange.all.each do |exchange| + exchange.update_attribute :incoming, exchange.incoming? + end + end + + def down + remove_column :exchanges, :incoming + end +end diff --git a/db/schema.rb b/db/schema.rb index b9f151fedf..892382d1d7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20140213003443) do +ActiveRecord::Schema.define(:version => 20140324025840) do create_table "adjustment_metadata", :force => true do |t| t.integer "adjustment_id" @@ -236,8 +236,9 @@ ActiveRecord::Schema.define(:version => 20140213003443) do t.integer "payment_enterprise_id" t.string "pickup_time" t.string "pickup_instructions" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.boolean "incoming", :default => false, :null => false end create_table "landing_page_images", :force => true do |t| diff --git a/spec/models/exchange_spec.rb b/spec/models/exchange_spec.rb index 675f7d475a..5dc4fa5a61 100644 --- a/spec/models/exchange_spec.rb +++ b/spec/models/exchange_spec.rb @@ -49,9 +49,8 @@ describe Exchange do let(:coordinator) { create(:distributor_enterprise) } let(:distributor) { create(:distributor_enterprise) } let(:oc) { create(:simple_order_cycle, coordinator: coordinator) } - - let(:incoming_exchange) { oc.exchanges.create! sender: supplier, receiver: coordinator } - let(:outgoing_exchange) { oc.exchanges.create! sender: coordinator, receiver: distributor } + let(:incoming_exchange) { oc.exchanges.create! sender: supplier, receiver: coordinator, incoming: true } + let(:outgoing_exchange) { oc.exchanges.create! sender: coordinator, receiver: distributor, incoming: false } it "returns true for incoming exchanges" do incoming_exchange.should be_incoming @@ -78,29 +77,62 @@ describe Exchange do describe "scopes" do let(:supplier) { create(:supplier_enterprise) } - let(:coordinator) { create(:distributor_enterprise) } + let(:coordinator) { create(:distributor_enterprise, is_primary_producer: true) } let(:distributor) { create(:distributor_enterprise) } let(:oc) { create(:simple_order_cycle, coordinator: coordinator) } - let!(:incoming_exchange) { oc.exchanges.create! sender: supplier, receiver: coordinator } - let!(:outgoing_exchange) { oc.exchanges.create! sender: coordinator, receiver: distributor } + describe "finding exchanges by direction" do + let!(:incoming_exchange) { oc.exchanges.create! sender: supplier, receiver: coordinator, incoming: true } + let!(:outgoing_exchange) { oc.exchanges.create! sender: coordinator, receiver: distributor, incoming: false } - it "finds incoming exchanges" do - Exchange.incoming.should == [incoming_exchange] + it "finds incoming exchanges" do + Exchange.incoming.should == [incoming_exchange] + end + + it "finds outgoing exchanges" do + Exchange.outgoing.should == [outgoing_exchange] + end + + it "correctly determines direction of exchanges between the same enterprise" do + incoming_exchange.update_attributes sender: coordinator, incoming: true + outgoing_exchange.update_attributes receiver: coordinator, incoming: false + Exchange.incoming.should == [incoming_exchange] + Exchange.outgoing.should == [outgoing_exchange] + end + + it "finds exchanges going to any of a number of enterprises" do + Exchange.to_enterprises([coordinator]).should == [incoming_exchange] + Exchange.to_enterprises([coordinator, distributor]).sort.should == [incoming_exchange, outgoing_exchange].sort + end + + it "finds exchanges coming from any of a number of enterprises" do + Exchange.from_enterprises([coordinator]).should == [outgoing_exchange] + Exchange.from_enterprises([supplier, coordinator]).sort.should == [incoming_exchange, outgoing_exchange].sort + end end - it "finds outgoing exchanges" do - Exchange.outgoing.should == [outgoing_exchange] - end + describe "finding exchanges supplying to a distributor" do + it "returns incoming exchanges" do + d = create(:distributor_enterprise) + ex = create(:exchange, order_cycle: oc, incoming: true) - it "finds exchanges going to any of a number of enterprises" do - Exchange.to_enterprises([coordinator]).should == [incoming_exchange] - Exchange.to_enterprises([coordinator, distributor]).sort.should == [incoming_exchange, outgoing_exchange].sort - end + oc.exchanges.supplying_to(d).should == [ex] + end - it "finds exchanges coming from any of a number of enterprises" do - Exchange.from_enterprises([coordinator]).should == [outgoing_exchange] - Exchange.from_enterprises([supplier, coordinator]).sort.should == [incoming_exchange, outgoing_exchange].sort + it "returns outgoing exchanges to the distributor" do + d = create(:distributor_enterprise) + ex = create(:exchange, order_cycle: oc, receiver: d, incoming: false) + + oc.exchanges.supplying_to(d).should == [ex] + end + + it "does not return outgoing exchanges to a different distributor" do + d1 = create(:distributor_enterprise) + d2 = create(:distributor_enterprise) + ex = create(:exchange, order_cycle: oc, receiver: d1, incoming: false) + + oc.exchanges.supplying_to(d2).should be_empty + end end it "finds exchanges with a particular variant" do @@ -167,6 +199,7 @@ describe Exchange do exchange.to_h.should == {'id' => exchange.id, 'order_cycle_id' => oc.id, 'sender_id' => exchange.sender_id, 'receiver_id' => exchange.receiver_id, + 'incoming' => exchange.incoming, 'payment_enterprise_id' => exchange.payment_enterprise_id, 'variant_ids' => exchange.variant_ids.sort, 'enterprise_fee_ids' => exchange.enterprise_fee_ids.sort, 'pickup_time' => exchange.pickup_time, 'pickup_instructions' => exchange.pickup_instructions, @@ -176,6 +209,7 @@ describe Exchange do it "converts to a hash of core attributes only" do exchange.to_h(true).should == {'sender_id' => exchange.sender_id, 'receiver_id' => exchange.receiver_id, + 'incoming' => exchange.incoming, 'payment_enterprise_id' => exchange.payment_enterprise_id, 'variant_ids' => exchange.variant_ids.sort, 'enterprise_fee_ids' => exchange.enterprise_fee_ids.sort, 'pickup_time' => exchange.pickup_time, 'pickup_instructions' => exchange.pickup_instructions} diff --git a/spec/models/order_cycle_spec.rb b/spec/models/order_cycle_spec.rb index 784d778682..c9d14a71f4 100644 --- a/spec/models/order_cycle_spec.rb +++ b/spec/models/order_cycle_spec.rb @@ -82,7 +82,7 @@ describe OrderCycle do p = create(:product) s = create(:supplier_enterprise) oc = create(:simple_order_cycle) - ex = create(:exchange, order_cycle: oc, sender: s, receiver: oc.coordinator) + ex = create(:exchange, order_cycle: oc, sender: s, receiver: oc.coordinator, incoming: true) ex.variants << p.master p.reload @@ -137,9 +137,9 @@ describe OrderCycle do it "reports its suppliers" do oc = create(:simple_order_cycle) - e1 = create(:exchange, + e1 = create(:exchange, incoming: true, order_cycle: oc, receiver: oc.coordinator, sender: create(:enterprise)) - e2 = create(:exchange, + e2 = create(:exchange, incoming: true, order_cycle: oc, receiver: oc.coordinator, sender: create(:enterprise)) oc.suppliers.sort.should == [e1.sender, e2.sender].sort @@ -148,9 +148,9 @@ describe OrderCycle do it "reports its distributors" do oc = create(:simple_order_cycle) - e1 = create(:exchange, + e1 = create(:exchange, incoming: false, order_cycle: oc, sender: oc.coordinator, receiver: create(:enterprise)) - e2 = create(:exchange, + e2 = create(:exchange, incoming: false, order_cycle: oc, sender: oc.coordinator, receiver: create(:enterprise)) oc.distributors.sort.should == [e1.receiver, e2.receiver].sort @@ -182,11 +182,11 @@ describe OrderCycle do @d1 = create(:enterprise) @d2 = create(:enterprise) - @e0 = create(:exchange, + @e0 = create(:exchange, incoming: true, order_cycle: @oc, sender: create(:enterprise), receiver: @oc.coordinator) - @e1 = create(:exchange, + @e1 = create(:exchange, incoming: false, order_cycle: @oc, sender: @oc.coordinator, receiver: @d1) - @e2 = create(:exchange, + @e2 = create(:exchange, incoming: false, order_cycle: @oc, sender: @oc.coordinator, receiver: @d2) @p0 = create(:simple_product)