diff --git a/perllib/Integrations/AlloyV2.pm b/perllib/Integrations/AlloyV2.pm index c2afe11b..982d704a 100644 --- a/perllib/Integrations/AlloyV2.pm +++ b/perllib/Integrations/AlloyV2.pm @@ -188,13 +188,20 @@ sub search { my $pages = int( $result_count / $pageSize ) + 1; my $query_body = $body_base; - $query_body->{type} = 'Query'; + my $call = 'aqs/'; + if ( $query_body->{properties}{joinAttributes} ) { + $query_body->{type} = 'Join'; + $call .= 'join'; + } else { + $query_body->{type} = 'Query'; + $call .= 'query'; + } my @results; my $page = 1; while ($page <= $pages) { my $result = $self->api_call( - call => "aqs/query", + call => $call, params => { page => $page, pageSize => $pageSize }, body => { aqs => $query_body }, ); @@ -202,7 +209,30 @@ sub search { $page++; next unless $result->{results}; - push @results, @{ $result->{results} } + push @results, @{ $result->{results} }; + + if ( my $join_results = $result->{joinResults} ) { + my %id_to_res = map { $_->{itemId} => $_ } @results; + + for my $jr ( @$join_results ) { + my $item_id = $jr->{itemId}; + + for my $jq ( @{ $jr->{joinQueries} } ) { + # Make sure attribute code is unique. + # E.g. Attribute code may originally be something like + # 'attributes_itemsTitle' but this doesn't make it clear + # if it is referring to a request, category, group, etc. + # joinAttributes contains full code 'path' so we use this + # instead. + my $attr = @{ $jq->{item}{attributes} }[0]; + my $attr_code = $jq->{joinAttributes}[0]; + $attr->{attributeCode} = $attr_code; + + # Append to top-level attribute list + push @{ $id_to_res{$item_id}{attributes} }, $attr; + } + } + } } return \@results; diff --git a/perllib/Open311/Endpoint/Integration/AlloyV2.pm b/perllib/Open311/Endpoint/Integration/AlloyV2.pm index f9800f52..fae6aa60 100644 --- a/perllib/Open311/Endpoint/Integration/AlloyV2.pm +++ b/perllib/Open311/Endpoint/Integration/AlloyV2.pm @@ -606,7 +606,13 @@ sub _get_inspection_updates { my $mapping = $self->config->{inspection_attribute_mapping}; return () unless $mapping; - my $updates = $self->fetch_updated_resources($self->config->{rfs_design}, $args->{start_date}, $args->{end_date}); + + my %join; + $join{joinAttributes} + = [ $mapping->{category_title}, $mapping->{group_title} ] + if $mapping->{category_title}; + + my $updates = $self->fetch_updated_resources($self->config->{rfs_design}, $args->{start_date}, $args->{end_date}, \%join); my $assigned_to_users = $self->get_assigned_to_users(@$updates); @@ -660,24 +666,14 @@ sub _get_inspection_updates { } } - if ( $mapping->{category} ) { - my $category_code = @{ $attributes->{ $mapping->{category} } || [] }[0]; - my $group_code = @{ $attributes->{ $mapping->{group} } || [] }[0]; + if ( $mapping->{category_title} ) { + $args{extras}{category} + = $attributes->{ $mapping->{category_title} } + if $attributes->{ $mapping->{category_title} }; - if ($category_code) { - my $res = $self->_find_category_by_code($category_code); - my $title = $self->alloy->attributes_to_hash( $res->[0] ) - ->{ $self->config->{category_title_attribute} } if @$res; - - $args{extras}{category} = $title if $title; - } - if ($group_code) { - my $res = $self->_find_group_by_code($group_code); - my $title = $self->alloy->attributes_to_hash( $res->[0] ) - ->{ $self->config->{group_title_attribute} } if @$res; - - $args{extras}{group} = $title if $title; - } + $args{extras}{group} + = $attributes->{ $mapping->{group_title} } + if $attributes->{ $mapping->{group_title} }; } push @updates, Open311::Endpoint::Service::Request::Update::mySociety->new( %args ); @@ -912,7 +908,7 @@ sub get_request_description { } sub fetch_updated_resources { - my ($self, $code, $start_date, $end_date) = @_; + my ($self, $code, $start_date, $end_date, $join) = @_; my @results; @@ -920,6 +916,7 @@ sub fetch_updated_resources { properties => { dodiCode => $code, attributes => ["all"], + %{ $join || {} }, }, children => [{ type => "And", @@ -1332,42 +1329,6 @@ sub _search_by_code { return $res; } -=head2 _find_category_by_code - -This looks up the C design in Alloy, and finds the entry -that matches the provided Alloy code. - -=cut - -sub _find_category_by_code { - my ( $self, $code ) = @_; - - my $res = $self->_search_by_code( { - dodi_code => $self->config->{category_list_code}, - item_code => $code, - } ); - - return $res; -} - -=head2 _find_group_by_code - -This looks up the C design in Alloy, and finds the entry -that matches the provided Alloy code. - -=cut - -sub _find_group_by_code { - my ( $self, $code ) = @_; - - my $res = $self->_search_by_code( { - dodi_code => $self->config->{group_list_code}, - item_code => $code, - } ); - - return $res; -} - sub call_reconstruct { my ($self, $id, $date) = @_; diff --git a/t/open311/endpoint/json/alloyv2/northumberland/customer_requests_query_response.json b/t/open311/endpoint/json/alloyv2/northumberland/customer_requests_query_response.json index ebf2f0b6..08f5bffa 100644 --- a/t/open311/endpoint/json/alloyv2/northumberland/customer_requests_query_response.json +++ b/t/open311/endpoint/json/alloyv2/northumberland/customer_requests_query_response.json @@ -1,4 +1,68 @@ { + "joinResults": [ + { + "itemId": "123456", + "joinQueries": [ + { + "item": { + "attributes": [ + { + "attributeCode": "attributes_itemsTitle", + "value": "Damaged / Missing / Facing Wrong Way" + } + ] + }, + "joinAttributes": [ + "root.attributes_customerRequestRequestCategory_63862851fb3d97038c4e1cfc.attributes_itemsTitle" + ] + }, + { + "item": { + "attributes": [ + { + "attributeCode": "attributes_itemsTitle", + "value": "Street Lighting" + } + ] + }, + "joinAttributes": [ + "root.attributes_customerRequestRequestGroup_638627f005cb250393c1705a.attributes_itemsTitle" + ] + } + ] + }, + { + "itemId": "234567", + "joinQueries": [ + { + "item": { + "attributes": [ + { + "attributeCode": "attributes_itemsTitle", + "value": "Fly-tipping/Rubbish Bin Overflowing" + } + ] + }, + "joinAttributes": [ + "root.attributes_customerRequestRequestCategory_63862851fb3d97038c4e1cfc.attributes_itemsTitle" + ] + }, + { + "item": { + "attributes": [ + { + "attributeCode": "attributes_itemsTitle", + "value": "Winter" + } + ] + }, + "joinAttributes": [ + "root.attributes_customerRequestRequestGroup_638627f005cb250393c1705a.attributes_itemsTitle" + ] + } + ] + } + ], "results": [ { "collection": "Live", diff --git a/t/open311/endpoint/northumberland_alloy.t b/t/open311/endpoint/northumberland_alloy.t index 7697445f..1f1737fa 100644 --- a/t/open311/endpoint/northumberland_alloy.t +++ b/t/open311/endpoint/northumberland_alloy.t @@ -174,6 +174,8 @@ $integration->mock('api_call', sub { } elsif ($designCode eq 'designs_contacts') { $content = '{}'; } + } elsif ($body && $call =~ 'aqs/join') { + $content = path(__FILE__)->sibling("json/alloyv2/northumberland/customer_requests_query_response.json")->slurp; } if (!$content) { @@ -414,6 +416,8 @@ subtest "check fetch updates" => sub { assigned_user_name => 'FMS User 123', assigned_user_email => '123@email.com', detailed_information => '', + category => 'Damaged / Missing / Facing Wrong Way', + group => 'Street Lighting', }, }, { description => '', @@ -427,6 +431,8 @@ subtest "check fetch updates" => sub { assigned_user_name => 'FMS User 345', assigned_user_email => '345@email.com', detailed_information => 'Hello there', + category => 'Fly-tipping/Rubbish Bin Overflowing', + group => 'Winter', }, }, ], 'correct json returned'; @@ -443,7 +449,7 @@ HERE POST => '/servicerequestupdates.json', jurisdiction_id => 'dummy', api_key => 'test', - service_code => 'Damaged_/_Missing_/_Facing_Wrong_Way', + service_code => 'Loose_/_Raised_/_Sunken', description => 'update', status => 'FIXED', service_request_id => '642062376be3a0036bbbb64b', @@ -455,40 +461,37 @@ HERE ok $res->is_success, 'valid request' or diag $res->content; - my $sent = pop @sent; my $attributes = $sent->{attributes}; - my $expected_status_attribute_code = 'attributes_customerRequestMainFMSStatus_63fcb297c9ec9c036ec35dfb'; - my $expected_status_attribute_value = '63fcb00c753aed036a5e43a2'; - - my $expected_extra_details_attribute_code = 'attributes_customerRequestFMSExtraDetails_646e07533726d8036a7a4022'; - my $expected_extra_details_attribute_value = $extra_details; - - my $expected_assigned_user_attribute_code = - 'attributes_customerRequestAssignedTo_653664b0557119eef53a97e1'; - my $expected_assigned_user_attribute_value = '123'; - - my $check_count = 0; - foreach (@{ $attributes }) { - if ($_->{attributeCode} eq $expected_status_attribute_code) { - is_deeply $_->{value}, [$expected_status_attribute_value], - "value sent in status attribute update is correct"; - $check_count++; - } - if ($_->{attributeCode} eq $expected_extra_details_attribute_code) { - ok $_->{value} eq $expected_extra_details_attribute_value, "value sent in extra_details attribute update is correct"; - $check_count++; - } - if ( $_->{attributeCode} eq $expected_assigned_user_attribute_code ) { - is_deeply $_->{value}, [$expected_assigned_user_attribute_value], - "value sent in assigned_to_user attribute update is correct"; - $check_count++; - } - } - is $check_count, 3, 'correct number of attributes tested'; + is_deeply $attributes, [ + { 'attributeCode' => + 'attributes_customerRequestMainFMSStatus_63fcb297c9ec9c036ec35dfb', + 'value' => ['63fcb00c753aed036a5e43a2'], + }, + { 'attributeCode' => + 'attributes_customerRequestFMSExtraDetails_646e07533726d8036a7a4022', + 'value' => 'Red and +yellow and + pink +', + }, + { 'attributeCode' => + 'attributes_customerRequestAssignedTo_653664b0557119eef53a97e1', + 'value' => ['123'], + }, + { 'attributeCode' => + 'attributes_customerRequestRequestCategory_63862851fb3d97038c4e1cfc', + 'value' => ['61fb016c4c5c56015448093e'], + }, + { 'attributeCode' => + 'attributes_customerRequestFMSUpdates_6387cc9805cb250393e00e2f', + 'value' => 'Customer update at 2023-05-15 14:55:55 +update', + }, + ]; - note 'unset assigned user'; + note 'unset assigned user; change category & group'; $res = $endpoint->run_test_request( POST => '/servicerequestupdates.json', @@ -502,21 +505,44 @@ HERE updated_datetime => '2023-05-15T14:55:55+00:00', 'attribute[extra_details]' => $extra_details, 'attribute[assigned_to_user_email]' => '', + 'attribute[group]' => 'Winter', ); ok $res->is_success, 'valid request' or diag $res->content; $sent = pop @sent; $attributes = $sent->{attributes}; - $check_count = 0; - for (@$attributes) { - if ( $_->{attributeCode} eq $expected_assigned_user_attribute_code ) { - is_deeply $_->{value}, [], - "empty arrayref sent for assigned_to_user attribute"; - $check_count++; - } - } - is $check_count, 1, 'correct number of attributes tested'; + + is_deeply $attributes, [ + { 'attributeCode' => + 'attributes_customerRequestMainFMSStatus_63fcb297c9ec9c036ec35dfb', + 'value' => ['63fcb00c753aed036a5e43a2'], + }, + { 'attributeCode' => + 'attributes_customerRequestFMSExtraDetails_646e07533726d8036a7a4022', + 'value' => 'Red and +yellow and + pink +', + }, + { 'attributeCode' => + 'attributes_customerRequestAssignedTo_653664b0557119eef53a97e1', + 'value' => [], + }, + { 'attributeCode' => + 'attributes_customerRequestRequestGroup_638627f005cb250393c1705a', + 'value' => ['61fafee3e3b879015205f7cc'], + }, + { 'attributeCode' => + 'attributes_customerRequestRequestCategory_63862851fb3d97038c4e1cfc', + 'value' => ['61fb016c4c5c56015448093f'], + }, + { 'attributeCode' => + 'attributes_customerRequestFMSUpdates_6387cc9805cb250393e00e2f', + 'value' => 'Customer update at 2023-05-15 14:55:55 +update', + }, + ]; }; done_testing; diff --git a/t/open311/endpoint/northumberland_alloy.yml b/t/open311/endpoint/northumberland_alloy.yml index 55fc4465..c7a234ea 100644 --- a/t/open311/endpoint/northumberland_alloy.yml +++ b/t/open311/endpoint/northumberland_alloy.yml @@ -170,6 +170,8 @@ "inspector_comments": "attributes_customerRequestInspectorsComments_638629fcfb3d97038c4e5d5a", "extra_details": "attributes_customerRequestFMSExtraDetails_646e07533726d8036a7a4022", "assigned_to_user": "attributes_customerRequestAssignedTo_653664b0557119eef53a97e1", + "category_title": "root.attributes_customerRequestRequestCategory_63862851fb3d97038c4e1cfc.attributes_itemsTitle", + "group_title": "root.attributes_customerRequestRequestGroup_638627f005cb250393c1705a.attributes_itemsTitle", }, "assigned_to_user_mapping": {