require 'spec_helper' describe Exchange do it "should be valid when built from factory" do expect(build(:exchange)).to be_valid end [:order_cycle, :sender, :receiver].each do |attr| it "should not be valid without #{attr}" do e = build(:exchange) e.send("#{attr}=", nil) expect(e).not_to be_valid end end it "should not be valid when (sender, receiver, direction) set are not unique for its order cycle" do e1 = create(:exchange) e2 = build(:exchange, order_cycle: e1.order_cycle, sender: e1.sender, receiver: e1.receiver, incoming: e1.incoming) expect(e2).not_to be_valid e2.incoming = !e2.incoming expect(e2).to be_valid e2.incoming = !e2.incoming e2.receiver = create(:enterprise) expect(e2).to be_valid e2.sender = e2.receiver e2.receiver = e1.receiver expect(e2).to be_valid end it "has exchange variants" do e = create(:exchange) p = create(:product) e.exchange_variants.create(variant: p.master) expect(e.variants.count).to eq(1) end it "has exchange fees" do e = create(:exchange) f = create(:enterprise_fee) e.exchange_fees.create(enterprise_fee: f) expect(e.enterprise_fees.count).to eq(1) end describe "exchange directionality" do let(:supplier) { create(:supplier_enterprise) } 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, incoming: true } let(:outgoing_exchange) { oc.exchanges.create! sender: coordinator, receiver: distributor, incoming: false } describe "reporting whether it is an incoming exchange" do it "returns true for incoming exchanges" do expect(incoming_exchange).to be_incoming end it "returns false for outgoing exchanges" do expect(outgoing_exchange).not_to be_incoming end end describe "finding the exchange participant (the enterprise other than the coordinator)" do it "returns the sender for incoming exchanges" do expect(incoming_exchange.participant).to eq(supplier) end it "returns the receiver for outgoing exchanges" do expect(outgoing_exchange.participant).to eq(distributor) end end end describe "reporting its role" do it "returns 'supplier' when it is an incoming exchange" do e = Exchange.new allow(e).to receive(:incoming?) { true } expect(e.role).to eq('supplier') end it "returns 'distributor' when it is an outgoing exchange" do e = Exchange.new allow(e).to receive(:incoming?) { false } expect(e.role).to eq('distributor') end end describe "products caching" do let!(:exchange) { create(:exchange) } it "refreshes the products cache on change" do expect(OpenFoodNetwork::ProductsCache).to receive(:exchange_changed).with(exchange) exchange.pickup_time = 'asdf' exchange.save end it "refreshes the products cache on destruction" do expect(OpenFoodNetwork::ProductsCache).to receive(:exchange_destroyed).with(exchange) exchange.destroy end end describe "scopes" do let(:supplier) { create(:supplier_enterprise) } let(:coordinator) { create(:distributor_enterprise, is_primary_producer: true) } let(:distributor) { create(:distributor_enterprise) } let(:oc) { create(:simple_order_cycle, coordinator: coordinator) } describe "finding exchanges managed by a particular user" do let(:user) do user = create(:user) user.spree_roles = [] user end before { Exchange.destroy_all } it "returns exchanges where the user manages both the sender and the receiver" do exchange = create(:exchange, order_cycle: oc) exchange.sender.users << user exchange.receiver.users << user expect(Exchange.managed_by(user)).to eq([exchange]) end it "does not return exchanges where the user manages only the sender" do exchange = create(:exchange, order_cycle: oc) exchange.sender.users << user expect(Exchange.managed_by(user)).to be_empty end it "does not return exchanges where the user manages only the receiver" do exchange = create(:exchange, order_cycle: oc) exchange.receiver.users << user expect(Exchange.managed_by(user)).to be_empty end it "does not return exchanges where the user manages neither enterprise" do exchange = create(:exchange, order_cycle: oc) expect(Exchange.managed_by(user)).to be_empty end end it "finds exchanges in a particular order cycle" do ex = create(:exchange, order_cycle: oc) expect(Exchange.in_order_cycle(oc)).to eq([ex]) end 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 expect(Exchange.incoming).to eq([incoming_exchange]) end it "finds outgoing exchanges" do expect(Exchange.outgoing).to eq([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 expect(Exchange.incoming).to eq([incoming_exchange]) expect(Exchange.outgoing).to eq([outgoing_exchange]) end it "finds exchanges coming from an enterprise" do expect(Exchange.from_enterprise(supplier)).to eq([incoming_exchange]) expect(Exchange.from_enterprise(coordinator)).to eq([outgoing_exchange]) end it "finds exchanges going to an enterprise" do expect(Exchange.to_enterprise(coordinator)).to eq([incoming_exchange]) expect(Exchange.to_enterprise(distributor)).to eq([outgoing_exchange]) end it "finds exchanges coming from any of a number of enterprises" do expect(Exchange.from_enterprises([coordinator])).to eq([outgoing_exchange]) expect(Exchange.from_enterprises([supplier, coordinator])).to match_array [incoming_exchange, outgoing_exchange] end it "finds exchanges going to any of a number of enterprises" do expect(Exchange.to_enterprises([coordinator])).to eq([incoming_exchange]) expect(Exchange.to_enterprises([coordinator, distributor])).to match_array [incoming_exchange, outgoing_exchange] end it "finds exchanges involving any of a number of enterprises" do expect(Exchange.involving([supplier])).to eq([incoming_exchange]) expect(Exchange.involving([coordinator])).to match_array [incoming_exchange, outgoing_exchange] expect(Exchange.involving([distributor])).to eq([outgoing_exchange]) end 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) expect(oc.exchanges.supplying_to(d)).to eq([ex]) end it "returns outgoing exchanges to the distributor" do d = create(:distributor_enterprise) ex = create(:exchange, order_cycle: oc, receiver: d, incoming: false) expect(oc.exchanges.supplying_to(d)).to eq([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) expect(oc.exchanges.supplying_to(d2)).to be_empty end end it "finds exchanges with a particular variant" do v = create(:variant) ex = create(:exchange) ex.variants << v expect(Exchange.with_variant(v)).to eq([ex]) end it "finds exchanges with any of a number of variants, without returning duplicates" do v1 = create(:variant) v2 = create(:variant) v3 = create(:variant) ex = create(:exchange) ex.variants << v1 ex.variants << v2 expect(Exchange.with_any_variant([v1, v2, v3])).to eq([ex]) end it "finds exchanges with a particular product's master variant" do p = create(:simple_product) ex = create(:exchange) ex.variants << p.master p.reload expect(Exchange.with_product(p)).to eq([ex]) end it "finds exchanges with a particular product's non-master variant" do p = create(:simple_product) v = create(:variant, product: p) ex = create(:exchange) ex.variants << v p.reload expect(Exchange.with_product(p)).to eq([ex]) end describe "sorting exchanges by primary enterprise name" do let(:e1) { create(:supplier_enterprise, name: 'ZZZ') } let(:e2) { create(:distributor_enterprise, name: 'AAA') } let(:e3) { create(:supplier_enterprise, name: 'CCC') } let!(:ex1) { create(:exchange, sender: e1, incoming: true) } let!(:ex2) { create(:exchange, receiver: e2, incoming: false) } let!(:ex3) { create(:exchange, sender: e3, incoming: true) } it "sorts" do expect(Exchange.by_enterprise_name).to eq([ex2, ex3, ex1]) end end end it "clones itself" do oc = create(:order_cycle) new_oc = create(:simple_order_cycle) ex1 = oc.exchanges.last ex1.update_attribute(:tag_list, "wholesale") ex2 = ex1.clone! new_oc expect(ex1.eql?(ex2)).to be true expect(ex2.reload.tag_list).to eq ["wholesale"] end describe "converting to hash" do let(:oc) { create(:order_cycle) } let(:exchange) do exchange = oc.exchanges.last exchange.save! allow(exchange).to receive(:variant_ids) { [1835, 1834] } # Test id ordering allow(exchange).to receive(:enterprise_fee_ids) { [1493, 1492] } # Test id ordering exchange end it "converts to a hash" do expect(exchange.to_h).to eq( 'id' => exchange.id, 'order_cycle_id' => oc.id, 'sender_id' => exchange.sender_id, 'receiver_id' => exchange.receiver_id, 'incoming' => exchange.incoming, 'variant_ids' => exchange.variant_ids.sort, 'enterprise_fee_ids' => exchange.enterprise_fee_ids.sort, 'pickup_time' => exchange.pickup_time, 'pickup_instructions' => exchange.pickup_instructions, 'receival_instructions' => exchange.receival_instructions, 'created_at' => exchange.created_at, 'updated_at' => exchange.updated_at ) end it "converts to a hash of core attributes only" do expect(exchange.to_h(true)).to eq( 'sender_id' => exchange.sender_id, 'receiver_id' => exchange.receiver_id, 'incoming' => exchange.incoming, 'variant_ids' => exchange.variant_ids.sort, 'enterprise_fee_ids' => exchange.enterprise_fee_ids.sort, 'pickup_time' => exchange.pickup_time, 'pickup_instructions' => exchange.pickup_instructions, 'receival_instructions' => exchange.receival_instructions ) end end describe "comparing equality" do it "compares Exchanges using to_h" do e1 = Exchange.new e2 = Exchange.new allow(e1).to receive(:to_h) { { 'sender_id' => 456 } } allow(e2).to receive(:to_h) { { 'sender_id' => 456 } } expect(e1.eql?(e2)).to be true end it "compares other objects using super" do exchange = Exchange.new exchange_fee = ExchangeFee.new expect(exchange.eql?(exchange_fee)).to be false end end end