From 4688d2da06cea6e65d2e098721a0cc1dba788d65 Mon Sep 17 00:00:00 2001 From: Agustin Moyano Date: Tue, 10 Mar 2020 15:24:47 -0300 Subject: [PATCH] Bug 20936: Add patron's hold history menu in OPAC This patch adds patron's hold history in OPAC. Right now, it only shows records from old_reserves table, but I'll wait till bug 20271 is pushed to show full history (old and new holds) To test: 1. apply this patch 2. Find a patron, place several holds and cancel or fulfill them 3. Go to patron's opac CHECK => There is no 'your holds history' option in menu 4. In admin preferences enable OPACHoldsHistory 5. Go back to patron's opac SUCCESS => There is a 'your holds history' menu option => Holds history displays all holds canceled or fulfilled 6. Filter, order and change page SUCCESS => All controls work as expected 7. Sign off. Table content is fetched from the api. If you see data, and you can order and filter then please sign off bug 24561. Date columns use $date function to transform dates strings from api (for example '2020-02-20') to 'dateformat' prefernce format ('02/20/20202'). If you change dateformat prefernce and see the changes reflected in date columns, please sign off bug 24455. Signed-off-by: Kyle M Hall --- Koha/REST/V1/Patrons/Holds.pm | 80 ++++++ api/v1/swagger/paths.json | 3 + api/v1/swagger/paths/public_patrons.json | 188 ++++++++++++++ .../bootstrap/en/includes/usermenu.inc | 24 +- .../bootstrap/en/modules/opac-holdsrecord.tt | 239 ++++++++++++++++++ opac/opac-holdsrecord.pl | 63 +++++ 6 files changed, 590 insertions(+), 7 deletions(-) create mode 100644 Koha/REST/V1/Patrons/Holds.pm create mode 100644 koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-holdsrecord.tt create mode 100755 opac/opac-holdsrecord.pl diff --git a/Koha/REST/V1/Patrons/Holds.pm b/Koha/REST/V1/Patrons/Holds.pm new file mode 100644 index 0000000000..5eb20cfa98 --- /dev/null +++ b/Koha/REST/V1/Patrons/Holds.pm @@ -0,0 +1,80 @@ +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 { + if ( blessed $_ && $_->isa('Koha::Exceptions') ) { + return $c->render( + status => 500, + openapi => { error => "$_" } + ); + } + else { + return $c->render( + status => 500, + openapi => { error => "Something went wrong, check Koha logs for details." } + ); + } + }; +} + +1; \ No newline at end of file diff --git a/api/v1/swagger/paths.json b/api/v1/swagger/paths.json index 0631ecb53b..8147952f75 100644 --- a/api/v1/swagger/paths.json +++ b/api/v1/swagger/paths.json @@ -104,6 +104,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" }, diff --git a/api/v1/swagger/paths/public_patrons.json b/api/v1/swagger/paths/public_patrons.json index 5db073c4eb..a62b8e6ede 100644 --- a/api/v1/swagger/paths/public_patrons.json +++ b/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" + ] + } } } \ No newline at end of file diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/includes/usermenu.inc b/koha-tmpl/opac-tmpl/bootstrap/en/includes/usermenu.inc index f1cdfa5ab2..7f06967756 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/includes/usermenu.inc +++ b/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 %] diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-holdsrecord.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-holdsrecord.tt new file mode 100644 index 0000000000..91888b8e59 --- /dev/null +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-holdsrecord.tt @@ -0,0 +1,239 @@ +[% 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-holdsrecord' %] +[% INCLUDE 'masthead.inc' %] + +
    + + +
    +
    +
    + +
    +
    +
    +

    Holds history

    + + [% IF READING_RECORD.size == 0 %] + You have never placed a hold from this library. + [% ELSE %] +
    +
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + +
    TitleAuthorBarcodeLibraryHold dateExpiration dateWaiting dateCancellation dateStatus
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    + [% END # / IF READING_RECORD.size %] +
    +
    +
    +
    +
    + +[% INCLUDE 'opac-bottom.inc' %] +[% BLOCK jsinclude %] +[% INCLUDE 'datatables.inc' %] +[% INCLUDE 'js-date-format.inc' %] + +[% END %] diff --git a/opac/opac-holdsrecord.pl b/opac/opac-holdsrecord.pl new file mode 100755 index 0000000000..c9a2d83ded --- /dev/null +++ b/opac/opac-holdsrecord.pl @@ -0,0 +1,63 @@ +#!/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::Koha; +use C4::Biblio; +use C4::Circulation; +use C4::Members; +use Koha::DateUtils; +use MARC::Record; + +use C4::Output; +use C4::Charset qw(StripNonXmlChars); +use Koha::Patrons; + +use Koha::ItemTypes; +use Koha::Ratings; + +my $query = new CGI; + +# if opacreadinghistory is disabled, leave immediately +if ( ! C4::Context->preference('OPACHoldsHistory') ) { + print $query->redirect("/cgi-bin/koha/errors/404.pl"); + exit; +} + +my ( $template, $borrowernumber, $cookie ) = get_template_and_user( + { + template_name => "opac-holdsrecord.tt", + query => $query, + type => "opac", + debug => 1, + } +); + +my $borr = Koha::Patrons->find( $borrowernumber )->unblessed; + +$template->param(%{$borr}); + +$template->param( + holdsrecview => 1, +); + +output_html_with_http_headers $query, $cookie, $template->output, undef, { force_no_caching => 1 }; -- 2.25.0