Skip to content

Commit

Permalink
feat: allow setting the packagings_complete field through API v3 (#7856)
Browse files Browse the repository at this point in the history
We have a field called packagings_complete that takes value 0 or 1 to indicate if the packagings field contains all element of the product.
This PR adds it to the API v3 WRITE product.
  • Loading branch information
stephanegigandet committed Dec 19, 2022
1 parent c294a5c commit fec330a
Show file tree
Hide file tree
Showing 10 changed files with 376 additions and 56 deletions.
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
}
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);
}
}
}
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

0 comments on commit fec330a

Please sign in to comment.