diff --git a/lib/open_food_network/permissions.rb b/lib/open_food_network/permissions.rb index 183826994d..509d4dc2d4 100644 --- a/lib/open_food_network/permissions.rb +++ b/lib/open_food_network/permissions.rb @@ -59,6 +59,36 @@ module OpenFoodNetwork Exchange.where(id: ids, order_cycle_id: order_cycle) end + # Find the variants within an exchange that a user can POTENTIALLY see + # Note that this does not determine whether they actually appear in outgoing exchanges + # as this requires first that the variant is included in an incoming exchange + def visible_variants_within(exchange) + if exchange.incoming + if managed_enterprises.pluck(:id).include?(exchange.receiver_id) || managed_enterprises.pluck(:id).include?(exchange.sender_id) + # All variants belonging to the producer + Spree::Variant.joins(:product).where('spree_products.supplier_id = (?)', exchange.sender_id) + else + [] # None + end + else + if managed_enterprises.pluck(:id).include?(exchange.receiver_id) || managed_enterprises.pluck(:id).include?(exchange.sender_id) + # Any variants of any producers that have granted the receiver P-OC + producers = granting(:add_to_order_cycle, to: [exchange.receiver], scope: Enterprise.is_primary_producer) + permitted_variants = Spree::Variant.joins(:product).where('spree_products.supplier_id IN (?)', producers) + # PLUS any variants that are already in the exchange, so things don't break + active_variants = exchange.variants + Spree::Variant.where(id: permitted_variants | active_variants) + else + # Any variants produced by MY PRODUCERS, where my producer has granted P-OC to the receiver + producers = granting(:add_to_order_cycle, to: [exchange.receiver], scope: managed_enterprises.is_primary_producer) + permitted_variants = Spree::Variant.joins(:product).where('spree_products.supplier_id IN (?)', producers) + # PLUS any of my producers variants that are already in the exchange, so things don't break + active_variants = exchange.variants.joins(:product).where('spree_products.supplier_id IN (?)', managed_enterprises.is_primary_producer) + Spree::Variant.where(id: permitted_variants | active_variants) + end + end + end + def managed_products managed_enterprise_products_ids = managed_enterprise_products.pluck :id permitted_enterprise_products_ids = related_enterprise_products.pluck :id diff --git a/spec/lib/open_food_network/permissions_spec.rb b/spec/lib/open_food_network/permissions_spec.rb index 009c024a78..cea24c5c52 100644 --- a/spec/lib/open_food_network/permissions_spec.rb +++ b/spec/lib/open_food_network/permissions_spec.rb @@ -171,6 +171,126 @@ module OpenFoodNetwork end end + describe "finding the variants within a given exchange which are visible to a user" do + let!(:producer1) { create(:supplier_enterprise) } + let!(:producer2) { create(:supplier_enterprise) } + let!(:v1) { create(:variant, product: create(:simple_product, supplier: producer1)) } + let!(:v2) { create(:variant, product: create(:simple_product, supplier: producer2)) } + let(:oc) { create(:simple_order_cycle) } + + describe "incoming exchanges" do + let!(:ex) { create(:exchange, order_cycle: oc, sender: producer1, receiver: e1, incoming: true) } + + context "as a manager of the coordinator" do + before do + permissions.stub(:managed_enterprises) { Enterprise.where(id: [e1]) } + end + + it "returns all variants belonging to the sending producer" do + visible = permissions.visible_variants_within(ex) + expect(visible).to include v1 + expect(visible).to_not include v2 + end + end + + context "as a manager of the producer" do + before do + permissions.stub(:managed_enterprises) { Enterprise.where(id: [producer1]) } + end + + it "returns all variants belonging to the sending producer" do + visible = permissions.visible_variants_within(ex) + expect(visible).to include v1 + expect(visible).to_not include v2 + end + end + + context "as a manager of a hub which has been granted P-OC by the producer" do + before do + permissions.stub(:managed_enterprises) { Enterprise.where(id: [e2]) } + create(:enterprise_relationship, parent: producer1, child: e2, permissions_list: [:add_to_order_cycle]) + end + + it "returns no variants" do + visible = permissions.visible_variants_within(ex) + expect(visible).to eq [] + end + end + end + + describe "outgoing exchanges" do + let!(:ex) { create(:exchange, order_cycle: oc, sender: e1, receiver: e2, incoming: false) } + + context "as a manager of the coordinator" do + before do + permissions.stub(:managed_enterprises) { Enterprise.where(id: [e1]) } + create(:enterprise_relationship, parent: producer1, child: e2, permissions_list: [:add_to_order_cycle]) + end + + it "returns all variants of any producer which has granted the outgoing hub P-OC" do + visible = permissions.visible_variants_within(ex) + expect(visible).to include v1 + expect(visible).to_not include v2 + end + end + + context "as manager of the outgoing hub" do + before do + permissions.stub(:managed_enterprises) { Enterprise.where(id: [e2]) } + create(:enterprise_relationship, parent: producer1, child: e2, permissions_list: [:add_to_order_cycle]) + end + + it "returns all variants of any producer which has granted the outgoing hub P-OC" do + visible = permissions.visible_variants_within(ex) + expect(visible).to include v1 + expect(visible).to_not include v2 + end + end + + context "as the manager of a producer which has granted P-OC to the outgoing hub" do + before do + permissions.stub(:managed_enterprises) { Enterprise.where(id: [producer1]) } + create(:enterprise_relationship, parent: producer1, child: e2, permissions_list: [:add_to_order_cycle]) + end + + it "returns all of my produced variants" do + visible = permissions.visible_variants_within(ex) + expect(visible).to include v1 + expect(visible).to_not include v2 + end + end + + context "as the manager of a producer which has not granted P-OC to the outgoing hub" do + before do + permissions.stub(:managed_enterprises) { Enterprise.where(id: [producer2]) } + create(:enterprise_relationship, parent: producer1, child: e2, permissions_list: [:add_to_order_cycle]) + end + + it "returns an empty array" do + expect(permissions.visible_variants_within(ex)).to eq [] + end + end + + # TODO: for backwards compatability, remove later + context "as the manager of a producer which has not granted P-OC to the outgoing hub, but which has variants already in the exchange" do + # This one won't be in the exchange, and so shouldn't be visible + let!(:v3) { create(:variant, product: create(:simple_product, supplier: producer2)) } + + before do + permissions.stub(:managed_enterprises) { Enterprise.where(id: [producer2]) } + create(:enterprise_relationship, parent: producer1, child: e2, permissions_list: [:add_to_order_cycle]) + ex.variants << v2 + end + + it "returns those variants that are in the exchange" do + visible = permissions.visible_variants_within(ex) + expect(visible).to_not include v1, v3 + expect(visible).to include v2 + end + end + end + end + describe "finding managed products" do let!(:p1) { create(:simple_product) } let!(:p2) { create(:simple_product) }