diff --git a/app/models/enterprise_relationship.rb b/app/models/enterprise_relationship.rb index 87e745f3c4..e8590215fa 100644 --- a/app/models/enterprise_relationship.rb +++ b/app/models/enterprise_relationship.rb @@ -13,6 +13,7 @@ class EnterpriseRelationship < ApplicationRecord after_save :update_permissions_of_child_variant_overrides before_destroy :revoke_all_child_variant_overrides + before_destroy :destroy_related_exchanges scope :with_enterprises, -> { joins(" @@ -102,6 +103,10 @@ class EnterpriseRelationship < ApplicationRecord child_variant_overrides.update_all(permission_revoked_at: Time.zone.now) end + def destroy_related_exchanges + Exchange.where(sender: parent, receiver: child, incoming: true).destroy_all + end + def child_variant_overrides VariantOverride.unscoped.for_hubs(child) .joins(variant: :product).where("spree_products.supplier_id IN (?)", parent) diff --git a/app/models/enterprise_relationship_permission.rb b/app/models/enterprise_relationship_permission.rb index 33bf4a2fe2..f92b10188f 100644 --- a/app/models/enterprise_relationship_permission.rb +++ b/app/models/enterprise_relationship_permission.rb @@ -1,5 +1,15 @@ # frozen_string_literal: true class EnterpriseRelationshipPermission < ApplicationRecord + belongs_to :enterprise_relationship default_scope { order('name') } + before_destroy :destroy_related_exchanges + + def destroy_related_exchanges + return if name != "add_to_order_cycle" + + Exchange + .where(sender: enterprise_relationship.parent, + receiver: enterprise_relationship.child, incoming: true).destroy_all + end end diff --git a/app/models/exchange_variant.rb b/app/models/exchange_variant.rb index 46ef647f89..ac835523af 100644 --- a/app/models/exchange_variant.rb +++ b/app/models/exchange_variant.rb @@ -3,4 +3,9 @@ class ExchangeVariant < ApplicationRecord belongs_to :exchange belongs_to :variant, class_name: 'Spree::Variant' + after_destroy :destroy_related_outgoing_variants + + def destroy_related_outgoing_variants + VariantDeleter.new.destroy_related_outgoing_variants(variant_id, exchange.order_cycle) + end end diff --git a/app/services/variant_deleter.rb b/app/services/variant_deleter.rb index fb9637f780..d294dfcb98 100644 --- a/app/services/variant_deleter.rb +++ b/app/services/variant_deleter.rb @@ -11,6 +11,15 @@ class VariantDeleter variant.destroy end + def destroy_related_outgoing_variants(variant_id, order_cycle) + internal_variants = ExchangeVariant.where(variant_id: variant_id). + joins(:exchange). + where( + exchanges: { order_cycle: order_cycle, incoming: false } + ) + internal_variants.destroy_all + end + private def only_variant_on_product?(variant) diff --git a/spec/models/enterprise_relationship_spec.rb b/spec/models/enterprise_relationship_spec.rb index ad2ea9627c..38d8196ff9 100644 --- a/spec/models/enterprise_relationship_spec.rb +++ b/spec/models/enterprise_relationship_spec.rb @@ -147,7 +147,7 @@ describe EnterpriseRelationship do end describe "callbacks" do - context "updating variant override permissions" do + describe "updating variant override permissions" do let(:hub) { create(:distributor_enterprise) } let(:producer) { create(:supplier_enterprise) } let(:some_other_producer) { create(:supplier_enterprise) } @@ -255,5 +255,101 @@ describe EnterpriseRelationship do end end end + describe "updating order cycles" do + let(:hub) { create(:distributor_enterprise) } + let(:producer) { create(:supplier_enterprise) } + let(:order_cycle) { create(:simple_order_cycle) } + let(:some_other_producer) { create(:supplier_enterprise) } + + context "when order_cycle permission is present" do + let!(:er) { + create(:enterprise_relationship, child: hub, parent: producer, + permissions_list: [ + :add_to_order_cycle, + :create_variant_overrides + ] ) + } + let!(:incoming_external_exchange) { + order_cycle.exchanges.create! sender: producer, receiver: hub, incoming: true + } + let!(:other_external_exchange) { + order_cycle.exchanges.create! sender: some_other_producer, receiver: hub, incoming: true + } + let!(:incoming_internal_exchange) { + order_cycle.exchanges.create! sender: hub, receiver: hub, incoming: true + } + let!(:outgoing_internal_exchange) { + order_cycle.exchanges.create! sender: hub, receiver: hub, incoming: false + } + let!(:variant) { create(:variant) } + let!(:some_other_variant) { create(:variant) } + let!(:incoming_external_variant) { + incoming_external_exchange.exchange_variants.create!( + exchange: incoming_external_exchange, variant: variant + ) + } + let!(:incoming_internal_only_variant) { + incoming_internal_exchange.exchange_variants.create!( + exchange: incoming_internal_exchange, variant: some_other_variant + ) + } + let!(:outgoing_internal_variant) { + outgoing_internal_exchange.exchange_variants.create!( + exchange: outgoing_internal_exchange, variant: variant + ) + } + let!(:outgoing_internal_only_variant) { + outgoing_internal_exchange.exchange_variants.create!( + exchange: outgoing_internal_exchange, variant: some_other_variant + ) + } + + # We need to destroy the exchange variants on all order cycles related to the ER if + # 'add_to_order_cycle' permission is removed. If they are left on the order cycle, the + # Taxons of the variants will still appear on the /shops page, despite the hub not + # actually offering the variants anymore. + context "removing exchanges and exchange variants" do + context "when the enterprise relationship is destroyed" do + before { er.destroy } + it "should destroy all exchanges and exchange variants related to ER" do + expect(Exchange.exists?(incoming_external_exchange.id)).to be false + expect(Exchange.exists?(other_external_exchange.id)).to be true + expect(ExchangeVariant.exists?(incoming_external_variant.id)).to be false + expect(ExchangeVariant.exists?(outgoing_internal_variant.id)).to be false + expect(ExchangeVariant.exists?(incoming_internal_only_variant.id)).to be true + expect(ExchangeVariant.exists?(outgoing_internal_only_variant.id)).to be true + end + end + end + + context "and is then removed" do + before { er.permissions_list = [:create_variant_overrides]; er.save! } + it "should destroy all exchanges and exchange variants related to ER" do + expect(Exchange.exists?(incoming_external_exchange.id)).to be false + expect(Exchange.exists?(other_external_exchange.id)).to be true + expect(ExchangeVariant.exists?(incoming_external_variant.id)).to be false + expect(ExchangeVariant.exists?(outgoing_internal_variant.id)).to be false + expect(ExchangeVariant.exists?(incoming_internal_only_variant.id)).to be true + expect(ExchangeVariant.exists?(outgoing_internal_only_variant.id)).to be true + end + + it "should not affect other exchanges or order cycles" do + expect(Exchange.exists?(outgoing_internal_exchange.id)).to be true + end + end + + context "and then some other permission is removed" do + before { er.permissions_list = [:add_to_order_cycle]; er.save! } + it "should have no effect on existing exchanges" do + expect(Exchange.exists?(incoming_external_exchange.id)).to be true + expect(Exchange.exists?(other_external_exchange.id)).to be true + expect(ExchangeVariant.exists?(incoming_external_variant.id)).to be true + expect(ExchangeVariant.exists?(outgoing_internal_variant.id)).to be true + expect(ExchangeVariant.exists?(incoming_internal_only_variant.id)).to be true + expect(ExchangeVariant.exists?(outgoing_internal_only_variant.id)).to be true + end + end + end + end end end