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

feat: allow setting the packagings_complete field through API v3 #7856

Merged
merged 5 commits into from
Dec 19, 2022
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/reference/schemas/packagings/packagings_complete.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
title: packagings_complete
x-stoplight:
id: hxnnsy954q1ey
type: integer
minimum: 0
maximum: 1
description: Indicate if the packagings array contains all the packaging parts of the product. This field can be set by users when they enter or verify packaging data. Possible values are 0 or 1.
2 changes: 2 additions & 0 deletions docs/reference/schemas/product.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1742,6 +1742,8 @@ properties:
like packaging_text_fr (for french).
packagings:
$ref: ./packagings/packagings.yaml
packagings_complete:
$ref: ./packagings/packagings_complete.yaml
photographers_tags:
type: array
items:
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/schemas/product_update_api_v3.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ properties:
$ref: ./packagings/packagings-write.yaml
packagings_add:
$ref: ./packagings/packagings-write.yaml
packagings_complete:
$ref: ./packagings/packagings_complete.yaml
160 changes: 104 additions & 56 deletions lib/ProductOpener/APIProductWrite.pm
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,103 @@ use ProductOpener::Products qw/:all/;
use ProductOpener::API qw/:all/;
use ProductOpener::Packaging qw/:all/;

=head2 update_field_with_0_or_1_value($request_ref, $product_ref, $field, $value)

Update a field that takes only 0 or 1 as a value (e.g. packagings_complete).

=cut

sub update_field_with_0_or_1_value ($request_ref, $product_ref, $field, $value) {

my $response_ref = $request_ref->{api_response};

# Check that the value is 0 or 1

if (($value != 0) and ($value != 1)) {

add_error(
$response_ref,
{
message => {id => "invalid_value_must_be_0_or_1"},
field => {id => $field},
impact => {id => "field_ignored"},
}
);
}
else {
$product_ref->{$field} = $value + 0; # add 0 to make sure the value is stored as a number
}
alexgarel marked this conversation as resolved.
Show resolved Hide resolved
return;
}

=head2 update_packagings($request_ref, $product_ref, $field, $is_addition, $value)

Update packagings.

=cut

sub update_packagings ($request_ref, $product_ref, $field, $is_addition, $value) {

my $request_body_ref = $request_ref->{body_json};
my $response_ref = $request_ref->{api_response};

if (ref($value) ne 'ARRAY') {
add_error(
$response_ref,
{
message => {id => "invalid_type_must_be_array"},
field => {id => $field},
impact => {id => "field_ignored"},
}
);
}
else {
if (not $is_addition) {
# We will replace the packagings structure if it already exists
$product_ref->{packagings} = [];
}

foreach my $input_packaging_ref (@{$value}) {

# Shape, material and recycling
foreach my $property ("shape", "material", "recycling") {
if (defined $input_packaging_ref->{$property}) {

# the API specifies that the property is a hash with either an id or a lc_name field
# (same structure as when the packagings structure is read)
# both will be treated the same way and be canonicalized
# by get_checked_and_taxonomized_packaging_component_data()

if (ref($input_packaging_ref->{$property}) eq 'HASH') {
$input_packaging_ref->{$property} = $input_packaging_ref->{$property}{id}
|| $input_packaging_ref->{$property}{lc_name};
}
else {
add_error(
$response_ref,
{
message => {id => "invalid_type_must_be_object"},
field => {id => $property},
impact => {id => "field_ignored"},
}
);
}
}
}

# Taxonomize the input packaging component data
my $packaging_ref = get_checked_and_taxonomized_packaging_component_data($request_body_ref->{tags_lc},
$input_packaging_ref, $response_ref);

if (defined $packaging_ref) {
# Add or combine with the existing packagings components array
add_or_combine_packaging_component_data($product_ref, $packaging_ref, $response_ref);
}
}
}
alexgarel marked this conversation as resolved.
Show resolved Hide resolved
return;
}

=head2 update_product_fields ($request_ref, $product_ref)

Update product fields based on input product data.
Expand All @@ -59,7 +156,6 @@ Update product fields based on input product data.

