From b1d95cac7f1c76c9a2590c8b825a072d4bce3092 Mon Sep 17 00:00:00 2001 From: Gaetan Craig-Riou Date: Tue, 16 Sep 2025 11:46:34 +1000 Subject: [PATCH] Display filter by variant tag rule We only support one of filter by inventory variants or filter by variants at any given time, based on enabled feature. If both features inventory and variant tag are enabled, variant tag takes precedence. --- app/components/tag_rule_form_component.rb | 7 ++ .../admin/enterprises_controller.rb | 22 ++++- app/controllers/admin/tag_rules_controller.rb | 2 +- app/models/tag_rule.rb | 2 + .../enterprises/form/_tag_rules.html.haml | 5 +- .../form/tag_rules/_default_rules.html.haml | 5 +- config/locales/en.yml | 3 + spec/system/admin/tag_rules_spec.rb | 98 ++++++++++++++++++- 8 files changed, 132 insertions(+), 12 deletions(-) diff --git a/app/components/tag_rule_form_component.rb b/app/components/tag_rule_form_component.rb index 8771bd2a64..c64a14f8b8 100644 --- a/app/components/tag_rule_form_component.rb +++ b/app/components/tag_rule_form_component.rb @@ -47,6 +47,13 @@ class TagRuleFormComponent < ViewComponent::Base taggable: "variant", visibility_field: "preferred_matched_variants_visibility", } + when "TagRule::FilterVariants" + { + text_top: t('components.tag_rule_form.tag_rules.variant_tagged_top'), + text_bottom: t('components.tag_rule_form.tag_rules.variant_tagged_bottom'), + taggable: "variant", + visibility_field: "preferred_matched_variants_visibility", + } end end diff --git a/app/controllers/admin/enterprises_controller.rb b/app/controllers/admin/enterprises_controller.rb index 779a9e8065..811515fdbc 100644 --- a/app/controllers/admin/enterprises_controller.rb +++ b/app/controllers/admin/enterprises_controller.rb @@ -51,6 +51,7 @@ module Admin load_tag_rule_types + load_tag_rules return unless params[:stimulus] @enterprise.is_primary_producer = params[:is_primary_producer] @@ -398,9 +399,26 @@ module Admin [t(".form.tag_rules.show_hide_order_cycles"), "FilterOrderCycles"] ] - return unless helpers.feature?(:inventory, @object) + if helpers.feature?(:variant_tag, @object) + @tag_rule_types.prepend([t(".form.tag_rules.show_hide_variants_new"), "FilterVariants"]) + elsif helpers.feature?(:inventory, @object) + @tag_rule_types.prepend([t(".form.tag_rules.show_hide_variants"), "FilterProducts"]) + end + end - @tag_rule_types.prepend([t(".form.tag_rules.show_hide_variants"), "FilterProducts"]) + def load_tag_rules + if helpers.feature?(:variant_tag, @object) + @default_rules = @enterprise.tag_rules.exclude_inventory.select(&:is_default) + @rules = @enterprise.tag_rules.exclude_inventory.prioritised.reject(&:is_default) + elsif helpers.feature?(:inventory, @object) + @default_rules = @enterprise.tag_rules.exclude_variant.select(&:is_default) + @rules = @enterprise.tag_rules.exclude_variant.prioritised.reject(&:is_default) + else + @default_rules = + @enterprise.tag_rules.exclude_inventory.exclude_variant.select(&:is_default) + @rules = + @enterprise.tag_rules.exclude_inventory.exclude_variant.prioritised.reject(&:is_default) + end end def setup_property diff --git a/app/controllers/admin/tag_rules_controller.rb b/app/controllers/admin/tag_rules_controller.rb index 360aea9f6d..0d5d06b35f 100644 --- a/app/controllers/admin/tag_rules_controller.rb +++ b/app/controllers/admin/tag_rules_controller.rb @@ -78,7 +78,7 @@ module Admin end def permitted_tag_rule_type - %w{FilterOrderCycles FilterPaymentMethods FilterProducts FilterShippingMethods} + %w{FilterOrderCycles FilterPaymentMethods FilterProducts FilterShippingMethods FilterVariants} end end end diff --git a/app/models/tag_rule.rb b/app/models/tag_rule.rb index 790e844334..d1efddb9da 100644 --- a/app/models/tag_rule.rb +++ b/app/models/tag_rule.rb @@ -7,6 +7,8 @@ class TagRule < ApplicationRecord scope :for, ->(enterprise) { where(enterprise_id: enterprise) } scope :prioritised, -> { order('priority ASC') } + scope :exclude_inventory, -> { where.not(type: "TagRule::FilterProducts") } + scope :exclude_variant, -> { where.not(type: "TagRule::FilterVariants") } def self.mapping_for(enterprises) self.for(enterprises).each_with_object({}) do |rule, mapping| diff --git a/app/views/admin/enterprises/form/_tag_rules.html.haml b/app/views/admin/enterprises/form/_tag_rules.html.haml index c5e0f98d01..24fc13747c 100644 --- a/app/views/admin/enterprises/form/_tag_rules.html.haml +++ b/app/views/admin/enterprises/form/_tag_rules.html.haml @@ -5,15 +5,14 @@ - # We use a high enough index increment so that the default tag rule should not overlap with the tag rules - # Rails will deal with non continous numbered tag_rules_attributes just fine, it saves us from having to manage the index state in javascript - current_rule_index = 1000 - - rules = @enterprise.tag_rules.prioritised.reject(&:is_default) - - if rules.empty? + - if @rules.empty? .no_tags = t('.no_tags_yet') = render 'admin/enterprises/form/tag_rules/default_rules', f:, current_rule_index: #customer-tag-rule - - tag_groups(rules).each_with_index do |group, group_index| + - tag_groups(@rules).each_with_index do |group, group_index| - current_group_index = group_index + 1 = render TagRuleGroupFormComponent.new(group:, index: group_index, customer_rule_index: current_rule_index, tag_rule_types: @tag_rule_types) - # Same as above, We use a high enough increcment so that the previous tag rule group does not overlap with the next tag rule group diff --git a/app/views/admin/enterprises/form/tag_rules/_default_rules.html.haml b/app/views/admin/enterprises/form/tag_rules/_default_rules.html.haml index 5f20fd9435..960b8b13d5 100644 --- a/app/views/admin/enterprises/form/tag_rules/_default_rules.html.haml +++ b/app/views/admin/enterprises/form/tag_rules/_default_rules.html.haml @@ -9,13 +9,12 @@ = t('.by_default') %i.text-big.icon-question-sign{ "data-controller": "help-modal-link", "data-action": "click->help-modal-link#open", "data-help-modal-link-target-value": "tag_rule_help_modal" } #default-tag-rule - - default_rules = @enterprise.tag_rules.select(&:is_default) - current_rule_index = 0 - - if default_rules.empty? + - if @default_rules.empty? .no_rules = t('.no_rules_yet') - else - - default_rules.each_with_index do |default_rule, index| + - @default_rules.each_with_index do |default_rule, index| - current_rule_index = index + 1 = render TagRuleFormComponent.new(rule: default_rule, index: index) %hr diff --git a/config/locales/en.yml b/config/locales/en.yml index 67b83796d9..aba0f24f28 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1419,6 +1419,7 @@ en: no_tags_yet: No tags apply to this enterprise yet add_new_tag: '+ Add A New Tag' show_hide_variants: 'Show or Hide variants in my shopfront' + show_hide_variants_new: 'Show or Hide variants in my shopfront' show_hide_shipping: 'Show or Hide shipping methods at checkout' show_hide_payment: 'Show or Hide payment methods at checkout' show_hide_order_cycles: 'Show or Hide order cycles in my shopfront' @@ -5076,6 +5077,8 @@ en: order_cycle_tagged_bottom: "are:" inventory_tagged_top: "Inventory variants tagged" inventory_tagged_bottom: "are:" + variant_tagged_top: "Variants tagged" + variant_tagged_bottom: "are:" visible: VISIBLE not_visible: NOT VISIBLE tag_rule_group_form: diff --git a/spec/system/admin/tag_rules_spec.rb b/spec/system/admin/tag_rules_spec.rb index 124d8de7d6..7b0490e690 100644 --- a/spec/system/admin/tag_rules_spec.rb +++ b/spec/system/admin/tag_rules_spec.rb @@ -8,6 +8,71 @@ RSpec.describe 'Tag Rules' do let!(:enterprise) { create(:distributor_enterprise) } + describe "loading rules" do + let!(:default_order_cycle_tag_rule) { + create(:filter_order_cycles_tag_rule, enterprise:, is_default: true) + } + let!(:inventory_order_cycle_rule) { create(:filter_order_cycles_tag_rule, enterprise:) } + let!(:default_inventory_tag_rule) { + create(:filter_products_tag_rule, enterprise:, is_default: true) + } + let!(:inventory_tag_rule) { create(:filter_products_tag_rule, enterprise:) } + let!(:default_variant_tag_rule) { + create(:filter_variants_tag_rule, enterprise:, is_default: true) + } + let!(:variant_tag_rule) { create(:filter_variants_tag_rule, enterprise:) } + + before do + visit_tag_rules + end + + it "displays all existing rules" do + within "#default-tag-rule" do + expect(page).to have_content "Order Cycles tagged" + expect(page).not_to have_content "Inventory variants tagged" + expect(page).not_to have_content "Variants tagged" + end + + within "#customer-tag-rule" do + expect(page).to have_content "Order Cycles tagged" + expect(page).not_to have_content "Inventory variants tagged" + expect(page).not_to have_content "Variants tagged" + end + end + + context "with inventory enabled", feature: :inventory do + it "does not display filter by variants rules" do + within "#default-tag-rule" do + expect(page).to have_content "Order Cycles tagged" + expect(page).to have_content "Inventory variants tagged" + expect(page).not_to have_content "Variants tagged" + end + + within "#customer-tag-rule" do + expect(page).to have_content "Order Cycles tagged" + expect(page).to have_content "Inventory variants tagged" + expect(page).not_to have_content "Variants tagged" + end + end + end + + context "with variant tag enabled", feature: :variant_tag do + it "does not display filter by inventory variants rules" do + within "#default-tag-rule" do + expect(page).to have_content "Order Cycles tagged" + expect(page).not_to have_content "Inventory variants tagged" + expect(page).to have_content "Variants tagged" + end + + within "#customer-tag-rule" do + expect(page).to have_content "Order Cycles tagged" + expect(page).not_to have_content "Inventory variants tagged" + expect(page).to have_content "Variants tagged" + end + end + end + end + context "creating" do before do visit_tag_rules @@ -90,6 +155,33 @@ RSpec.describe 'Tag Rules' do expect(tag_rule.preferred_matched_order_cycles_visibility).to eq "hidden" end + context "when variant_tag enabled", feature: :variant_tag do + it "allows creation of filter variant type" do + # Creating a new tag + expect(page).to have_content 'No tags apply to this enterprise yet' + click_button '+ Add A New Tag' + fill_in_tag "New Product" + + # New FilterProducts Rule + click_button '+ Add A New Rule' + tomselect_select 'Show or Hide variants in my shop', from: 'rule_type_selector' + click_button "Add Rule" + within("#customer-tag-rule #tr_1001") do + fill_in_tag "new product" + tomselect_select "VISIBLE", + from: "enterprise_tag_rules_attributes_1001_preferred_matched_" \ + "variants_visibility" + end + + click_button 'Update' + + tag_rule = TagRule::FilterVariants.last + expect(tag_rule.preferred_customer_tags).to eq "New Product" + expect(tag_rule.preferred_variant_tags).to eq "new product" + expect(tag_rule.preferred_matched_variants_visibility).to eq "visible" + end + end + context "when inventory enabled", feature: :inventory do it "allows creation of filter variant type" do # Creating a new tag @@ -118,7 +210,7 @@ RSpec.describe 'Tag Rules' do end end - context "updating" do + context "updating", feature: :inventory do let!(:default_fsm_tag_rule) { create(:filter_shipping_methods_tag_rule, enterprise:, preferred_matched_shipping_methods_visibility: @@ -242,10 +334,10 @@ RSpec.describe 'Tag Rules' do context "deleting" do let!(:tag_rule) { - create(:filter_products_tag_rule, enterprise:, preferred_customer_tags: "member" ) + create(:filter_order_cycles_tag_rule, enterprise:, preferred_customer_tags: "member" ) } let!(:default_rule) { - create(:filter_products_tag_rule, is_default: true, enterprise: ) + create(:filter_order_cycles_tag_rule, is_default: true, enterprise: ) } before do