From 91391a4554d1d44bb0737225feecb0bb971cf690 Mon Sep 17 00:00:00 2001 From: Koha User Date: Wed, 10 Apr 2024 09:09:39 +0200 Subject: [PATCH] Bug 36562: [REST API] Add GET endpoint for counting checkouts Test plan: curl -v -s -u koha:koha --request GET http://kohadev.local/api/v1/checkouts/count?patron_id=1 Available parameters and permissions are the same than for listing checkouts --- Koha/REST/V1/Checkouts.pm | 34 ++++++++++++++++++ api/v1/swagger/definitions/count.yaml | 6 ++++ api/v1/swagger/paths/checkouts.yaml | 51 +++++++++++++++++++++++++++ api/v1/swagger/swagger.yaml | 4 +++ t/db_dependent/api/v1/checkouts.t | 20 ++++++++++- 5 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 api/v1/swagger/definitions/count.yaml diff --git a/Koha/REST/V1/Checkouts.pm b/Koha/REST/V1/Checkouts.pm index a7749f1210..9aa388bd01 100644 --- a/Koha/REST/V1/Checkouts.pm +++ b/Koha/REST/V1/Checkouts.pm @@ -420,4 +420,38 @@ sub allows_renewal { }; } +=head3 get + +count checkout + +=cut + +sub count { + my $c = shift->openapi->valid_input or return; + + my $checked_in = $c->param('checked_in'); + $c->req->params->remove('checked_in'); + + try { + my $checkouts_set; + + if ( $checked_in ) { + $checkouts_set = Koha::Old::Checkouts->new; + } else { + $checkouts_set = Koha::Checkouts->new; + } + + my $count = { + 'count' => scalar(@{ $c->objects->search( $checkouts_set ) }) + }; + + return $c->render( + status => 200, + openapi => $count + ); + } catch { + $c->unhandled_exception($_); + }; +} + 1; diff --git a/api/v1/swagger/definitions/count.yaml b/api/v1/swagger/definitions/count.yaml new file mode 100644 index 0000000000..fd20ca132b --- /dev/null +++ b/api/v1/swagger/definitions/count.yaml @@ -0,0 +1,6 @@ +--- +type: object +properties: + count: + type: string + description: Number of entity that match the request \ No newline at end of file diff --git a/api/v1/swagger/paths/checkouts.yaml b/api/v1/swagger/paths/checkouts.yaml index 5964f61cb7..e6d83f2d51 100644 --- a/api/v1/swagger/paths/checkouts.yaml +++ b/api/v1/swagger/paths/checkouts.yaml @@ -414,3 +414,54 @@ $ref: "../swagger.yaml#/definitions/error" x-koha-authorization: allow-owner: true +"/checkouts/count": + get: + x-mojo-to: Checkouts#count + operationId: countCheckouts + tags: + - checkouts + summary: Count checkouts + parameters: + - $ref: "../swagger.yaml#/parameters/patron_id_qp" + - $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/request_id_header" + - name: checked_in + in: query + description: By default, current checkouts are returned, when this is true then + checked in checkouts are returned as result. + type: boolean + produces: + - application/json + responses: + "200": + description: Count of checkouts + schema: + $ref: "../swagger.yaml#/definitions/count" + "403": + description: Access forbidden + schema: + $ref: "../swagger.yaml#/definitions/error" + "404": + description: Not found + schema: + $ref: "../swagger.yaml#/definitions/error" + "500": + description: | + Internal server error. Possible `error_code` attribute values: + + * `internal_server_error` + schema: + $ref: "../swagger.yaml#/definitions/error" + "503": + description: Under maintenance + schema: + $ref: "../swagger.yaml#/definitions/error" + x-koha-authorization: + permissions: + - circulate: circulate_remaining_permissions + - circulate: manage_bookings diff --git a/api/v1/swagger/swagger.yaml b/api/v1/swagger/swagger.yaml index 9ec3c135d3..16eedfdc3d 100644 --- a/api/v1/swagger/swagger.yaml +++ b/api/v1/swagger/swagger.yaml @@ -162,6 +162,8 @@ definitions: $ref: ./definitions/vendor.yaml vendor_issue: $ref: ./definitions/vendor_issue.yaml + count: + $ref: ./definitions/count.yaml paths: /acquisitions/baskets/managers: $ref: ./paths/acquisitions_baskets.yaml#/~1acquisitions~1baskets~1managers @@ -263,6 +265,8 @@ paths: $ref: "./paths/checkouts.yaml#/~1checkouts~1{checkout_id}~1renewal" "/checkouts/availability": $ref: "./paths/checkouts.yaml#/~1checkouts~1availability" + "/checkouts/count": + $ref: "./paths/checkouts.yaml#/~1checkouts~1count" /circulation-rules/kinds: $ref: ./paths/circulation-rules.yaml#/~1circulation-rules~1kinds /cities: diff --git a/t/db_dependent/api/v1/checkouts.t b/t/db_dependent/api/v1/checkouts.t index 8f306df0e0..009ab4102d 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 => 108; +use Test::More tests => 120; use Test::MockModule; use Test::Mojo; use t::lib::Mocks; @@ -61,11 +61,19 @@ my $patron_id = $patron->borrowernumber; my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode }; +$t->get_ok( "//$userid:$password@/api/v1/checkouts/count?patron_id=$patron_id" ) + ->status_is(200) + ->json_is('/count' => 0); + $t->get_ok( "//$userid:$password@/api/v1/checkouts?patron_id=$patron_id" ) ->status_is(200) ->json_is([]); my $notexisting_patron_id = $patron_id + 1; +$t->get_ok( "//$userid:$password@/api/v1/checkouts/count?patron_id=$notexisting_patron_id" ) + ->status_is(200) + ->json_is('/count' => 0); + $t->get_ok( "//$userid:$password@/api/v1/checkouts?patron_id=$notexisting_patron_id" ) ->status_is(200) ->json_is([]); @@ -120,6 +128,10 @@ my $date_due3 = Koha::DateUtils::dt_from_string( $issue3->date_due ); my $issue4 = C4::Circulation::AddIssue($patron, $item4->barcode); C4::Circulation::AddReturn($item4->barcode, $branchcode); +$t->get_ok( "//$userid:$password@/api/v1/checkouts/count?patron_id=$patron_id" ) + ->status_is(200) + ->json_is('/count' => 2); + $t->get_ok( "//$userid:$password@/api/v1/checkouts?patron_id=$patron_id" ) ->status_is(200) ->json_is('/0/patron_id' => $patron_id) @@ -160,6 +172,12 @@ $t->get_ok( "//$unauth_userid:$unauth_password@/api/v1/checkouts/" . $issue3->is required_permissions => { circulate => "circulate_remaining_permissions" } }); +$t->get_ok( "//$unauth_userid:$unauth_password@/api/v1/checkouts/count?patron_id=$patron_id") + ->status_is(403)->json_is({ + error => "Authorization failure. Missing required permission(s).", + required_permissions => [{"circulate" => "circulate_remaining_permissions"}, {"circulate" => "manage_bookings"}] + }); + $t->get_ok( "//$userid:$password@/api/v1/checkouts?patron_id=$patron_id") ->status_is(200) ->json_is('/0/patron_id' => $patron_id) -- 2.25.1