From 3b9ee6205b728f2a3df10b2238788894d4cea03e Mon Sep 17 00:00:00 2001 From: Aleisha Amohia Date: Mon, 22 Feb 2021 17:55:22 +1300 Subject: [PATCH] Bug 15565: Place multiple holds on one record on staff client Test plan: 0) git bz apply 15565 1) restart_all 2) Set the maxreserves system preference to 3 (from 50) 3) Set the following circulation rules: holds allowed (total) = 10 (from unlimited) holds allowed (daily) = 10 (from unlimited) holds per record (count) = 10 (from 2) 3) Set up a record with 4 items E.g. add 3 items to http://localhost:8081/cgi-bin/koha/catalogue/detail.pl?biblionumber=29 4) Go to place a hold on this record in Staff Interface 5) Notice that the items table under 'Place a hold on a specific item' now uses checkboxes instead of radio buttons 6) Check all 4 checkboxes. Confirm that when you check the 4th checkbox, an alert pops up warning the you've reached the maximum. Confirm that when you close the alert, the checkbox is not checked. 7) Set the following circulation rules one by one and test that each one alone can trigger the alert: holds allowed (total) = 2 (from 10) holds allowed (daily) = 2 (from 10) holds per record (count) = 2 (from 10) 8) Set the circulation rules and syspref all to 4+. Check some items and confirm the holds. 9) Perform the same above actions on the OPAC Sponsored-by: Catalyst IT Signed-off-by: David Cook Signed-off-by: Victor Grousset/tuxayo --- .../prog/en/modules/reserve/request.tt | 45 +++++++++++++---- reserve/placerequest.pl | 48 +++++++++++-------- reserve/request.pl | 30 ++++++++++-- 3 files changed, 91 insertions(+), 32 deletions(-) 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 1a397b07ef..88346721e0 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt @@ -496,10 +496,10 @@ - [% IF remaining_holds_for_record > 1 %] + [% IF lowest_value > 1 %]
  • - +
  • [% ELSE %] @@ -584,9 +584,9 @@ Hold must be record level [% ELSIF ( itemloo.available ) %] - + [% ELSIF ( itemloo.override ) %] - + [% ELSE %] @@ -1051,6 +1051,8 @@ columns_settings_borrowers_table = [% TablesSettings.GetColumns( 'circ', 'circulation', 'table_borrowers', 'json' ) | $raw %]; $.fn.select2.defaults.set("width", "100%" ); $.fn.select2.defaults.set("dropdownAutoWidth", true ); + var MSG_EXCEEDED_MAX_HOLDS = __("Patron reached the maximum number of holds."); + var max_holds = "[% lowest_value | $raw %]"; $(document).ready(function() { $('#cancellation-reason-fieldset').hide(); @@ -1367,23 +1369,48 @@ if(this.checked){ $("input[name=checkitem]").each(function() { $(this).prop("checked", false); + $("#holds_to_place_count").val('1'); }); } }); $("input[name=checkitem]").click(function() { - onechecked = 0; + numchecked = 0; $("input[name=checkitem]").each(function() { if(this.checked){ - onechecked = 1; + numchecked++; } }); - if(onechecked == 1){ - $("#requestany").prop("checked", false); - $("#holds_to_place_count").prop('disabled', true); + if(numchecked > 0){ + if ( numchecked > max_holds ) { + alert(MSG_EXCEEDED_MAX_HOLDS); + $(this).prop('checked',false); + } else { + $("#requestany").prop("checked", false); + $("#holds_to_place_count").prop('disabled', true); + $("#holds_to_place_count").val(numchecked); + } } else { $("#requestany").prop("checked",true); $("#holds_to_place_count").prop('disabled', false); } + if ( remainingHold - numchecked <= 0 ) { + alert(MSG_EXCEEDED_HOLDS_PER_RECORD); + [% IF !Koha.Preference('AllowHoldPolicyOverride') %] + $('input[name=checkitem]:not(:checked)').attr('disabled','disabled'); + [% END %] + } + if ( remainingHoldsToday - numchecked <= 0 ) { + alert(MSG_EXCEEDED_HOLDS_PER_DAY); + [% IF !Koha.Preference('AllowHoldPolicyOverride') %] + $('input[name=checkitem]:not(:checked)').attr('disabled','disabled'); + [% END %] + } + if ( maxreserves - numchecked <= 0 ) { + alert(MSG_EXCEEDED_MAXRESERVES_SYSPREF); + [% IF !Koha.Preference('AllowHoldPolicyOverride') %] + $('input[name=checkitem]:not(:checked)').attr('disabled','disabled'); + [% END %] + } }); var prev_rank_request; $("select[name=rank-request]").on("focus", function() { diff --git a/reserve/placerequest.pl b/reserve/placerequest.pl index ea81592ef0..48f58a5aa6 100755 --- a/reserve/placerequest.pl +++ b/reserve/placerequest.pl @@ -49,7 +49,7 @@ my $startdate = $input->param('reserve_date') || ''; my @rank = $input->multi_param('rank-request'); my $type = $input->param('type'); my $title = $input->param('title'); -my $checkitem = $input->param('checkitem'); +my @checkitems = $input->multi_param('checkitem'); my $expirationdate = $input->param('expiration_date'); my $itemtype = $input->param('itemtype') || undef; my $non_priority = $input->param('non_priority'); @@ -62,6 +62,7 @@ $biblionumbers ||= $biblionumber . '/'; my $bad_bibs = $input->param('bad_bibs'); my $holds_to_place_count = $input->param('holds_to_place_count') || 1; +$holds_to_place_count = scalar( @checkitems ) if @checkitems; my %bibinfos = (); my @biblionumbers = split '/', $biblionumbers; @@ -72,7 +73,16 @@ foreach my $bibnum (@biblionumbers) { $bibinfos{$bibnum} = \%bibinfo; } -my $found; +my @found; +unless ( C4::Context->preference('ReservesNeedReturns') ) { + foreach my $checkitem ( @checkitems ) { + # if we have an item selected, and the pickup branch is the same as + # the holdingbranch of the doc, we force the value $rank and $found + $rank[0] = '0'; + my $item = Koha::Items->find( $checkitem ); + push @found, ( $item->holdingbranch eq $branch ? 'W' : undef ); + } +} if ( $type eq 'str8' && $borrower ) { @@ -91,14 +101,9 @@ if ( $type eq 'str8' && $borrower ) { } my $can_override = C4::Context->preference('AllowHoldPolicyOverride'); - if ( defined $checkitem && $checkitem ne '' ) { - - my $item = Koha::Items->find($checkitem); - - if ( $item->biblionumber ne $biblionumber ) { - $biblionumber = $item->biblionumber; - } - + if ( @checkitems and @checkitems == 1 ) { + # item-level hold + my $item = Koha::Items->find( $checkitems[0] ); my $can_item_be_reserved = CanItemBeReserved($borrower->{'borrowernumber'}, $item->itemnumber, $branch)->{status}; if ( $can_item_be_reserved eq 'OK' || ( $can_item_be_reserved ne 'itemAlreadyOnHold' && $can_override ) ) { @@ -112,8 +117,8 @@ if ( $type eq 'str8' && $borrower ) { expiration_date => $expirationdate, notes => $notes, title => $title, - itemnumber => $checkitem, - found => $found, + itemnumber => $checkitems[0], + found => $found[0], itemtype => $itemtype, non_priority => $non_priority, } @@ -121,7 +126,8 @@ if ( $type eq 'str8' && $borrower ) { } - } elsif (@biblionumbers > 1) { + } elsif ( @biblionumbers > 1 ) { + # hold on multiple titles (multi-hold) my $bibinfo = $bibinfos{$biblionumber}; if ( $can_override || CanBookBeReserved($borrower->{'borrowernumber'}, $biblionumber)->{status} eq 'OK' ) { AddReserve( @@ -134,8 +140,8 @@ if ( $type eq 'str8' && $borrower ) { expiration_date => $expirationdate, notes => $notes, title => $bibinfo->{title}, - itemnumber => $checkitem, - found => $found, + itemnumber => undef, + found => undef, itemtype => $itemtype, non_priority => $non_priority, } @@ -144,20 +150,24 @@ if ( $type eq 'str8' && $borrower ) { } else { # place a request on 1st available for ( my $i = 0 ; $i < $holds_to_place_count ; $i++ ) { + my $item; + if ( $checkitems[$i] ) { + $item = Koha::Items->find( $checkitems[$i] ); + } if ( $can_override || CanBookBeReserved($borrower->{'borrowernumber'}, $biblionumber)->{status} eq 'OK' ) { AddReserve( { branchcode => $branch, borrowernumber => $borrower->{'borrowernumber'}, - biblionumber => $biblionumber, + biblionumber => ( $item ? $item->biblionumber : $biblionumber ), priority => $rank[0], reservation_date => $startdate, expiration_date => $expirationdate, notes => $notes, title => $title, - itemnumber => $checkitem, - found => $found, - itemtype => $itemtype, + itemnumber => $checkitems[$i], + found => $found[$i], + itemtype => ( $item ? $item->effective_itemtype : undef ), non_priority => $non_priority, } ); diff --git a/reserve/request.pl b/reserve/request.pl index 49d8a2fa26..54fb6ebe2d 100755 --- a/reserve/request.pl +++ b/reserve/request.pl @@ -30,6 +30,7 @@ use Modern::Perl; use CGI qw ( -utf8 ); use List::MoreUtils qw/uniq/; +use List::Util qw[min max]; use Date::Calc qw/Date_to_Days/; use C4::Output; use C4::Auth; @@ -349,11 +350,32 @@ foreach my $biblionumber (@biblionumbers) { # we must find out what the maximum number of holds they can place for the patron is my $max_holds_for_record = GetMaxPatronHoldsForRecord( $patron->borrowernumber, $biblionumber ); my $remaining_holds_for_record = $max_holds_for_record - $holds->count(); - $biblioloopiter{remaining_holds_for_record} = $max_holds_for_record; - $template->param( max_holds_for_record => $max_holds_for_record ); - $template->param( remaining_holds_for_record => $remaining_holds_for_record ); - } + # Determine how many holds the patron can place per day on this biblio record. + # Then calculate how many holds the patron can place subtracting holds already placed today + my $today_holds = Koha::Holds->search({ + borrowernumber => $patron->borrowernumber, + reservedate => dt_from_string->date, + })->count; + + my $biblio_obj = Koha::Biblios->find( $biblionumber ); + my $holds_allowed_on_record_today = $biblio_obj->allowed_holds( $patron ); + my $remaining_holds_allowed_today = $holds_allowed_on_record_today - $today_holds; + my $maxreserves = C4::Context->preference('maxreserves'); + + $biblioloopiter{remaining_holds_for_record} = $remaining_holds_for_record; + $biblioloopiter{remaining_holds_allowed_today} = $remaining_holds_allowed_today; + + # Determine what is the lowest value + my $lowestvalue = min( $maxreserves, $remaining_holds_for_record, $remaining_holds_allowed_today ); + + $template->param( + max_holds_for_record => $max_holds_for_record, + remaining_holds_for_record => $remaining_holds_for_record, + lowest_value => $lowestvalue, + remaining_holds_allowed_today => $remaining_holds_allowed_today, + ); + } my $count = Koha::Holds->search( { biblionumber => $biblionumber } )->count(); my $totalcount = $count; -- 2.31.1