diff --git a/lib/ProductOpener/Images.pm b/lib/ProductOpener/Images.pm index ecbc1eeaa137a..bc38c4b5e6eb8 100644 --- a/lib/ProductOpener/Images.pm +++ b/lib/ProductOpener/Images.pm @@ -715,10 +715,6 @@ sub process_image_upload ($product_id, $imagefield, $user_id, $time, $comment, $ $log->debug("process_image_upload", {product_id => $product_id, imagefield => $imagefield}) if $log->is_debug(); - # The product_id can be prefixed by a server (e.g. off:[code]) with a different $www_root - my $product_www_root = www_root_for_product_id($product_id); - my $product_data_root = data_root_for_product_id($product_id); - # debug message passed back to apps in case of an error my $debug = "product_id: $product_id - user_id: $user_id - imagefield: $imagefield"; @@ -770,7 +766,7 @@ sub process_image_upload ($product_id, $imagefield, $user_id, $time, $comment, $ local $log->context->{time} = $time; # Check if we have already received this image before - my $images_ref = retrieve("$product_data_root/products/$path/images.sto"); + my $images_ref = retrieve("$BASE_DIRS{PRODUCTS}/$path/images.sto"); defined $images_ref or $images_ref = {}; my $file_size = -s $file; @@ -806,7 +802,7 @@ sub process_image_upload ($product_id, $imagefield, $user_id, $time, $comment, $ # create them # Create the directories for the product - my $target_image_dir = "$product_www_root/images/products/$path"; + my $target_image_dir = "$BASE_DIRS{PRODUCTS_IMAGES}/$path"; ensure_dir_created_or_die($target_image_dir); my $lock_path = "$target_image_dir/$imgid.lock"; @@ -1054,15 +1050,15 @@ sub process_image_upload ($product_id, $imagefield, $user_id, $time, $comment, $ # Create a link to the image in /new_images so that it can be batch processed by OCR # and computer vision algorithms - (-e "$product_data_root/new_images") or mkdir("$product_data_root/new_images", 0755); + (-e "$BASE_DIRS{PRODUCTS}/new_images") or mkdir("$BASE_DIRS{PRODUCTS}/new_images", 0755); my $code = $product_id; $code =~ s/.*\///; symlink("$target_image_dir/$imgid.jpg", - "$product_data_root/new_images/" . time() . "." . $code . "." . $imagefield . "." . $imgid . ".jpg"); + "$BASE_DIRS{PRODUCTS}/new_images/" . time() . "." . $code . "." . $imagefield . "." . $imgid . ".jpg"); # Save the image file size so that we can skip the image before processing it if it is uploaded again $images_ref->{$size_orig} = $imgid; - store("$product_data_root/products/$path/images.sto", $images_ref); + store("$BASE_DIRS{PRODUCTS}/$path/images.sto", $images_ref); } else { # Could not read image @@ -1289,10 +1285,7 @@ sub process_image_crop ($user_id, $product_id, $id, $imgid, $angle, $normalize, my $new_product_ref = retrieve_product($product_id); my $rev = $new_product_ref->{rev} + 1; # For naming images - # The product_id can be prefixed by a server (e.g. off:[code]) with a different $www_root - my $product_www_root = www_root_for_product_id($product_id); - - my $source_path = "$product_www_root/images/products/$path/$imgid.jpg"; + my $source_path = "$BASE_DIRS{PRODUCTS_IMAGES}/$path/$imgid.jpg"; local $log->context->{code} = $code; local $log->context->{product_id} = $product_id; @@ -1407,7 +1400,7 @@ sub process_image_crop ($user_id, $product_id, $id, $imgid, $angle, $normalize, $background->Resize(geometry => "${w}x${h}!"); - my $bg_path = "$product_www_root/images/products/$path/$imgid.${crop_size}.background.jpg"; + my $bg_path = "$BASE_DIRS{PRODUCTS_IMAGES}/$path/$imgid.${crop_size}.background.jpg"; $log->debug("writing background image to file", {width => $background->Get('width'), path => $bg_path}) if $log->is_debug(); $imagemagick_error = $background->Write("jpeg:${bg_path}"); @@ -1582,7 +1575,7 @@ sub process_image_crop ($user_id, $product_id, $id, $imgid, $angle, $normalize, $filename = $id . "." . $rev; _set_magickal_options($source, undef); - my $full_path = "$product_www_root/images/products/$path/$filename.full.jpg"; + my $full_path = "$BASE_DIRS{PRODUCTS_IMAGES}/$path/$filename.full.jpg"; local $log->context->{full_path} = $full_path; $imagemagick_error = $source->Write("jpeg:${full_path}"); ($imagemagick_error) @@ -1603,7 +1596,7 @@ sub process_image_crop ($user_id, $product_id, $id, $imgid, $angle, $normalize, $log->trace("performing adaptive threshold") if $log->is_trace(); $img2->AdaptiveThreshold(width => $window, height => $window); - $img2->Write("jpeg:$product_www_root/images/products/$path/$filename.full.lat.jpg"); + $img2->Write("jpeg:$BASE_DIRS{PRODUCTS_IMAGES}/$path/$filename.full.lat.jpg"); } $log->debug("generating resized versions") if $log->is_debug(); @@ -1634,7 +1627,7 @@ sub process_image_crop ($user_id, $product_id, $id, $imgid, $angle, $normalize, ); _set_magickal_options($img, $w); - my $final_path = "$product_www_root/images/products/$path/$filename.$max.jpg"; + my $final_path = "$BASE_DIRS{PRODUCTS_IMAGES}/$path/$filename.$max.jpg"; my $imagemagick_error = $img->Write("jpeg:${final_path}"); if (($imagemagick_error) and ($imagemagick_error =~ /(\d+)/) and ($1 >= 400)) { # ImageMagick returns a string starting with a number greater than 400 for errors diff --git a/lib/ProductOpener/Products.pm b/lib/ProductOpener/Products.pm index 140d113dd7953..763e9a5edd8c4 100644 --- a/lib/ProductOpener/Products.pm +++ b/lib/ProductOpener/Products.pm @@ -70,15 +70,12 @@ BEGIN { &normalize_code_with_gs1_ai &assign_new_code &product_id_for_owner - &server_for_product_id - &data_root_for_product_id - &www_root_for_product_id + &server_for_product_type &split_code &product_path &product_path_from_id &product_id_from_path &product_exists - &product_exists_on_other_server &get_owner_id &init_product &retrieve_product @@ -452,9 +449,7 @@ Example: 1234567890123 :- 123/456/789/0123 =cut -# We temporarily keep the old split_code() so that during the migration, -# we can check if the old path exists (in which case we use it) and if not, we use the new path. -sub old_split_code ($code) { +sub split_code ($code) { # Require at least 4 digits (some stores use very short internal barcodes, they are likely to be conflicting) if (not is_valid_code($code)) { @@ -463,37 +458,8 @@ sub old_split_code ($code) { return "invalid"; } - # First splits into 3 sections of 3 numbers and the last section with the remaining numbers - my $path = $code; - # Remove leading 0s that were added to normalize the code + # Remove leading zeroes $code =~ s/^0+//; - if ($code =~ /^(.{3})(.{3})(.{3})(.*)$/) { - $path = "$1/$2/$3/$4"; - } - return $path; -} - -sub split_code ($code) { - - # TODO: remove old_split_code() once all products have been migrated to the new path - my $old_path = old_split_code($code); - # If the old path exists, the product has not been migrated yet, so we use the old path - # Note: this does not work on the pro platform, as we are missing the org-id component of the path. - if (-e "$BASE_DIRS{PRODUCTS}/$old_path/product.sto") { - $log->debug("old_split_code path exists, using old path", {code => $code, old_path => $old_path}) - if $log->is_debug(); - return $old_path; - } - else { - $log->debug("old_split_code path does not exist", {code => $code, old_path => $old_path}) if $log->is_debug(); - } - - # Require at least 4 digits (some stores use very short internal barcodes, they are likely to be conflicting) - if (not is_valid_code($code)) { - - $log->info("invalid code", {code => $code}) if $log->is_info(); - return "invalid"; - } # Pad code with 0s if it has less than 13 digits if (length($code) < 13) { @@ -517,10 +483,6 @@ If the products on the server are public, the product id is equal to the product If the products on the server are private (e.g. on the platform for producers), the product_id is of the form user-[user id]/[code] or org-[organization id]/code. -The product id can be prefixed by a server id to indicate that is is on another server -(e.g. Open Food Facts, Open Beauty Facts, Open Products Facts or Open Pet Food Facts) -e.g. off:[code] - =head3 Parameters =head4 Owner id @@ -556,15 +518,13 @@ sub product_id_for_owner ($ownerid, $code) { } } -=head2 server_for_product_id ( $product_id ) +=head2 server_for_product_type ( $product_type ) Returns the server for the product, if it is not on the current server. =head3 Parameters -=head4 $product_id - -Product id of the form [code], [owner-id]/[code], or [server-id]:[code] or [server-id]:[owner-id]/[code] +=head4 $product_type =head3 Return values @@ -572,78 +532,16 @@ undef is the product is on the current server, or server id of the server of the =cut -sub server_for_product_id ($product_id) { - - if ($product_id =~ /:/) { +sub server_for_product_type ($product_type) { - my $server = $`; + if ((defined $product_type) and ($product_type ne $options{product_type})) { - return $server; + return $options{product_types_flavors}{$product_type}; } return; } -=head2 data_root_for_product_id ( $product_id ) - -Returns the data root for the product, possibly on another server. - -=head3 Parameters - -=head4 $product_id - -Product id of the form [code], [owner-id]/[code], or [server-id]:[code] - -=head3 Return values - -The data root for the product. - -=cut - -sub data_root_for_product_id ($product_id) { - - if ($product_id =~ /:/) { - - my $server = $`; - - if ((defined $options{other_servers}) and (defined $options{other_servers}{$server})) { - return $options{other_servers}{$server}{data_root}; - } - } - - return $data_root; -} - -=head2 www_root_for_product_id ( $product_id ) - -Returns the www root for the product, possibly on another server. - -=head3 Parameters - -=head4 $product_id - -Product id of the form [code], [owner-id]/[code], or [server-id]:[code] - -=head3 Return values - -The www root for the product. - -=cut - -sub www_root_for_product_id ($product_id) { - - if ($product_id =~ /:/) { - - my $server = $`; - - if ((defined $options{other_servers}) and (defined $options{other_servers}{$server})) { - return $options{other_servers}{$server}{www_root}; - } - } - - return $www_root; -} - =head2 product_path_from_id ( $product_id ) Returns the relative path for the product. @@ -652,7 +550,7 @@ Returns the relative path for the product. =head4 $product_id -Product id of the form [code], [owner-id]/[code], or [server-id]:[code] +Product id of the form [code], [owner-id]/[code] =head3 Return values @@ -662,17 +560,14 @@ The relative path for the product. sub product_path_from_id ($product_id) { - my $product_id_without_server = $product_id; - $product_id_without_server =~ s/(.*)://; - if ( (defined $server_options{private_products}) and ($server_options{private_products}) - and ($product_id_without_server =~ /\//)) + and ($product_id =~ /\//)) { return $` . "/" . split_code($'); } else { - return split_code($product_id_without_server); + return split_code($product_id); } } @@ -744,35 +639,6 @@ sub product_exists ($product_id) { } } -sub product_exists_on_other_server ($server, $id) { - - if (not((defined $options{other_servers}) and (defined $options{other_servers}{$server}))) { - return 0; - } - - my $server_data_root = $options{other_servers}{$server}{data_root}; - - my $path = product_path_from_id($id); - - $log->debug("product_exists_on_other_server", - {id => $id, server => $server, server_data_root => $server_data_root, path => $path}) - if $log->is_debug(); - - if (-e "$server_data_root/products/$path") { - - my $product_ref = retrieve("$server_data_root/products/$path/product.sto"); - if ((not defined $product_ref) or ($product_ref->{deleted})) { - return 0; - } - else { - return $product_ref; - } - } - else { - return 0; - } -} - sub get_owner_id ($userid, $orgid, $ownerid) { if ((defined $server_options{private_products}) and ($server_options{private_products})) { @@ -932,27 +798,21 @@ sub init_product ($userid, $orgid, $code, $countryid) { sub retrieve_product ($product_id, $include_deleted = 0) { my $path = product_path_from_id($product_id); - my $product_data_root = data_root_for_product_id($product_id); - my $full_product_path = "$product_data_root/products/$path/product.sto"; + my $full_product_path = "$BASE_DIRS{PRODUCTS}/$path/product.sto"; $log->debug( "retrieve_product", { product_id => $product_id, - product_data_root => $product_data_root, - path => $path, full_product_path => $full_product_path } ) if $log->is_debug(); my $product_ref = retrieve($full_product_path); - my $server = server_for_product_id($product_id); - if (not defined $product_ref) { - $log->debug("retrieve_product - product does not exist", - {product_id => $product_id, product_data_root => $product_data_root, path => $path, server => $server}) + $log->debug("retrieve_product - product does not exist", {product_id => $product_id, path => $path}) if $log->is_debug(); } else { @@ -961,9 +821,7 @@ sub retrieve_product ($product_id, $include_deleted = 0) { "retrieve_product - deleted product", { product_id => $product_id, - product_data_root => $product_data_root, path => $path, - server => $server } ) if $log->is_debug(); return; @@ -971,13 +829,14 @@ sub retrieve_product ($product_id, $include_deleted = 0) { # If the product is on another server, set the server field so that it will be saved in the other server if we save it + my $server = server_for_product_type($product_ref->{product_type}); + if (defined $server) { $product_ref->{server} = $server; $log->debug( "retrieve_product - product on another server", { product_id => $product_id, - product_data_root => $product_data_root, path => $path, server => $server } @@ -999,9 +858,8 @@ sub retrieve_product_rev ($product_id, $rev, $include_deleted = 0) { } my $path = product_path_from_id($product_id); - my $product_data_root = data_root_for_product_id($product_id); - my $product_ref = retrieve("$product_data_root/products/$path/$rev.sto"); + my $product_ref = retrieve("$BASE_DIRS{PRODUCTS}/$path/$rev.sto"); if (defined $product_ref) { @@ -1010,7 +868,7 @@ sub retrieve_product_rev ($product_id, $rev, $include_deleted = 0) { } # If the product is on another server, set the server field so that it will be saved in the other server if we save it - my $server = server_for_product_id($product_id); + my $server = server_for_product_type($product_ref->{product_type}); if (defined $server) { $product_ref->{server} = $server; } @@ -1053,7 +911,7 @@ sub change_product_code ($product_ref, $new_code) { } else { # check that the new code is available - if (-e "$data_root/products/" . product_path_from_id($new_code) . "/product.sto") { + if (-e "$BASE_DIRS{PRODUCTS}/" . product_path_from_id($new_code) . "/product.sto") { $log->warn("cannot change product code, because the new code already exists", {code => $code, new_code => $new_code}) if $log->is_warn(); @@ -1211,14 +1069,11 @@ sub store_product ($user_id, $product_ref, $comment) { my $new_server = $product_ref->{server}; # Update the product_type from the server if (defined $options{flavors_product_types}{$new_server}) { - my $errors_ref = []; - change_product_type($product_ref, $options{flavors_product_types}{$new_server}, $errors_ref); + my $error = change_product_type($product_ref, $options{flavors_product_types}{$new_server}); # Log if we have an error - if (scalar(@{$errors_ref}) > 0) { - $log->error( - "store_product - change_product_type - errors", - {errors => $errors_ref, product_ref => $product_ref} - ); + if ($error) { + $log->error("store_product - change_product_type - error", + {error => $error, product_ref => $product_ref}); } } delete $product_ref->{server}; @@ -1299,22 +1154,18 @@ sub store_product ($user_id, $product_ref, $comment) { my $prefix_path = $path; $prefix_path =~ s/\/[^\/]+$//; # remove the last subdir: we'll move it - if ($path eq $prefix_path) { - # short barcodes with no prefix - $prefix_path = ''; - } $log->debug("creating product directories", {path => $path, prefix_path => $prefix_path}) if $log->is_debug(); # Create the directories for the product - ensure_dir_created_or_die("$data_root/products/$prefix_path"); - ensure_dir_created_or_die("$www_root/images/products/$prefix_path"); + ensure_dir_created_or_die("$BASE_DIRS{PRODUCTS}/$prefix_path"); + ensure_dir_created_or_die("$BASE_DIRS{PRODUCTS_IMAGES}/$prefix_path"); # Check if we are updating the product in place: # the code changed, but it is the same path # this can happen if the path is already normalized, but the code is not # in that case we just want to update the code, and remove the old one from MongoDB # we don't need to move the directories - if ("$BASE_DIRS{PRODUCTS}/$old_path" eq "$data_root/products/$path") { + if ("$BASE_DIRS{PRODUCTS}/$old_path" eq "$BASE_DIRS{PRODUCTS}/$path") { $log->debug("updating product code in place", {old_code => $old_code, code => $code}) if $log->is_debug(); delete $product_ref->{old_code}; # remove the old product from the previous collection @@ -1328,8 +1179,8 @@ sub store_product ($user_id, $product_ref, $comment) { $product_ref->{_id} = $product_ref->{code} . ''; # treat id as string; } - if ( (!-e "$data_root/products/$path") - and (!-e "$www_root/images/products/$path")) + if ( (!-e "$BASE_DIRS{PRODUCTS}/$path") + and (!-e "$BASE_DIRS{PRODUCTS_IMAGES}/$path")) { # File::Copy move() is intended to move files, not # directories. It does work on directories if the @@ -1348,7 +1199,7 @@ sub store_product ($user_id, $product_ref, $comment) { $log->debug("moving product data", {source => "$BASE_DIRS{PRODUCTS}/$old_path", destination => "$BASE_DIRS{PRODUCTS}/$path"}) if $log->is_debug(); - dirmove("$BASE_DIRS{PRODUCTS}/$old_path", "$data_root/products/$path") + dirmove("$BASE_DIRS{PRODUCTS}/$old_path", "$BASE_DIRS{PRODUCTS}/$path") or $log->error( "could not move product data", { @@ -1362,15 +1213,15 @@ sub store_product ($user_id, $product_ref, $comment) { "moving product images", { source => "$BASE_DIRS{PRODUCTS_IMAGES}/$old_path", - destination => "$www_root/images/products/$path" + destination => "$BASE_DIRS{PRODUCTS_IMAGES}/$path" } ) if $log->is_debug(); - dirmove("$BASE_DIRS{PRODUCTS_IMAGES}/$old_path", "$www_root/images/products/$path") + dirmove("$BASE_DIRS{PRODUCTS_IMAGES}/$old_path", "$BASE_DIRS{PRODUCTS_IMAGES}/$path") or $log->error( "could not move product images", { source => "$BASE_DIRS{PRODUCTS_IMAGES}/$old_path", - destination => "$www_root/images/products/$path", + destination => "$BASE_DIRS{PRODUCTS_IMAGES}/$path", error => $! } ); @@ -1388,15 +1239,15 @@ sub store_product ($user_id, $product_ref, $comment) { } else { - (-e "$data_root/products/$path") + (-e "$BASE_DIRS{PRODUCTS}/$path") and $log->error("cannot move product data, because the destination already exists", {source => "$BASE_DIRS{PRODUCTS}/$old_path", destination => "$BASE_DIRS{PRODUCTS}/$path"}); - (-e "$www_root/products/$path") + (-e "$BASE_DIRS{PRODUCTS_IMAGES}/$path") and $log->error( "cannot move product images data, because the destination already exists", { source => "$BASE_DIRS{PRODUCTS_IMAGES}/$old_path", - destination => "$www_root/images/products/$path" + destination => "$BASE_DIRS{PRODUCTS_IMAGES}/$path" } ); } @@ -1406,12 +1257,12 @@ sub store_product ($user_id, $product_ref, $comment) { if ($rev < 1) { # Create the directories for the product - ensure_dir_created_or_die("$data_root/products/$path"); - ensure_dir_created_or_die("$www_root/images/products/$path"); + ensure_dir_created_or_die("$BASE_DIRS{PRODUCTS}/$path"); + ensure_dir_created_or_die("$BASE_DIRS{PRODUCTS_IMAGES}/$path"); } # Check lock and previous version - my $changes_ref = retrieve("$data_root/products/$path/changes.sto"); + my $changes_ref = retrieve("$BASE_DIRS{PRODUCTS}/$path/changes.sto"); if (not defined $changes_ref) { $changes_ref = []; } @@ -1532,7 +1383,7 @@ sub store_product ($user_id, $product_ref, $comment) { } # First store the product data in a .sto file on disk - store("$data_root/products/$path/$rev.sto", $product_ref); + store("$BASE_DIRS{PRODUCTS}/$path/$rev.sto", $product_ref); # Also store the product in MongoDB, unless it was marked as deleted if ($product_ref->{deleted}) { @@ -1548,16 +1399,16 @@ sub store_product ($user_id, $product_ref, $comment) { } # Update link - my $link = "$data_root/products/$path/product.sto"; + my $link = "$BASE_DIRS{PRODUCTS}/$path/product.sto"; if (-l $link) { unlink($link) or $log->error("could not unlink old product.sto", {link => $link, error => $!}); } symlink("$rev.sto", $link) or $log->error("could not symlink to new revision", - {source => "$data_root/products/$path/$rev.sto", link => $link, error => $!}); + {source => "$BASE_DIRS{PRODUCTS}/$path/$rev.sto", link => $link, error => $!}); - store("$data_root/products/$path/changes.sto", $changes_ref); + store("$BASE_DIRS{PRODUCTS}/$path/changes.sto", $changes_ref); log_change($product_ref, $change_ref); $log->debug("store_product - done", {code => $code, product_id => $product_id}) if $log->is_debug(); @@ -2306,7 +2157,7 @@ sub compute_product_history_and_completeness ($current_product_ref, $changes_ref if (not defined $rev) { $rev = $revs; # was not set before June 2012 } - my $product_ref = retrieve("$data_root/products/$path/$rev.sto"); + my $product_ref = retrieve("$BASE_DIRS{PRODUCTS}/$path/$rev.sto"); # if not found, we may be be updating the product, with the latest rev not set yet if ((not defined $product_ref) or ($rev == $current_product_ref->{rev})) { diff --git a/tests/integration/api_v3_product_read.t b/tests/integration/api_v3_product_read.t index bd915a30546d5..1140f1ef12ec1 100644 --- a/tests/integration/api_v3_product_read.t +++ b/tests/integration/api_v3_product_read.t @@ -59,6 +59,12 @@ my $tests_ref = [ path => '/api/v3/product/4260392550101', expected_status_code => 200, }, + { + test_case => 'get-existing-product-with-leading-zero', + method => 'GET', + path => '/api/v3/product/04260392550101', + expected_status_code => 200, + }, { test_case => 'get-existing-product-gs1-caret', method => 'GET', diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-ai-data-str.json b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-ai-data-str.json index e4d9026fee348..5d9f208e2d6b2 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-ai-data-str.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-ai-data-str.json @@ -106,7 +106,7 @@ "origins_of_ingredients" : { "aggregated_origins" : [ { - "epi_score" : 0, + "epi_score" : "0", "origin" : "en:unknown", "percent" : 100, "transportation_score" : 0 diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-fnc1.json b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-fnc1.json index e4d9026fee348..5d9f208e2d6b2 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-fnc1.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-fnc1.json @@ -106,7 +106,7 @@ "origins_of_ingredients" : { "aggregated_origins" : [ { - "epi_score" : 0, + "epi_score" : "0", "origin" : "en:unknown", "percent" : 100, "transportation_score" : 0 diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-gs.json b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-gs.json index 5d9f208e2d6b2..e4d9026fee348 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-gs.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-gs1-gs.json @@ -106,7 +106,7 @@ "origins_of_ingredients" : { "aggregated_origins" : [ { - "epi_score" : "0", + "epi_score" : 0, "origin" : "en:unknown", "percent" : 100, "transportation_score" : 0 diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-with-leading-zero.json b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-with-leading-zero.json new file mode 100644 index 0000000000000..2b506b5c46744 --- /dev/null +++ b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product-with-leading-zero.json @@ -0,0 +1,1175 @@ +{ + "code" : "04260392550101", + "errors" : [], + "product" : { + "_id" : "4260392550101", + "_keywords" : [ + "cookie", + "organic", + "product", + "some", + "tester" + ], + "added_countries_tags" : [], + "additives_n" : 0, + "additives_original_tags" : [], + "additives_tags" : [], + "allergens" : "", + "allergens_from_ingredients" : "en:eggs, en:milk, apple, milk, eggs", + "allergens_from_user" : "(en) ", + "allergens_hierarchy" : [ + "en:apple", + "en:eggs", + "en:milk" + ], + "allergens_tags" : [ + "en:apple", + "en:eggs", + "en:milk" + ], + "amino_acids_tags" : [], + "categories" : "cookies", + "categories_hierarchy" : [ + "en:snacks", + "en:sweet-snacks", + "en:biscuits-and-cakes", + "en:biscuits-and-crackers", + "en:biscuits" + ], + "categories_lc" : "en", + "categories_properties" : { + "agribalyse_proxy_food_code:en" : "24000" + }, + "categories_properties_tags" : [ + "all-products", + "categories-known", + "agribalyse-food-code-unknown", + "agribalyse-proxy-food-code-24000", + "agribalyse-proxy-food-code-known", + "ciqual-food-code-unknown", + "agribalyse-known", + "agribalyse-24000" + ], + "categories_tags" : [ + "en:snacks", + "en:sweet-snacks", + "en:biscuits-and-cakes", + "en:biscuits-and-crackers", + "en:biscuits" + ], + "checkers_tags" : [], + "code" : "4260392550101", + "codes_tags" : [ + "code-13", + "4260392550xxx", + "426039255xxxx", + "42603925xxxxx", + "4260392xxxxxx", + "426039xxxxxxx", + "42603xxxxxxxx", + "4260xxxxxxxxx", + "426xxxxxxxxxx", + "42xxxxxxxxxxx", + "4xxxxxxxxxxxx" + ], + "complete" : 0, + "completeness" : 0.5, + "correctors_tags" : [], + "created_t" : "--ignore--", + "creator" : "tests", + "data_quality_bugs_tags" : [], + "data_quality_errors_tags" : [], + "data_quality_info_tags" : [ + "en:packaging-data-incomplete", + "en:ingredients-percent-analysis-ok", + "en:ecoscore-extended-data-not-computed", + "en:food-groups-1-known", + "en:food-groups-2-known", + "en:food-groups-3-unknown" + ], + "data_quality_tags" : [ + "en:packaging-data-incomplete", + "en:ingredients-percent-analysis-ok", + "en:ecoscore-extended-data-not-computed", + "en:food-groups-1-known", + "en:food-groups-2-known", + "en:food-groups-3-unknown", + "en:ecoscore-origins-of-ingredients-origins-are-100-percent-unknown", + "en:ecoscore-production-system-no-label" + ], + "data_quality_warnings_tags" : [ + "en:ecoscore-origins-of-ingredients-origins-are-100-percent-unknown", + "en:ecoscore-production-system-no-label" + ], + "ecoscore_data" : { + "adjustments" : { + "origins_of_ingredients" : { + "aggregated_origins" : [ + { + "epi_score" : "0", + "origin" : "en:unknown", + "percent" : 100, + "transportation_score" : 0 + } + ], + "epi_score" : 0, + "epi_value" : -5, + "origins_from_categories" : [ + "en:unknown" + ], + "origins_from_origins_field" : [ + "en:unknown" + ], + "transportation_score" : 0, + "transportation_scores" : { + "ad" : 0, + "al" : 0, + "at" : 0, + "ax" : 0, + "ba" : 0, + "be" : 0, + "bg" : 0, + "ch" : 0, + "cy" : 0, + "cz" : 0, + "de" : 0, + "dk" : 0, + "dz" : 0, + "ee" : 0, + "eg" : 0, + "es" : 0, + "fi" : 0, + "fo" : 0, + "fr" : 0, + "gg" : 0, + "gi" : 0, + "gr" : 0, + "hr" : 0, + "hu" : 0, + "ie" : 0, + "il" : 0, + "im" : 0, + "is" : 0, + "it" : 0, + "je" : 0, + "lb" : 0, + "li" : 0, + "lt" : 0, + "lu" : 0, + "lv" : 0, + "ly" : 0, + "ma" : 0, + "mc" : 0, + "md" : 0, + "me" : 0, + "mk" : 0, + "mt" : 0, + "nl" : 0, + "no" : 0, + "pl" : 0, + "ps" : 0, + "pt" : 0, + "ro" : 0, + "rs" : 0, + "se" : 0, + "si" : 0, + "sj" : 0, + "sk" : 0, + "sm" : 0, + "sy" : 0, + "tn" : 0, + "tr" : 0, + "ua" : 0, + "uk" : 0, + "us" : 0, + "va" : 0, + "world" : 0, + "xk" : 0 + }, + "transportation_value" : 0, + "transportation_values" : { + "ad" : 0, + "al" : 0, + "at" : 0, + "ax" : 0, + "ba" : 0, + "be" : 0, + "bg" : 0, + "ch" : 0, + "cy" : 0, + "cz" : 0, + "de" : 0, + "dk" : 0, + "dz" : 0, + "ee" : 0, + "eg" : 0, + "es" : 0, + "fi" : 0, + "fo" : 0, + "fr" : 0, + "gg" : 0, + "gi" : 0, + "gr" : 0, + "hr" : 0, + "hu" : 0, + "ie" : 0, + "il" : 0, + "im" : 0, + "is" : 0, + "it" : 0, + "je" : 0, + "lb" : 0, + "li" : 0, + "lt" : 0, + "lu" : 0, + "lv" : 0, + "ly" : 0, + "ma" : 0, + "mc" : 0, + "md" : 0, + "me" : 0, + "mk" : 0, + "mt" : 0, + "nl" : 0, + "no" : 0, + "pl" : 0, + "ps" : 0, + "pt" : 0, + "ro" : 0, + "rs" : 0, + "se" : 0, + "si" : 0, + "sj" : 0, + "sk" : 0, + "sm" : 0, + "sy" : 0, + "tn" : 0, + "tr" : 0, + "ua" : 0, + "uk" : 0, + "us" : 0, + "va" : 0, + "world" : 0, + "xk" : 0 + }, + "value" : -5, + "values" : { + "ad" : -5, + "al" : -5, + "at" : -5, + "ax" : -5, + "ba" : -5, + "be" : -5, + "bg" : -5, + "ch" : -5, + "cy" : -5, + "cz" : -5, + "de" : -5, + "dk" : -5, + "dz" : -5, + "ee" : -5, + "eg" : -5, + "es" : -5, + "fi" : -5, + "fo" : -5, + "fr" : -5, + "gg" : -5, + "gi" : -5, + "gr" : -5, + "hr" : -5, + "hu" : -5, + "ie" : -5, + "il" : -5, + "im" : -5, + "is" : -5, + "it" : -5, + "je" : -5, + "lb" : -5, + "li" : -5, + "lt" : -5, + "lu" : -5, + "lv" : -5, + "ly" : -5, + "ma" : -5, + "mc" : -5, + "md" : -5, + "me" : -5, + "mk" : -5, + "mt" : -5, + "nl" : -5, + "no" : -5, + "pl" : -5, + "ps" : -5, + "pt" : -5, + "ro" : -5, + "rs" : -5, + "se" : -5, + "si" : -5, + "sj" : -5, + "sk" : -5, + "sm" : -5, + "sy" : -5, + "tn" : -5, + "tr" : -5, + "ua" : -5, + "uk" : -5, + "us" : -5, + "va" : -5, + "world" : -5, + "xk" : -5 + }, + "warning" : "origins_are_100_percent_unknown" + }, + "packaging" : { + "non_recyclable_and_non_biodegradable_materials" : 0, + "packagings" : [ + { + "ecoscore_material_score" : 50, + "ecoscore_shape_ratio" : 1, + "material" : "en:wood", + "number_of_units" : 1, + "recycling" : "en:recycle", + "shape" : "en:box" + }, + { + "ecoscore_material_score" : 81, + "ecoscore_shape_ratio" : 1, + "material" : "en:glass", + "number_of_units" : 6, + "quantity_per_unit" : "25cl", + "quantity_per_unit_unit" : "cl", + "quantity_per_unit_value" : 25, + "recycling" : "en:reuse", + "shape" : "en:bottle" + }, + { + "ecoscore_material_score" : 76, + "ecoscore_shape_ratio" : 0.2, + "material" : "en:steel", + "number_of_units" : 3, + "recycling" : "en:recycle", + "shape" : "en:lid" + }, + { + "ecoscore_material_score" : 0, + "ecoscore_shape_ratio" : 0.1, + "material" : "en:plastic", + "non_recyclable_and_non_biodegradable" : "maybe", + "number_of_units" : 1, + "recycling" : "en:discard", + "shape" : "en:film" + } + ], + "score" : 16.2, + "value" : -8 + }, + "production_system" : { + "labels" : [], + "value" : 0, + "warning" : "no_label" + }, + "threatened_species" : { + "ingredient" : "en:palm-oil", + "value" : -10 + } + }, + "agribalyse" : { + "agribalyse_proxy_food_code" : "24000", + "co2_agriculture" : 2.3635185, + "co2_consumption" : 0, + "co2_distribution" : 0.019437894, + "co2_packaging" : 0.10986902, + "co2_processing" : 0.22831584, + "co2_total" : 2.856230424, + "co2_transportation" : 0.13508917, + "code" : "24000", + "dqr" : "2.14", + "ef_agriculture" : 0.27654213, + "ef_consumption" : 0, + "ef_distribution" : 0.0047895045, + "ef_packaging" : 0.01090994, + "ef_processing" : 0.04151582, + "ef_total" : 0.3448030585, + "ef_transportation" : 0.011045664, + "is_beverage" : 0, + "name_en" : "Biscuit (cookie)", + "name_fr" : "Biscuit sec, sans précision", + "score" : 70, + "version" : "3.1.1" + }, + "grade" : "c", + "grades" : { + "ad" : "c", + "al" : "c", + "at" : "c", + "ax" : "c", + "ba" : "c", + "be" : "c", + "bg" : "c", + "ch" : "c", + "cy" : "c", + "cz" : "c", + "de" : "c", + "dk" : "c", + "dz" : "c", + "ee" : "c", + "eg" : "c", + "es" : "c", + "fi" : "c", + "fo" : "c", + "fr" : "c", + "gg" : "c", + "gi" : "c", + "gr" : "c", + "hr" : "c", + "hu" : "c", + "ie" : "c", + "il" : "c", + "im" : "c", + "is" : "c", + "it" : "c", + "je" : "c", + "lb" : "c", + "li" : "c", + "lt" : "c", + "lu" : "c", + "lv" : "c", + "ly" : "c", + "ma" : "c", + "mc" : "c", + "md" : "c", + "me" : "c", + "mk" : "c", + "mt" : "c", + "nl" : "c", + "no" : "c", + "pl" : "c", + "ps" : "c", + "pt" : "c", + "ro" : "c", + "rs" : "c", + "se" : "c", + "si" : "c", + "sj" : "c", + "sk" : "c", + "sm" : "c", + "sy" : "c", + "tn" : "c", + "tr" : "c", + "ua" : "c", + "uk" : "c", + "us" : "c", + "va" : "c", + "world" : "c", + "xk" : "c" + }, + "missing" : { + "labels" : 1, + "origins" : 1 + }, + "missing_data_warning" : 1, + "score" : 47, + "scores" : { + "ad" : 47, + "al" : 47, + "at" : 47, + "ax" : 47, + "ba" : 47, + "be" : 47, + "bg" : 47, + "ch" : 47, + "cy" : 47, + "cz" : 47, + "de" : 47, + "dk" : 47, + "dz" : 47, + "ee" : 47, + "eg" : 47, + "es" : 47, + "fi" : 47, + "fo" : 47, + "fr" : 47, + "gg" : 47, + "gi" : 47, + "gr" : 47, + "hr" : 47, + "hu" : 47, + "ie" : 47, + "il" : 47, + "im" : 47, + "is" : 47, + "it" : 47, + "je" : 47, + "lb" : 47, + "li" : 47, + "lt" : 47, + "lu" : 47, + "lv" : 47, + "ly" : 47, + "ma" : 47, + "mc" : 47, + "md" : 47, + "me" : 47, + "mk" : 47, + "mt" : 47, + "nl" : 47, + "no" : 47, + "pl" : 47, + "ps" : 47, + "pt" : 47, + "ro" : 47, + "rs" : 47, + "se" : 47, + "si" : 47, + "sj" : 47, + "sk" : 47, + "sm" : 47, + "sy" : 47, + "tn" : 47, + "tr" : 47, + "ua" : 47, + "uk" : 47, + "us" : 47, + "va" : 47, + "world" : 47, + "xk" : 47 + }, + "status" : "known" + }, + "ecoscore_grade" : "c", + "ecoscore_score" : 47, + "ecoscore_tags" : [ + "c" + ], + "editors_tags" : [ + "tests" + ], + "entry_dates_tags" : "--ignore--", + "food_groups" : "en:biscuits-and-cakes", + "food_groups_tags" : [ + "en:sugary-snacks", + "en:biscuits-and-cakes" + ], + "forest_footprint_data" : { + "footprint_per_kg" : 0.00145833333333333, + "grade" : "a", + "ingredients" : [ + { + "conditions_tags" : [ + [ + "labels", + "en:organic" + ] + ], + "footprint_per_kg" : 0.00145833333333333, + "matching_tag_id" : "en:egg", + "percent" : 9.375, + "percent_estimate" : 9.375, + "processing_factor" : 1, + "tag_id" : "en:egg", + "tag_type" : "ingredients", + "type" : { + "deforestation_risk" : 0.1, + "name" : "Oeufs Bio", + "soy_feed_factor" : 0.028, + "soy_yield" : 0.18 + } + } + ] + }, + "generic_name" : "Tester", + "generic_name_en" : "Tester", + "id" : "4260392550101", + "informers_tags" : [ + "tests" + ], + "ingredients" : [ + { + "ciqual_food_code" : "13050", + "ecobalyse_code" : "apple-fr", + "id" : "en:apple", + "is_in_taxonomy" : 1, + "percent_estimate" : 62.5, + "percent_max" : 100, + "percent_min" : 25, + "text" : "apple", + "vegan" : "yes", + "vegetarian" : "yes" + }, + { + "ciqual_proxy_food_code" : "19051", + "ecobalyse_code" : "milk", + "id" : "en:milk", + "is_in_taxonomy" : 1, + "percent_estimate" : 18.75, + "percent_max" : 50, + "percent_min" : 0, + "text" : "milk", + "vegan" : "no", + "vegetarian" : "yes" + }, + { + "ciqual_food_code" : "22000", + "ecobalyse_code" : "egg-indoor-code3", + "id" : "en:egg", + "is_in_taxonomy" : 1, + "percent_estimate" : 9.375, + "percent_max" : 33.3333333333333, + "percent_min" : 0, + "text" : "eggs", + "vegan" : "no", + "vegetarian" : "yes" + }, + { + "ciqual_food_code" : "16129", + "ecobalyse_code" : "refined-palm-oil", + "from_palm_oil" : "yes", + "id" : "en:palm-oil", + "is_in_taxonomy" : 1, + "percent_estimate" : 9.375, + "percent_max" : 25, + "percent_min" : 0, + "text" : "palm oil", + "vegan" : "yes", + "vegetarian" : "yes" + } + ], + "ingredients_analysis" : { + "en:non-vegan" : [ + "en:milk", + "en:egg" + ], + "en:palm-oil" : [ + "en:palm-oil" + ] + }, + "ingredients_analysis_tags" : [ + "en:palm-oil", + "en:non-vegan", + "en:vegetarian" + ], + "ingredients_hierarchy" : [ + "en:apple", + "en:fruit", + "en:malaceous-fruit", + "en:milk", + "en:dairy", + "en:egg", + "en:palm-oil", + "en:oil-and-fat", + "en:vegetable-oil-and-fat", + "en:palm-oil-and-fat" + ], + "ingredients_lc" : "en", + "ingredients_n" : 4, + "ingredients_n_tags" : [ + "4", + "1-10" + ], + "ingredients_non_nutritive_sweeteners_n" : 0, + "ingredients_original_tags" : [ + "en:apple", + "en:milk", + "en:egg", + "en:palm-oil" + ], + "ingredients_percent_analysis" : 1, + "ingredients_sweeteners_n" : 0, + "ingredients_tags" : [ + "en:apple", + "en:fruit", + "en:malaceous-fruit", + "en:milk", + "en:dairy", + "en:egg", + "en:palm-oil", + "en:oil-and-fat", + "en:vegetable-oil-and-fat", + "en:palm-oil-and-fat" + ], + "ingredients_text" : "apple, milk, eggs, palm oil", + "ingredients_text_en" : "apple, milk, eggs, palm oil", + "ingredients_text_with_allergens" : "apple, milk, eggs, palm oil", + "ingredients_text_with_allergens_en" : "apple, milk, eggs, palm oil", + "ingredients_with_specified_percent_n" : 0, + "ingredients_with_specified_percent_sum" : 0, + "ingredients_with_unspecified_percent_n" : 4, + "ingredients_with_unspecified_percent_sum" : 100, + "ingredients_without_ciqual_codes" : [], + "ingredients_without_ciqual_codes_n" : 0, + "ingredients_without_ecobalyse_ids" : [], + "ingredients_without_ecobalyse_ids_n" : 0, + "interface_version_created" : "20150316.jqm2", + "interface_version_modified" : "20150316.jqm2", + "known_ingredients_n" : 10, + "labels" : "organic", + "labels_hierarchy" : [ + "en:organic" + ], + "labels_lc" : "en", + "labels_tags" : [ + "en:organic" + ], + "lang" : "en", + "languages" : { + "en:english" : 5 + }, + "languages_codes" : { + "en" : 5 + }, + "languages_hierarchy" : [ + "en:english" + ], + "languages_tags" : [ + "en:english", + "en:1" + ], + "last_edit_dates_tags" : "--ignore--", + "last_editor" : "tests", + "last_modified_by" : "tests", + "last_modified_t" : "--ignore--", + "last_updated_t" : "--ignore--", + "lc" : "en", + "link" : "http://world.openfoodfacts.org/", + "main_countries_tags" : [], + "minerals_tags" : [], + "misc_tags" : [ + "en:ecoscore-changed", + "en:ecoscore-computed", + "en:ecoscore-extended-data-not-computed", + "en:ecoscore-grade-changed", + "en:ecoscore-missing-data-labels", + "en:ecoscore-missing-data-origins", + "en:ecoscore-missing-data-warning", + "en:forest-footprint-a", + "en:forest-footprint-computed", + "en:nutriscore-2021-c-2023-c", + "en:nutriscore-2021-same-as-2023", + "en:nutriscore-computed", + "en:nutriscore-missing-nutrition-data", + "en:nutriscore-missing-nutrition-data-energy", + "en:nutriscore-missing-nutrition-data-fat", + "en:nutriscore-missing-nutrition-data-proteins", + "en:nutriscore-missing-nutrition-data-saturated-fat", + "en:nutriscore-missing-nutrition-data-sodium", + "en:nutriscore-missing-nutrition-data-sugars", + "en:nutriscore-using-estimated-nutrition-facts", + "en:nutrition-all-nutriscore-values-known", + "en:nutrition-fruits-vegetables-legumes-estimate-from-ingredients", + "en:nutrition-fruits-vegetables-nuts-estimate-from-ingredients", + "en:nutrition-no-fiber", + "en:nutrition-not-enough-data-to-compute-nutrition-score", + "en:packagings-not-complete", + "en:packagings-not-empty", + "en:packagings-not-empty-but-not-complete", + "en:packagings-number-of-components-4", + "en:main-countries-new-product" + ], + "nova_group" : 3, + "nova_group_debug" : "", + "nova_groups" : "3", + "nova_groups_markers" : { + "3" : [ + [ + "categories", + "en:sweet-snacks" + ] + ] + }, + "nova_groups_tags" : [ + "en:3-processed-foods" + ], + "nucleotides_tags" : [], + "nutrient_levels" : {}, + "nutrient_levels_tags" : [], + "nutriments" : { + "fruits-vegetables-legumes-estimate-from-ingredients_100g" : 62.5, + "fruits-vegetables-legumes-estimate-from-ingredients_serving" : 62.5, + "fruits-vegetables-nuts-estimate-from-ingredients_100g" : 62.5, + "fruits-vegetables-nuts-estimate-from-ingredients_serving" : 62.5, + "nova-group" : 3, + "nova-group_100g" : 3, + "nova-group_serving" : 3, + "nutrition-score-fr" : 3, + "nutrition-score-fr_100g" : 3 + }, + "nutriments_estimated" : { + "alcohol_100g" : 0, + "beta-carotene_100g" : 1.19375e-05, + "calcium_100g" : 0.0333875, + "carbohydrates_100g" : 7.6484375, + "cholesterol_100g" : 0.03778125, + "copper_100g" : 2.678125e-05, + "energy-kcal_100g" : 134.5875, + "energy-kj_100g" : 558.75, + "energy_100g" : 558.75, + "fat_100g" : 10.4134375, + "fiber_100g" : 0.8125, + "fructose_100g" : 3.77578125, + "galactose_100g" : 0, + "glucose_100g" : 2.0565625, + "iodine_100g" : 7.09375e-06, + "iron_100g" : 0.0002265625, + "lactose_100g" : 0.924375, + "magnesium_100g" : 0.00570625, + "maltose_100g" : 0.00703125, + "manganese_100g" : 2.73828125e-05, + "pantothenic-acid_100g" : 0.0002590625, + "phosphorus_100g" : 0.0445625, + "phylloquinone_100g" : 1.153125e-06, + "polyols_100g" : 0.36875, + "potassium_100g" : 0.09825, + "proteins_100g" : 1.974375, + "salt_100g" : 0.0496875, + "saturated-fat_100g" : 4.903125, + "selenium_100g" : 1.2290625e-06, + "sodium_100g" : 0.019725, + "starch_100g" : 0, + "sucrose_100g" : 0.51953125, + "sugars_100g" : 7.2621875, + "vitamin-a_100g" : 1.739625e-05, + "vitamin-b12_100g" : 2.278125e-07, + "vitamin-b1_100g" : 2.509375e-05, + "vitamin-b2_100g" : 9.34375e-05, + "vitamin-b6_100g" : 4.54375e-05, + "vitamin-b9_100g" : 4.10625e-06, + "vitamin-c_100g" : 0.00274375, + "vitamin-d_100g" : 1.903125e-07, + "vitamin-e_100g" : 0.001657625, + "vitamin-pp_100g" : 8.003125e-05, + "water_100g" : 78.365625, + "zinc_100g" : 0.0002046875 + }, + "nutriscore" : { + "2021" : { + "category_available" : 1, + "data" : { + "energy" : 558.75, + "energy_points" : 1, + "energy_value" : 558.8, + "fiber" : 0.8125, + "fiber_points" : 0, + "fiber_value" : 0.81, + "fruits_vegetables_nuts_colza_walnut_olive_oils" : 62.5, + "fruits_vegetables_nuts_colza_walnut_olive_oils_points" : 2, + "fruits_vegetables_nuts_colza_walnut_olive_oils_value" : 62.5, + "is_beverage" : 0, + "is_cheese" : 0, + "is_fat" : 0, + "is_water" : 0, + "negative_points" : 6, + "positive_points" : 3, + "proteins" : 1.974375, + "proteins_points" : 1, + "proteins_value" : 1.97, + "saturated_fat" : 4.903125, + "saturated_fat_points" : 4, + "saturated_fat_value" : 4.9, + "sodium" : 19.725, + "sodium_points" : 0, + "sodium_value" : 19.7, + "sugars" : 7.2621875, + "sugars_points" : 1, + "sugars_value" : 7.26 + }, + "grade" : "c", + "nutrients_available" : 1, + "nutriscore_applicable" : 1, + "nutriscore_computed" : 1, + "score" : 3 + }, + "2023" : { + "category_available" : 1, + "data" : { + "components" : { + "negative" : [ + { + "id" : "energy", + "points" : 1, + "points_max" : 10, + "unit" : "kJ", + "value" : 558.75 + }, + { + "id" : "sugars", + "points" : 2, + "points_max" : 15, + "unit" : "g", + "value" : 7.26 + }, + { + "id" : "saturated_fat", + "points" : 4, + "points_max" : 10, + "unit" : "g", + "value" : 4.9 + }, + { + "id" : "salt", + "points" : 0, + "points_max" : 20, + "unit" : "g", + "value" : 0.05 + } + ], + "positive" : [ + { + "id" : "proteins", + "points" : 0, + "points_max" : 7, + "unit" : "g", + "value" : 1.97 + }, + { + "id" : "fiber", + "points" : 0, + "points_max" : 5, + "unit" : "g", + "value" : 0.81 + }, + { + "id" : "fruits_vegetables_legumes", + "points" : 2, + "points_max" : 5, + "unit" : "%", + "value" : 62.5 + } + ] + }, + "count_proteins" : 1, + "count_proteins_reason" : "negative_points_less_than_11", + "is_beverage" : 0, + "is_cheese" : 0, + "is_fat_oil_nuts_seeds" : 0, + "is_red_meat_product" : 0, + "is_water" : 0, + "negative_points" : 7, + "negative_points_max" : 55, + "positive_nutrients" : [ + "proteins", + "fiber", + "fruits_vegetables_legumes" + ], + "positive_points" : 2, + "positive_points_max" : 17 + }, + "grade" : "c", + "nutrients_available" : 1, + "nutriscore_applicable" : 1, + "nutriscore_computed" : 1, + "score" : 5 + } + }, + "nutriscore_2021_tags" : [ + "c" + ], + "nutriscore_2023_tags" : [ + "c" + ], + "nutriscore_data" : { + "energy" : 558.75, + "energy_points" : 1, + "energy_value" : 558.8, + "fiber" : 0.8125, + "fiber_points" : 0, + "fiber_value" : 0.81, + "fruits_vegetables_nuts_colza_walnut_olive_oils" : 62.5, + "fruits_vegetables_nuts_colza_walnut_olive_oils_points" : 2, + "fruits_vegetables_nuts_colza_walnut_olive_oils_value" : 62.5, + "grade" : "c", + "is_beverage" : 0, + "is_cheese" : 0, + "is_fat" : 0, + "is_water" : 0, + "negative_points" : 6, + "positive_points" : 3, + "proteins" : 1.974375, + "proteins_points" : 1, + "proteins_value" : 1.97, + "saturated_fat" : 4.903125, + "saturated_fat_points" : 4, + "saturated_fat_value" : 4.9, + "score" : 3, + "sodium" : 19.725, + "sodium_points" : 0, + "sodium_value" : 19.7, + "sugars" : 7.2621875, + "sugars_points" : 1, + "sugars_value" : 7.26 + }, + "nutriscore_grade" : "c", + "nutriscore_score" : 3, + "nutriscore_score_opposite" : -3, + "nutriscore_tags" : [ + "c" + ], + "nutriscore_version" : "2021", + "nutrition_data_per" : "100g", + "nutrition_data_prepared_per" : "100g", + "nutrition_grade_fr" : "c", + "nutrition_grades" : "c", + "nutrition_grades_tags" : [ + "c" + ], + "nutrition_score_beverage" : 0, + "nutrition_score_debug" : "missing energy_100g - missing fat_100g - missing saturated-fat_100g - missing sugars_100g - missing sodium_100g - missing proteins_100g", + "nutrition_score_warning_fruits_vegetables_legumes_estimate_from_ingredients" : 1, + "nutrition_score_warning_fruits_vegetables_legumes_estimate_from_ingredients_value" : 62.5, + "nutrition_score_warning_fruits_vegetables_nuts_estimate_from_ingredients" : 1, + "nutrition_score_warning_fruits_vegetables_nuts_estimate_from_ingredients_value" : 62.5, + "nutrition_score_warning_nutriments_estimated" : 1, + "origin" : "france", + "origin_en" : "france", + "other_nutritional_substances_tags" : [], + "packaging_materials_tags" : [ + "en:glass", + "en:plastic", + "en:steel", + "en:wood" + ], + "packaging_recycling_tags" : [ + "en:discard", + "en:recycle", + "en:reuse" + ], + "packaging_shapes_tags" : [ + "en:bottle", + "en:box", + "en:film", + "en:lid" + ], + "packaging_text" : "1 wooden box to recycle, 6 25cl glass bottles to reuse, 3 steel lids to recycle, 1 plastic film to discard", + "packaging_text_en" : "1 wooden box to recycle, 6 25cl glass bottles to reuse, 3 steel lids to recycle, 1 plastic film to discard", + "packagings" : [ + { + "material" : { + "id" : "en:wood" + }, + "number_of_units" : 1, + "recycling" : { + "id" : "en:recycle" + }, + "shape" : { + "id" : "en:box" + } + }, + { + "material" : { + "id" : "en:glass" + }, + "number_of_units" : 6, + "quantity_per_unit" : "25cl", + "quantity_per_unit_unit" : "cl", + "quantity_per_unit_value" : 25, + "recycling" : { + "id" : "en:reuse" + }, + "shape" : { + "id" : "en:bottle" + } + }, + { + "material" : { + "id" : "en:steel" + }, + "number_of_units" : 3, + "recycling" : { + "id" : "en:recycle" + }, + "shape" : { + "id" : "en:lid" + } + }, + { + "material" : { + "id" : "en:plastic" + }, + "number_of_units" : 1, + "recycling" : { + "id" : "en:discard" + }, + "shape" : { + "id" : "en:film" + } + } + ], + "packagings_materials" : { + "all" : {}, + "en:glass" : {}, + "en:metal" : {}, + "en:plastic" : {}, + "en:unknown" : {} + }, + "packagings_n" : 4, + "photographers_tags" : [], + "pnns_groups_1" : "Sugary snacks", + "pnns_groups_1_tags" : [ + "sugary-snacks", + "known" + ], + "pnns_groups_2" : "Biscuits and cakes", + "pnns_groups_2_tags" : [ + "biscuits-and-cakes", + "known" + ], + "popularity_key" : 0, + "product_name" : "Some product", + "product_name_en" : "Some product", + "product_quantity" : "100", + "product_quantity_unit" : "g", + "product_type" : "food", + "quantity" : "100 g", + "removed_countries_tags" : [], + "rev" : 1, + "serving_quantity" : "10", + "serving_quantity_unit" : "g", + "serving_size" : "10 g", + "states" : "en:to-be-completed, en:nutrition-facts-completed, en:ingredients-completed, en:expiration-date-to-be-completed, en:packaging-code-to-be-completed, en:characteristics-to-be-completed, en:origins-to-be-completed, en:categories-completed, en:brands-to-be-completed, en:packaging-to-be-completed, en:quantity-completed, en:product-name-completed, en:photos-to-be-uploaded", + "states_hierarchy" : [ + "en:to-be-completed", + "en:nutrition-facts-completed", + "en:ingredients-completed", + "en:expiration-date-to-be-completed", + "en:packaging-code-to-be-completed", + "en:characteristics-to-be-completed", + "en:origins-to-be-completed", + "en:categories-completed", + "en:brands-to-be-completed", + "en:packaging-to-be-completed", + "en:quantity-completed", + "en:product-name-completed", + "en:photos-to-be-uploaded" + ], + "states_tags" : [ + "en:to-be-completed", + "en:nutrition-facts-completed", + "en:ingredients-completed", + "en:expiration-date-to-be-completed", + "en:packaging-code-to-be-completed", + "en:characteristics-to-be-completed", + "en:origins-to-be-completed", + "en:categories-completed", + "en:brands-to-be-completed", + "en:packaging-to-be-completed", + "en:quantity-completed", + "en:product-name-completed", + "en:photos-to-be-uploaded" + ], + "traces" : "", + "traces_from_ingredients" : "", + "traces_from_user" : "(en) ", + "traces_hierarchy" : [], + "traces_tags" : [], + "unknown_ingredients_n" : 0, + "unknown_nutrients_tags" : [], + "vitamins_tags" : [], + "weighers_tags" : [] + }, + "result" : { + "id" : "product_found", + "lc_name" : "Product found", + "name" : "Product found" + }, + "status" : "success", + "warnings" : [] +} diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product.json b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product.json index 4adbddb8d6ca5..7863697d88b3c 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-existing-product.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-existing-product.json @@ -106,7 +106,7 @@ "origins_of_ingredients" : { "aggregated_origins" : [ { - "epi_score" : 0, + "epi_score" : "0", "origin" : "en:unknown", "percent" : 100, "transportation_score" : 0 diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-fields-all-knowledge-panels.json b/tests/integration/expected_test_results/api_v3_product_read/get-fields-all-knowledge-panels.json index 39b0d6a150c13..c9898fd947d4f 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-fields-all-knowledge-panels.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-fields-all-knowledge-panels.json @@ -106,7 +106,7 @@ "origins_of_ingredients" : { "aggregated_origins" : [ { - "epi_score" : 0, + "epi_score" : "0", "origin" : "en:unknown", "percent" : 100, "transportation_score" : 0 diff --git a/tests/integration/expected_test_results/api_v3_product_read/get-fields-all.json b/tests/integration/expected_test_results/api_v3_product_read/get-fields-all.json index 7863697d88b3c..4adbddb8d6ca5 100644 --- a/tests/integration/expected_test_results/api_v3_product_read/get-fields-all.json +++ b/tests/integration/expected_test_results/api_v3_product_read/get-fields-all.json @@ -106,7 +106,7 @@ "origins_of_ingredients" : { "aggregated_origins" : [ { - "epi_score" : "0", + "epi_score" : 0, "origin" : "en:unknown", "percent" : 100, "transportation_score" : 0