From d3bb4fc2a45bcc12a39bd92f863747488913d03d Mon Sep 17 00:00:00 2001 From: danyonsewell Date: Fri, 12 May 2023 03:02:09 +0000 Subject: [PATCH] Bug 24401: REST API: Check-in Updating files to include API endpoints for check-ins Test plan: 1) Apply bug 23336 as there are dependencies in there required for this to work 2) Apply this patch 3) Run unit tests in t/db_dependent/api/v1/checkouts.t 4) Make POST request to http://yourlibrary/api/v1/checkouts with request body containing 'item_id' & 'library_id' properties. - Observe returned data and HTTP code - 201 for item checked in - 403 for check in not allowed - 409 for Item not found - 400 for item not checked out Sponsored-by: Auckland University of Technology --- Koha/REST/V1/Checkouts.pm | 61 ++++++++++++++++++++++++++ api/v1/swagger/paths/checkouts.yaml | 36 ++++++++++++++++ api/v1/swagger/swagger.yaml | 6 +++ t/db_dependent/api/v1/checkouts.t | 66 ++++++++++++++++++++++++++++- 4 files changed, 167 insertions(+), 2 deletions(-) diff --git a/Koha/REST/V1/Checkouts.pm b/Koha/REST/V1/Checkouts.pm index 2fd756e3ae..4f6d016930 100644 --- a/Koha/REST/V1/Checkouts.pm +++ b/Koha/REST/V1/Checkouts.pm @@ -244,6 +244,67 @@ sub add { }; } +=head3 delete + +Removing the checked out item from the issues table and adding it to the +old_issues table + +=cut + +sub delete { + + my $c = shift->openapi->valid_input or return; + + my $body = $c->validation->param('body'); + my $item_id = $body->{item_id}; + + return try { + my $item = Koha::Items->find($item_id); + unless ($item) { + return $c->render( + status => 409, + openapi => { + error => 'Item not found' + } + ); + } + my $checkout = Koha::Checkouts->find({ itemnumber => $item_id }); + unless ( $checkout ) { + return $c->render( + status => 400, + openapi => { error => "Item not checked out" } + ); + } + my $library_id = $c->validation->output->{library_id}; + unless ( $library_id ) { + $library_id = $checkout->patron->branchcode; + } + my $library = Koha::Libraries->find( $library_id ); + + try { + my $barcode = $item->barcode; + my ( $returned ) = C4::Circulation::AddReturn( $barcode, $library_id ); + + unless ( $returned ) { + return $c->render( + status => 403, + openapi => { error => "Checkin not allowed" } + ); + } + + $c->res->headers->location( $c->req->url->to_string ); + return $c->render( + status => 201, + openapi => $item->to_api + ); + } + catch { + $c->unhandled_exception($_); + }; + } + } + + =head3 get_renewals List Koha::Checkout::Renewals diff --git a/api/v1/swagger/paths/checkouts.yaml b/api/v1/swagger/paths/checkouts.yaml index afe6e5660c..aa17f419a8 100644 --- a/api/v1/swagger/paths/checkouts.yaml +++ b/api/v1/swagger/paths/checkouts.yaml @@ -123,6 +123,42 @@ x-koha-authorization: permissions: circulate: circulate_remaining_permissions + delete: + x-mojo-to: Checkouts#delete + operationId: deletecheckout + tags: + - checkouts + - items + summary: Check in an item + parameters: + - name: body + in: body + description: A JSON object containing information about the checkout + required: true + schema: + $ref: "../swagger.yaml#/definitions/checkout" + consumes: + - application/json + produces: + - application/json + responses: + "201": + description: Item returned + "400": + description: Item not checked out + schema: + $ref: "../swagger.yaml#/definitions/error" + "403": + description: Checkin not allowed + schema: + $ref: "../swagger.yaml#/definitions/error" + "409": + description: Item not found + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + circulate: circulate_remaining_permissions "/checkouts/{checkout_id}": get: x-mojo-to: Checkouts#get diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index 0eff0139c7..c93feb5fa1 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -528,6 +528,12 @@ parameters: in: query name: item_id type: integer + library_id_qp: + description: Internal library identifier. If not provided, will ues checkout patron's home library + in: query + name: library_id + required: false + type: string job_id_pp: description: Job internal identifier in: path diff --git a/t/db_dependent/api/v1/checkouts.t b/t/db_dependent/api/v1/checkouts.t index 2e749aa874..a2c9f39eef 100755 --- a/t/db_dependent/api/v1/checkouts.t +++ b/t/db_dependent/api/v1/checkouts.t @@ -17,7 +17,7 @@ use Modern::Perl; -use Test::More tests => 101; +use Test::More tests => 102; use Test::MockModule; use Test::Mojo; use t::lib::Mocks; @@ -375,6 +375,8 @@ subtest 'add checkout' => sub { my $item1 = $builder->build_sample_item; my $item1_id = $item1->id; + my $item2 = $builder->build_sample_item; + my $item2_id = $item2->id; my %issuingimpossible = (); my %needsconfirmation = (); @@ -420,7 +422,7 @@ subtest 'add checkout' => sub { ); $t->post_ok( "//$userid:$password@/api/v1/checkouts?confirmation=$token" => json => { - item_id => $item1_id, + item_id => $item2_id, patron_id => $patron_id } )->status_is(201)->or(sub { diag $t->tx->res->body }); @@ -428,3 +430,63 @@ subtest 'add checkout' => sub { $schema->storage->txn_rollback; }; + +subtest 'delete checkout' => sub { + + plan tests => 11; + + $schema->storage->txn_begin; + my $librarian = $builder->build_object( + { + class => 'Koha::Patrons', + value => { flags => 2 } + } + ); + 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 } + } + ); + my $unauth_password = 'thePassword000'; + $patron->set_password( + { password => $unauth_password, skip_validattion => 1 } ); + my $unauth_userid = $patron->userid; + + my $branch = $builder->build_object( { class => 'Koha::Libraries' } ); + my $library_id = $branch->id; + my $item1 = $builder->build_sample_item; + my $item1_id = $item1->id; + + + $t->delete_ok( + "//$unauth_userid:$unauth_password@/api/v1/checkouts" => json => + { item_id => $item1_id, library_id => $library_id } )->status_is(403) + ->json_is( + { + error => "Authorization failure. Missing required permission(s).", + required_permissions => + { circulate => "circulate_remaining_permissions" } + } + ); + + $t->delete_ok( "//$userid:$password@/api/v1/checkouts" => json => + { item_id => $item1_id, library_id => $library_id } )->status_is(400) + ->json_is( + '/error' => 'Item not checked out' ); + + AddIssue( $patron->unblessed, $item1->barcode ); + $t->delete_ok( "//$userid:$password@/api/v1/checkouts" => json => + { item_id => $item1_id, library_id => $library_id } )->status_is(201); + + $item1->delete; + $t->delete_ok( "//$userid:$password@/api/v1/checkouts/" => json => + { item_id => $item1_id, library_id => $library_id } )->status_is(409) + ->json_is( + '/error' => 'Item not found' ); + $schema->storage->txn_rollback; +}; -- 2.41.0