@@ -, +, @@ 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 - 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 --- 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(-) --- a/Koha/REST/V1/Checkouts.pm +++ a/Koha/REST/V1/Checkouts.pm @@ -284,6 +284,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 --- a/api/v1/swagger/paths/checkouts.yaml +++ a/api/v1/swagger/paths/checkouts.yaml @@ -122,6 +122,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 --- a/api/v1/swagger/swagger.yaml +++ a/api/v1/swagger/swagger.yaml @@ -544,6 +544,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 --- a/t/db_dependent/api/v1/checkouts.t +++ a/t/db_dependent/api/v1/checkouts.t @@ -17,7 +17,7 @@ use Modern::Perl; -use Test::More tests => 105; +use Test::More tests => 106; use Test::MockModule; use Test::Mojo; use t::lib::Mocks; @@ -435,6 +435,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 = (); @@ -471,7 +473,7 @@ subtest 'add checkout' => sub { my $token = Koha::Token->new->generate_jwt( { id => $librarian->id . ":" . $item1_id . ":confirm1:confirm2" } ); $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 } ); @@ -515,3 +517,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; +}; --