@@ -, +, @@ you should not be able to ( default is 1 per record ) you should be able to place 3 holds for one patron on a given record. A 4th hold should result in a message stating the patron has placed the max number of holds allowed on this record. --reject and has not tested it! --- C4/Reserves.pm | 59 +++++++++++++--------- installer/data/mysql/sysprefs.sql | 1 + installer/data/mysql/updatedatabase.pl | 9 ++++ .../en/modules/admin/preferences/circulation.pref | 7 ++- .../prog/en/modules/reserve/request.tt | 4 +- .../opac-tmpl/bootstrap/en/modules/opac-reserve.tt | 2 + opac/opac-reserve.pl | 22 +++++--- reserve/request.pl | 19 +++++-- 8 files changed, 85 insertions(+), 38 deletions(-) --- a/C4/Reserves.pm +++ a/C4/Reserves.pm @@ -417,36 +417,47 @@ sub GetReservesFromItemnumber { =head2 GetReservesFromBorrowernumber - $borrowerreserv = GetReservesFromBorrowernumber($borrowernumber,$tatus); - -TODO :: Descritpion + $borrowerreserv = GetReservesFromBorrowernumber($borrowernumber[,$status][,$biblionumber][,$itemnumber]); =cut sub GetReservesFromBorrowernumber { - my ( $borrowernumber, $status ) = @_; - my $dbh = C4::Context->dbh; - my $sth; - if ($status) { - $sth = $dbh->prepare(" - SELECT * - FROM reserves - WHERE borrowernumber=? - AND found =? - ORDER BY reservedate - "); - $sth->execute($borrowernumber,$status); - } else { - $sth = $dbh->prepare(" - SELECT * - FROM reserves - WHERE borrowernumber=? - ORDER BY reservedate - "); - $sth->execute($borrowernumber); + my ( $borrowernumber, $found, $biblionumber, $itemnumber ) = @_; + + my @params; + + my $sql = "SELECT * FROM reserves WHERE borrowernumber = ?"; + push( @params, $borrowernumber ); + + if ( $biblionumber ) { + $sql .= " AND biblionumber = ? "; + push( @params, $biblionumber ); + } + + if ( $itemnumber ) { + $sql .= " AND itemnumber = ? "; + push( @params, $itemnumber ); } + + if ( $found ) { + $sql .= " AND found = ? "; + push( @params, $found ); + } + + $sql .= " ORDER BY reservedate "; + + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare( $sql ); + + $sth->execute( @params ); + my $data = $sth->fetchall_arrayref({}); - return @$data; + + if ( scalar @$data ) { + return @$data; + } else { + return (); + } } #------------------------------------------------------------------------------------- =head2 CanBookBeReserved --- a/installer/data/mysql/sysprefs.sql +++ a/installer/data/mysql/sysprefs.sql @@ -198,6 +198,7 @@ INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` ('MarcFieldsToOrder','',NULL,'Set the mapping values for a new order line created from a MARC record in a staged file. In a YAML format.','textarea'), ('MARCOrgCode','OSt','','Define MARC Organization Code for MARC21 records - http://www.loc.gov/marc/organizations/orgshome.html','free'), ('MaxFine',NULL,'','Maximum fine a patron can have for all late returns at one moment. Single item caps are specified in the circulation rules matrix.','Integer'), +('MaxHoldsPerRecord', '1', 'The maximum number of holds allowed per bibliographic record per borrower', 'Integer'), ('MaxItemsForBatch','1000',NULL,'Max number of items record to process in a batch (modification or deletion)','Integer'), ('maxItemsInSearchResults','20',NULL,'Specify the maximum number of items to display for each result on a page of results','free'), ('maxoutstanding','5','','maximum amount withstanding to be able make holds','Integer'), --- a/installer/data/mysql/updatedatabase.pl +++ a/installer/data/mysql/updatedatabase.pl @@ -9669,6 +9669,15 @@ if ( CheckVersion($DBversion) ) { SetVersion ($DBversion); } +$DBversion = "3.19.00.XXX"; +if ( CheckVersion($DBversion) ) { + $dbh->do(q| + INSERT IGNORE INTO systempreferences (variable,value,explanation,options,type) VALUES ('MaxHoldsPerRecord', '1', 'The maximum number of holds allowed per bibliographic record per borrower', NULL, 'Integer') + |); + print "Upgrade to $DBversion done (Bug 7710 - multiple holds per title)\n"; + SetVersion ($DBversion); +} + =head1 FUNCTIONS =head2 TableExists($table) --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref @@ -515,7 +515,12 @@ Circulation: - Patrons can only have - pref: maxreserves class: integer - - holds at once. + - total holds at a time. + - + - Patrons can only place + - pref: MaxHoldsPerRecord + class: integer + - holds on a single record at a time. - - pref: emailLibrarianWhenHoldIsPlaced choices: --- a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt @@ -62,7 +62,7 @@ function check() { } if (alreadyreserved > "0"){ - msg += (_("- This patron had already placed a hold on this item") + "\n" + _("Please cancel the previous hold first") + "\n"); + msg += (_("This patron has already placed the maximum number of holds for this record.") + "\n\n" + _("Please cancel a previous hold first.") + "\n"); } if (msg == "") return(true); @@ -260,7 +260,7 @@ function checkMultiHold() {
  • Age restricted
  • [% END %] [% IF ( alreadyreserved ) %] -
  • [% borrowerfirstname %] [% borrowersurname %] already has a hold on this item
  • +
  • [% borrowerfirstname %] [% borrowersurname %] has already placed the maximum allowed number of holds on this record< /li> [% END %] [% IF ( none_available ) %]
  • No items are available to be placed on hold
  • --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-reserve.tt +++ a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-reserve.tt @@ -154,6 +154,8 @@ [% ELSE %] [% IF ( bibitemloo.already_patron_possession ) %]
    This title cannot be requested because it's already in your possession.
    + [% ELSIF bibitemloo.max_holds %] +
    This title cannot be requested. You have already placed the maximum number of requests allowed for this title.
    [% ELSE %]
    This title cannot be requested.
    [% END %] --- a/opac/opac-reserve.pl +++ a/opac/opac-reserve.pl @@ -40,6 +40,7 @@ use Date::Calc qw/Today Date_to_Days/; # use Data::Dumper; my $maxreserves = C4::Context->preference("maxreserves"); +my $max_holds_per_record = C4::Context->preference('MaxHoldsPerRecord'); my $query = new CGI; my ( $template, $borrowernumber, $cookie ) = get_template_and_user( @@ -348,12 +349,10 @@ 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; + $biblioDataHash{$biblionumber}->{holds_count}++; } } + } unless ($noreserves) { @@ -397,6 +396,7 @@ foreach my $biblioNum (@biblionumbers) { $biblioLoopIter{reservecount} = $biblioData->{reservecount}; $biblioLoopIter{already_reserved} = $biblioData->{already_reserved}; $biblioLoopIter{mandatorynotes}=0; #FIXME: For future use + $biblioLoopIter{holds_count} = $biblioData->{holds_count}; if (!$itemLevelTypes && $biblioData->{itemtype}) { $biblioLoopIter{description} = $itemTypes->{$biblioData->{itemtype}}{description}; @@ -525,14 +525,17 @@ foreach my $biblioNum (@biblionumbers) { $policy_holdallowed = 0; } - if (IsAvailableForItemLevelRequest($itemNum) and $policy_holdallowed and CanItemBeReserved($borrowernumber,$itemNum) eq 'OK' and ($itemLoopIter->{already_reserved} ne 1)) { + if (IsAvailableForItemLevelRequest($itemNum) and $policy_holdallowed and CanItemBeReserved($borrowernumber,$itemNum) and ($itemLoopIter->{holds_count} < $max_holds_per_record )) { $itemLoopIter->{available} = 1; $numCopiesAvailable++; } $itemLoopIter->{imageurl} = getitemtypeimagelocation( 'opac', $itemTypes->{ $itemInfo->{itype} }{imageurl} ); - # Show serial enumeration when needed + # Don't allow multiple item level holds on the same item if borrowers can place multiple holds on one bib + $itemLoopIter->{available} = 0 if ( GetReservesFromBorrowernumber( $borrowernumber, undef, undef, $itemNum ) ); + + # Show serial enumeration when needed if ($itemLoopIter->{enumchron}) { $itemdata_enumchron = 1; } @@ -549,6 +552,13 @@ foreach my $biblioNum (@biblionumbers) { if ($biblioLoopIter{already_reserved}) { $biblioLoopIter{holdable} = undef; } + + if ($biblioLoopIter{holds_count} >= $max_holds_per_record) { + $biblioLoopIter{holdable} = undef; + $anyholdable = undef; + $biblioLoopIter{max_holds} = 1; + } + my $canReserve = CanBookBeReserved($borrowernumber,$biblioNum); unless ($canReserve eq 'OK') { $biblioLoopIter{holdable} = undef; --- a/reserve/request.pl +++ a/reserve/request.pl @@ -174,6 +174,7 @@ $template->param( messageborrower => $messageborrower ); # FIXME launch another time GetMember perhaps until my $borrowerinfo = GetMember( borrowernumber => $borrowernumber_hold ); +my $max_holds_per_record = C4::Context->preference('MaxHoldsPerRecord'); my @biblionumbers = (); my $biblionumbers = $input->param('biblionumbers'); @@ -229,15 +230,17 @@ foreach my $biblionumber (@biblionumbers) { } } - if ( $holds_count ) { - $alreadyreserved = 1; - $biblioloopiter{warn} = 1; - $biblioloopiter{alreadyres} = 1; + if ( $holds_count > $max_holds_per_record ) { + $alreadyreserved = 1; + $biblioloopiter{warn} = 1; + $biblioloopiter{alreadyres} = 1; + $biblioloopiter{maxreserves} = $max_holds_per_record; } $template->param( - alreadyreserved => $alreadyreserved, + alreadyreserved => $alreadyreserved, alreadypossession => $alreadypossession, + maxreserves => $maxreserves, ); # FIXME think @optionloop, is maybe obsolete, or must be switchable by a systeme preference fixed rank or not @@ -446,6 +449,12 @@ foreach my $biblionumber (@biblionumbers) { $itemdata_enumchron = 1; } + # Don't allow multiple item level holds on the same item if borrowers can place multiple holds on one bib + if ( GetReservesFromBorrowernumber( $borrowerinfo->{borrowernumber}, undef, undef, $itemnumber) ) { + $item->{available} = 0; + $item->{override} = 0; + } + push @{ $biblioitem->{itemloop} }, $item; } --