Bug 42679: Add GET /patrons/{patron_id}/overdues_count endpoint
Returns the count of overdue checkouts for a patron as a plain integer. Computed live from the database (date_due < NOW()) to ensure accuracy, as overdue status is time-based with no discrete event to trigger updates. This endpoint is intended for async loading in the patron search table, allowing the main search results to render immediately while overdues are fetched separately per visible page. Test plan: 1. Apply patch 2. Run: $ ktd --shell k$ prove t/db_dependent/api/v1/patrons_overdues_count.t => SUCCESS: Tests pass! 3. Sign off :-D Signed-off-by: David Nind <david@davidnind.com> Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com> Signed-off-by: Pedro Amorim <pedro.amorim@openfifth.co.uk>
This commit is contained in:
parent
5d75b6fdad
commit
f7caec076f
|
|
@ -503,4 +503,26 @@ sub guarantors_can_see_checkouts {
|
|||
};
|
||||
}
|
||||
|
||||
=head3 overdues_count
|
||||
|
||||
Controller function that returns the count of overdue checkouts for a patron.
|
||||
|
||||
=cut
|
||||
|
||||
sub overdues_count {
|
||||
my $c = shift->openapi->valid_input or return;
|
||||
|
||||
return try {
|
||||
my $patron = Koha::Patrons->find( $c->param('patron_id') );
|
||||
return $c->render_resource_not_found("Patron") unless $patron;
|
||||
|
||||
return $c->render(
|
||||
status => 200,
|
||||
openapi => $patron->overdues->count,
|
||||
);
|
||||
} catch {
|
||||
$c->unhandled_exception($_);
|
||||
};
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
|||
|
|
@ -740,3 +740,43 @@
|
|||
x-koha-authorization:
|
||||
permissions:
|
||||
ill: "1"
|
||||
|
||||
"/patrons/{patron_id}/overdues_count":
|
||||
get:
|
||||
x-mojo-to: Patrons#overdues_count
|
||||
operationId: getPatronOverduesCount
|
||||
tags:
|
||||
- patrons
|
||||
summary: Get count of overdue checkouts for a patron
|
||||
parameters:
|
||||
- $ref: "../swagger.yaml#/parameters/patron_id_pp"
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: Overdue count
|
||||
schema:
|
||||
type: integer
|
||||
"400":
|
||||
description: Bad request
|
||||
schema:
|
||||
$ref: "../swagger.yaml#/definitions/error"
|
||||
"401":
|
||||
description: Authentication required
|
||||
schema:
|
||||
$ref: "../swagger.yaml#/definitions/error"
|
||||
"403":
|
||||
description: Access forbidden
|
||||
schema:
|
||||
$ref: "../swagger.yaml#/definitions/error"
|
||||
"404":
|
||||
description: Patron not found
|
||||
schema:
|
||||
$ref: "../swagger.yaml#/definitions/error"
|
||||
"500":
|
||||
description: Internal server error
|
||||
schema:
|
||||
$ref: "../swagger.yaml#/definitions/error"
|
||||
x-koha-authorization:
|
||||
permissions:
|
||||
- borrowers: "list_borrowers"
|
||||
|
|
|
|||
|
|
@ -549,6 +549,8 @@ paths:
|
|||
$ref: ./paths/patrons.yaml#/~1patrons
|
||||
"/patrons/{patron_id}":
|
||||
$ref: "./paths/patrons.yaml#/~1patrons~1{patron_id}"
|
||||
"/patrons/{patron_id}/overdues_count":
|
||||
$ref: "./paths/patrons.yaml#/~1patrons~1{patron_id}~1overdues_count"
|
||||
"/patrons/{patron_id}/account":
|
||||
$ref: "./paths/patrons_account.yaml#/~1patrons~1{patron_id}~1account"
|
||||
"/patrons/{patron_id}/account/credits":
|
||||
|
|
@ -1515,6 +1517,9 @@ tags:
|
|||
- description: "Manage search field mappings"
|
||||
name: search_mappings
|
||||
x-displayName: Search mappings
|
||||
- description: "Search patrons via Elasticsearch"
|
||||
name: search
|
||||
x-displayName: Search
|
||||
- description: "Manage SIP2 accounts"
|
||||
name: sip2_accounts
|
||||
x-displayName: SIP2 Accounts
|
||||
|
|
|
|||
|
|
@ -0,0 +1,94 @@
|
|||
#!/usr/bin/env perl
|
||||
|
||||
# This file is part of Koha.
|
||||
#
|
||||
# Koha is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Koha is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Koha; if not, see <https://www.gnu.org/licenses>.
|
||||
|
||||
use Modern::Perl;
|
||||
|
||||
use Test::NoWarnings;
|
||||
use Test::More tests => 3;
|
||||
use Test::Mojo;
|
||||
|
||||
use t::lib::TestBuilder;
|
||||
use t::lib::Mocks;
|
||||
|
||||
use Koha::Checkouts;
|
||||
use Koha::Database;
|
||||
use Koha::DateUtils qw( dt_from_string );
|
||||
|
||||
my $schema = Koha::Database->new->schema;
|
||||
my $builder = t::lib::TestBuilder->new;
|
||||
|
||||
t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
|
||||
|
||||
my $t = Test::Mojo->new('Koha::REST::V1');
|
||||
|
||||
subtest 'overdues_count unauthorized' => sub {
|
||||
plan tests => 2;
|
||||
|
||||
$schema->storage->txn_begin;
|
||||
|
||||
my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
|
||||
|
||||
$t->get_ok( "/api/v1/patrons/" . $patron->borrowernumber . "/overdues_count" )->status_is(401);
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
|
||||
subtest 'overdues_count' => sub {
|
||||
plan tests => 8;
|
||||
|
||||
$schema->storage->txn_begin;
|
||||
|
||||
my $librarian = $builder->build_object(
|
||||
{
|
||||
class => 'Koha::Patrons',
|
||||
value => { flags => 2**4 } # borrowers flag
|
||||
}
|
||||
);
|
||||
my $password = 'thePassword123';
|
||||
$librarian->set_password( { password => $password, skip_validation => 1 } );
|
||||
my $userid = $librarian->userid;
|
||||
|
||||
my $patron = $builder->build_object( { class => 'Koha::Patrons' } );
|
||||
|
||||
# No checkouts - 0 overdues
|
||||
$t->get_ok( "//$userid:$password\@/api/v1/patrons/" . $patron->borrowernumber . "/overdues_count" )
|
||||
->status_is(200)
|
||||
->json_is(0);
|
||||
|
||||
# Add an overdue checkout
|
||||
my $item = $builder->build_sample_item();
|
||||
$builder->build(
|
||||
{
|
||||
source => 'Issue',
|
||||
value => {
|
||||
borrowernumber => $patron->borrowernumber,
|
||||
itemnumber => $item->itemnumber,
|
||||
date_due => '2020-01-01 00:00:00',
|
||||
branchcode => $patron->branchcode,
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
$t->get_ok( "//$userid:$password\@/api/v1/patrons/" . $patron->borrowernumber . "/overdues_count" )
|
||||
->status_is(200)
|
||||
->json_is(1);
|
||||
|
||||
# Non-existent patron
|
||||
$t->get_ok("//$userid:$password\@/api/v1/patrons/999999999/overdues_count")->status_is(404);
|
||||
|
||||
$schema->storage->txn_rollback;
|
||||
};
|
||||
Loading…
Reference in New Issue