diff --git a/lib/ProductOpener/APITaxonomySuggestions.pm b/lib/ProductOpener/APITaxonomySuggestions.pm index f9283e4f4df06..e29c4512bc121 100644 --- a/lib/ProductOpener/APITaxonomySuggestions.pm +++ b/lib/ProductOpener/APITaxonomySuggestions.pm @@ -125,10 +125,8 @@ sub taxonomy_suggestions_api ($request_ref) { } # Generate suggestions else { - my $options_relavant = {%$options_ref}; - delete $options_relavant->{get_synonyms}; my @suggestions - = get_taxonomy_suggestions_with_synonyms($tagtype, $search_lc, $string, $context_ref, $options_relavant); + = get_taxonomy_suggestions_with_synonyms($tagtype, $search_lc, $string, $context_ref, $options_ref); $log->debug("taxonomy_suggestions_api", @suggestions) if $log->is_debug(); $response_ref->{suggestions} = [map {$_->{tag}} @suggestions]; if ($options_ref->{get_synonyms}) { diff --git a/lib/ProductOpener/TaxonomySuggestions.pm b/lib/ProductOpener/TaxonomySuggestions.pm index 642108e4481a7..628d2d3ad5a4f 100644 --- a/lib/ProductOpener/TaxonomySuggestions.pm +++ b/lib/ProductOpener/TaxonomySuggestions.pm @@ -379,6 +379,12 @@ By priority, the function returns: - limit: limit of number of results - format (not yet defined and implemented) +=head3 Return value + +An array of suggestions hashes with the following fields: +- tag: the tag to suggest +- matched_synonym: the synonym that matched the input string + =cut sub filter_suggestions_matching_string_with_synonyms ($tags_ref, $tagtype, $search_lc, $string, $options_ref) { @@ -424,7 +430,12 @@ sub filter_suggestions_matching_string_with_synonyms ($tags_ref, $tagtype, $sear my $stringid = get_string_id_for_lang("no_language", normalize_packager_codes($string)); foreach my $canon_tagid (@$tags_ref) { next if $canon_tagid !~ /^$stringid/; - push @suggestions, normalize_packager_codes($canon_tagid); + my $normalized_tag = normalize_packager_codes($canon_tagid); + my $suggestion_ref = { + tag => $normalized_tag, + matched_synonym => $normalized_tag + }; + push @suggestions, $suggestion_ref; last if ++$suggestions_count >= $limit; } } @@ -467,24 +478,24 @@ sub filter_suggestions_matching_string_with_synonyms ($tags_ref, $tagtype, $sear } ) if $log->is_debug(); - my $to_add = { + my $suggestion_ref = { tag => $tag, matched_synonym => $best_match->{match} }; # matching at start, best matches if ($best_match->{type} eq "start") { - push @suggestions, $to_add; + push @suggestions, $suggestion_ref; # count matches at start so that we can return only if we have enough matches $suggestions_count++; last if $suggestions_count >= $limit; } # matching inside elsif ($best_match->{type} eq "inside") { - push @suggestions_c, $to_add; + push @suggestions_c, $suggestion_ref; } # fuzzy match elsif ($best_match->{type} eq "fuzzy") { - push @suggestions_f, $to_add; + push @suggestions_f, $suggestion_ref; } } } diff --git a/tests/integration/api_v3_taxonomy_suggestions.t b/tests/integration/api_v3_taxonomy_suggestions.t index a9aee1bbca176..27201f4e6a785 100755 --- a/tests/integration/api_v3_taxonomy_suggestions.t +++ b/tests/integration/api_v3_taxonomy_suggestions.t @@ -35,188 +35,165 @@ my $tests_ref = [ test_case => 'categories-no-string', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=categories', - expected_status_code => 200, }, { test_case => 'categories-string-strawberry', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=categories&string=strawberry', - expected_status_code => 200, }, { test_case => 'categories-term-strawberry', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=categories&term=strawberry', - expected_status_code => 200, }, { test_case => 'categories-string-fraise', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=categories&string=fraise', - expected_status_code => 200, }, { test_case => 'categories-string-fr-fraise', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=categories&string=fraise&lc=fr', - expected_status_code => 200, }, { test_case => 'categories-string-fr-frais', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=categories&string=frais&lc=fr', - expected_status_code => 200, }, { test_case => 'categories-string-fr-cafe-accent', method => 'GET', - path => '/api/v3/taxonomy_suggestions?tagtype=categories&string=Café&lc=fr', - expected_status_code => 200, - }, - { - test_case => 'categories-string-fr-cafe-accent', - method => 'GET', - path => '/api/v3/taxonomy_suggestions?tagtype=categories&string=Café&lc=fr', - expected_status_code => 200, + path => '/api/v3/taxonomy_suggestions?tagtype=categories&string=caf%C3%A9&lc=fr', }, { test_case => 'allergens-string-fr-o-get-synonyms', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=allergens&string=o&lc=fr&get_synonyms=1', - expected_status_code => 200, }, # Packaging suggestions return most popular suggestions first { test_case => 'packaging-shapes', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_shapes', - expected_status_code => 200, }, { test_case => 'packaging-shapes-fr', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_shapes&lc=fr', - expected_status_code => 200, }, { test_case => 'packaging-shapes-string-po', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_shapes&string=po', - expected_status_code => 200, }, { test_case => 'packaging-shapes-string-fr-po', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_shapes&string=po&lc=fr', - expected_status_code => 200, }, # Packaging shape suggestions can be specific to a country and categories, and shape { test_case => 'packaging-shapes-cc-fr', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_shapes&cc=fr', - expected_status_code => 200, }, # categories can contain a comma separated list of taxonomy entry ids, entry name or synonym in the lc language { test_case => 'packaging-shapes-categories-mango-nectars-beverages', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_shapes&categories=mango%20nectars,beverages', - expected_status_code => 200, }, { test_case => 'packaging-shapes-cc-fr-categories-yogurt', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_shapes&cc=fr&categories=yogurt', - expected_status_code => 200, }, { test_case => 'packaging-shapes-cc-fr-categories-en-yogurts', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_shapes&cc=fr&categories=en:yogurts', - expected_status_code => 200, }, { test_case => 'packaging-shapes-cc-fr-categories-yaourt-fr', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_shapes&cc=fr&categories=yaourt&lc=fr', - expected_status_code => 200, }, # Packaging materials suggestions can be specific to a country and categories, and shape { test_case => 'packaging-materials', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_materials', - expected_status_code => 200, }, { test_case => 'packaging-materials-cc-fr', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_materials&cc=fr', - expected_status_code => 200, }, { test_case => 'packaging-materials-cc-fr-shape-pot', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_materials&cc=fr&shape=pot', - expected_status_code => 200, }, { test_case => 'packaging-materials-cc-fr-categories-yaourt-shape-pot', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_materials&cc=fr&categories=yogurts&shape=pot', - expected_status_code => 200, }, # match with xx: synonyms { test_case => 'packaging-materials-1', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_materials&string=1', - expected_status_code => 200, }, { test_case => 'packaging-materials-01', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_materials&string=01', - expected_status_code => 200, }, { test_case => 'packaging-materials-1-pet', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_materials&string=1-pet', - expected_status_code => 200, }, { test_case => 'packaging-materials-pet-1', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_materials&string=pet-1', - expected_status_code => 200, }, # Packaging recycling { test_case => 'packaging-recycling-fr-recy', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_recycling&cc=fr&string=recy', - expected_status_code => 200, }, { test_case => 'packaging-recycling-fr-bac-ver', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_recycling&cc=fr&string=bac-ver', - expected_status_code => 200, }, { test_case => 'packaging-recycling-fr-bac-verre', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_recycling&cc=fr&string=bac-verre', - expected_status_code => 200, }, { test_case => 'packaging-recycling-fr-bac-tri', method => 'GET', path => '/api/v3/taxonomy_suggestions?tagtype=packaging_recycling&cc=fr&string=bac-tri', - expected_status_code => 200, }, + # packaging codes / EMB codes: not a taxonomy, but can have suggestions too + { + test_case => 'emb-codes', + method => 'GET', + path => '/api/v3/taxonomy_suggestions?tagtype=emb_codes&string=fr%2056', + }, + # suggestions with synonyms + { + test_case => 'categories-string-fr-tart-get-synonyms', + method => 'GET', + path => '/api/v3/taxonomy_suggestions?tagtype=categories&string=tart&lc=fr&get_synonyms=1', + } ]; execute_api_tests(__FILE__, $tests_ref); diff --git a/tests/integration/expected_test_results/api_v3_taxonomy_suggestions/categories-string-fr-tart-get-synonyms.json b/tests/integration/expected_test_results/api_v3_taxonomy_suggestions/categories-string-fr-tart-get-synonyms.json new file mode 100644 index 0000000000000..784401c517709 --- /dev/null +++ b/tests/integration/expected_test_results/api_v3_taxonomy_suggestions/categories-string-fr-tart-get-synonyms.json @@ -0,0 +1,59 @@ +{ + "errors" : [], + "matched_synonyms" : { + "Flammekueches" : "Tarte flambée", + "Produits à tartiner" : "Tartinables", + "Quiches au poireau" : "Tartes aux poireaux", + "Quiches au poisson" : "Tartes au poisson", + "Quiches au saumon" : "Tartes au saumon", + "Quiches aux épinards" : "Tartes aux épinards", + "Salades d'œufs" : "Tartinades d'œufs", + "Tartares d'algues" : "Tartares d'algues", + "Tartares de boeuf" : "Tartares de boeuf", + "Tartares de viande" : "Tartares de viande", + "Tarte au vin" : "Tarte au vin", + "Tarte aux fruits rouges" : "Tarte aux fruits rouges", + "Tarte aux groseilles" : "Tarte aux groseilles", + "Tarte aux noix de Saint-Jacques" : "Tarte aux noix de Saint-Jacques", + "Tarte aux poires amandine" : "Tarte aux poires amandine", + "Tarte à l'oignon" : "Tarte à l'oignon", + "Tarte à la provençale" : "Tarte à la provençale", + "Tarte épinard chèvre" : "Tarte épinard chèvre", + "Tartelettes" : "Tartelettes", + "Tartelettes au caramel" : "Tartelettes au caramel", + "Tartelettes au chocolat" : "Tartelettes au chocolat", + "Tartelettes au citron" : "Tartelettes au citron", + "Tartelettes aux fruits entiers ou coupés" : "Tartelettes aux fruits entiers ou coupés", + "Tartelettes à l'abricot" : "Tartelettes à l'abricot", + "Tartelettes à la fraise" : "Tartelettes à la fraise" + }, + "status" : "success", + "suggestions" : [ + "Flammekueches", + "Produits à tartiner", + "Quiches au poireau", + "Quiches au poisson", + "Quiches au saumon", + "Quiches aux épinards", + "Salades d'œufs", + "Tartares d'algues", + "Tartares de boeuf", + "Tartares de viande", + "Tarte au vin", + "Tarte aux fruits rouges", + "Tarte aux groseilles", + "Tarte aux noix de Saint-Jacques", + "Tarte aux poires amandine", + "Tarte à l'oignon", + "Tarte à la provençale", + "Tarte épinard chèvre", + "Tartelettes", + "Tartelettes au caramel", + "Tartelettes au chocolat", + "Tartelettes au citron", + "Tartelettes aux fruits entiers ou coupés", + "Tartelettes à l'abricot", + "Tartelettes à la fraise" + ], + "warnings" : [] +} diff --git a/tests/integration/expected_test_results/api_v3_taxonomy_suggestions/emb-codes.json b/tests/integration/expected_test_results/api_v3_taxonomy_suggestions/emb-codes.json new file mode 100644 index 0000000000000..b9ab97e8b38f5 --- /dev/null +++ b/tests/integration/expected_test_results/api_v3_taxonomy_suggestions/emb-codes.json @@ -0,0 +1,32 @@ +{ + "errors" : [], + "status" : "success", + "suggestions" : [ + "FR 56.003.001 EC", + "FR 56.003.002 EC", + "FR 56.003.003 EC", + "FR 56.003.004 EC", + "FR 56.003.005 EC", + "FR 56.003.006 EC", + "FR 56.003.007 EC", + "FR 56.003.015 EC", + "FR 56.003.801 EC", + "FR 56.005.002 EC", + "FR 56.005.801 EC", + "FR 56.007.002 EC", + "FR 56.007.017 EC", + "FR 56.007.032 EC", + "FR 56.007.045 EC", + "FR 56.007.051 EC", + "FR 56.007.057 EC", + "FR 56.007.059 EC", + "FR 56.007.061 EC", + "FR 56.007.066 EC", + "FR 56.007.068 EC", + "FR 56.007.069 EC", + "FR 56.007.076 EC", + "FR 56.007.078 EC", + "FR 56.007.079 EC" + ], + "warnings" : [] +}