@@ -, +, @@ => Holds history displays all holds canceled or fulfilled --- Koha/REST/V1/Patrons/Holds.pm | 69 +++++ api/v1/swagger/paths.json | 3 + api/v1/swagger/paths/public_patrons.json | 188 ++++++++++++++ .../bootstrap/en/includes/usermenu.inc | 24 +- .../bootstrap/en/modules/opac-holdshistory.tt | 235 ++++++++++++++++++ opac/opac-holdshistory.pl | 50 ++++ 6 files changed, 562 insertions(+), 7 deletions(-) create mode 100644 Koha/REST/V1/Patrons/Holds.pm create mode 100644 koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-holdshistory.tt create mode 100755 opac/opac-holdshistory.pl --- a/Koha/REST/V1/Patrons/Holds.pm +++ a/Koha/REST/V1/Patrons/Holds.pm @@ -0,0 +1,69 @@ +package Koha::REST::V1::Patrons::Holds; + +# 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 +# along with Koha; if not, see . + +use Modern::Perl; + +use Mojo::Base 'Mojolicious::Controller'; + +use Koha::Patrons; + +use Scalar::Util qw(blessed); +use Koha::DateUtils; +use Try::Tiny; + +=head1 NAME + +Koha::REST::V1::Patrons::Holds + +=head1 API + +=head2 Methods + +=head3 list + +Mehtod that handles listing patron's holds + +=cut + +sub list { + my $c = shift->openapi->valid_input or return; + my $patron_id = $c->validation->param('patron_id'); + my $old = $c->validation->param('old'); + my $patron = Koha::Patrons->find($patron_id); + + unless ($patron) { + return $c->render( status => 404, openapi => { error => "Patron not found." } ); + } + + return try { + my $holds_set; + if($old) { + $holds_set = Koha::Old::Holds->new; + } else { + $holds_set = Koha::Holds->new; + } + + delete $c->validation->output->{old}; + #$c->stash_embed( {spec => $c->match->endpoint->pattern->defaults->{'openapi.op_spec'}} ); + my $holds = $c->objects->search( $holds_set ); + return $c->render( status => 200, openapi => $holds ); + } + catch { + $c->unhandled_exception($_); + }; +} + +1; --- a/api/v1/swagger/paths.json +++ a/api/v1/swagger/paths.json @@ -107,6 +107,9 @@ "/public/patrons/{patron_id}/guarantors/can_see_checkouts": { "$ref": "paths/public_patrons.json#/~1public~1patrons~1{patron_id}~1guarantors~1can_see_checkouts" }, + "/public/patrons/{patron_id}/holds": { + "$ref": "paths/public_patrons.json#/~1public~1patrons~1{patron_id}~1holds" + }, "/return_claims": { "$ref": "paths/return_claims.json#/~1return_claims" }, --- a/api/v1/swagger/paths/public_patrons.json +++ a/api/v1/swagger/paths/public_patrons.json @@ -236,5 +236,193 @@ "allow-owner": true } } + }, + "/public/patrons/{patron_id}/holds": { + "get": { + "x-mojo-to": "Patrons::Holds#list", + "operationId": "listPatronsOldHolds", + "tags": [ + "patron" + ], + "parameters": [ + { + "$ref": "../parameters.json#/patron_id_pp" + }, + { + "name": "hold_id", + "in": "query", + "description": "Internal reserve identifier", + "type": "integer" + }, + { + "name": "hold_date", + "in": "query", + "description": "Hold", + "type": "string", + "format": "date" + }, + { + "name": "biblio_id", + "in": "query", + "description": "Internal biblio identifier", + "type": "integer" + }, + { + "name": "pickup_library_id", + "in": "query", + "description": "Internal library identifier for the pickup library", + "type": "string" + }, + { + "name": "cancelation_date", + "in": "query", + "description": "The date the hold was cancelled", + "type": "string", + "format": "date" + }, + { + "name": "notes", + "in": "query", + "description": "Notes related to this hold", + "type": "string" + }, + { + "name": "priority", + "in": "query", + "description": "Where in the queue the patron sits", + "type": "integer" + }, + { + "name": "status", + "in": "query", + "description": "Found status", + "type": "string" + }, + { + "name": "timestamp", + "in": "query", + "description": "Time of latest update", + "type": "string" + }, + { + "name": "item_id", + "in": "query", + "description": "Internal item identifier", + "type": "integer" + }, + { + "name": "waiting_date", + "in": "query", + "description": "Date the item was marked as waiting for the patron", + "type": "string" + }, + { + "name": "expiration_date", + "in": "query", + "description": "Date the hold expires", + "type": "string" + }, + { + "name": "lowest_priority", + "in": "query", + "description": "Lowest priority", + "type": "boolean" + }, + { + "name": "suspended", + "in": "query", + "description": "Suspended", + "type": "boolean" + }, + { + "name": "suspended_until", + "in": "query", + "description": "Suspended until", + "type": "string" + }, + { + "name": "old", + "in": "query", + "description": "Fetch holds history", + "type": "boolean" + }, + { + "$ref": "../parameters.json#/match" + }, + { + "$ref": "../parameters.json#/order_by" + }, + { + "$ref": "../parameters.json#/page" + }, + { + "$ref": "../parameters.json#/per_page" + }, + { + "$ref": "../parameters.json#/q_param" + }, + { + "$ref": "../parameters.json#/q_body" + }, + { + "$ref": "../parameters.json#/q_header" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "List of holds history", + "schema": { + "$ref": "../definitions.json#/holds" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "401": { + "description": "Authentication required", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "404": { + "description": "Patron not found", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "503": { + "description": "Under maintenance", + "schema": { + "$ref": "../definitions.json#/error" + } + } + }, + "x-koha-authorization": { + "allow-owner": true + }, + "x-koha-embed": [ + "item", + "biblio", + "branch" + ] + } } } --- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/usermenu.inc +++ a/koha-tmpl/opac-tmpl/bootstrap/en/includes/usermenu.inc @@ -58,14 +58,24 @@ your search history [% END %] - [% IF ( opacreadinghistory ) %] - [% IF ( readingrecview ) %] -
  • - [% ELSE %] -
  • + [% IF opacreadinghistory || Koha.Preference('OPACHoldsHistory') == 1 %] + [% IF opacreadinghistory %] + [% IF ( readingrecview ) %] +
  • + [% ELSE %] +
  • + [% END %] + your reading history
  • + [% END %] + [% IF Koha.Preference('OPACHoldsHistory') == 1 %] + [% IF ( holdsrecview ) %] +
  • + [% ELSE %] +
  • + [% END %] + your holds history
  • [% END %] - your reading history - [% IF ( OPACPrivacy ) %] + [% IF ( OPACPrivacy || Koha.Preference('OPACHoldsPrivacy') == 1 ) %] [% IF ( privacyview ) %]
  • [% ELSE %] --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-holdshistory.tt +++ a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-holdshistory.tt @@ -0,0 +1,235 @@ +[% USE raw %] +[% USE Koha %] +[% USE KohaDates %] +[% INCLUDE 'doc-head-open.inc' %] +[% IF ( LibraryNameTitle ) %][% LibraryNameTitle | html %][% ELSE %]Koha online[% END %] catalog › Your holds history +[% INCLUDE 'doc-head-close.inc' %] +[% BLOCK cssinclude %] + +[% END %] + +[% INCLUDE 'bodytag.inc' bodyid='opac-holdshistory' %] +[% INCLUDE 'masthead.inc' %] + +
    + + +
    +
    +
    + +
    +
    +
    +

    Holds history

    + + [% IF old_holds_count == 0 %] + You have never placed a hold from this library. + [% ELSE %] +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + +
    TitleAuthorBarcodeLibraryHold dateExpiration dateWaiting dateCancellation dateStatus
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + [% END # / IF old_holds_count %] +
    +
    +
    +
    +
    + +[% INCLUDE 'opac-bottom.inc' %] +[% BLOCK jsinclude %] +[% INCLUDE 'datatables.inc' %] +[% INCLUDE 'js-date-format.inc' %] + +[% END %] --- a/opac/opac-holdshistory.pl +++ a/opac/opac-holdshistory.pl @@ -0,0 +1,50 @@ +#!/usr/bin/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 . + + +use Modern::Perl; + +use CGI qw ( -utf8 ); + +use C4::Auth; +use C4::Output; + +use Koha::Patrons; + +my $query = new CGI; + +# if opacreadinghistory is disabled, leave immediately +unless ( C4::Context->preference('OPACHoldsHistory') ) { + print $query->redirect("/cgi-bin/koha/errors/404.pl"); + exit; +} + +my ( $template, $patron_id, $cookie ) = get_template_and_user( + { + template_name => "opac-holdshistory.tt", + query => $query, + type => "opac" + } +); + +my $patron = Koha::Patrons->find( $patron_id ); + +$template->param( + old_holds_count => $patron->old_holds->count, +); + +output_html_with_http_headers $query, $cookie, $template->output, undef, { force_no_caching => 1 }; --