- [% 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 ) %] - + [% ELSE %] - - + + + [% 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 %] | [% IF ( item_level_itypes ) %] --- a/opac/opac-reserve.pl +++ a/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}; --- a/reserve/placerequest.pl +++ a/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; } --- a/reserve/request.pl +++ a/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/; @@ -234,38 +234,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 @@ -328,6 +334,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; } @@ -347,6 +355,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}; } @@ -444,13 +454,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; --