diff --git a/C4/Reserves.pm b/C4/Reserves.pm index a8e70e57ec..6b26f7f213 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -1183,6 +1183,8 @@ for a bib. If C<$rank> is 'del', the hold request is cancelled. +If C<$rank> is 'recall', the hold request is converted to a recall request. + If C<$rank> is an integer greater than zero, the priority of the request is set to that value. Since priority != 0 means that the item is not waiting on the hold shelf, setting the @@ -1240,6 +1242,43 @@ sub ModReserve { if ( $rank eq "del" ) { $hold->cancel( { cancellation_reason => $cancellation_reason } ); + } elsif ( $rank eq "recall" ) { + if ( !$biblionumber ) { + $biblionumber = $hold->biblionumber; + } + my $biblio = Koha::Biblios->find($biblionumber); + if ( !$borrowernumber ) { + $borrowernumber = $hold->borrowernumber; + } + my $patron = Koha::Patrons->find($borrowernumber); + if ( $hold->item_level_hold ) { + if ( $hold->item->can_be_recalled( { patron => $patron, hold_convert => 1 } ) ) { + my ( $recall, $due_interval, $due_date ) = Koha::Recalls->add_recall( + { + patron => $patron, + biblio => $biblio, + branchcode => $branchcode, + expirationdate => $date, + interface => 'intranet', + item => $hold->item, + } + ); + $hold->cancel( { cancellation_reason => $cancellation_reason } ); + } + } else { + if ( $biblio->can_be_recalled( { patron => $patron, hold_convert => 1 } ) ) { + my ( $recall, $due_interval, $due_date ) = Koha::Recalls->add_recall( + { + patron => $patron, + biblio => $biblio, + branchcode => $branchcode, + expirationdate => $date, + interface => 'intranet', + } + ); + $hold->cancel( { cancellation_reason => $cancellation_reason } ); + } + } } elsif ( $hold->found && $hold->priority eq '0' && $date ) { # The only column that can be updated for a found hold is the expiration date diff --git a/Koha/Biblio.pm b/Koha/Biblio.pm index d8bf30c219..fc86dcbb1c 100644 --- a/Koha/Biblio.pm +++ b/Koha/Biblio.pm @@ -2239,6 +2239,8 @@ sub recalls { Does biblio-level checks and returns the items attached to this biblio that are available for recall +If hold_convert $param is included, this is a check to convert a hold to a recall, so we should not check for an existing hold. + =cut sub can_be_recalled { @@ -2264,7 +2266,7 @@ sub can_be_recalled { my @all_itemnumbers; foreach my $item (@all_items) { push( @all_itemnumbers, $item->itemnumber ); - if ( $item->can_be_recalled( { patron => $patron } ) ) { + if ( $item->can_be_recalled( { patron => $patron, hold_convert => $params->{hold_convert} } ) ) { push( @itemtypes, $item->effective_itemtype ); push( @itemnumbers, $item->itemnumber ); push( @items, $item ); diff --git a/Koha/Item.pm b/Koha/Item.pm index d8f314a8b7..95ae6cbbdf 100644 --- a/Koha/Item.pm +++ b/Koha/Item.pm @@ -2643,6 +2643,8 @@ sub recall { Does item-level checks and returns if items can be recalled by this borrower +If hold_convert $param is included, this is a check to convert a hold to a recall, so we should not check for an existing hold. + =cut sub can_be_recalled { @@ -2704,9 +2706,12 @@ sub can_be_recalled { ->count > 0 ); # check if this patron has already reserved this item - return 0 - if ( Koha::Holds->search( { itemnumber => $self->itemnumber, borrowernumber => $patron->borrowernumber } ) - ->count > 0 ); + unless ( $params->{hold_convert} ) { + return 0 + if ( + Koha::Holds->search( { itemnumber => $self->itemnumber, borrowernumber => $patron->borrowernumber } ) + ->count > 0 ); + } } # check item availability diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/modals/holds_table_modals.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/modals/holds_table_modals.inc index e8a458bfb1..668a6cc518 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/modals/holds_table_modals.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/modals/holds_table_modals.inc @@ -95,3 +95,48 @@ [% END %] + +[% BLOCK 'convert-to-recall-modal' %] + +[% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/request.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/request.tt index 4fb0832668..dbf329d8f2 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/request.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/request.tt @@ -2,18 +2,36 @@ [% USE Asset %] [% USE Koha %] [% USE KohaDates %] +[% USE Branches %] +[% USE Categories %] +[% USE AuthorisedValues %] +[% USE ItemTypes %] [% PROCESS 'i18n.inc' %] [% SET footerjs = 1 %] [% INCLUDE 'doc-head-open.inc' %] +[% SET libraries = Branches.all %] +[% SET categories = Categories.all.unblessed %] +[% SET columns = ['name', 'cardnumber', 'dateofbirth', 'category', 'branch', 'address', 'phone'] %] +[% PROCESS "patron-search.inc" %] [% FILTER collapse %] - [% t("Existing recalls") | html %] + [% t("Place a recall") | html %] › [% t("Recalls") | html %] › [% t("Koha") | html %] [% END %] [% INCLUDE 'doc-head-close.inc' %] +[% FILTER collapse %] + +[% END %] - + [% WRAPPER 'header.inc' %] [% INCLUDE 'circ-search.inc' %] [% END %] @@ -27,40 +45,264 @@ [% INCLUDE 'biblio-title.inc' link = 1 %] [% END %] [% WRAPPER breadcrumb_item bc_active= 1 %] - Existing recalls + Place a recall [% END %] [% END #/ WRAPPER breadcrumbs %] [% END #/ WRAPPER sub-header.inc %] -[% WRAPPER 'main-container.inc' aside='biblio-view-menu' %] -

Existing recalls

+[% WRAPPER 'main-container.inc' aside='biblio-view-menu' wide_centered=1 %] +

Recalls

- [% IF Koha.Preference('UseRecalls') != "off" %] - [% IF recalls.count %] -
-
- [% INCLUDE 'csrf-token.inc' %] - - - Select all - [% INCLUDE 'recalls.inc' %] -
- -
-
-
- - [% ELSE %] -
No recalls have been made.
+

Place a recall on [% INCLUDE 'biblio-title.inc' link = 1 %]

+ + [% IF patron %] + + [% IF error %] +
Cannot place recalls: check your circulation rules.
[% END %] - [% ELSE %] -
Recalls have not been enabled. Enable the UseRecalls system preference to use recalls.
- [% END %] -[% END %] + + [% IF patron_holds_count %] +
Patron has placed one or more record-level holds. Convert a hold to a recall.
+ [% END %] + +
+
+ Recall details + +
    +
  1. + [% INCLUDE 'patron-title.inc' %] + +
  2. + +
  3. +
+
+ +
+ Recall next available item + +
    + [% UNLESS ( single_branch_mode ) %] +
  1. + + +
  2. + [% END %] +
+ +
+ [% INCLUDE 'csrf-token.inc' %] + + + + [% IF error %] + + [% ELSE %] + + [% END %] + Cancel +
+
+ +
+ Recall a specific item + + + + + + + + [% UNLESS ( single_branch_mode ) %] + + + [% END %] + + + + + + + + + [% FOREACH item IN items %] + + + + + [% UNLESS ( single_branch_mode ) %] + + + [% END %] + + + + + + + [% END # FOREACH item IN items %] + +
 Item typeBarcodeHome libraryHolding libraryCollectionCall numberCopy numberVol no.Information
+ [% IF item.can_be_recalled( patron => patron ) %] + + [% ELSE %] + + + + [% END %] + [% ItemTypes.GetDescription( item.effective_itemtype ) | html %][% item.barcode | html %][% Branches.GetName( item.homebranch ) | html %][% Branches.GetName( item.holdingbranch) | html %][% AuthorisedValues.GetByCode( 'CCODE', item.ccode, 1 ) | html %][% item.itemcallnumber | html %][% item.copynumber | html %][% item.enumchron | html %] + [% IF ( item.checkout ) %] + Due [% item.checkout.date_due | $KohaDates %] + [% ELSIF ( item.get_transfer ) %] + In transit from [% Branches.GetName( item.get_transfer.frombranch ) | html %] to [% Branches.GetName( item.get_transfer.tobranch ) | html %] since + [% item.get_transfer.datesent | $KohaDates %] + [% END %] + [% IF ( item.itemlost || item.withdrawn ) %] + Unavailable (lost or withdrawn) + [% END %] + [% IF ( item.notforloan ) %] + Not for loan ([% item.notforloan | html %]) + [% END %] + [% hold = item.current_holds.next %] + [% IF ( item.recall ) %] + + [% IF ( item.recall.waiting_date ) %] + Waiting for patron at [% Branches.GetName( item.recall.pickup_library_id ) | html %] since [% item.recall.waiting_date | $KohaDates %]. + [% ELSIF ( item.recall.item_id == item.itemnumber ) %] + Recalled by patron expected at [% Branches.GetName( item.recall.pickup_library_id ) | html %] since [% item.recall.created_date | $KohaDates %]. + [% END %] + + [% ELSIF ( hold.waitingdate ) %] + Waiting for patron at [% Branches.GetName( hold.branchcode ) | html %] since [% hold.waitingdate | $KohaDates %]. + [% ELSIF ( hold.borrowernumber == logged_in_user.borrowernumber ) %] + Patron has already placed a hold on this item. + [% END # / IF ( item.recall or hold ) %] +
+ +
+ [% INCLUDE 'csrf-token.inc' %] + + + [% IF error %] + + [% ELSE %] + + [% END %] + Cancel +
+
+
+ [% ELSE # patron %] + + [% IF Koha.Preference('UseRecalls') == 'opac' %] +
Due to the UseRecalls system preference, recalls cannot be placed through the staff interface.
+ [% ELSE %] +
+

Search patrons

+ [% WRAPPER tabs id= "circ_recalls_select" %] + [% WRAPPER tabs_nav %] + [% WRAPPER tab_item tabname= "recalls_patronsearch_pane" bt_active= 1 %]Patrons[% END %] + [% END # /WRAPPER tabs_nav %] + + [% WRAPPER tab_panels %] + [% WRAPPER tab_panel tabname="recalls_patronsearch_pane" bt_active= 1 %] + [% PROCESS patron_search_filters_simple %] + [% PROCESS patron_search_table table_id => 'table_borrowers', open_on_row_click => 1 %] + [% END # /tab_panel# %] + [% END # /WRAPPER tab_panels %] + [% END # /WRAPPER tabs %] +
+ [% END %] + +
+

Existing recalls

+ + [% IF Koha.Preference('UseRecalls') != "off" %] + [% IF recalls.count %] +
+
+ [% INCLUDE 'csrf-token.inc' %] + + + Select all + [% INCLUDE 'recalls.inc' %] +
+ +
+
+
+ + [% ELSE %] +
No recalls have been made.
+ [% END %] + [% ELSE %] +
Recalls have not been enabled. Enable the UseRecalls system preference to use recalls.
+ [% END %] +
+ [% END # patron %] +[% END # WRAPPER %] [% MACRO jsinclude BLOCK %] [% Asset.js("js/recalls.js") | $raw %] [% INCLUDE 'datatables.inc' %] + [% INCLUDE 'calendar.inc' %] + [% INCLUDE 'select2.inc' %] + [% SET url_biblio_params = "biblionumber=" _ biblio.biblionumber %] + [% UNLESS patron %] + [% SET search_results_block_id = 'recalls_patronsearch_pane_panel' %] + [%# adjusting variable for patron-search.inc %] + [% PROCESS patron_search_js table_id => 'table_borrowers', categories => categories, libraries => libraries, columns => columns, open_on_row_click => 1, on_click_url => '/cgi-bin/koha/recalls/request.pl?' _ url_biblio_params, redirect_if_one_result => 1, redirect_url => '/cgi-bin/koha/recalls/request.pl?' _ url_biblio_params, redirect_if_attribute_equal => 'cardnumber' %] + + [% END %] + + [% END %] [% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt index 960f6e153c..4566e72a95 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt @@ -327,6 +327,14 @@

No club with this name, please, try another

[% END %] + + [% IF ( recallerror ) %] +
+

Hold cannot be converted to a recall

+

A recall cannot be placed for one or more holds. Check your circulation and fine rules.

+
+ [% END %] +
[% UNLESS multi_hold %] [% IF clubcount %] @@ -1383,6 +1391,11 @@ [% END %] + [% IF Koha.Preference('UseRecalls').match('staff') %] +
+ +
+ [% END %]
[% FOREACH biblioloo IN biblioloop %] @@ -1465,6 +1478,8 @@ [% PROCESS 'cancel-hold-modal' form_action = 'request.pl' %] +[% PROCESS 'convert-to-recall-modal' form_action = 'modrequest.pl' %] +