+ [% IF ( recall.in_transit ) %]
+ In transit to [% recall.library.branchname | html %]
+ [% ELSIF ( recall.waiting ) %]
+ Ready for pickup
+ [% ELSIF ( recall.expired ) %]
+ Expired on [% recall.expirationdate | $KohaDates %]
+ [% ELSIF ( recall.cancelled ) %]
+ Cancelled on [% recall.cancellationdate | $KohaDates %]
+ [% ELSIF ( recall.overdue ) %]
+ Overdue to be returned
+ [% ELSIF ( recall.finished ) %]
+ Fulfilled
+ [% ELSE %]
+ Requested
+ [% END %]
+
+
+ [% UNLESS viewing_old %]
+
+ [% IF recall.requested and recall.checkout %]
+ Due to be returned by [% recall.checkout.date_due | $KohaDates %]
+ [% ELSIF recall.waiting and RECALL.expirationdate %]
+ Pick up by [% RECALL.expirationdate | $KohaDates %]
+ [% ELSE %]
+ -
+ [% END %]
+
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt
+++ a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt
@@ -497,14 +497,22 @@ Note that permanent location is a code, and location may be an authval.
There is an item level hold on this item (priority = [% hold.priority | html %]).
[% END %]
[% END %]
- [% UNLESS ( item.itemnotforloan || item.notforloan_per_itemtype || item.onloan || item.itemlost || item.withdrawn || item.damaged || item.transfertwhen || hold ) %]
- Available
+
+ [% IF item.recalled %]
+ [% IF item.recall.waitingdate %]
+ Waiting at [% Branches.GetName( item.recall.branchcode ) | html %] since [% item.recall.waitingdate | $KohaDates %]
+ [% ELSE %]
+ Item recalled by [% item.recall.patron.firstname | html %] [% item.recall.patron.surname | html %] ([% item.recall.patron.cardnumber | html %]) on [% item.recall.recalldate | $KohaDates %]
+ [% END %]
+ [% END %]
+
+ [% UNLESS ( item.itemnotforloan || item.notforloan_per_itemtype || item.onloan || item.itemlost || item.withdrawn || item.damaged || item.transfertwhen || hold || item.recalled ) %]
+ Available
[% END %]
[% IF ( item.restricted ) %]
([% item.restrictedvalue | html %])
[% END %]
-
[% item.datelastseen | $KohaDates %]
[% item.dateaccessioned | $KohaDates %]
@@ -1038,6 +1046,7 @@ Note that permanent location is a code, and location may be an authval.
[% MACRO jsinclude BLOCK %]
[% INCLUDE 'catalog-strings.inc' %]
[% Asset.js("js/catalog.js") | $raw %]
+ [% Asset.js("js/recalls.js") | $raw %]
[% Asset.js("js/coce.js") | $raw %]
[% Asset.js("lib/Chocolat/js/chocolat.js") | $raw %]
[% INCLUDE 'str/members-menu.inc' %]
[% Asset.js("js/members-menu.js") | $raw %]
+ [% Asset.js("js/recalls.js") | $raw %]
[% END %]
[% INCLUDE 'intranet-bottom.inc' %]
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/printslip.tt
+++ a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/printslip.tt
@@ -8,6 +8,8 @@
Transfers print receipt › Circulation › Koha
[% ELSIF ( caller == 'members' ) %]
Print receipt for [% borrowernumber | html %] › Patrons › Koha
+[% ELSIF ( caller == 'recall' ) %]
+Recall print receipt › Circulation &rsqaquo; Koha
[% ELSIF ( title ) %][%# FIXME title is never defined %]
[% title | html %] › Patrons › Koha
[% END %]
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/renew.tt
+++ a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/renew.tt
@@ -164,6 +164,9 @@
[% ELSIF error == "onsite_checkout" %]
Item cannot be renewed because it's an onsite checkout
+ [% ELSIF error == 'recalled' %]
+
This item has been recalled.
+
[% ELSE %]
[% error | html %]
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt
+++ a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt
@@ -625,7 +625,7 @@
[% END # /IF transfer || needstransfer %]
- [% IF ( reserved ) %]
+ [% IF ( reserved and !recalled and !waitingrecall ) %]
@@ -737,6 +737,199 @@
[% END #/IF reserved %]
+
+ [% IF ( recalled ) %]
+
+
+
+
+
+
+
+
+ [% END #/IF recalled %]
+
+ [% IF ( waitingrecall ) %]
+
+
+
+
+
+
+
+
+ [% END #/IF recalledwaiting %]
[% END # /IF found %]
@@ -1030,6 +1223,11 @@
[% END %]
[% END %]
var columns_settings = [% TablesSettings.GetColumns( 'circ', 'returns', 'checkedintable', 'json' ) | $raw %]
+
+ [% IF recall_slip %]
+ Dopop('/cgi-bin/koha/recalls/recall_pickup_slip.pl?recall_id=[% recall_id | uri %]');
+ [% END %]
+
var returns_table = KohaTable("checkedintable", {
"bFilter":false,
"bPaginate":false,
@@ -1113,6 +1311,11 @@
this.form.submit();
});
+ $('.print-recall').on("click",function(e){
+ this.form.recall_slip.value = 1;
+ this.form.submit();
+ });
+
$('.cancel-hold').on("click",function(e){
this.form.cancel_reserve.value = 1;
this.form.submit();
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/transferstoreceive.tt
+++ a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/transferstoreceive.tt
@@ -82,6 +82,8 @@
[% reser.patron.first_valid_email_address | html %]
[% END %]
+ [% ELSIF ( reser.recall ) %]
+ Recall requested by [% reser.recall.patron.surname | html %][% IF reser.recall.patron.firstname %], [% reser.recall.patron.firstname | html %][% END %] ([% reser.recall.patron.cardnumber | html %])
[% ELSE %]
None
[% END %]
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt
+++ a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt
@@ -741,6 +741,14 @@
[% END %]
+
+ [% IF Koha.Preference('UseRecalls') %]
+
[% END # /IF exceeded_maxreserves %]
[% ELSE # UNLESS multi_hold %]
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt
+++ a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt
@@ -96,6 +96,8 @@
[% CASE 'NOTICES' %]Notices[% UNLESS Koha.Preference('NoticesLog') %] [% END %]
[% CASE 'NEWS' %]News[% UNLESS Koha.Preference('NewsLog') %] [% END %]
+[% CASE 'RECALLS' %]Recalls[% UNLESS Koha.Preference('RecallsLog') %] [% END %]
+
[% CASE %][% module | html %]
[% END %]
[% END %]
@@ -142,6 +144,9 @@
[% CASE 'SERIAL CLAIM' %]Serial claim
[% CASE 'ACQUISITION CLAIM' %]Acquisition claim
[% CASE 'ACQUISITION ORDER' %]Acquisition order
+[% CASE 'FULFILL' %]Fulfill
+[% CASE 'OVERDUE' %]Overdue
+[% CASE 'EXPIRE' %]Expire
[% CASE %][% action | html %]
[% END %]
[% END %]
@@ -212,7 +217,7 @@
[% ELSE %]
[% END %]
- [% FOREACH modx IN [ 'AUTH' 'CATALOGUING' 'AUTHORITIES' 'MEMBERS' 'ACQUISITIONS' 'SERIAL' 'HOLDS' 'ILL' 'CIRCULATION' 'CLAIMS' 'FINES' 'SYSTEMPREFERENCE' 'CRONJOBS', 'REPORTS', 'SEARCHENGINE', 'NOTICES', 'NEWS' ] %]
+ [% FOREACH modx IN [ 'AUTH' 'CATALOGUING' 'AUTHORITIES' 'MEMBERS' 'ACQUISITIONS' 'SERIAL' 'HOLDS' 'ILL' 'CIRCULATION' 'CLAIMS' 'FINES' 'SYSTEMPREFERENCE' 'CRONJOBS', 'REPORTS', 'SEARCHENGINE', 'NOTICES', 'NEWS', 'RECALLS' ] %]
[% IF modules.grep(modx).size %]
[% ELSE %]
@@ -234,7 +239,7 @@
[% END %]
- [% FOREACH actx IN [ 'ADD' 'DELETE' 'MODIFY' 'ISSUE' 'RETURN' 'RENEW' 'CREATE' 'CANCEL' 'SUSPEND' 'RESUME' 'ADDCIRCMESSAGE' 'DELCIRCMESSAGE' 'STATUS_CHANGE' 'PATRON_NOTICE' 'CHANGE PASS' 'Run' 'EDIT_MAPPINGS' 'RESET_MAPPINGS' 'ADD_BASKET' 'MODIFY_BASKET' 'MODIFY_BASKET_HEADER' 'MODIFY_BASKET_USERS' 'CLOSE_BASKET' 'APPROVE_BASKET' 'REOPEN_BASKET' 'CANCEL_ORDER' 'CREATE_ORDER' 'MODIFY_ORDER' 'CREATE_INVOICE_ADJUSTMENT' 'UPDATE_INVOICE_ADJUSTMENT' 'DELETE_INVOICE_ADJUSTMENT' 'RECEIVE_ORDER' 'MODIFY_BUDGET' 'MODIFY_FUND' 'CREATE_FUND' 'DELETE_FUND' ] %]
+ [% FOREACH actx IN [ 'ADD' 'DELETE' 'MODIFY' 'ISSUE' 'RETURN' 'RENEW' 'CREATE' 'CANCEL' 'SUSPEND' 'RESUME' 'ADDCIRCMESSAGE' 'DELCIRCMESSAGE' 'STATUS_CHANGE' 'PATRON_NOTICE' 'CHANGE PASS' 'Run' 'EDIT_MAPPINGS' 'RESET_MAPPINGS' 'ADD_BASKET' 'MODIFY_BASKET' 'MODIFY_BASKET_HEADER' 'MODIFY_BASKET_USERS' 'CLOSE_BASKET' 'APPROVE_BASKET' 'REOPEN_BASKET' 'CANCEL_ORDER' 'CREATE_ORDER' 'MODIFY_ORDER' 'CREATE_INVOICE_ADJUSTMENT' 'UPDATE_INVOICE_ADJUSTMENT' 'DELETE_INVOICE_ADJUSTMENT' 'RECEIVE_ORDER' 'MODIFY_BUDGET' 'MODIFY_FUND' 'CREATE_FUND' 'DELETE_FUND' 'OVERDUE' 'EXPIRE' 'FULFILL' ] %]
[% IF actions.grep(actx).size %]
[% ELSE %]
@@ -365,6 +370,12 @@
[% ELSE %]
[% loopro.object | html %]
[% END %]
+ [% ELSIF ( loopro.module == 'RECALLS' ) %]
+ [% IF loopro.recall.item_level_recall %]
+ Item-level recall on item
+ [% ELSE %]
+ Biblio-level recall on biblio
+ [% END %]
[% ELSE %]
[% loopro.object | html %]
[% END %]
--- a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js
+++ a/koha-tmpl/intranet-tmpl/prog/js/checkouts.js
@@ -368,6 +368,10 @@ $(document).ready(function() {
onsite_checkout += " (" + __("On-site checkout") + ")";
}
+ if ( oObj.recalled == 1 ) {
+ title += " - This item has been recalled and the due date updated.";
+ }
+
title += " "
+ "" + RECALLED + ""
+ + "";
+
+ span_style = "display: none";
+ span_class = "renewals-allowed-recalled";
} else if ( oObj.can_renew_error == "on_reserve" ) {
msg += ""
+"" + __("On hold") + ""
@@ -591,7 +602,9 @@ $(document).ready(function() {
"bSortable": false,
"bVisible": AllowCirculate ? true : false,
"mDataProp": function ( oObj ) {
- if ( oObj.can_renew_error == "on_reserve" ) {
+ if ( oObj.can_renew_error == "recalled" ) {
+ return "" + __("Recalled") + "";
+ } else if ( oObj.can_renew_error == "on_reserve" ) {
return "" + __("On hold") + "";
} else if ( oObj.materials ) {
return "";
--- a/koha-tmpl/intranet-tmpl/prog/js/recalls.js
+++ a/koha-tmpl/intranet-tmpl/prog/js/recalls.js
@@ -0,0 +1,175 @@
+$(document).ready(function() {
+
+ $(".cancel_recall").click(function(e){
+ if (confirmDelete(__("Are you sure you want to remove this recall?"))){
+ var $self = $(this);
+ var $recall_id = $(this).data('id');
+ var $action = $(this).data('action');
+ var ajaxData = {
+ 'recall_id': $recall_id,
+ 'action' : $action,
+ };
+
+ $.ajax({
+ url: '/cgi-bin/koha/svc/recall',
+ type: 'POST',
+ dataType: 'json',
+ data: ajaxData,
+ })
+ .done(function(data) {
+ var message = "";
+ if(data.success == 0) {
+ message = __("The recall may have already been cancelled. Please refresh the page.");
+ } else {
+ message = __("Cancelled");
+ }
+ $self.parent().parent().parent().parent().html(message);
+ });
+ }
+ });
+
+ $(".expire_recall").click(function(e){
+ if (confirmDelete(__("Are you sure you want to expire this recall?"))){
+ var $self = $(this);
+ var $recall_id = $(this).data('id');
+ var $action = $(this).data('action');
+ var ajaxData = {
+ 'recall_id': $recall_id,
+ 'action' : $action,
+ };
+
+ $.ajax({
+ url: '/cgi-bin/koha/svc/recall',
+ type: 'POST',
+ dataType: 'json',
+ data: ajaxData,
+ })
+ .done(function(data) {
+ var message = "";
+ if(data.success == 0) {
+ message = __("The recall may have already been expired. Please refresh the page.");
+ } else {
+ message = __("Expired");
+ }
+ $self.parent().parent().parent().parent().html(message);
+ });
+ }
+ });
+
+ $(".revert_recall").click(function(e){
+ if (confirmDelete(__("Are you sure you want to revert the waiting status of this recall?"))){
+ var $self = $(this);
+ var $recall_id = $(this).data('id');
+ var $action = $(this).data('action');
+ var ajaxData = {
+ 'recall_id': $recall_id,
+ 'action' : $action,
+ };
+
+ $.ajax({
+ url: '/cgi-bin/koha/svc/recall',
+ type: 'POST',
+ dataType: 'json',
+ data: ajaxData,
+ })
+ .done(function(data) {
+ var message = "";
+ if(data.success == 0) {
+ message = __("The recall waiting status may have already been reverted. Please refresh the page.");
+ } else {
+ message = __("Status updated");
+ }
+ $self.parent().parent().parent().parent().html(message);
+ });
+ }
+ });
+
+ $(".overdue_recall").click(function(e){
+ if (confirmDelete(__("Are you sure you want to mark this recall as overdue?"))){
+ var $self = $(this);
+ var $recall_id = $(this).data('id');
+ var $action = $(this).data('action');
+ var ajaxData = {
+ 'recall_id': $recall_id,
+ 'action' : $action,
+ };
+
+ $.ajax({
+ url: '/cgi-bin/koha/svc/recall',
+ type: 'POST',
+ dataType: 'json',
+ data: ajaxData,
+ })
+ .done(function(data) {
+ var message = "";
+ if(data.success == 0) {
+ message = __("The recall may have already been marked as overdue. Please refresh the page.");
+ } else {
+ message = __("Marked overdue");
+ }
+ $self.parent().parent().parent().parent().html(message);
+ });
+ }
+ });
+
+ $(".transit_recall").click(function(e){
+ if (confirmDelete(__("Are you sure you want to remove this recall and return the item to it's home library?"))){
+ var $self = $(this);
+ var $recall_id = $(this).data('id');
+ var $action = $(this).data('action');
+ var ajaxData = {
+ 'recall_id': $recall_id,
+ 'action' : $action,
+ };
+
+ $.ajax({
+ url: '/cgi-bin/koha/svc/recall',
+ type: 'POST',
+ dataType: 'json',
+ data: ajaxData,
+ })
+ .done(function(data) {
+ var message = "";
+ if(data.success == 0) {
+ message = __("The recall may have already been removed. Please refresh the page.");
+ } else {
+ message = __("Cancelled");
+ }
+ $self.parent().parent().parent().parent().html(message);
+ });
+ }
+ });
+
+ $("#recalls-table").dataTable($.extend(true, {}, dataTablesDefaults, {
+ "aoColumnDefs": [
+ { 'bSortable': false, 'aTargets': [ 'nosort' ] },
+ { "sType": "title-string", "aTargets" : [ "title-string" ] },
+ { "sType": "anti-the", "aTargets": [ "anti-the" ] }
+ ],
+ "sPaginationType": "full_numbers"
+ }));
+
+ $("#cancel_selected").click(function(e){
+ if ($("input[name='recall_ids']:checked").length > 0){
+ return confirmDelete(__("Are you sure you want to remove the selected recall(s)?"));
+ } else {
+ alert(__("Please make a selection."));
+ }
+ });
+
+ $("#select_all").click(function(){
+ if ($("#select_all").prop("checked")){
+ $("input[name='recall_ids']").prop("checked", true);
+ } else {
+ $("input[name='recall_ids']").prop("checked", false);
+ }
+ });
+
+ $("#hide_old").click(function(){
+ if ($("#hide_old").prop("checked")){
+ $(".old").show();
+ } else {
+ $(".old").hide();
+ }
+ });
+});
--- a/members/moremember.pl
+++ a/members/moremember.pl
@@ -273,6 +273,8 @@ $template->param(
files => Koha::Patron::Files->new( borrowernumber => $borrowernumber ) ->GetFilesInfo(),
#debarments => scalar GetDebarments({ borrowernumber => $borrowernumber }),
has_modifications => $has_modifications,
+ recalls => $patron->recalls,
+ specific_patron => 1,
);
output_html_with_http_headers $input, $cookie, $template->output;
--- a/members/recallshistory.pl
+++ a/members/recallshistory.pl
@@ -0,0 +1,47 @@
+#!/usr/bin/perl
+
+# Copyright 2020 Aleisha Amohia
+#
+# 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 qw( get_template_and_user );
+use C4::Output qw( output_html_with_http_headers );
+
+my $input = CGI->new;
+my ($template, $loggedinuser, $cookie)= get_template_and_user(
+ {
+ template_name => "members/recallshistory.tt",
+ query => $input,
+ type => "intranet",
+ authnotrequired => 0,
+ flagsrequired => { recalls => 1 },
+ debug => 1,
+ }
+);
+
+my $borrowernumber = $input->param('borrowernumber');
+my $recalls = Koha::Recalls->search({ borrowernumber => $borrowernumber }, { order_by => { '-desc' => 'recalldate' } });
+my $patron = Koha::Patrons->find( $borrowernumber );
+
+$template->param(
+ patron => $patron,
+ recalls => $recalls,
+ recallsview => 1,
+ specific_patron => 1,
+);
+
+output_html_with_http_headers $input, $cookie, $template->output;
--- a/recalls/recall_pickup_slip.pl
+++ a/recalls/recall_pickup_slip.pl
@@ -0,0 +1,74 @@
+#!/usr/bin/perl
+
+# Copyright 2020 Aleisha Amohia
+#
+# 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::Context;
+use C4::Output qw( output_html_with_http_headers );
+use C4::Auth qw( get_template_and_user );
+
+my $input = new CGI;
+
+my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
+ {
+ template_name => "circ/printslip.tt",
+ query => $input,
+ type => "intranet",
+ authnotrequired => 0,
+ flagsrequired => { circulate => "circulate_remaining_permissions" },
+ }
+);
+
+my $recallid = $input->param('recall_id');
+my $recall = Koha::Recalls->find($recallid);
+
+my $itemnumber;
+if ( $recall->itemnumber ){
+ $itemnumber = $recall->itemnumber;
+} else {
+ $itemnumber = $recall->checkout->itemnumber;
+}
+
+# Print slip to inform library staff of details of recall requester, so the item can be put aside for requester
+my $letter = C4::Letters::GetPreparedLetter(
+ module => 'circulation',
+ letter_code => 'RECALL_REQUESTER_DET',
+ message_transport_type => 'print',
+ tables => {
+ 'branches' => $recall->branchcode,
+ 'borrowers' => $recall->borrowernumber,
+ 'biblio' => $recall->biblionumber,
+ 'items' => $itemnumber,
+ 'recalls' => $recall->recall_id,
+ }
+);
+
+my ($slip, $is_html);
+if ($letter) {
+ $slip = $letter->{content};
+ $is_html = $letter->{is_html};
+}
+
+$template->param(
+ slip => $slip,
+ plain => !$is_html,
+ caller => 'recall',
+);
+
+output_html_with_http_headers $input, $cookie, $template->output;
--- a/recalls/recalls_old_queue.pl
+++ a/recalls/recalls_old_queue.pl
@@ -0,0 +1,47 @@
+#!/usr/bin/perl
+
+# Copyright 2020 Aleisha Amohia
+#
+# 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 qw( get_template_and_user );
+use C4::Output qw( output_html_with_http_headers );
+use Koha::BiblioFrameworks;
+
+my $query = new CGI;
+my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user(
+ {
+ template_name => "recalls/recalls_old_queue.tt",
+ query => $query,
+ type => "intranet",
+ authnotrequired => 0,
+ flagsrequired => { recalls => "manage_recalls" },
+ debug => 1,
+ }
+);
+
+my $recalls = Koha::Recalls->search({ old => 1 });
+$template->param(
+ recalls => $recalls,
+ viewing_old => 1
+);
+
+# Checking if there is a Fast Cataloging Framework
+$template->param( fast_cataloging => 1 ) if Koha::BiblioFrameworks->find( 'FA' );
+
+# writing the template
+output_html_with_http_headers $query, $cookie, $template->output;
--- a/recalls/recalls_overdue.pl
+++ a/recalls/recalls_overdue.pl
@@ -0,0 +1,61 @@
+#!/usr/bin/perl
+
+# Copyright 2020 Aleisha Amohia
+#
+# 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 qw( get_template_and_user );
+use C4::Output qw( output_html_with_http_headers );
+use Koha::BiblioFrameworks;
+use Koha::DateUtils;
+
+my $query = new CGI;
+my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user(
+ {
+ template_name => "recalls/recalls_overdue.tt",
+ query => $query,
+ type => "intranet",
+ authnotrequired => 0,
+ flagsrequired => { recalls => "manage_recalls" },
+ debug => 1,
+ }
+);
+
+my $op = $query->param('op') || 'list';
+my @recall_ids = $query->multi_param('recall_ids');
+
+if ( $op eq 'cancel_multiple_recalls' ) {
+ foreach my $id ( @recall_ids ) {
+ Koha::Recalls->find( $id )->set_cancelled;
+ }
+ $op = 'list'
+}
+
+if ( $op eq 'list' ) {
+ my $recalls = Koha::Recalls->search({ status => 'O' });
+ # will be set as Overdue by the misc/cronjobs/recall/overdue_recalls.pl cronjob
+ $template->param(
+ recalls => $recalls,
+ checkboxes => 1,
+ );
+}
+
+# Checking if there is a Fast Cataloging Framework
+$template->param( fast_cataloging => 1 ) if Koha::BiblioFrameworks->find( 'FA' );
+
+# writing the template
+output_html_with_http_headers $query, $cookie, $template->output;
--- a/recalls/recalls_queue.pl
+++ a/recalls/recalls_queue.pl
@@ -0,0 +1,57 @@
+#!/usr/bin/perl
+
+# Copyright 2020 Aleisha Amohia
+#
+# 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 qw( get_template_and_user );
+use C4::Output qw( output_html_with_http_headers );
+use Koha::BiblioFrameworks;
+
+my $query = new CGI;
+my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user(
+ {
+ template_name => "recalls/recalls_queue.tt",
+ query => $query,
+ type => "intranet",
+ authnotrequired => 0,
+ flagsrequired => { recalls => 'manage_recalls' },
+ debug => 1,
+ }
+);
+
+my $op = $query->param('op') || 'list';
+my @recall_ids = $query->multi_param('recall_ids');
+if ( $op eq 'cancel_multiple_recalls' ) {
+ foreach my $id ( @recall_ids ) {
+ Koha::Recalls->find( $id )->set_cancelled;
+ }
+ $op = 'list'
+}
+elsif ( $op eq 'list' ) {
+ my $recalls = Koha::Recalls->search({ old => undef });
+ $template->param(
+ recalls => $recalls,
+ checkboxes => 1,
+ );
+}
+
+# Checking if there is a Fast Cataloging Framework
+$template->param( fast_cataloging => 1 ) if Koha::BiblioFrameworks->find( 'FA' );
+
+# writing the template
+output_html_with_http_headers $query, $cookie, $template->output;
--- a/recalls/recalls_to_pull.pl
+++ a/recalls/recalls_to_pull.pl
@@ -0,0 +1,126 @@
+#!/usr/bin/perl
+
+# Copyright 2020 Aleisha Amohia
+#
+# 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 qw( get_template_and_user );
+use C4::Output qw( output_html_with_http_headers );
+use Koha::BiblioFrameworks;
+
+my $query = new CGI;
+my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user(
+ {
+ template_name => "recalls/recalls_to_pull.tt",
+ query => $query,
+ type => "intranet",
+ authnotrequired => 0,
+ flagsrequired => { recalls => 'manage_recalls' },
+ debug => 1,
+ }
+);
+
+my $op = $query->param('op') || 'list';
+my $recall_id = $query->param('recall_id');
+if ( $op eq 'cancel' ) {
+ my $recall = Koha::Recalls->find( $recall_id );
+ if ( $recall->in_transit ) {
+ C4::Items::ModItemTransfer( $recall->item->itemnumber, $recall->item->holdingbranch, $recall->item->homebranch, 'CancelRecall' );
+ }
+ $recall->set_cancelled;
+ $op = 'list';
+}
+
+if ( $op eq 'list' ) {
+ my @recalls = Koha::Recalls->search({ status => [ 'R','O','T' ] });
+ my @pull_list;
+ my %seen_bib;
+ foreach my $recall ( @recalls ) {
+ if ( $seen_bib{$recall->biblionumber} ){
+ # we've already looked at the recalls on this biblio
+ next;
+ } else {
+ # this is an unseen biblio
+ $seen_bib{$recall->biblionumber}++;
+
+ # get recall data about this biblio
+ my @this_bib_recalls = Koha::Recalls->search({ biblionumber => $recall->biblionumber, status => [ 'R','O','T' ] }, { order_by => { -asc => 'recalldate' } });
+ my $recalls_count = scalar @this_bib_recalls;
+ my @unique_patrons = do { my %seen; grep { !$seen{$_->borrowernumber}++ } @this_bib_recalls };
+ my $patrons_count = scalar @unique_patrons;
+ my $first_recall = $this_bib_recalls[0];
+
+ my $items_count = 0;
+ my @callnumbers;
+ my @copynumbers;
+ my @enumchrons;
+ my @itemtypes;
+ my @locations;
+ my @libraries;
+
+ my @items = Koha::Items->search({ biblionumber => $recall->biblionumber });
+ foreach my $item ( @items ) {
+ if ( $item->can_be_waiting_recall and !$item->checkout ) {
+ # if item can be pulled to fulfill recall, collect item data
+ $items_count++;
+ push( @callnumbers, $item->itemcallnumber ) if ( $item->itemcallnumber );
+ push( @copynumbers, $item->copynumber ) if ( $item->copynumber );
+ push( @enumchrons, $item->enumchron ) if ( $item->enumchron );
+ push( @itemtypes, $item->effective_itemtype ) if ( $item->effective_itemtype );
+ push( @locations, $item->location ) if ( $item->location );
+ push( @libraries, $item->holdingbranch ) if ( $item->holdingbranch );
+ }
+ }
+
+ if ( $items_count > 0 ) {
+ # don't push data if there are no items available for this recall
+
+ # get unique values
+ my @unique_callnumbers = do { my %seen; grep { !$seen{$_}++ } @callnumbers };
+ my @unique_copynumbers = do { my %seen; grep { !$seen{$_}++ } @copynumbers };
+ my @unique_enumchrons = do { my %seen; grep { !$seen{$_}++ } @enumchrons };
+ my @unique_itemtypes = do { my %seen; grep { !$seen{$_}++ } @itemtypes };
+ my @unique_locations = do { my %seen; grep { !$seen{$_}++ } @locations };
+ my @unique_libraries = do { my %seen; grep { !$seen{$_}++ } @libraries };
+
+ push( @pull_list, {
+ biblio => $recall->biblio,
+ items_count => $items_count,
+ recalls_count => $recalls_count,
+ patrons_count => $patrons_count,
+ pull_count => $items_count <= $recalls_count ? $items_count : $recalls_count,
+ first_recall => $first_recall,
+ callnumbers => \@unique_callnumbers,
+ copynumbers => \@unique_copynumbers,
+ enumchrons => \@unique_enumchrons,
+ itemtypes => \@unique_itemtypes,
+ locations => \@unique_locations,
+ libraries => \@unique_libraries,
+ });
+ }
+ }
+ }
+ $template->param(
+ recalls => \@pull_list,
+ );
+}
+
+# Checking if there is a Fast Cataloging Framework
+$template->param( fast_cataloging => 1 ) if Koha::BiblioFrameworks->find( 'FA' );
+
+# writing the template
+output_html_with_http_headers $query, $cookie, $template->output;
--- a/recalls/recalls_waiting.pl
+++ a/recalls/recalls_waiting.pl
@@ -0,0 +1,76 @@
+#!/usr/bin/perl
+
+# Copyright 2020 Aleisha Amohia
+#
+# 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 qw( get_template_and_user );
+use C4::Output qw( output_html_with_http_headers );
+use Koha::Recalls;
+use Koha::BiblioFrameworks;
+use Koha::DateUtils;
+use Koha::Patrons;
+
+my $query = new CGI;
+my ( $template, $loggedinuser, $cookie, $flags ) = get_template_and_user(
+ {
+ template_name => "recalls/recalls_waiting.tt",
+ query => $query,
+ type => "intranet",
+ authnotrequired => 0,
+ flagsrequired => { recalls => "manage_recalls" },
+ debug => 1,
+ }
+);
+
+my $op = $query->param('op') || 'list';
+
+if ( $op eq 'modify' ) {
+ my $expire = $query->param('expire') || '';
+ my $revert = $query->param('revert') || '';
+ my $recall_id = $query->param('recall_id');
+ if ( $expire ) {
+ Koha::Recalls->find( $recall_id )->set_expired({ interface => 'INTRANET' });
+ } elsif ( $revert ) {
+ Koha::Recalls->find( $recall_id )->revert_waiting;
+ }
+ $op = 'list';
+}
+
+if ( $op eq 'list' ) {
+ my @recalls = Koha::Recalls->search({ status => 'W' });
+ my $borrower = Koha::Patrons->find( $loggedinuser );
+ my @over;
+ my $maxdelay = C4::Context->preference('RecallsMaxPickUpDelay') || 7;
+ my $today = dt_from_string();
+ foreach my $r ( @recalls ){
+ my $lastwaitingday = dt_from_string( $r->waitingdate )->add( days => $maxdelay );
+ if ( $today > $lastwaitingday ){
+ push @over, $r;
+ }
+ }
+ $template->param(
+ recalls => \@recalls,
+ over => \@over,
+ );
+}
+
+# Checking if there is a Fast Cataloging Framework
+$template->param( fast_cataloging => 1 ) if Koha::BiblioFrameworks->find( 'FA' );
+
+# writing the template
+output_html_with_http_headers $query, $cookie, $template->output;
--- a/recalls/request.pl
+++ a/recalls/request.pl
@@ -0,0 +1,65 @@
+#!/usr/bin/perl
+
+# Copyright 2020 Aleisha Amohia
+#
+# 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 C4::Search;
+use Koha::Recalls;
+use Koha::Biblios;
+
+my $input = CGI->new;
+my ($template, $loggedinuser, $cookie)= get_template_and_user(
+ {
+ template_name => "recalls/request.tt",
+ query => $input,
+ type => "intranet",
+ authnotrequired => 0,
+ flagsrequired => { recalls => "manage_recalls" },
+ debug => 1,
+ }
+);
+
+my $op = $input->param('op') || 'list';
+my @recall_ids = $input->multi_param('recall_ids');
+my $biblionumber = $input->param('biblionumber');
+my $recalls = Koha::Recalls->search({ biblionumber => $biblionumber, old => undef });
+my $biblio = Koha::Biblios->find( $biblionumber );
+
+if ( $op eq 'cancel_multiple_recalls' ) {
+ foreach my $id ( @recall_ids ) {
+ Koha::Recalls->find( $id )->set_cancelled;
+ }
+ $op = 'list'
+}
+
+if ( $op eq 'list' ) {
+ $recalls = Koha::Recalls->search({ biblionumber => $biblionumber, old => undef });
+ $biblio = Koha::Biblios->find( $biblionumber );
+}
+
+$template->param(
+ recalls => $recalls,
+ recallsview => 1,
+ biblio => $biblio,
+ checkboxes => 1,
+ C4::Search::enabled_staff_search_views,
+);
+
+output_html_with_http_headers $input, $cookie, $template->output;
--- a/reserve/request.pl
+++ a/reserve/request.pl
@@ -345,6 +345,9 @@ foreach my $biblionumber (@biblionumbers) {
}
elsif ( $canReserve->{status} eq 'alreadypossession' ) {
$template->param( $canReserve->{status} => 1);
+ }
+ elsif ( $canReserve->{status} eq 'recall' ) {
+ $template->param( $canReserve->{status} => 1 );
$biblioloopiter{ $canReserve->{status} } = 1;
}
else {
--- a/svc/checkouts
+++ a/svc/checkouts
@@ -209,6 +209,27 @@ while ( my $c = $sth->fetchrow_hashref() ) {
$materials = $descriptions->{lib} // $c->{materials};
}
my @subtitles = split(/ \| /, $c->{'subtitle'} // '' );
+
+ my $item = Koha::Items->find( $c->{itemnumber} );
+ my $recalled = 0;
+ my $recall = undef;
+ $recall = $item->check_recalls if $item->can_be_waiting_recall;
+ if ( defined $recall ) {
+ if ( $recall->item_level_recall ) {
+ if ( $recall->itemnumber == $c->{itemnumber} ) {
+ # item-level recall on this item
+ $recalled = 1;
+ } else {
+ $recalled = 0;
+ }
+ } else {
+ # biblio-level recall, but don't want to mark recalled if the recall has been allocated a different item
+ if ( !$recall->waiting ) {
+ $recalled = 1;
+ }
+ }
+ }
+
my $checkout = {
DT_RowId => $c->{itemnumber} . '-' . $c->{borrowernumber},
title => $c->{title},
@@ -281,6 +302,7 @@ while ( my $c = $sth->fetchrow_hashref() ) {
cardnumber => $c->{cardnumber},
},
issued_today => !$c->{not_issued_today},
+ recalled => $recalled,
};
if ( $c->{not_issued_today} ) {
--- a/svc/recall
+++ a/svc/recall
@@ -0,0 +1,89 @@
+#!/usr/bin/perl
+
+# Copyright 2020 Aleisha Amohia
+#
+# 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;
+use JSON qw(encode_json);
+
+use C4::Context;
+use C4::Auth qw(check_cookie_auth);
+use C4::Output qw(output_with_http_headers);
+use C4::Circulation qw(AddReturn);
+use Koha::Recalls;
+
+my $input = new CGI;
+my $json = encode_json({ success => 0 });
+
+my ( $auth_status, $sessionID ) = check_cookie_auth( $input->cookie('CGISESSID'), { recall => 'manage_recalls' } );
+
+if ( $auth_status ne "ok" ) {
+ print $input->header(-type => 'text/plain', -status => '403 Forbidden');
+ exit 0;
+}
+
+my $recall_id = $input->param('recall_id');
+my $recall = Koha::Recalls->find( $recall_id );
+unless ( $recall ) {
+ my $json = encode_json({ success => 0 });
+ output_with_http_headers( $input, undef, $json, "json" );
+ exit;
+}
+
+my $op = $input->param('action');
+
+if ( $op eq 'cancel' ) {
+ # cancel recall
+ $recall->set_cancelled;
+ if ( $recall->cancelled ){
+ $json = encode_json({ success => 1 });
+ }
+
+} elsif ( $op eq 'expire' ) {
+ # expire recall
+ $recall->set_expired({ interface => 'INTRANET' });
+ if ( $recall->expired ){
+ $json = encode_json({ success => 1 });
+ }
+
+} elsif ( $op eq 'revert' ) {
+ # revert recall waiting status
+ $recall->revert_waiting;
+ if ( $recall->requested ){
+ $json = encode_json({ success => 1 });
+ }
+
+} elsif ( $op eq 'overdue' ) {
+ # mark recall as overdue
+ $recall->set_overdue({ interface => 'INTRANET' });
+ if ( $recall->overdue ){
+ $json = encode_json({ success => 1 });
+ }
+
+} elsif ( $op eq 'transit' ) {
+ # cancel recall and return item to home library
+ if ( $recall->in_transit ) {
+ C4::Items::ModItemTransfer( $recall->item->itemnumber, $recall->item->holdingbranch, $recall->item->homebranch, 'CancelRecall' );
+ }
+ $recall->set_cancelled;
+ if ( $recall->cancelled ){
+ $json = encode_json({ success => 1 });
+ }
+}
+
+output_with_http_headers( $input, undef, $json, "json" );
--- a/tools/letter.pl
+++ a/tools/letter.pl
@@ -249,7 +249,7 @@ sub add_form {
{value => 'items.fine', text => 'items.fine'},
add_fields('borrowers');
if ($module eq 'circulation') {
- push @{$field_selection}, add_fields('additional_contents');
+ push @{$field_selection}, add_fields('additional_contents', 'recalls');
}
--- a/tools/viewlog.pl
+++ a/tools/viewlog.pl
@@ -189,6 +189,15 @@ if ($do_it) {
}
}
+ # get recall information
+ if ( $log->module eq "RECALLS" ) {
+ if ( $log->object ) {
+ my $recall = Koha::Recalls->find( $log->object );
+ if ( $recall && $output eq 'screen' ) {
+ $result->{recall} = $recall;
+ }
+ }
+ }
push @data, $result;
}
if ( $output eq "screen" ) {
--