diff --git a/cgi/product_jqm_multilingual.pl b/cgi/product_jqm_multilingual.pl index 059648b30289d..f2383e669db21 100755 --- a/cgi/product_jqm_multilingual.pl +++ b/cgi/product_jqm_multilingual.pl @@ -52,7 +52,7 @@ =head1 DESCRIPTION use ProductOpener::Ingredients qw/:all/; use ProductOpener::Images qw/:all/; use ProductOpener::DataQuality qw/:all/; -use ProductOpener::Ecoscore qw/:all/; +use ProductOpener::EnvironmentalScore qw/:all/; use ProductOpener::Packaging qw/:all/; use ProductOpener::ForestFootprint qw/:all/; use ProductOpener::Text qw/remove_tags_and_quote/; @@ -266,8 +266,8 @@ =head1 DESCRIPTION push @app_fields, "creator"; } - if ($request_ref->{admin} or ($User_id eq "ecoscore-impact-estimator")) { - push @app_fields, ("ecoscore_extended_data", "ecoscore_extended_data_version"); + if ($request_ref->{admin} or ($User_id eq "environmental-score-impact-estimator")) { + push @app_fields, ("environmental_score_extended_data", "environmental_score_extended_data_version"); } # generate a list of potential languages for language specific fields @@ -385,7 +385,7 @@ =head1 DESCRIPTION } } - elsif ($field eq "ecoscore_extended_data") { + elsif ($field eq "environmental_score_extended_data") { # we expect a JSON value if (defined single_param($field)) { $product_ref->{$field} = decode_json(single_param($field)); diff --git a/cgi/product_multilingual.pl b/cgi/product_multilingual.pl index e86c5cdecef17..d6d2c415c14da 100755 --- a/cgi/product_multilingual.pl +++ b/cgi/product_multilingual.pl @@ -45,7 +45,7 @@ use ProductOpener::KnowledgePanelsContribution qw/create_contribution_card_panel/; use ProductOpener::URL qw/:all/; use ProductOpener::DataQuality qw/:all/; -use ProductOpener::Ecoscore qw/:all/; +use ProductOpener::EnvironmentalScore qw/:all/; use ProductOpener::Packaging qw/apply_rules_to_augment_packaging_component_data get_checked_and_taxonomized_packaging_component_data/; use ProductOpener::ForestFootprint qw/:all/; diff --git a/cgi/search.pl b/cgi/search.pl index fd8279399bf8b..0e78ce4f6de98 100755 --- a/cgi/search.pl +++ b/cgi/search.pl @@ -110,7 +110,7 @@ my @search_fields = qw(brands categories packaging labels origins manufacturing_places emb_codes purchase_places stores countries - ingredients additives allergens traces nutrition_grades nova_groups ecoscore languages creator editors states); + ingredients additives allergens traces nutrition_grades nova_groups environmental_score languages creator editors states); $request_ref->{admin} and push @search_fields, "lang"; @@ -352,7 +352,7 @@ my @other_search_fields = ( "additives_n", "ingredients_n", "known_ingredients_n", "unknown_ingredients_n", "fruits-vegetables-nuts-estimate-from-ingredients", - "forest_footprint", "product_quantity", "nova_group", 'ecoscore_score', + "forest_footprint", "product_quantity", "nova_group", 'environmental_score_score', ); # Add the fields related to packaging diff --git a/external-data/ecoscore/agribalyse/AGRIBALYSE3.1.1_produits alimentaires.xlsx b/external-data/environmental_score/agribalyse/AGRIBALYSE3.1.1_produits alimentaires.xlsx similarity index 100% rename from external-data/ecoscore/agribalyse/AGRIBALYSE3.1.1_produits alimentaires.xlsx rename to external-data/environmental_score/agribalyse/AGRIBALYSE3.1.1_produits alimentaires.xlsx diff --git a/external-data/ecoscore/agribalyse/AGRIBALYSE_summary.csv b/external-data/environmental_score/agribalyse/AGRIBALYSE_summary.csv similarity index 100% rename from external-data/ecoscore/agribalyse/AGRIBALYSE_summary.csv rename to external-data/environmental_score/agribalyse/AGRIBALYSE_summary.csv diff --git a/external-data/ecoscore/agribalyse/AGRIBALYSE_version.txt b/external-data/environmental_score/agribalyse/AGRIBALYSE_version.txt similarity index 100% rename from external-data/ecoscore/agribalyse/AGRIBALYSE_version.txt rename to external-data/environmental_score/agribalyse/AGRIBALYSE_version.txt diff --git a/external-data/ecoscore/agribalyse/AGRIBALYSE_vf.csv.0 b/external-data/environmental_score/agribalyse/AGRIBALYSE_vf.csv.0 similarity index 100% rename from external-data/ecoscore/agribalyse/AGRIBALYSE_vf.csv.0 rename to external-data/environmental_score/agribalyse/AGRIBALYSE_vf.csv.0 diff --git a/external-data/ecoscore/agribalyse/AGRIBALYSE_vf.csv.1 b/external-data/environmental_score/agribalyse/AGRIBALYSE_vf.csv.1 similarity index 100% rename from external-data/ecoscore/agribalyse/AGRIBALYSE_vf.csv.1 rename to external-data/environmental_score/agribalyse/AGRIBALYSE_vf.csv.1 diff --git a/external-data/ecoscore/agribalyse/AGRIBALYSE_vf.csv.2 b/external-data/environmental_score/agribalyse/AGRIBALYSE_vf.csv.2 similarity index 100% rename from external-data/ecoscore/agribalyse/AGRIBALYSE_vf.csv.2 rename to external-data/environmental_score/agribalyse/AGRIBALYSE_vf.csv.2 diff --git a/external-data/ecoscore/agribalyse/AGRIBALYSE_vf.csv.3 b/external-data/environmental_score/agribalyse/AGRIBALYSE_vf.csv.3 similarity index 100% rename from external-data/ecoscore/agribalyse/AGRIBALYSE_vf.csv.3 rename to external-data/environmental_score/agribalyse/AGRIBALYSE_vf.csv.3 diff --git a/external-data/ecoscore/agribalyse/AGRIBALYSE_vf.csv.4 b/external-data/environmental_score/agribalyse/AGRIBALYSE_vf.csv.4 similarity index 100% rename from external-data/ecoscore/agribalyse/AGRIBALYSE_vf.csv.4 rename to external-data/environmental_score/agribalyse/AGRIBALYSE_vf.csv.4 diff --git a/external-data/ecoscore/agribalyse/AGRIBALYSE_vf.csv.5 b/external-data/environmental_score/agribalyse/AGRIBALYSE_vf.csv.5 similarity index 100% rename from external-data/ecoscore/agribalyse/AGRIBALYSE_vf.csv.5 rename to external-data/environmental_score/agribalyse/AGRIBALYSE_vf.csv.5 diff --git a/external-data/ecoscore/agribalyse/AGRIBALYSE_vf.csv.6 b/external-data/environmental_score/agribalyse/AGRIBALYSE_vf.csv.6 similarity index 100% rename from external-data/ecoscore/agribalyse/AGRIBALYSE_vf.csv.6 rename to external-data/environmental_score/agribalyse/AGRIBALYSE_vf.csv.6 diff --git a/external-data/ecoscore/agribalyse/ssconvert.sh b/external-data/environmental_score/agribalyse/ssconvert.sh similarity index 100% rename from external-data/ecoscore/agribalyse/ssconvert.sh rename to external-data/environmental_score/agribalyse/ssconvert.sh diff --git a/external-data/ecoscore/data/Eco_score_Calculateur.csv.11 b/external-data/environmental_score/data/Eco_score_Calculateur.csv.11 similarity index 100% rename from external-data/ecoscore/data/Eco_score_Calculateur.csv.11 rename to external-data/environmental_score/data/Eco_score_Calculateur.csv.11 diff --git a/external-data/ecoscore/data/Eco_score_Calculateur.csv.12 b/external-data/environmental_score/data/Eco_score_Calculateur.csv.12 similarity index 100% rename from external-data/ecoscore/data/Eco_score_Calculateur.csv.12 rename to external-data/environmental_score/data/Eco_score_Calculateur.csv.12 diff --git a/external-data/ecoscore/data/Eco_score_Calculateur.csv.9 b/external-data/environmental_score/data/Eco_score_Calculateur.csv.9 similarity index 100% rename from external-data/ecoscore/data/Eco_score_Calculateur.csv.9 rename to external-data/environmental_score/data/Eco_score_Calculateur.csv.9 diff --git a/external-data/ecoscore/data/distances.csv b/external-data/environmental_score/data/distances.csv similarity index 100% rename from external-data/ecoscore/data/distances.csv rename to external-data/environmental_score/data/distances.csv diff --git a/external-data/ecoscore/data/fr_countries.csv b/external-data/environmental_score/data/fr_countries.csv similarity index 100% rename from external-data/ecoscore/data/fr_countries.csv rename to external-data/environmental_score/data/fr_countries.csv diff --git a/external-data/ecoscore/data/fr_packaging_materials.csv b/external-data/environmental_score/data/fr_packaging_materials.csv similarity index 100% rename from external-data/ecoscore/data/fr_packaging_materials.csv rename to external-data/environmental_score/data/fr_packaging_materials.csv diff --git a/external-data/ecoscore/data/fr_packaging_shapes.csv b/external-data/environmental_score/data/fr_packaging_shapes.csv similarity index 100% rename from external-data/ecoscore/data/fr_packaging_shapes.csv rename to external-data/environmental_score/data/fr_packaging_shapes.csv diff --git a/external-data/ecoscore/data/ssconvert.sh b/external-data/environmental_score/data/ssconvert.sh similarity index 100% rename from external-data/ecoscore/data/ssconvert.sh rename to external-data/environmental_score/data/ssconvert.sh diff --git a/html/images/attributes/src/green-score-a-plus.svg b/html/images/attributes/src/green-score-a-plus.svg new file mode 100644 index 0000000000000..528836531f172 --- /dev/null +++ b/html/images/attributes/src/green-score-a-plus.svg @@ -0,0 +1,606 @@ + + diff --git a/html/images/attributes/src/green-score-a.svg b/html/images/attributes/src/green-score-a.svg new file mode 100644 index 0000000000000..2288ae674ef55 --- /dev/null +++ b/html/images/attributes/src/green-score-a.svg @@ -0,0 +1,1014 @@ + + diff --git a/html/images/attributes/src/green-score-b.svg b/html/images/attributes/src/green-score-b.svg new file mode 100644 index 0000000000000..65b748a610c1a --- /dev/null +++ b/html/images/attributes/src/green-score-b.svg @@ -0,0 +1,907 @@ + + diff --git a/html/images/attributes/src/green-score-c.svg b/html/images/attributes/src/green-score-c.svg new file mode 100644 index 0000000000000..f25a8dfe85781 --- /dev/null +++ b/html/images/attributes/src/green-score-c.svg @@ -0,0 +1,907 @@ + + diff --git a/html/images/attributes/src/green-score-d.svg b/html/images/attributes/src/green-score-d.svg new file mode 100644 index 0000000000000..8752eb8022f83 --- /dev/null +++ b/html/images/attributes/src/green-score-d.svg @@ -0,0 +1,907 @@ + + diff --git a/html/images/attributes/src/green-score-e.svg b/html/images/attributes/src/green-score-e.svg new file mode 100644 index 0000000000000..a29fd16b97e19 --- /dev/null +++ b/html/images/attributes/src/green-score-e.svg @@ -0,0 +1,924 @@ + + diff --git a/html/images/attributes/src/green-score-f.svg b/html/images/attributes/src/green-score-f.svg new file mode 100644 index 0000000000000..b056a42041489 --- /dev/null +++ b/html/images/attributes/src/green-score-f.svg @@ -0,0 +1,135 @@ + + diff --git a/html/images/attributes/src/green-score-not-applicable.svg b/html/images/attributes/src/green-score-not-applicable.svg new file mode 100644 index 0000000000000..807a0db18a85a --- /dev/null +++ b/html/images/attributes/src/green-score-not-applicable.svg @@ -0,0 +1,986 @@ + + diff --git a/html/images/attributes/src/green-score-unknown.svg b/html/images/attributes/src/green-score-unknown.svg new file mode 100644 index 0000000000000..50b5178792b5f --- /dev/null +++ b/html/images/attributes/src/green-score-unknown.svg @@ -0,0 +1,907 @@ + + diff --git a/lib/ProductOpener/API.pm b/lib/ProductOpener/API.pm index bc90e5d24f100..947df3e0ed6e6 100644 --- a/lib/ProductOpener/API.pm +++ b/lib/ProductOpener/API.pm @@ -70,7 +70,7 @@ use ProductOpener::Tags qw/%language_fields display_taxonomy_tag/; use ProductOpener::Text qw/remove_tags_and_quote/; use ProductOpener::Attributes qw/compute_attributes/; use ProductOpener::KnowledgePanels qw/create_knowledge_panels initialize_knowledge_panels_options/; -use ProductOpener::Ecoscore qw/localize_ecoscore/; +use ProductOpener::EnvironmentalScore qw/localize_environmental_score/; use ProductOpener::Packaging qw/%packaging_taxonomies/; use ProductOpener::Permissions qw/has_permission/; use ProductOpener::GeoIP qw/get_country_for_ip_api/; @@ -625,6 +625,55 @@ sub customize_packagings ($request_ref, $product_ref) { return $customized_packagings_ref; } +=head2 api_compatibility_for_field ($field, $api_version) + +To support older API versions that can request fields that have been renamed or changed, +we rename older requested fields to the new field names to construct the response. + +Resulting fields will then be renamed back to older names by the api_compatibility_for_product function. + +=cut + +sub api_compatibility_for_field ($field, $api_version) { + + # API 3.1 - 2024/12/18 - ecoscore* fields have been renamed to environmental_score* + if ($api_version < 3.1) { + if ($field =~ /^ecoscore/) { + $field = "environmental_score" . $'; + } + } + + return $field; +} + +=head2 api_compatibility_for_product ($product_ref, $api_version) + +The response schema can change between API versions. This function transforms the product object to match the requested API version. + +=cut + +sub api_compatibility_for_product ($product_ref, $api_version) { + + $log->debug("api_compatibility_for_product - start", {api_version => $api_version}) if $log->is_debug(); + + # no requested version, return the product as is + if (not defined $api_version) { + return $product_ref; + } + + # API 3.1 - 2024/12/18 - ecoscore* fields have been renamed to environmental_score* + if ($api_version < 3.1) { + foreach my $subfield (qw/data grade score tags/) { + if (defined $product_ref->{"environmental_score_" . $subfield}) { + $product_ref->{"ecoscore_" . $subfield} = $product_ref->{"environmental_score_" . $subfield}; + delete $product_ref->{"environmental_score_" . $subfield}; + } + } + } + + return $product_ref; +} + =head2 customize_response_for_product ( $request_ref, $product_ref, $fields_comma_separated_list, $fields_ref ) Using the fields parameter, API product or search queries can request @@ -680,7 +729,7 @@ sub customize_response_for_product ($request_ref, $product_ref, $fields_comma_se my $carbon_footprint_computed = 0; - # Special case if fields is empty, or contains only "none" or "raw": we do not need to localize the Eco-Score + # Special case if fields is empty, or contains only "none" or "raw": we do not need to localize the Environmental-Score if ((scalar @fields) == 0) { return {}; @@ -695,14 +744,17 @@ sub customize_response_for_product ($request_ref, $product_ref, $fields_comma_se } } - # Localize the Eco-Score fields that depend on the country of the request - if (feature_enabled("ecoscore", $product_ref)) { - localize_ecoscore($request_ref->{cc}, $product_ref); + # Localize the Environmental-Score fields that depend on the country of the request + if (feature_enabled("environmental_score", $product_ref)) { + localize_environmental_score($request_ref->{cc}, $product_ref); } # lets compute each requested field foreach my $field (@fields) { + # Compatibility with older API versions + $field = api_compatibility_for_field($field, $request_ref->{api_version}); + if ($field eq 'all') { # Return all fields of the product, with processing that depends on the API version used # e.g. in API v3, the "packagings" structure is more verbose than the stored version @@ -733,12 +785,12 @@ sub customize_response_for_product ($request_ref, $product_ref, $fields_comma_se next; } - # Eco-Score details in simple HTML - if ($field eq "ecoscore_details_simple_html") { - if ((1 or $show_ecoscore) and (defined $product_ref->{ecoscore_data})) { + # Environmental-Score details in simple HTML + if ($field eq "environmental_score_details_simple_html") { + if ((1 or $show_environmental_score) and (defined $product_ref->{environmental_score_data})) { $customized_product_ref->{$field} - = display_ecoscore_calculation_details_simple_html($request_ref->{cc}, - $product_ref->{ecoscore_data}); + = display_environmental_score_calculation_details_simple_html($request_ref->{cc}, + $product_ref->{environmental_score_data}); } next; } @@ -858,6 +910,9 @@ sub customize_response_for_product ($request_ref, $product_ref, $fields_comma_se # TODO: it would be great to return errors when the caller requests fields that are invalid (e.g. typos) } + # Before returning the product, we need to make sure that the fields are compatible with the requested API version + api_compatibility_for_product($customized_product_ref, $request_ref->{api_version}); + return $customized_product_ref; } diff --git a/lib/ProductOpener/Attributes.pm b/lib/ProductOpener/Attributes.pm index 1984a91fb242d..3c8a8df96071d 100644 --- a/lib/ProductOpener/Attributes.pm +++ b/lib/ProductOpener/Attributes.pm @@ -67,7 +67,7 @@ use ProductOpener::Food qw/@nutrient_levels/; use ProductOpener::Ingredients qw/:all/; use ProductOpener::Lang qw/f_lang_in_lc lang lang_in_other_lc/; use ProductOpener::Display qw/$static_subdomain/; -use ProductOpener::Ecoscore qw/:all/; +use ProductOpener::EnvironmentalScore qw/:all/; use ProductOpener::ProductsFeatures qw/feature_enabled/; use Data::DeepAccess qw(deep_get); @@ -282,8 +282,8 @@ sub initialize_attribute ($attribute_id, $target_lc) { $attribute_ref->{panel_id} = "nutriscore"; } elsif ($attribute_id eq "ecoscore") { - $attribute_ref->{icon_url} = "$static_subdomain/images/attributes/dist/ecoscore-a.svg"; - $attribute_ref->{panel_id} = "ecoscore"; + $attribute_ref->{icon_url} = "$static_subdomain/images/attributes/dist/green-score-a.svg"; + $attribute_ref->{panel_id} = "environmental_score"; } elsif ($attribute_id eq "forest_footprint") { $attribute_ref->{icon_url} = "$static_subdomain/images/attributes/dist/forest-footprint-a.svg"; @@ -612,9 +612,13 @@ sub compute_attribute_nutriscore ($product_ref, $target_lc, $target_cc) { return $attribute_ref; } -=head2 compute_attribute_ecoscore ( $product_ref, $target_lc, $target_cc ) +=head2 compute_attribute_environmental_score ( $product_ref, $target_lc, $target_cc ) -Computes an environmental impact attribute based on the Eco-Score. +Computes an environmental impact attribute based on the Environmental-Score. + +Note: before 2025, the Environmental-Score was called the Eco-Score, +as the id of the attribute is stored inside clients, we keep the +id "ecoscore" for the attribute. =head3 Arguments @@ -629,7 +633,7 @@ This parameter sets the desired language for the user facing strings. =head4 country code $target_cc -The Eco-Score depends on the country of the consumer (as the transport bonus/malus depends on it) +The Environmental-Score depends on the country of the consumer (as the transport bonus/malus depends on it) =head3 Return value @@ -637,35 +641,47 @@ The return value is a reference to the resulting attribute data structure. =head4 % Match -To differentiate products more finely, the match is based on the Eco-Score score -that is used to define the Eco-Score grade from A+ to F. +To differentiate products more finely, the match is based on the Environmental-Score score +that is used to define the Environmental-Score grade from A+ to F. =cut -sub compute_attribute_ecoscore ($product_ref, $target_lc, $target_cc) { +sub compute_attribute_environmental_score ($product_ref, $target_lc, $target_cc) { - $log->debug("compute ecoscore attribute", - {code => $product_ref->{code}, ecoscore_data => $product_ref->{ecoscore_data}}) + $log->debug("compute environmental_score attribute", + {code => $product_ref->{code}, environmental_score_data => $product_ref->{environmental_score_data}}) if $log->is_debug(); + # Note: before 2025, the Environmental-Score was called the Eco-Score, + # as the id of the attribute is stored inside clients, we keep the + # id "ecoscore" for the attribute. my $attribute_id = "ecoscore"; + # 2024/12: If we do not have yet environmental_score_data, we use ecoscore_data + # (or possibly for older revisions) + # TBD: remove this code once all products have been updated (but we won't show the score for old revisions) + if ((not defined $product_ref->{environmental_score_data}) and (defined $product_ref->{ecoscore_data})) { + $product_ref->{environmental_score_data} = $product_ref->{ecoscore_data}; + } + my $attribute_ref = initialize_attribute($attribute_id, $target_lc); - if ((defined $product_ref->{ecoscore_data}) and ($product_ref->{ecoscore_data}{status} eq "known")) { + if ( (defined $product_ref->{environmental_score_data}) + and ($product_ref->{environmental_score_data}{status} eq "known")) + { $attribute_ref->{status} = "known"; - my $score = $product_ref->{ecoscore_score} // 0; - my $grade = $product_ref->{ecoscore_grade}; + my $score = $product_ref->{environmental_score_score} // 0; + my $grade = $product_ref->{environmental_score_grade}; - if ( (defined $product_ref->{ecoscore_data}{"scores"}) - and (defined $product_ref->{ecoscore_data}{"scores"}{$target_cc})) + if ( (defined $product_ref->{environmental_score_data}{"scores"}) + and (defined $product_ref->{environmental_score_data}{"scores"}{$target_cc})) { - $score = $product_ref->{ecoscore_data}{"scores"}{$target_cc} // 0; - $grade = $product_ref->{ecoscore_data}{"grades"}{$target_cc}; + $score = $product_ref->{environmental_score_data}{"scores"}{$target_cc} // 0; + $grade = $product_ref->{environmental_score_data}{"grades"}{$target_cc}; } - $log->debug("compute ecoscore attribute - known", + $log->debug("compute environmental_score attribute - known", {code => $product_ref->{code}, score => $score, grade => $grade}) if $log->is_debug(); @@ -690,45 +706,53 @@ sub compute_attribute_ecoscore ($product_ref, $target_lc, $target_cc) { $letter_grade = "A+"; } $attribute_ref->{title} - = sprintf(lang_in_other_lc($target_lc, "attribute_ecoscore_grade_title"), $letter_grade); + = sprintf(lang_in_other_lc($target_lc, "attribute_environmental_score_grade_title"), $letter_grade); $attribute_ref->{description} - = lang_in_other_lc($target_lc, "attribute_ecoscore_" . $grade_underscore . "_description"); + = lang_in_other_lc($target_lc, "attribute_environmental_score_" . $grade_underscore . "_description"); $attribute_ref->{description_short} - = lang_in_other_lc($target_lc, "attribute_ecoscore_" . $grade_underscore . "_description_short"); + = lang_in_other_lc($target_lc, + "attribute_environmental_score_" . $grade_underscore . "_description_short"); } - $attribute_ref->{icon_url} = "$static_subdomain/images/attributes/dist/ecoscore-$grade.svg"; + $attribute_ref->{icon_url} = "$static_subdomain/images/attributes/dist/green-score-$grade.svg"; } - # Eco-Score is not-applicable - elsif ((defined $product_ref->{ecoscore_grade}) and ($product_ref->{ecoscore_grade} eq "not-applicable")) { + # Environmental-Score is not-applicable + elsif ( (defined $product_ref->{environmental_score_grade}) + and ($product_ref->{environmental_score_grade} eq "not-applicable")) + { $attribute_ref->{status} = "unknown"; - $attribute_ref->{icon_url} = "$static_subdomain/images/attributes/dist/ecoscore-not-applicable.svg"; + $attribute_ref->{icon_url} = "$static_subdomain/images/attributes/dist/green-score-not-applicable.svg"; $attribute_ref->{match} = 0; if ($target_lc ne "data") { - $attribute_ref->{title} = lang_in_other_lc($target_lc, "attribute_ecoscore_not_applicable_title"); + $attribute_ref->{title} + = lang_in_other_lc($target_lc, "attribute_environmental_score_not_applicable_title"); $attribute_ref->{description} = f_lang_in_lc( $target_lc, - "f_attribute_ecoscore_not_applicable_description", + "f_attribute_environmental_score_not_applicable_description", { category => display_taxonomy_tag_name( - $target_lc, "categories", - deep_get($product_ref, qw/ecoscore_data ecoscore_not_applicable_for_category/) + $target_lc, + "categories", + deep_get( + $product_ref, qw/environmental_score_data environmental_score_not_applicable_for_category/ + ) ) } ); $attribute_ref->{description_short} - = lang_in_other_lc($target_lc, "attribute_ecoscore_not_applicable_description_short"); + = lang_in_other_lc($target_lc, "attribute_environmental_score_not_applicable_description_short"); } } - # Eco-Score is unknown + # Environmental-Score is unknown else { $attribute_ref->{status} = "unknown"; - $attribute_ref->{icon_url} = "$static_subdomain/images/attributes/dist/ecoscore-unknown.svg"; + $attribute_ref->{icon_url} = "$static_subdomain/images/attributes/dist/green-score-unknown.svg"; $attribute_ref->{match} = 0; if ($target_lc ne "data") { - $attribute_ref->{title} = lang_in_other_lc($target_lc, "attribute_ecoscore_unknown_title"); - $attribute_ref->{description} = lang_in_other_lc($target_lc, "attribute_ecoscore_unknown_description"); + $attribute_ref->{title} = lang_in_other_lc($target_lc, "attribute_environmental_score_unknown_title"); + $attribute_ref->{description} + = lang_in_other_lc($target_lc, "attribute_environmental_score_unknown_description"); $attribute_ref->{description_short} - = lang_in_other_lc($target_lc, "attribute_ecoscore_unknown_description_short"); + = lang_in_other_lc($target_lc, "attribute_environmental_score_unknown_description_short"); } } @@ -1651,7 +1675,7 @@ If $target_lc is equal to "data", no strings are returned. =head4 country code $target_cc -Needed for some country specific attributes like the Eco-Score. +Needed for some country specific attributes like the Environmental-Score. =head4 options $options_ref @@ -1722,8 +1746,8 @@ sub compute_attributes ($product_ref, $target_lc, $target_cc, $options_ref) { # Environment - if (feature_enabled("ecoscore")) { - $attribute_ref = compute_attribute_ecoscore($product_ref, $target_lc, $target_cc); + if (feature_enabled("environmental_score")) { + $attribute_ref = compute_attribute_environmental_score($product_ref, $target_lc, $target_cc); add_attribute_to_group($product_ref, $target_lc, "environment", $attribute_ref); } @@ -1792,7 +1816,7 @@ The return value is a reference to the resulting attribute data structure. sub compute_attribute_repairability_index_france ($product_ref, $target_lc, $target_cc) { $log->debug("compute repairability index attribute", - {code => $product_ref->{code}, ecoscore_data => $product_ref->{labels_tags}}) + {code => $product_ref->{code}, environmental_score_data => $product_ref->{labels_tags}}) if $log->is_debug(); my $attribute_id = "repairability_index_france"; diff --git a/lib/ProductOpener/Config_obf.pm b/lib/ProductOpener/Config_obf.pm index 2b1062bba6ef0..b821da196e7df 100644 --- a/lib/ProductOpener/Config_obf.pm +++ b/lib/ProductOpener/Config_obf.pm @@ -354,7 +354,7 @@ HTML ); # tag types (=facets) that should be indexed by web crawlers, all other tag types are not indexable -@index_tag_types = qw(brands categories labels additives nova_groups ecoscore nutrition_grades products); +@index_tag_types = qw(brands categories labels additives nova_groups environmental_score nutrition_grades products); # fields in product edit form, above ingredients and nutrition facts @@ -436,7 +436,7 @@ HTML @drilldown_fields = qw( nutrition_grades nova_groups - ecoscore + environmental_score brands categories labels @@ -505,8 +505,8 @@ HTML food_groups states brand_owner - ecoscore_score - ecoscore_grade + environmental_score_score + environmental_score_grade nutrient_levels_tags product_quantity owner diff --git a/lib/ProductOpener/Config_off.pm b/lib/ProductOpener/Config_off.pm index e42afc16ad543..3203e05c0674a 100644 --- a/lib/ProductOpener/Config_off.pm +++ b/lib/ProductOpener/Config_off.pm @@ -863,8 +863,8 @@ $options{replace_existing_values_when_importing_those_tags_fields} = { food_groups states brand_owner - ecoscore_score - ecoscore_grade + environmental_score_score + environmental_score_grade nutrient_levels_tags product_quantity owner @@ -933,15 +933,15 @@ $options{off_export_fields_groups} = [ "nova_groups", "nutriscore_grade", "nutriscore_score", - "ecoscore_grade", - "ecoscore_score", - "ecoscore_data.missing_key_data", - "ecoscore_data.agribalyse.code", - "ecoscore_data.adjustments.origins_of_ingredients.value", - "ecoscore_data.adjustments.packaging.value", - "ecoscore_data.adjustments.packaging.non_recyclable_and_non_biodegradable_materials", - "ecoscore_data.adjustments.production_system.value", - "ecoscore_data.adjustments.threatened_species.value", + "environmental_score_grade", + "environmental_score_score", + "environmental_score_data.missing_key_data", + "environmental_score_data.agribalyse.code", + "environmental_score_data.adjustments.origins_of_ingredients.value", + "environmental_score_data.adjustments.packaging.value", + "environmental_score_data.adjustments.packaging.non_recyclable_and_non_biodegradable_materials", + "environmental_score_data.adjustments.production_system.value", + "environmental_score_data.adjustments.threatened_species.value", ] ], ]; @@ -965,6 +965,9 @@ $options{attribute_groups} = [ ], ["ingredients_analysis", ["vegan", "vegetarian", "palm_oil_free",]], ["labels", ["labels_organic", "labels_fair_trade"]], + # Note: before 2025, the Environmental-Score was called the Eco-Score, + # as the id of the attribute is stored inside clients, we keep the + # id "ecoscore" for the attribute. ["environment", ["ecoscore", "forest_footprint",]], ]; diff --git a/lib/ProductOpener/Config_opf.pm b/lib/ProductOpener/Config_opf.pm index 7f08fb198c6b6..f8fa32521bd12 100644 --- a/lib/ProductOpener/Config_opf.pm +++ b/lib/ProductOpener/Config_opf.pm @@ -430,7 +430,7 @@ HTML @drilldown_fields = qw( nutrition_grades nova_groups - ecoscore + environmental_score brands categories labels @@ -499,8 +499,8 @@ HTML food_groups states brand_owner - ecoscore_score - ecoscore_grade + environmental_score_score + environmental_score_grade nutrient_levels_tags product_quantity owner diff --git a/lib/ProductOpener/Config_opff.pm b/lib/ProductOpener/Config_opff.pm index 14c2f74ed10a0..0802d992e7631 100644 --- a/lib/ProductOpener/Config_opff.pm +++ b/lib/ProductOpener/Config_opff.pm @@ -382,7 +382,7 @@ XML ); # tag types (=facets) that should be indexed by web crawlers, all other tag types are not indexable -@index_tag_types = qw(brands categories labels additives nova_groups ecoscore nutrition_grades products); +@index_tag_types = qw(brands categories labels additives nova_groups environmental_score nutrition_grades products); # fields in product edit form, above ingredients and nutrition facts @@ -464,7 +464,7 @@ XML @drilldown_fields = qw( nutrition_grades nova_groups - ecoscore + environmental_score brands categories labels @@ -533,8 +533,8 @@ XML food_groups states brand_owner - ecoscore_score - ecoscore_grade + environmental_score_score + environmental_score_grade nutrient_levels_tags product_quantity owner diff --git a/lib/ProductOpener/DataQualityFood.pm b/lib/ProductOpener/DataQualityFood.pm index 5560f592cb08d..16fd780e1a176 100644 --- a/lib/ProductOpener/DataQualityFood.pm +++ b/lib/ProductOpener/DataQualityFood.pm @@ -51,7 +51,7 @@ use ProductOpener::Config qw(:all); use ProductOpener::Store qw(get_string_id_for_lang); use ProductOpener::Tags qw(:all); use ProductOpener::Food qw(%categories_nutriments_per_country); -use ProductOpener::Ecoscore qw(is_ecoscore_extended_data_more_precise_than_agribalyse); +use ProductOpener::EnvironmentalScore qw(is_environmental_score_extended_data_more_precise_than_agribalyse); use ProductOpener::Units qw(extract_standard_unit); use Data::DeepAccess qw(deep_exists); @@ -2651,40 +2651,43 @@ sub check_ingredients_with_specified_percent ($product_ref) { return; } -=head2 check_ecoscore_data( PRODUCT_REF ) +=head2 check_environmental_score_data( PRODUCT_REF ) Checks for data needed to compute the Eco-score. =cut -sub check_ecoscore_data ($product_ref) { +sub check_environmental_score_data ($product_ref) { - if (defined $product_ref->{ecoscore_data}) { + if (defined $product_ref->{environmental_score_data}) { - foreach my $adjustment (sort keys %{$product_ref->{ecoscore_data}{adjustments}}) { + foreach my $adjustment (sort keys %{$product_ref->{environmental_score_data}{adjustments}}) { - if (defined $product_ref->{ecoscore_data}{adjustments}{$adjustment}{warning}) { - my $warning = $adjustment . '-' . $product_ref->{ecoscore_data}{adjustments}{$adjustment}{warning}; + if (defined $product_ref->{environmental_score_data}{adjustments}{$adjustment}{warning}) { + my $warning + = $adjustment . '-' . $product_ref->{environmental_score_data}{adjustments}{$adjustment}{warning}; $warning =~ s/_/-/g; - push @{$product_ref->{data_quality_warnings_tags}}, 'en:ecoscore-' . $warning; + push @{$product_ref->{data_quality_warnings_tags}}, 'en:environmental-score-' . $warning; } } } - # Extended Eco-Score data from impact estimator - if (defined $product_ref->{ecoscore_extended_data}) { + # Extended Environmental-Score data from impact estimator + if (defined $product_ref->{environmental_score_extended_data}) { - push @{$product_ref->{data_quality_info_tags}}, 'en:ecoscore-extended-data-computed'; + push @{$product_ref->{data_quality_info_tags}}, 'en:environmental-score-extended-data-computed'; - if (is_ecoscore_extended_data_more_precise_than_agribalyse($product_ref)) { - push @{$product_ref->{data_quality_info_tags}}, 'en:ecoscore-extended-data-more-precise-than-agribalyse'; + if (is_environmental_score_extended_data_more_precise_than_agribalyse($product_ref)) { + push @{$product_ref->{data_quality_info_tags}}, + 'en:environmental-score-extended-data-more-precise-than-agribalyse'; } else { - push @{$product_ref->{data_quality_info_tags}}, 'en:ecoscore-extended-data-less-precise-than-agribalyse'; + push @{$product_ref->{data_quality_info_tags}}, + 'en:environmental-score-extended-data-less-precise-than-agribalyse'; } } else { - push @{$product_ref->{data_quality_info_tags}}, 'en:ecoscore-extended-data-not-computed'; + push @{$product_ref->{data_quality_info_tags}}, 'en:environmental-score-extended-data-not-computed'; } return; @@ -2802,7 +2805,7 @@ sub check_quality_food ($product_ref) { check_categories($product_ref); check_labels($product_ref); compare_nutriscore_with_value_from_producer($product_ref); - check_ecoscore_data($product_ref); + check_environmental_score_data($product_ref); check_food_groups($product_ref); check_incompatible_tags($product_ref); diff --git a/lib/ProductOpener/Display.pm b/lib/ProductOpener/Display.pm index 1c3081681902b..da1589497e8c8 100644 --- a/lib/ProductOpener/Display.pm +++ b/lib/ProductOpener/Display.pm @@ -124,7 +124,7 @@ BEGIN { %file_timestamps - $show_ecoscore + $show_environmental_score $attributes_options_ref $knowledge_panels_options_ref @@ -158,7 +158,7 @@ use ProductOpener::Data use ProductOpener::Text qw(escape_char escape_single_quote_and_newlines get_decimal_formatter get_percent_formatter remove_tags_and_quote); use ProductOpener::Nutriscore qw(%points_thresholds compute_nutriscore_grade); -use ProductOpener::Ecoscore qw(localize_ecoscore); +use ProductOpener::EnvironmentalScore qw(localize_environmental_score); use ProductOpener::Attributes qw(compute_attributes list_attributes); use ProductOpener::KnowledgePanels qw(create_knowledge_panels initialize_knowledge_panels_options); use ProductOpener::KnowledgePanelsTags qw(create_tag_knowledge_panels); @@ -333,14 +333,14 @@ $images_subdomain = format_subdomain('images'); =head2 url_for_text ( $textid ) Return the localized URL for a text. (e.g. "data" points to /data in English and /donnees in French) -Note: This currently only has ecoscore +Note: This currently only has environmental_score =cut # Note: the following urls are currently hardcoded, but the idea is to build the mapping table # at startup from the available translated texts in the repository. (TODO) my %urls_for_texts = ( - "ecoscore" => { + "environmental_score" => { en => "eco-score-the-environmental-impact-of-food-products", de => "eco-score-die-umweltauswirkungen-von-lebensmitteln", es => "eco-score-el-impacto-medioambiental-de-los-productos-alimenticios", @@ -960,8 +960,8 @@ CSS $attributes_options_ref = {}; $knowledge_panels_options_ref = {}; - if (not feature_enabled("ecoscore")) { - $knowledge_panels_options_ref->{skip_ecoscore} = 1; + if (not feature_enabled("environmental_score")) { + $knowledge_panels_options_ref->{skip_environmental_score} = 1; } if (not feature_enabled("forest_footprint")) { $knowledge_panels_options_ref->{skip_forest_footprint} = 1; @@ -1263,8 +1263,9 @@ sub display_robots_txt_and_exit ($request_ref) { defined $tag_value_plural and length($tag_value_plural) != 0 - # ecoscore has the same value for singular and plural, and products should not be disabled - and ($type !~ /^ecoscore|products$/) and not(exists($disallow_paths_localized_set{$tag_value_plural})) + # environmental_score has the same value for singular and plural, and products should not be disabled + and ($type !~ /^environmental_score|products$/) + and not(exists($disallow_paths_localized_set{$tag_value_plural})) ) { $disallow_paths_localized_set{$tag_value_plural} = undef; @@ -1727,7 +1728,7 @@ sub query_list_of_tags ($request_ref, $query_ref) { my $default_sort_by = "count"; # except for scores where we sort alphabetically (A to E, and 1 to 4) - if (($groupby_tagtype =~ /^nutriscore|nutrition_grades|ecoscore|nova_groups/)) { + if (($groupby_tagtype =~ /^nutriscore|nutrition_grades|environmental_score|nova_groups/)) { $default_sort_by = "tag"; } @@ -2030,7 +2031,7 @@ sub display_list_of_tags ($request_ref, $query_ref) { } # display_percent parameter: display the percentage of products for each tag - # This is useful only for tags that have unique values like Nutri-Score and Eco-Score + # This is useful only for tags that have unique values like Nutri-Score and Environmental-Score my $display_percent = single_param("display_percent"); foreach my $tagcount_ref (@tags) { my $count = $tagcount_ref->{count}; @@ -2038,9 +2039,9 @@ sub display_list_of_tags ($request_ref, $query_ref) { $stats{all_tags_products} += $count; } - # For the Eco-Score, we want to display A+ before A even though A+ is after A in alphabetical order + # For the Environmental-Score, we want to display A+ before A even though A+ is after A in alphabetical order # If the tagid "a" is followed by tagid "a-plus", invert them - if (($tagtype eq 'ecoscore') and (defined $tags[1])) { + if (($tagtype eq 'environmental_score') and (defined $tags[1])) { if (($tags[0]{_id} eq 'a') and ($tags[1]{_id} eq 'a-plus')) { my $tags_tmp = $tags[0]; @@ -2212,7 +2213,7 @@ sub display_list_of_tags ($request_ref, $query_ref) { $html .= "
[% lang('source_ademe_agribalyse_for_category') %] - [% panel.agribalyse_category_name %] + [% panel.agribalyse_category_name %] ([% lang('source_ademe_agribalyse') %])
` @@ -38,16 +38,16 @@ { "element_type": "table", "table_element": { - "id": "ecoscore_carbon_impact_by_stages_table", + "id": "environmental_score_carbon_impact_by_stages_table", "table_type": "percents", - "title": "[% edq(lang('ecoscore_impact_detail_by_stages')) %]", + "title": "[% edq(lang('environmental_score_impact_detail_by_stages')) %]", "columns": [ { - "text": "[% edq(lang('ecoscore_stage')) %]", + "text": "[% edq(lang('environmental_score_stage')) %]", "type": "text", }, { - "text": "[% edq(lang('ecoscore_impact')) %]", + "text": "[% edq(lang('environmental_score_impact')) %]", "type": "percent", } ], @@ -58,12 +58,12 @@ "values": [ { "icon_url": "[% static_subdomain %]/images/icons/dist/[% step %].svg", - "text": "[% edq(lang("ecoscore_$step")) %]" + "text": "[% edq(lang("environmental_score_$step")) %]" }, { [% co2_step = "co2_$step" %] - "text": "[% (100 * product.ecoscore_data.agribalyse.$co2_step / product.ecoscore_data.agribalyse.co2_total) FILTER format('%.1f'); %] %", - "percent": [% (100 * product.ecoscore_data.agribalyse.$co2_step / product.ecoscore_data.agribalyse.co2_total) %] + "text": "[% (100 * product.environmental_score_data.agribalyse.$co2_step / product.environmental_score_data.agribalyse.co2_total) FILTER format('%.1f'); %] %", + "percent": [% (100 * product.environmental_score_data.agribalyse.$co2_step / product.environmental_score_data.agribalyse.co2_total) %] } ], }, diff --git a/templates/api/knowledge-panels/environment/ecoscore/production_system.tt.json b/templates/api/knowledge-panels/environment/ecoscore/production_system.tt.json deleted file mode 100644 index e5f692c31e007..0000000000000 --- a/templates/api/knowledge-panels/environment/ecoscore/production_system.tt.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "level" :"info", - "topics": [ - "environment" - ], - [% IF product.ecoscore_data.adjustments.production_system.value == 0 %] - "evaluation": "neutral", - "title_element": { - "title": "[% edq(lang('ecoscore_production_system_no_labels_with_environmental_benefits')) %]", - "icon_color_from_evaluation": true, - "icon_url": "[% static_subdomain %]/images/icons/dist/agriculture.svg", - "icon_size": "small", - }, - [% ELSE %] - "evaluation": "good", - "title_element": { - "icon_color_from_evaluation": true, - "icon_url": "[% static_subdomain %]/images/icons/dist/agriculture.svg", - "icon_size": "small", - "subtitle": "[% edq(lang('bonus')) %][% sep %]: +[% product.ecoscore_data.adjustments.production_system.value %]", - [% IF product.ecoscore_data.adjustments.production_system.value >= 20 %] - "title": "[% edq(lang('ecoscore_production_system_labels_with_environmental_benefits_very_high')) %]", - [% ELSIF product.ecoscore_data.adjustments.production_system.value >= 15 %] - "title": "[% edq(lang('ecoscore_production_system_labels_with_environmental_benefits_high')) %]", - [% ELSE %] - "title": "[% edq(lang('ecoscore_production_system_labels_with_environmental_benefits')) %]", - [% END %] - }, - "elements": [ - [% FOREACH label IN product.ecoscore_data.adjustments.production_system.labels %] - { - "element_type": "panel", - "panel_element": { - "panel_id": "environment_label_[% label %]", - } - }, - [% END %] - ] - [% END %] -} diff --git a/templates/api/knowledge-panels/environment/environment_card.tt.json b/templates/api/knowledge-panels/environment/environment_card.tt.json index 04d88db8ae01f..a3e9fb77dfab9 100644 --- a/templates/api/knowledge-panels/environment/environment_card.tt.json +++ b/templates/api/knowledge-panels/environment/environment_card.tt.json @@ -11,14 +11,14 @@ { "element_type": "panel", "panel_element": { - "panel_id": "ecoscore", + "panel_id": "environmental_score", }, }, - [% IF panels.ecoscore_extended.defined %] + [% IF panels.environmental_score_extended.defined %] { "element_type": "panel", "panel_element": { - "panel_id": "ecoscore_extended", + "panel_id": "environmental_score_extended", }, }, [% END %] @@ -35,7 +35,7 @@ { "element_type": "panel_group", "panel_group_element": { - "title": "[% edq(lang('ecoscore_packaging')) %]", + "title": "[% edq(lang('environmental_score_packaging')) %]", "panel_group_id": "packaging_recycling", "panel_ids": [ "packaging_recycling", @@ -50,7 +50,7 @@ { "element_type": "panel_group", "panel_group_element": { - "title": "[% edq(lang('ecoscore_transportation')) %]", + "title": "[% edq(lang('environmental_score_transportation')) %]", "panel_ids": [ [% IF panels.manufacturing_place.defined %]"manufacturing_place",[% END %] [% IF panels.origins_of_ingredients.defined %]"origins_of_ingredients",[% END %] @@ -62,20 +62,20 @@ { "element_type": "panel_group", "panel_group_element": { - "title": "[% edq(lang('ecoscore_threatened_species')) %]", + "title": "[% edq(lang('environmental_score_threatened_species')) %]", "panel_ids": [ "palm_oil" ], }, }, [% END %] - [% IF product.ecoscore_data.adjustments.production_system.value.defined AND product.ecoscore_data.adjustments.production_system.value != 0 %] + [% IF product.environmental_score_data.adjustments.production_system.value.defined AND product.environmental_score_data.adjustments.production_system.value != 0 %] { "element_type": "panel_group", "panel_group_element": { "title": "[% edq(lang('labels_p')) FILTER ucfirst %]", "panel_ids": [ - [% FOREACH label IN product.ecoscore_data.adjustments.production_system.labels %] + [% FOREACH label IN product.environmental_score_data.adjustments.production_system.labels %] "environment_label_[% label %]", [% END %] ], diff --git a/templates/api/knowledge-panels/environment/ecoscore/agribalyse.tt.json b/templates/api/knowledge-panels/environment/environmental_score/agribalyse.tt.json similarity index 60% rename from templates/api/knowledge-panels/environment/ecoscore/agribalyse.tt.json rename to templates/api/knowledge-panels/environment/environmental_score/agribalyse.tt.json index c1cf0e9cdbffe..59dc049aa867f 100644 --- a/templates/api/knowledge-panels/environment/ecoscore/agribalyse.tt.json +++ b/templates/api/knowledge-panels/environment/environmental_score/agribalyse.tt.json @@ -19,16 +19,16 @@ "type": "summary", "html": `[% lang('categories_s') FILTER ucfirst %][% sep %]: - [% panel.agribalyse_category_name %] + [% panel.agribalyse_category_name %]
→ [% lang('ecoscore_learn_more') %]
+→ [% lang('environmental_score_learn_more') %]
` }, }, diff --git a/templates/api/knowledge-panels/environment/ecoscore/ecoscore_extended.tt.json b/templates/api/knowledge-panels/environment/environmental_score/environmental_score_extended.tt.json similarity index 84% rename from templates/api/knowledge-panels/environment/ecoscore/ecoscore_extended.tt.json rename to templates/api/knowledge-panels/environment/environmental_score/environmental_score_extended.tt.json index eec437f3aefac..a60dac6e9a9ae 100644 --- a/templates/api/knowledge-panels/environment/ecoscore/ecoscore_extended.tt.json +++ b/templates/api/knowledge-panels/environment/environmental_score/environmental_score_extended.tt.json @@ -1,4 +1,4 @@ -[% SET climate_change_ratio_to_category = panel.climate_change / panel.ecoscore_extended_data_for_category.climate_change %] +[% SET climate_change_ratio_to_category = panel.climate_change / panel.environmental_score_extended_data_for_category.climate_change %] // "title": "[% edq(f_lang('f_equal_to_driving_km_in_a_petrol_car', { 'kilometers' => driving_100g_rounded } )) %]", @@ -45,12 +45,12 @@Estimated impact for the category ([% display_taxonomy_tag_name("categories",panel.ecoscore_extended_data_for_category.category_id) %]):
+ [% IF panel.environmental_score_extended_data_for_category.defined %] +Estimated impact for the category ([% display_taxonomy_tag_name("categories",panel.environmental_score_extended_data_for_category.category_id) %]):
- [% lang('ecoscore_calculation_details') %] » + [% lang('environmental_score_calculation_details') %] »
-