sub update_product_fields ($request_ref, $product_ref) {

my $response_ref = $request_ref->{api_response};
my $request_body_ref = $request_ref->{body_json};

$request_ref->{updated_product_fields} = {};
Expand All @@ -71,65 +167,17 @@ sub update_product_fields ($request_ref, $product_ref) {
my $value = $input_product_ref->{$field};

# Packaging components
if ($field =~ /^(packagings)(_add)?/) {
if ($field =~ /^(packagings)(_add)?$/) {
$request_ref->{updated_product_fields}{$1} = 1;
my $is_addition = (defined $2) ? 1 : 0;

if (ref($value) ne 'ARRAY') {
add_error(
$response_ref,
{
message => {id => "invalid_type_must_be_array"},
field => {id => $field},
impact => {id => "field_ignored"},
}
);
}
else {
if (not $is_addition) {
# We will replace the packagings structure if it already exists
$product_ref->{packagings} = [];
}

foreach my $input_packaging_ref (@{$value}) {

# Shape, material and recycling
foreach my $property ("shape", "material", "recycling") {
if (defined $input_packaging_ref->{$property}) {

# the API specifies that the property is a hash with either an id or a lc_name field
# (same structure as when the packagings structure is read)
# both will be treated the same way and be canonicalized
# by get_checked_and_taxonomized_packaging_component_data()

if (ref($input_packaging_ref->{$property}) eq 'HASH') {
$input_packaging_ref->{$property} = $input_packaging_ref->{$property}{id}
|| $input_packaging_ref->{$property}{lc_name};
}
else {
add_error(
$response_ref,
{
message => {id => "invalid_type_must_be_object"},
field => {id => $property},
impact => {id => "field_ignored"},
}
);
}
}
}

# Taxonomize the input packaging component data
my $packaging_ref
= get_checked_and_taxonomized_packaging_component_data($request_body_ref->{tags_lc},
$input_packaging_ref, $response_ref);
update_packagings($request_ref, $product_ref, $field, $is_addition, $value);
}
# packagings_complete contains 0 or 1 and is used to indicate that all packaging components are listed in the packagings field
elsif ($field eq "packagings_complete") {
$request_ref->{updated_product_fields}{$field} = 1;

if (defined $packaging_ref) {
# Add or combine with the existing packagings components array
add_or_combine_packaging_component_data($product_ref, $packaging_ref, $response_ref);
}
}
}
update_field_with_0_or_1_value($request_ref, $product_ref, $field, $value);
}
}
return;
Expand Down
3 changes: 3 additions & 0 deletions po/common/common.pot
Original file line number Diff line number Diff line change
Expand Up @@ -6512,3 +6512,6 @@ msgctxt "api_message_invalid_user_id_and_password"
msgid "Invalid user id and password"
msgstr "Invalid user id and password"

msgctxt "api_message_invalid_value_must_be_0_or_1"
msgid "Invalid value: must be 0 or 1"
msgstr "Invalid value: must be 0 or 1"
3 changes: 3 additions & 0 deletions po/common/en.po
Original file line number Diff line number Diff line change
Expand Up @@ -6456,3 +6456,6 @@ msgctxt "api_message_invalid_user_id_and_password"
msgid "Invalid user id and password"
msgstr "Invalid user id and password"

msgctxt "api_message_invalid_value_must_be_0_or_1"
msgid "Invalid value: must be 0 or 1"
msgstr "Invalid value: must be 0 or 1"
68 changes: 68 additions & 0 deletions tests/integration/api_v3_product_write.t
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,74 @@ my $tests_ref = [
}
}'
},
# Packaging complete
{
test_case => 'patch-packagings-complete-0',
method => 'PATCH',
path => '/api/v3/product/1234567890016',
body => '{
"fields": "packagings,packagings_complete",
"tags_lc": "en",
"product": {
"packagings": [
{
"number_of_units": 1,
"shape": {"lc_name": "bottle"},
"recycling": {"lc_name": "recycle"}
}
],
"packagings_complete": 0
}
}'
},
{
test_case => 'patch-packagings-complete-1',
method => 'PATCH',
path => '/api/v3/product/1234567890016',
body => '{
"fields": "packagings,packagings_complete",
"tags_lc": "en",
"product": {
"packagings": [
{
"number_of_units": 1,
"shape": {"lc_name": "bottle"},
"recycling": {"lc_name": "recycle"}
},
{
"number_of_units": 1,
"shape": {"lc_name": "lid"},
"recycling": {"lc_name": "recycle"}
}
],
"packagings_complete": 1
}
}'
},
{
test_case => 'patch-packagings-complete-2',
method => 'PATCH',
path => '/api/v3/product/1234567890016',
body => '{
"fields": "packagings,packagings_complete",
"tags_lc": "en",
"product": {
"packagings": [
{
"number_of_units": 1,
"shape": {"lc_name": "bottle"},
"recycling": {"lc_name": "recycle"}
},
{
"number_of_units": 1,
"shape": {"lc_name": "lid"},
"recycling": {"lc_name": "recycle"}
}
],
"packagings_complete": 2
}
}'
},
];

execute_api_tests(__FILE__, $tests_ref);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"code" : "1234567890016",
"errors" : [],
"product" : {
"packagings" : [
{
"number_of_units" : 1,
"recycling" : {
"id" : "en:recycle",
"lc_name" : "Recycle"
},
"shape" : {
"id" : "en:bottle",
"lc_name" : "Bottle"
}
}
],
"packagings_complete" : 0
},
"status" : "success_with_warnings",
"warnings" : [
{
"field" : {
"id" : "material",
"value" : null
},
"impact" : {
"id" : "field_ignored",
"lc_name" : "Field ignored",
"name" : "Field ignored"
},
"message" : {
"id" : "missing_field",
"lc_name" : "Missing field",
"name" : "Missing field"
}
}
]
}
Loading