From d700d73139e0ec5c5d526aefb4305a2b08cd9665 Mon Sep 17 00:00:00 2001 From: Tomas Cohen Arazi Date: Thu, 30 Mar 2023 11:01:08 +0200 Subject: [PATCH] Bug 22440: Add GET /ill_requests Co-authored-by: Pedro Amorim Signed-off-by: Martin Renvoize --- Koha/Illrequest.pm | 96 ++++++++++++++ api/v1/swagger/definitions/ill_request.yaml | 137 ++++++++++++++++++++ api/v1/swagger/paths/illrequests.yaml | 118 ++++------------- api/v1/swagger/swagger.yaml | 4 + t/db_dependent/api/v1/illrequests.t | 58 ++++++++- 5 files changed, 319 insertions(+), 94 deletions(-) create mode 100644 api/v1/swagger/definitions/ill_request.yaml diff --git a/Koha/Illrequest.pm b/Koha/Illrequest.pm index 4187ba152e..227484d95c 100644 --- a/Koha/Illrequest.pm +++ b/Koha/Illrequest.pm @@ -24,6 +24,8 @@ use Try::Tiny qw( catch try ); use DateTime; use C4::Letters; + +use Koha::Cache::Memory::Lite; use Koha::Database; use Koha::DateUtils qw( dt_from_string ); use Koha::Exceptions::Ill; @@ -1879,6 +1881,100 @@ sub TO_JSON { =head2 Internal methods +=head3 to_api_mapping + +=cut + +sub to_api_mapping { + return { + illrequest_id => 'ill_request_id', + borrowernumber => 'patron_id', + branchcode => 'library_id', + status_alias => 'status_av', + placed => 'requested_date', + replied => 'replied_date', + updated => 'timestamp', + completed => 'completed_date', + accessurl => 'access_url', + price_paid => 'paid_price', + notesopac => 'opac_notes', + notesstaff => 'staff_notes', + orderid => 'ill_backend_request_id', + backend => 'ill_backend_id', + }; +} + +=head3 strings_map + + my $strings = $self->string_map({ [ public => 0|1 ] }); + +Returns a map of column name to string representations. Extra information +is returned depending on the column characteristics as shown below. + +Accepts a param hashref where the I key denotes whether we want the public +or staff client strings. + +Example: + + { + status => { + backend => 'backendName', + str => 'Status description', + type => 'ill_status', + }, + status_alias => { + category => 'ILL_STATUS_ALIAS, + str => $value, # the AV description, depending on $params->{public} + type => 'av', + } + } + +=cut + +sub strings_map { + my ( $self, $params ) = @_; + + my $cache = Koha::Cache::Memory::Lite->get_instance(); + my $cache_key = 'ill:status_graph:' . $self->backend; + + my $status_graph_union = $cache->get($cache_key); + unless ($status_graph_union) { + $status_graph_union = $self->capabilities; + $cache->set( $cache_key, $status_graph_union ); + } + + my $status_string = + ( exists $status_graph_union->{ $self->status } && defined $status_graph_union->{ $self->status }->{name} ) + ? $status_graph_union->{ $self->status }->{name} + : $self->status; + + my $status_code = + ( exists $status_graph_union->{ $self->status } && defined $status_graph_union->{ $self->status }->{id} ) + ? $status_graph_union->{ $self->status }->{id} + : $self->status; + + my $strings = { + status => { + backend => $self->backend, # the backend identifier + str => $status_string, # the status description, taken from the status graph + code => $status_code, # the status id, taken from the status graph + type => 'ill_status', # fixed type + } + }; + + my $status_alias = $self->statusalias; + if ($status_alias) { + $strings->{"status_alias"} = { + category => 'ILL_STATUS_ALIAS', + str => $params->{public} ? $status_alias->lib_opac : $status_alias->lib, + code => $status_alias->authorised_value, + type => 'av', + }; + } + + return $strings; +} + =head3 _type =cut diff --git a/api/v1/swagger/definitions/ill_request.yaml b/api/v1/swagger/definitions/ill_request.yaml new file mode 100644 index 0000000000..6178944755 --- /dev/null +++ b/api/v1/swagger/definitions/ill_request.yaml @@ -0,0 +1,137 @@ +--- +type: object +properties: + ill_request_id: + type: integer + description: Internal ILL request identifier + biblio_id: + type: + - integer + - "null" + description: Internal bibliographic record identifier + patron_id: + type: + - integer + - "null" + description: Internal patron id + due_date: + type: + - string + - "null" + format: date-time + description: Date and time the request item should be due when checked out + library_id: + type: string + description: Internal library identifier + requested_date: + type: string + format: date + description: Date the request was placed by the patron + replied_date: + type: + - string + - "null" + format: date + description: FIXME + timestamp: + type: string + format: date-time + description: Date and time of last object update + completed_date: + type: + - string + - "null" + format: date + description: Date the request was marked as completed + access_url: + type: + - string + - "null" + description: A URL for accessing the item + status: + type: string + description: | + The status the request is at. + + Note: This is defined by each backend. Please refer to the specific backend's + documentation or code to understand the possible values. + medium: + type: + - string + - "null" + description: Description of the ILL item medium + cost: + type: + - string + - "null" + description: Default request cost + paid_price: + type: + - string + - "null" + description: Effective request cost + opac_notes: + type: + - string + - "null" + description: Note that is visible to the patron + staff_notes: + type: + - string + - "null" + description: Interal staff note about the request + ill_backend_id: + type: string + description: The ILL backend identifier string + ill_backend_request_id: + type: + - string + - "null" + description: Backend-specific request id + status_av: + type: + - string + - "null" + description: The authorised value category the field is linked to + biblio: + type: + - object + - "null" + description: The linked biblio object (x-koha-embed) + comments: + type: + - array + - "null" + description: The linked comment objects (x-koha-embed) + comments_count: + type: + - integer + - "null" + description: The linked comment objects count (x-koha-embed) + ill_extended_attributes: + type: + - array + - "null" + description: The linked extended ill request attributes (x-koha-embed) + library: + type: + - object + - "null" + description: The linked library object (x-koha-embed) + id_prefix: + type: + - string + - "null" + description: The id_prefix of the request (x-koha-embed) + patron: + type: + - object + - "null" + description: The linked patron object (x-koha-embed) + _strings: + type: + - object + - "null" + description: Expanded coded fiels (x-koha-embed) + +additionalProperties: false diff --git a/api/v1/swagger/paths/illrequests.yaml b/api/v1/swagger/paths/illrequests.yaml index 1e3224bda0..bcee3d85a5 100644 --- a/api/v1/swagger/paths/illrequests.yaml +++ b/api/v1/swagger/paths/illrequests.yaml @@ -1,118 +1,52 @@ --- -/illrequests: +/ill_requests: get: x-mojo-to: Illrequests#list operationId: listIllrequests tags: - - illrequests + - ill_requests summary: List ILL requests parameters: - - name: embed - in: query - description: Additional objects that should be embedded in the response - required: false + - $ref: "../swagger.yaml#/parameters/page" + - $ref: "../swagger.yaml#/parameters/per_page" + - $ref: "../swagger.yaml#/parameters/match" + - $ref: "../swagger.yaml#/parameters/order_by" + - $ref: "../swagger.yaml#/parameters/q_param" + - $ref: "../swagger.yaml#/parameters/q_body" + - $ref: "../swagger.yaml#/parameters/q_header" + - $ref: "../swagger.yaml#/parameters/request_id_header" + - name: x-koha-embed + in: header + required: false + description: Embed list sent as a request header type: array - collectionFormat: csv items: type: string enum: - - patron - - library - - capabilities - - metadata - - requested_partners + - +strings + - biblio - comments - - status_alias - - name: backend - in: query - description: The name of a ILL backend - required: false - type: string - - name: orderid - in: query - description: The order ID of a request - required: false - type: string - - name: biblionumber - in: query - description: Internal biblio identifier - required: false - type: integer - - name: borrowernumber - in: query - description: Internal patron identifier - required: false - type: integer - - name: completed - in: query - description: The date the request was considered completed - required: false - type: string - - name: completed_formatted - in: query - description: The date the request was considered complete formatted - required: false - type: string - - name: status - in: query - description: A full status string e.g. REQREV - required: false - type: string - - name: cost - in: query - description: The quoted cost of the request - required: false - type: number - - name: price_paid - in: query - description: The final cost of the request - required: false - type: number - - name: medium - in: query - description: The medium of the requested item - required: false - type: string - - name: updated - in: query - description: The last updated date of the request - required: false - type: string - - name: updated_formatted - in: query - description: The last updated date of the request formatted - required: false - type: string - - name: placed - in: query - description: The date the request was placed - required: false - type: string - - name: placed_formatted - in: query - description: The date the request was placed formatted - required: false - type: string - - name: branchcode - in: query - description: Library ID - required: false - type: string + - comments+count + - ill_extended_attributes + - library + - id_prefix + - patron + collectionFormat: csv produces: - application/json responses: "200": description: A list of ILL requests - "401": - description: Authentication required schema: - $ref: "../swagger.yaml#/definitions/error" + type: array + items: + $ref: "../swagger.yaml#/definitions/ill_request" "403": description: Access forbidden schema: $ref: "../swagger.yaml#/definitions/error" "404": - description: ILL requests not found + description: Patron not found schema: $ref: "../swagger.yaml#/definitions/error" "500": diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index 7d5e04f62d..ddb4167f96 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -52,6 +52,8 @@ definitions: $ref: ./definitions/ill_backend.yaml ill_backends: $ref: ./definitions/ill_backends.yaml + ill_request: + $ref: ./definitions/ill_request.yaml import_batch_profile: $ref: ./definitions/import_batch_profile.yaml import_batch_profiles: @@ -245,6 +247,8 @@ paths: $ref: "./paths/ill_backends.yaml#/~1ill_backends~1{ill_backend_id}" /illrequests: $ref: ./paths/illrequests.yaml#/~1illrequests + /ill_requests: + $ref: ./paths/illrequests.yaml#/~1ill_requests "/import_batches/{import_batch_id}/records/{import_record_id}/matches/chosen": $ref: "./paths/import_batches.yaml#/~1import_batches~1{import_batch_id}~1records~1{import_record_id}~1matches~1chosen" /import_batch_profiles: diff --git a/t/db_dependent/api/v1/illrequests.t b/t/db_dependent/api/v1/illrequests.t index 31c220c724..0b4cd312bf 100755 --- a/t/db_dependent/api/v1/illrequests.t +++ b/t/db_dependent/api/v1/illrequests.t @@ -17,12 +17,14 @@ use Modern::Perl; -use Test::More tests => 1; +use Test::More tests => 2; use Test::MockModule; use Test::MockObject; use Test::Mojo; +use JSON qw(encode_json); + use t::lib::TestBuilder; use t::lib::Mocks; @@ -36,7 +38,7 @@ t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 ); my $t = Test::Mojo->new('Koha::REST::V1'); -subtest 'list() tests' => sub { +subtest 'list_legacy() tests' => sub { plan tests => 30; @@ -94,6 +96,7 @@ subtest 'list() tests' => sub { class => 'Koha::Illrequests', value => { backend => 'Mock', + biblio_id => undef, branchcode => $library->branchcode, borrowernumber => $patron_1->borrowernumber, status => 'STATUS1', @@ -129,6 +132,7 @@ subtest 'list() tests' => sub { class => 'Koha::Illrequests', value => { backend => 'Mock', + biblio_id => undef, branchcode => $library->branchcode, borrowernumber => $patron_2->borrowernumber, status => 'STATUS2', @@ -173,6 +177,56 @@ subtest 'list() tests' => sub { $schema->storage->txn_rollback; }; +subtest 'list() tests' => sub { + + plan tests => 9; + + $schema->storage->txn_begin; + + Koha::Illrequests->search->delete; + + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 2 ** 22 } # 22 => ill + } + ); + my $password = 'thePassword123'; + $librarian->set_password( { password => $password, skip_validation => 1 } ); + my $userid = $librarian->userid; + + my $patron = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 0 } + } + ); + + $patron->set_password( { password => $password, skip_validation => 1 } ); + my $unauth_userid = $patron->userid; + + $t->get_ok("//$userid:$password@/api/v1/ill_requests") + ->status_is(200) + ->json_is( [] ); + + my $req_1 = $builder->build_object({ class => 'Koha::Illrequests', value => { biblio_id => undef, status => 'REQ' } }); + my $req_2 = $builder->build_object({ class => 'Koha::Illrequests', value => { biblio_id => undef, status => 'REQ' } } ); + my $ret = $builder->build_object({ class => 'Koha::Illrequests', value => { biblio_id => undef, status => 'RET' } } ); + + $t->get_ok("//$userid:$password@/api/v1/ill_requests") + ->status_is(200) + ->json_is( [ $req_1->to_api, $req_2->to_api, $ret->to_api ]); + + my $query = encode_json({ status => 'REQ' }); + + # Filtering works + $t->get_ok("//$userid:$password@/api/v1/ill_requests?q=$query" ) + ->status_is(200) + ->json_is( [ $req_1->to_api, $req_2->to_api ]); + + $schema->storage->txn_rollback; +}; + sub add_formatted { my $req = shift; my @format_dates = ( 'placed', 'updated', 'completed' ); -- 2.40.1