Bug 14695 - Add ability to place multiple item holds on a given record per patron

Signed-off-by: Nick Clemens <nick@bywatersolutions.com>

Signed-off-by: Jason M. Burds <JBurds@dubuque.lib.ia.us>
Signed-off-by: Benjamin Rokseth <benjamin.rokseth@kul.oslo.kommune.no>
This commit is contained in:
Kyle M Hall 2015-12-29 19:14:19 +00:00
parent abeed5b5f1
commit bc39f0392b
6 changed files with 317 additions and 148 deletions

View File

@ -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 <http://koha-community.org/>

View File

@ -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

View File

@ -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<document.form.checkitem.length;i++){
if (document.form.checkitem[i].checked == true) {
count_reserv++ ;
}
count_reserv++ ;
}
}
// for only one item, check the checkitem without consider the loop checkitem
if (i==0){
if (document.form.checkitem.checked == true) {
count_reserv++;
}
}
if (document.form.checkitem.checked == true) {
count_reserv++;
}
}
}
if (document.form.request.checked == true){
count_reserv++ ;
}
if (document.form.alreadyreserved && document.form.alreadyreserved.value == "1"){
alreadyreserved++ ;
if (document.form.requestany.checked == true){
count_reserv++ ;
}
if (count_reserv == "0"){
msg += (_("- Please select an item to place a hold") + "\n");
}
if (count_reserv >= "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 ) %]
<li><strong>Too many holds: </strong> <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %] </a> can only place a maximum of [% maxreserves %] total holds.</li>
[% ELSIF ( alreadypossession ) %]
<li> <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %]</a> <strong>is already in possession</strong> of one item</li>
<li> <a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %]</a> <strong>is already in possession</strong> of one item</lie
[% ELSIF ( alreadyreserved ) %]
<li><a href="/cgi-bin/koha/members/moremember.pl?borrowernumber=[% borrowernumber %]">[% borrowerfirstname %] [% borrowersurname %]</a> <strong>already has a hold</strong> on this item </li>
[% ELSIF ( ageRestricted ) %]
@ -402,11 +393,34 @@ function checkMultiHold() {
</li>
[% UNLESS ( multi_hold ) %]
<li> <label for="requestany">Place a hold on the next available item </label>
<input type="checkbox" id="requestany" name="request" checked="checked" value="Any" />
<li> <label for="requestany">Hold next available item </label>
[% IF force_hold_level == 'item' %]
<input type="checkbox" id="requestany" name="request" disabled="true" />
[% ELSIF force_hold_level == 'record' %]
<input type="checkbox" id="requestany" checked="checked" value="Any" disabled="true"/>
<input type="hidden" name="request" value="Any"/>
[% ELSE %]
<input type="checkbox" id="requestany" name="request" checked="checked" value="Any" />
[% END %]
<input type="hidden" name="biblioitem" value="[% biblioitemnumber %]" />
<input type="hidden" name="alreadyreserved" value="[% alreadyreserved %]" />
</li>
[% IF max_holds_for_record > 1 %]
[% SET count = 1 %]
<li>
<label for="holds_to_place_count">Holds to place (count)</label>
<select name="holds_to_place_count" id="holds_to_place_count">
[% WHILE count <= max_holds_for_record %]
<option value="[% count %]">[% count %]</option>
[% SET count = count + 1 %]
[% END %]
</select>
</li>
[% ELSE %]
<input type="hidden" name="holds_to_place_count" value="1";
[% END %]
[% END %]
</ol>
@ -431,7 +445,12 @@ function checkMultiHold() {
[% IF ( bibitemloo.publicationyear ) %]<li><span class="label">Publication year:</span> [% bibitemloo.publicationyear %]</li>[% END %]
</ol>
<h2 style="padding: 0 1em;">Place a hold on a specific item</h2>
<h2 style="padding: 0 1em;">
Place a hold on a specific item
[% IF bibitemloo.force_hold_level == 'item' %]
<span class="error"><i>(Required)</i></span>
[% END %]
</h2>
<table id="requestspecific">
<thead>
<tr>
@ -451,18 +470,44 @@ function checkMultiHold() {
</tr>
</thead>
<tbody>
[% SET selected = 0 %]
[% FOREACH itemloo IN bibitemloo.itemloop %]
[% UNLESS ( itemloo.hide ) %]
<tr class="[% itemloo.backgroundcolor %]">
<td>
[% IF ( itemloo.available ) %]
[% IF itemloo.force_hold_level == 'record' # Patron has placed a record level hold previously for this record %]
<span class="error">
<i class="fa fa-times fa-lg" alt="Cannot be put on hold"></i>
Hold must be record level
</span>
[% ELSIF ( itemloo.available ) %]
<input type="radio" name="checkitem" value="[% itemloo.itemnumber %]" />
[% ELSIF ( itemloo.override ) %]
<input type="radio" name="checkitem" class="needsoverride" value="[% itemloo.itemnumber %]" />
<img src="[% interface %]/[% theme %]/img/famfamfam/silk/error.png" alt="Requires override of hold policy" />
<i class="fa fa-exclamation-triangle fa-lg" style="color:gold" alt="Requires override of hold policy"/></i>
[% ELSE %]
<input disabled="disabled" type="radio" name="checkitem" value="[% itemloo.itemnumber %]" />
<img src="[% interface %]/[% theme %]/img/famfamfam/silk/cross.png" alt="Cannot be put on hold" />
<span class="error">
<i class="fa fa-times fa-lg" alt="Cannot be put on hold"></i>
[% 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 %]
</span>
[% END %]
</td>
[% IF ( item_level_itypes ) %]

View File

@ -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};

View File

@ -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;
}

View File

@ -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 $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 );
}
# 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 (not C4::Context->preference('AllowHoldsOnPatronsPossessions') and CheckIfIssuedToPatron($borrowerinfo->{borrowernumber},$biblionumber)) {
$alreadypossession = 1;
if ( !C4::Context->preference('AllowHoldsOnPatronsPossessions')
&& CheckIfIssuedToPatron( $borrowerinfo->{borrowernumber}, $biblionumber ) )
{
$template->param( alreadypossession => $alreadypossession, );
}
# get existing reserves .....
my $reserves = GetReservesFromBiblionumber({ biblionumber => $biblionumber, all_dates => 1 });
my $count = scalar( @$reserves );
my $count = Koha::Holds->search( { biblionumber => $biblionumber } )->count();
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++;
}
}
if ( $holds_count ) {
$alreadyreserved = 1;
$biblioloopiter{warn} = 1;
$biblioloopiter{alreadyres} = 1;
}
$template->param(
alreadyreserved => $alreadyreserved,
alreadypossession => $alreadypossession,
);
# 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;