From bc39f0392bbebaad4c083f81308f652a325be042 Mon Sep 17 00:00:00 2001 From: Kyle M Hall Date: Tue, 29 Dec 2015 19:14:19 +0000 Subject: [PATCH] Bug 14695 - Add ability to place multiple item holds on a given record per patron Signed-off-by: Nick Clemens Signed-off-by: Jason M. Burds Signed-off-by: Benjamin Rokseth --- C4/Reserves.pm | 137 +++++++++++++----- Koha/Holds.pm | 32 ++++ .../prog/en/modules/reserve/request.tt | 117 ++++++++++----- opac/opac-reserve.pl | 44 +++--- reserve/placerequest.pl | 58 ++++---- reserve/request.pl | 75 ++++++---- 6 files changed, 316 insertions(+), 147 deletions(-) diff --git a/C4/Reserves.pm b/C4/Reserves.pm index efb7f04d15..e7066d244f 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -44,6 +44,7 @@ use Koha::Holds; use Koha::Libraries; use Koha::Items; use Koha::ItemTypes; +use Koha::Patrons; use List::MoreUtils qw( firstidx any ); use Carp; @@ -143,6 +144,8 @@ BEGIN { &GetReservesControlBranch IsItemOnHoldAndFound + + GetMaxPatronHoldsForRecord ); @EXPORT_OK = qw( MergeHolds ); } @@ -170,12 +173,7 @@ sub AddReserve { $title, $checkitem, $found, $itemtype ) = @_; - if ( Koha::Holds->search( { borrowernumber => $borrowernumber, biblionumber => $biblionumber } )->count() > 0 ) { - carp("AddReserve: borrower $borrowernumber already has a hold for biblionumber $biblionumber"); - return; - } - - my $dbh = C4::Context->dbh; + my $dbh = C4::Context->dbh; $resdate = output_pref( { str => dt_from_string( $resdate ), dateonly => 1, dateformat => 'iso' }) or output_pref({ dt => dt_from_string, dateonly => 1, dateformat => 'iso' }); @@ -464,7 +462,8 @@ sub CanItemBeReserved { my $dbh = C4::Context->dbh; my $ruleitemtype; # itemtype of the matching issuing rule - my $allowedreserves = 0; + my $allowedreserves = 0; # Total number of holds allowed across all records + my $holds_per_record = 1; # Total number of holds allowed for this one given record # we retrieve borrowers and items informations # # item->{itype} will come for biblioitems if necessery @@ -477,26 +476,16 @@ sub CanItemBeReserved { if ( $item->{damaged} && !C4::Context->preference('AllowHoldsOnDamagedItems') ); - #Check for the age restriction + # Check for the age restriction my ( $ageRestriction, $daysToAgeRestriction ) = C4::Circulation::GetAgeRestriction( $biblioData->{agerestriction}, $borrower ); return 'ageRestricted' if $daysToAgeRestriction && $daysToAgeRestriction > 0; - my $controlbranch = C4::Context->preference('ReservesControlBranch'); + # Check that the patron doesn't have an item level hold on this item already + return 'itemAlreadyOnHold' + if Koha::Holds->search( { borrowernumber => $borrowernumber, itemnumber => $itemnumber } )->count(); - # we retrieve user rights on this itemtype and branchcode - my $sth = $dbh->prepare( - q{ - SELECT categorycode, itemtype, branchcode, reservesallowed - FROM issuingrules - WHERE (categorycode in (?,'*') ) - AND (itemtype IN (?,'*')) - AND (branchcode IN (?,'*')) - ORDER BY categorycode DESC, - itemtype DESC, - branchcode DESC - } - ); + my $controlbranch = C4::Context->preference('ReservesControlBranch'); my $querycount = q{ SELECT count(*) AS count @@ -520,15 +509,27 @@ sub CanItemBeReserved { } # we retrieve rights - $sth->execute( $borrower->{'categorycode'}, $item->{'itype'}, $branchcode ); - if ( my $rights = $sth->fetchrow_hashref() ) { - $ruleitemtype = $rights->{itemtype}; - $allowedreserves = $rights->{reservesallowed}; + if ( my $rights = GetHoldRule( $borrower->{'categorycode'}, $item->{'itype'}, $branchcode ) ) { + $ruleitemtype = $rights->{itemtype}; + $allowedreserves = $rights->{reservesallowed}; + $holds_per_record = $rights->{holds_per_record}; } else { $ruleitemtype = '*'; } + my $item = Koha::Items->find( $itemnumber ); + my $holds = Koha::Holds->search( + { + borrowernumber => $borrowernumber, + biblionumber => $item->biblionumber, + found => undef, # Found holds don't count against a patron's holds limit + } + ); + if ( $holds->count() >= $holds_per_record ) { + return "tooManyHoldsForThisRecord"; + } + # we retrieve count $querycount .= "AND $branchfield = ?"; @@ -758,8 +759,8 @@ sub GetReservesToBranch { my $dbh = C4::Context->dbh; my $sth = $dbh->prepare( "SELECT reserve_id,borrowernumber,reservedate,itemnumber,timestamp - FROM reserves - WHERE priority='0' + FROM reserves + WHERE priority='0' AND branchcode=?" ); $sth->execute( $frombranch ); @@ -784,7 +785,7 @@ sub GetReservesForBranch { my $query = " SELECT reserve_id,borrowernumber,reservedate,itemnumber,waitingdate - FROM reserves + FROM reserves WHERE priority='0' AND found='W' "; @@ -1414,7 +1415,7 @@ sub ModReserveMinusPriority { my $dbh = C4::Context->dbh; my $query = " UPDATE reserves - SET priority = 0 , itemnumber = ? + SET priority = 0 , itemnumber = ? WHERE reserve_id = ? "; my $sth_upd = $dbh->prepare($query); @@ -1651,7 +1652,7 @@ sub ToggleLowestPriority { my $sth = $dbh->prepare( "UPDATE reserves SET lowestPriority = NOT lowestPriority WHERE reserve_id = ?"); $sth->execute( $reserve_id ); - + _FixPriority({ reserve_id => $reserve_id, rank => '999999' }); } @@ -1835,7 +1836,7 @@ sub _FixPriority { $priority[$j]->{'reserve_id'} ); } - + $sth = $dbh->prepare( "SELECT reserve_id FROM reserves WHERE lowestPriority = 1 ORDER BY priority" ); $sth->execute(); @@ -2073,7 +2074,7 @@ sub _koha_notify_reserve { if (! $notification_sent) { &$send_notification('print', 'HOLD'); } - + } =head2 _ShiftPriorityByDateAndPriority @@ -2502,6 +2503,76 @@ sub IsItemOnHoldAndFound { return $found; } +=head2 GetMaxPatronHoldsForRecord + +my $holds_per_record = ReservesControlBranch( $borrowernumber, $biblionumber ); + +For multiple holds on a given record for a given patron, the max +number of record level holds that a patron can be placed is the highest +value of the holds_per_record rule for each item if the record for that +patron. This subroutine finds and returns the highest holds_per_record +rule value for a given patron id and record id. + +=cut + +sub GetMaxPatronHoldsForRecord { + my ( $borrowernumber, $biblionumber ) = @_; + + my $patron = Koha::Patrons->find($borrowernumber); + my @items = Koha::Items->search( { biblionumber => $biblionumber } ); + + my $controlbranch = C4::Context->preference('ReservesControlBranch'); + + my $categorycode = $patron->categorycode; + my $branchcode; + $branchcode = $patron->branchcode if ( $controlbranch eq "PatronLibrary" ); + + my $max = 0; + foreach my $item (@items) { + my $itemtype = $item->effective_itemtype(); + + $branchcode = $item->homebranch if ( $controlbranch eq "ItemHomeLibrary" ); + + my $rule = GetHoldRule( $categorycode, $itemtype, $branchcode ); + my $holds_per_record = $rule ? $rule->{holds_per_record} : 0; + $max = $holds_per_record if $holds_per_record > $max; + } + + return $max; +} + +=head2 GetHoldRule + +my $rule = GetHoldRule( $categorycode, $itemtype, $branchcode ); + +Returns the matching hold related issuingrule fields for a given +patron category, itemtype, and library. + +=cut + +sub GetHoldRule { + my ( $categorycode, $itemtype, $branchcode ) = @_; + + my $dbh = C4::Context->dbh; + + my $sth = $dbh->prepare( + q{ + SELECT categorycode, itemtype, branchcode, reservesallowed, holds_per_record + FROM issuingrules + WHERE (categorycode in (?,'*') ) + AND (itemtype IN (?,'*')) + AND (branchcode IN (?,'*')) + ORDER BY categorycode DESC, + itemtype DESC, + branchcode DESC + } + ); + + $sth->execute( $categorycode, $itemtype, $branchcode ); + + return $sth->fetchrow_hashref(); +} + =head1 AUTHOR Koha Development Team diff --git a/Koha/Holds.pm b/Koha/Holds.pm index d1d8b292e7..b5c24aa1b9 100644 --- a/Koha/Holds.pm +++ b/Koha/Holds.pm @@ -49,6 +49,38 @@ sub waiting { return $self->search( { found => 'W' } ); } +=head3 forced_hold_level + +If a patron has multiple holds for a single record, +those holds must be either all record level holds, +or they must all be item level holds. + +This method should be used with Hold sets where all +Hold objects share the same patron and record. + +This method will return 'item' if the patron has +at least one item level hold. It will return 'record' +if the patron has holds but none are item level, +Finally, if the patron has no holds, it will return +undef which indicateds the patron may select either +record or item level holds, barring any other rules +that would prevent one or the other. +=cut + +sub forced_hold_level { + my ($self) = @_; + + my $force_hold_level; + + if ( $self->count() ) { + my $has_item_level_holds; + map { $has_item_level_holds ||= $_->itemnumber } $self->as_list(); + $force_hold_level = $has_item_level_holds ? 'item' : 'record'; + } + + return $force_hold_level; +} + =head3 type =cut 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 ba53b3a118..e4e54677e2 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt @@ -49,49 +49,39 @@ $(document).ready(function() { }); function check() { - var msg = ""; - var count_reserv = 0; - var alreadyreserved = 0; + var msg = ""; + var count_reserv = 0; // check if we have checkitem form if (document.form.checkitem){ for (i=0;i= "2"){ - msg += (_("- You may only place a hold on one item at a time") + "\n"); + msg += (_("- Please select an item to place a hold") + "\n"); } - if (alreadyreserved > "0"){ - msg += (_("- This patron had already placed a hold on this item") + "\n" + _("Please cancel the previous hold first") + "\n"); + if (msg == "") { + $('#hold-request-form').preventDoubleFormSubmit(); + return(true); + } else { + alert(msg); + return(false); } - - if (msg == "") return(true); - else { - alert(msg); - return(false); - } } function checkMultiHold() { @@ -117,6 +107,8 @@ function checkMultiHold() { $("#multi_hold_bibs").val(biblionumbers); $("#bad_bibs").val(badBibs); + $('#hold-request-form').preventDoubleFormSubmit(); + return true; } @@ -164,7 +156,6 @@ function checkMultiHold() { $("#" + fieldID).val(""); }); - $('#hold-request-form').preventDoubleFormSubmit(); [% UNLESS ( borrowernumber || borrowers || noitems ) %] [% IF ( CircAutocompl ) %] @@ -271,7 +262,7 @@ function checkMultiHold() { [% IF ( exceeded_maxreserves ) %]
  • Too many holds: [% borrowerfirstname %] [% borrowersurname %] can only place a maximum of [% maxreserves %] total holds.
  • [% ELSIF ( alreadypossession ) %] -
  • [% borrowerfirstname %] [% borrowersurname %] is already in possession of one item
  • +
  • [% borrowerfirstname %] [% borrowersurname %] is already in possession of one item[% borrowerfirstname %] [% borrowersurname %] already has a hold on this item
  • [% ELSIF ( ageRestricted ) %] @@ -402,11 +393,34 @@ function checkMultiHold() { [% UNLESS ( multi_hold ) %] -
  • - +
  • + [% IF force_hold_level == 'item' %] + + [% ELSIF force_hold_level == 'record' %] + + + [% ELSE %] + + [% END %]
  • + + [% IF max_holds_for_record > 1 %] + [% SET count = 1 %] +
  • + + +
  • + [% ELSE %] + @@ -431,7 +445,12 @@ function checkMultiHold() { [% IF ( bibitemloo.publicationyear ) %]
  • Publication year: [% bibitemloo.publicationyear %]
  • [% END %] -

    Place a hold on a specific item

    +

    + Place a hold on a specific item + [% IF bibitemloo.force_hold_level == 'item' %] + (Required) + [% END %] +

    @@ -451,18 +470,44 @@ function checkMultiHold() { + [% SET selected = 0 %] [% FOREACH itemloo IN bibitemloo.itemloop %] [% UNLESS ( itemloo.hide ) %] [% IF ( item_level_itypes ) %] diff --git a/opac/opac-reserve.pl b/opac/opac-reserve.pl index 58dac17b48..1fd2f82a1d 100755 --- a/opac/opac-reserve.pl +++ b/opac/opac-reserve.pl @@ -359,17 +359,6 @@ unless ( $noreserves ) { } } -foreach my $res (@reserves) { - foreach my $biblionumber (@biblionumbers) { - if ( $res->{'biblionumber'} == $biblionumber && $res->{'borrowernumber'} == $borrowernumber) { -# $template->param( message => 1 ); -# $noreserves = 1; -# $template->param( already_reserved => 1 ); - $biblioDataHash{$biblionumber}->{already_reserved} = 1; - } - } -} - unless ($noreserves) { $template->param( select_item_types => 1 ); } @@ -468,9 +457,6 @@ foreach my $biblioNum (@biblionumbers) { # the item could be reserved for this borrower vi a host record, flag this $reservedfor //= ''; - if ($reservedfor eq $borrowernumber){ - $itemLoopIter->{already_reserved} = 1; - } if ( defined $reservedate ) { $itemLoopIter->{backgroundcolor} = 'reserved'; @@ -515,12 +501,12 @@ foreach my $biblioNum (@biblionumbers) { $itemLoopIter->{nocancel} = 1; } - # if the items belongs to a host record, show link to host record - if ($itemInfo->{biblionumber} ne $biblioNum){ - $biblioLoopIter{hostitemsflag} = 1; - $itemLoopIter->{hostbiblionumber} = $itemInfo->{biblionumber}; - $itemLoopIter->{hosttitle} = GetBiblioData($itemInfo->{biblionumber})->{title}; - } + # if the items belongs to a host record, show link to host record + if ( $itemInfo->{biblionumber} ne $biblioNum ) { + $biblioLoopIter{hostitemsflag} = 1; + $itemLoopIter->{hostbiblionumber} = $itemInfo->{biblionumber}; + $itemLoopIter->{hosttitle} = GetBiblioData( $itemInfo->{biblionumber} )->{title}; + } # If there is no loan, return and transfer, we show a checkbox. $itemLoopIter->{notforloan} = $itemLoopIter->{notforloan} || 0; @@ -569,6 +555,24 @@ foreach my $biblioNum (@biblionumbers) { $biblioLoopIter{holdable} &&= CanBookBeReserved($borrowernumber,$biblioNum) eq 'OK'; + # For multiple holds per record, if a patron has previously placed a hold, + # the patron can only place more holds of the same type. That is, if the + # patron placed a record level hold, all the holds the patron places must + # be record level. If the patron placed an item level hold, all holds + # the patron places must be item level + my $forced_hold_level = Koha::Holds->search( + { + borrowernumber => $borrowernumber, + biblionumber => $biblioNum, + found => undef, + } + )->forced_hold_level(); + if ($forced_hold_level) { + $biblioLoopIter{force_hold} = 1 if $forced_hold_level eq 'item'; + $biblioLoopIter{itemholdable} = 0 if $forced_hold_level eq 'record'; + } + + push @$biblioLoop, \%biblioLoopIter; $anyholdable = 1 if $biblioLoopIter{holdable}; diff --git a/reserve/placerequest.pl b/reserve/placerequest.pl index f48103b530..c896c9d6d9 100755 --- a/reserve/placerequest.pl +++ b/reserve/placerequest.pl @@ -56,6 +56,7 @@ my $borrower = GetMember( 'borrowernumber' => $borrowernumber ); my $multi_hold = $input->param('multi_hold'); my $biblionumbers = $multi_hold ? $input->param('biblionumbers') : ($biblionumber . '/'); my $bad_bibs = $input->param('bad_bibs'); +my $holds_to_place_count = $input->param('holds_to_place_count') || 1; my %bibinfos = (); my @biblionumbers = split '/', $biblionumbers; @@ -79,30 +80,28 @@ if (defined $checkitem && $checkitem ne ''){ } } -if ($type eq 'str8' && $borrower){ +if ( $type eq 'str8' && $borrower ) { - foreach my $biblionumber (keys %bibinfos) { - my $count=@bibitems; - @bibitems=sort @bibitems; - my $i2=1; + foreach my $biblionumber ( keys %bibinfos ) { + my $count = @bibitems; + @bibitems = sort @bibitems; + my $i2 = 1; my @realbi; - $realbi[0]=$bibitems[0]; - for (my $i=1;$i<$count;$i++) { - my $i3=$i2-1; - if ($realbi[$i3] ne $bibitems[$i]) { - $realbi[$i2]=$bibitems[$i]; + $realbi[0] = $bibitems[0]; + for ( my $i = 1 ; $i < $count ; $i++ ) { + my $i3 = $i2 - 1; + if ( $realbi[$i3] ne $bibitems[$i] ) { + $realbi[$i2] = $bibitems[$i]; $i2++; } } - if (defined $checkitem && $checkitem ne ''){ - my $item = GetItem($checkitem); - if ($item->{'biblionumber'} ne $biblionumber) { - $biblionumber = $item->{'biblionumber'}; - } - } - - + if ( defined $checkitem && $checkitem ne '' ) { + my $item = GetItem($checkitem); + if ( $item->{'biblionumber'} ne $biblionumber ) { + $biblionumber = $item->{'biblionumber'}; + } + } if ($multi_hold) { my $bibinfo = $bibinfos{$biblionumber}; @@ -110,7 +109,11 @@ if ($type eq 'str8' && $borrower){ $bibinfo->{rank},$startdate,$expirationdate,$notes,$bibinfo->{title},$checkitem,$found); } else { # place a request on 1st available - AddReserve($branch,$borrower->{'borrowernumber'},$biblionumber,\@realbi,$rank[0],$startdate,$expirationdate,$notes,$title,$checkitem,$found, $itemtype); + for ( my $i = 0 ; $i < $holds_to_place_count ; $i++ ) { + AddReserve( $branch, $borrower->{'borrowernumber'}, + $biblionumber, \@realbi, $rank[0], $startdate, $expirationdate, $notes, $title, + $checkitem, $found, $itemtype ); + } } } @@ -119,13 +122,16 @@ if ($type eq 'str8' && $borrower){ $biblionumbers .= $bad_bibs; } print $input->redirect("request.pl?biblionumbers=$biblionumbers&multi_hold=1"); - } else { + } + else { print $input->redirect("request.pl?biblionumber=$biblionumber"); } -} elsif ($borrower eq ''){ - print $input->header(); - print "Invalid borrower number please try again"; -# Not sure that Dump() does HTML escaping. Use firebug or something to trace -# instead. -# print $input->Dump; +} +elsif ( $borrower eq '' ) { + print $input->header(); + print "Invalid borrower number please try again"; + + # Not sure that Dump() does HTML escaping. Use firebug or something to trace + # instead. + # print $input->Dump; } diff --git a/reserve/request.pl b/reserve/request.pl index 1980abb9e4..b44493feb0 100755 --- a/reserve/request.pl +++ b/reserve/request.pl @@ -26,8 +26,8 @@ script to place reserves/requests =cut -use strict; -use warnings; +use Modern::Perl; + use C4::Branch; use CGI qw ( -utf8 ); use List::MoreUtils qw/uniq/; @@ -235,38 +235,44 @@ foreach my $biblionumber (@biblionumbers) { $biblioloopiter{$canReserve} = 1; } - my $alreadypossession; - if (not C4::Context->preference('AllowHoldsOnPatronsPossessions') and CheckIfIssuedToPatron($borrowerinfo->{borrowernumber},$biblionumber)) { - $alreadypossession = 1; + my $force_hold_level; + if ( $borrowerinfo->{borrowernumber} ) { + # For multiple holds per record, if a patron has previously placed a hold, + # the patron can only place more holds of the same type. That is, if the + # patron placed a record level hold, all the holds the patron places must + # be record level. If the patron placed an item level hold, all holds + # the patron places must be item level + my $holds = Koha::Holds->search( + { + borrowernumber => $borrowerinfo->{borrowernumber}, + biblionumber => $biblionumber, + found => undef, + } + ); + $force_hold_level = $holds->forced_hold_level(); + $biblioloopiter{force_hold_level} = $force_hold_level; + $template->param( force_hold_level => $force_hold_level ); + + # For a librarian to be able to place multiple record holds for a patron for a record, + # we must find out what the maximum number of holds they can place for the patron is + my $max_holds_for_record = GetMaxPatronHoldsForRecord( $borrowerinfo->{borrowernumber}, $biblionumber ); + $max_holds_for_record = $max_holds_for_record - $holds->count(); + $biblioloopiter{max_holds_for_record} = $max_holds_for_record; + $template->param( max_holds_for_record => $max_holds_for_record ); } - # get existing reserves ..... - my $reserves = GetReservesFromBiblionumber({ biblionumber => $biblionumber, all_dates => 1 }); - my $count = scalar( @$reserves ); - my $totalcount = $count; - my $holds_count = 0; - my $alreadyreserved = 0; - - foreach my $res (@$reserves) { - if ( defined $res->{found} ) { # found can be 'W' or 'T' - $count--; - } - - if ( defined $borrowerinfo && defined($borrowerinfo->{borrowernumber}) && ($borrowerinfo->{borrowernumber} eq $res->{borrowernumber}) ) { - $holds_count++; - } + # Check to see if patron is allowed to place holds on records where the + # patron already has an item from that record checked out + my $alreadypossession; + if ( !C4::Context->preference('AllowHoldsOnPatronsPossessions') + && CheckIfIssuedToPatron( $borrowerinfo->{borrowernumber}, $biblionumber ) ) + { + $template->param( alreadypossession => $alreadypossession, ); } - if ( $holds_count ) { - $alreadyreserved = 1; - $biblioloopiter{warn} = 1; - $biblioloopiter{alreadyres} = 1; - } - $template->param( - alreadyreserved => $alreadyreserved, - alreadypossession => $alreadypossession, - ); + my $count = Koha::Holds->search( { biblionumber => $biblionumber } )->count(); + my $totalcount = $count; # FIXME think @optionloop, is maybe obsolete, or must be switchable by a systeme preference fixed rank or not # make priorities options @@ -329,6 +335,8 @@ foreach my $biblionumber (@biblionumbers) { my $num_override = 0; my $hiddencount = 0; + $biblioitem->{force_hold_level} = $force_hold_level; + if ( $biblioitem->{biblioitemnumber} ne $biblionumber ) { $biblioitem->{hostitemsflag} = 1; } @@ -348,6 +356,8 @@ foreach my $biblionumber (@biblionumbers) { foreach my $itemnumber ( @{ $itemnumbers_of_biblioitem{$biblioitemnumber} } ) { my $item = $iteminfos_of->{$itemnumber}; + $item->{force_hold_level} = $force_hold_level; + unless (C4::Context->preference('item-level_itypes')) { $item->{itype} = $biblioitem->{itemtype}; } @@ -445,13 +455,14 @@ foreach my $biblionumber (@biblionumbers) { $item->{'holdallowed'} = $branchitemrule->{'holdallowed'}; + my $can_item_be_reserved = CanItemBeReserved( $borrowerinfo->{borrowernumber}, $itemnumber ); + $item->{not_holdable} = $can_item_be_reserved unless ( $can_item_be_reserved eq 'OK' ); + if ( !$item->{cantreserve} && !$exceeded_maxreserves && IsAvailableForItemLevelRequest($item, $borrowerinfo) - && CanItemBeReserved( - $borrowerinfo->{borrowernumber}, $itemnumber - ) eq 'OK' + && $can_item_be_reserved eq 'OK' ) { $item->{available} = 1; -- 2.39.5
    - [% IF ( itemloo.available ) %] + [% IF itemloo.force_hold_level == 'record' # Patron has placed a record level hold previously for this record %] + + + Hold must be record level + + [% ELSIF ( itemloo.available ) %] [% ELSIF ( itemloo.override ) %] - Requires override of hold policy + [% ELSE %] - - Cannot be put on hold + + + [% IF itemloo.not_holdable %] + [% IF itemloo.not_holdable == 'damaged' %] + Item damaged + [% ELSIF itemloo.not_holdable == 'ageRestricted' %] + Age restricted + [% ELSIF itemloo.not_holdable == 'tooManyHoldsForThisRecord' %] + Exceeded max holds per record + [% ELSIF itemloo.not_holdable == 'tooManyReserves' %] + Too many holds + [% ELSIF itemloo.not_holdable == 'notReservable' %] + Not holdable + [% ELSIF itemloo.not_holdable == 'cannotReserveFromOtherBranches' %] + Patron is from different library + [% ELSIF itemloo.not_holdable == 'itemAlreadyOnHold' %] + Patron already has hold for this item + [% ELSE %] + [% itemloo.not_holdable %] + [% END %] + [% END %] + [% END %]