Add endpoint to provide autocomplete tag for variant

It return a list of available tags and number of related rules, based on
the given enterprise and a partial match on the given tag
This commit is contained in:
Gaetan Craig-Riou
2025-09-29 14:23:10 +10:00
parent bd39595917
commit 3bb9eb9765
6 changed files with 73 additions and 2 deletions

View File

@@ -41,6 +41,7 @@ module Admin
end
end
# Used by the tag input autocomplete
def map_by_tag
respond_to do |format|
format.json do
@@ -50,6 +51,26 @@ module Admin
end
end
# Use to populate autocomplete with available rule for the given tag/enterprise
def variant_tag_rules
tag_rules =
TagRule.matching_variant_tag_rules_by_enterprises(params[:enterprise_id], params[:q])
@formatted_tag_rules = tag_rules.each_with_object({}) do |rule, mapping|
rule.preferred_customer_tags.split(",").each do |tag|
if mapping[tag]
mapping[tag][:rules] += 1
else
mapping[tag] = { tag:, rules: 1 }
end
end
end.values
respond_with do |format|
format.html { render :variant_tag_rules, layout: false }
end
end
private
def collection_actions

View File

@@ -10,6 +10,7 @@ class TagRule < ApplicationRecord
scope :exclude_inventory, -> { where.not(type: "TagRule::FilterProducts") }
scope :exclude_variant, -> { where.not(type: "TagRule::FilterVariants") }
# TODO doesn not exluce inventory and or variant tag rule
def self.mapping_for(enterprises)
self.for(enterprises).each_with_object({}) do |rule, mapping|
rule.preferred_customer_tags.split(",").each do |tag|
@@ -22,6 +23,14 @@ class TagRule < ApplicationRecord
end
end
def self.matching_variant_tag_rules_by_enterprises(enterprise_id, tag)
rules = where(type: "TagRule::FilterVariants").for(enterprise_id)
return [] if rules.empty?
rules.select { |r| r.preferred_customer_tags =~ /#{tag}/ }
end
# The following method must be overriden in a concrete tagRule
def tags
raise NotImplementedError, 'please use concrete TagRule'

View File

@@ -0,0 +1,3 @@
- @formatted_tag_rules.each do |tag_rule|
%li.suggestion-item{ role: "option", "data-autocomplete-value": tag_rule[:tag], "data-autocomplete-label": tag_rule[:tag] }
= t("admin.products_v3.tag_rules.rules_per_tag", tag: tag_rule[:tag], count: tag_rule[:rules])

View File

@@ -1026,6 +1026,10 @@ en:
clone:
success: Successfully cloned the product
error: Unable to clone the product
tag_rules:
rules_per_tag:
one: "%{tag} has 1 rule"
other: "%{tag} has %{count} rules"
product_import:
title: Product Import
file_not_found: File not found or could not be opened

View File

@@ -91,8 +91,9 @@ Openfoodnetwork::Application.routes.draw do
resources :customers, only: [:index, :create, :update, :destroy, :show]
resources :tag_rules, only: [], format: :json do
get :map_by_tag, on: :collection
resources :tag_rules, only: [] do
get :map_by_tag, on: :collection, format: :json
get :variant_tag_rules, on: :collection
end
resource :contents

View File

@@ -9,6 +9,39 @@ RSpec.describe TagRule do
end
end
describe ".matching_variant_tag_rules_by_enterprises" do
let(:enterprise) { create(:enterprise) }
let!(:rule1) {
create(:filter_variants_tag_rule, enterprise:, preferred_customer_tags: "filtered" )
}
let!(:rule2) {
create(:filter_variants_tag_rule, enterprise:, preferred_customer_tags: "filtered" )
}
let!(:rule3) {
create(:filter_variants_tag_rule, enterprise:, preferred_customer_tags: "filtered" )
}
let!(:rule4) {
create(:filter_variants_tag_rule, enterprise:, preferred_customer_tags: "other-tag" )
}
let!(:rule5) {
create(:filter_order_cycles_tag_rule, enterprise:, preferred_customer_tags: "filtered" )
}
it "returns a list of rule partially matching the tag" do
rules = described_class.matching_variant_tag_rules_by_enterprises(enterprise.id, "filte")
expect(rules).to include rule1, rule2, rule3
expect(rules).not_to include rule4
end
context "when no matching rules" do
it "returns an empty array" do
rules = described_class.matching_variant_tag_rules_by_enterprises(enterprise.id, "no-tag")
expect(rules).to eq([])
end
end
end
describe '#tags' do
subject(:rule) { Class.new(TagRule).new }