From 70c5bc11bf718fc698d71752887fdcb4a416f6f9 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: 1) Apply patch and restart services 2) Set the maxreserves system preference to 3 3) Set the following circulation rules: holds allowed (total) = 10 holds allowed (daily) = 10 holds per record (count) = 10 3) Set up a record with 4 items 4) Go to place a hold on this record 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 unchecks itself. 7) Try setting different values for the above circulation rules that are lower than the number of items on this record. Confirm the alert pops up as expected. 8) Set the circulation rules and syspref all to 4+. Check some items and confirm the holds. 9) Confirm that item-level holds are placed on all selected items. Sponsored-by: Catalyst IT --- .../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 dc85eff568..a7ae84eb90 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt @@ -471,10 +471,10 @@ - [% IF remaining_holds_for_record > 1 %] + [% IF lowest_value > 1 %]
  • - +
  • [% ELSE %] @@ -559,9 +559,9 @@ Hold must be record level [% ELSIF ( itemloo.available ) %] - + [% ELSIF ( itemloo.override ) %] - + [% ELSE %] @@ -1015,6 +1015,8 @@ cannotBeTransferred: _("Cannot be transferred to pickup library") } columns_settings_borrowers_table = [% TablesSettings.GetColumns( 'circ', 'circulation', 'table_borrowers', 'json' ) | $raw %]; + 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(); @@ -1273,23 +1275,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 38d6f56ed2..c25f2f8ad1 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; @@ -343,11 +344,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.11.0