Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: rename ecoscore/eco-score fields to "environmental score" - ready for review #11117

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 4 additions & 4 deletions cgi/product_jqm_multilingual.pl
Original file line number Diff line number Diff line change
Expand Up @@ -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/;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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));
Expand Down
2 changes: 1 addition & 1 deletion cgi/product_multilingual.pl
Original file line number Diff line number Diff line change
Expand Up @@ -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/;
Expand Down
4 changes: 2 additions & 2 deletions cgi/search.pl
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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
Expand Down
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name still contains Eco_score

File renamed without changes.
75 changes: 65 additions & 10 deletions lib/ProductOpener/API.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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/;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {};
Expand All @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down
89 changes: 53 additions & 36 deletions lib/ProductOpener/Attributes.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -283,7 +283,7 @@ sub initialize_attribute ($attribute_id, $target_lc) {
}
elsif ($attribute_id eq "ecoscore") {
$attribute_ref->{icon_url} = "$static_subdomain/images/attributes/dist/ecoscore-a.svg";
$attribute_ref->{panel_id} = "ecoscore";
$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";
Expand Down Expand Up @@ -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

Expand All @@ -629,43 +633,48 @@ 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

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";

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();

Expand All @@ -690,45 +699,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";
}
# 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->{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->{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");
}
}

Expand Down Expand Up @@ -1651,7 +1668,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

Expand Down Expand Up @@ -1722,8 +1739,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);
}

Expand Down Expand Up @@ -1792,7 +1809,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";
Expand Down
Loading
Loading