[HEAD] (bug #3323) allow rules for reserves in issuing rules.
authorNahuel ANGELINETTI <nahuel.angelinetti@biblibre.com>
Fri, 12 Jun 2009 15:53:43 +0000 (17:53 +0200)
committerHenri-Damien LAURENT <henridamien.laurent@biblibre.com>
Mon, 13 Jul 2009 10:42:36 +0000 (12:42 +0200)
This patch move reserves to issuing rules, and check reserves from branchcode/categorycode/itemtype when it's possible.
In some case we cannot know the branchcode or the itemtype of the document needed to be reserved, so default values(in issuing rules) are used.
It introduce a new syspref : ReservesControlBranch that define which branch should be used to control the user reserves rights and a new column in issuingrules table to store reserves rules.

C4/Circulation.pm
C4/Reserves.pm
admin/smart-rules.pl
installer/data/mysql/en/mandatory/sysprefs.sql
installer/data/mysql/fr-FR/1-Obligatoire/unimarc_standard_systemprefs.sql
installer/data/mysql/kohastructure.sql
installer/data/mysql/updatedatabase.pl
koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tmpl
opac/opac-reserve.pl
reserve/request.pl

index 7ed516f..e33828b 100644 (file)
@@ -712,7 +712,7 @@ sub CanBookBeIssued {
     if ( $borrower->{'dateexpiry'} eq '0000-00-00') {
         $issuingimpossible{EXPIRED} = 1;
     } else {
-        my @expirydate=  split /-/,$borrower->{'dateexpiry'};
+        my @expirydate=  split (/-/,$borrower->{'dateexpiry'});
         if($expirydate[0]==0 || $expirydate[1]==0|| $expirydate[2]==0 ||
             Date_to_Days(Today) > Date_to_Days( @expirydate )) {
             $issuingimpossible{EXPIRED} = 1;                                   
index 90c6fd7..bd6bd8c 100644 (file)
@@ -112,6 +112,8 @@ BEGIN {
         &ModReserveCancelAll
         &ModReserveMinusPriority
         
+        &CanBookBeReserved
+        &CanItemBeReserved
         &CheckReserves
         &CancelReserve
 
@@ -326,6 +328,180 @@ sub GetReservesFromBorrowernumber {
 }
 #-------------------------------------------------------------------------------------
 
+=item CanBookBeReserved
+
+$error = &CanBookBeReserved($borrowernumber, $biblionumber)
+
+=cut
+
+sub CanBookBeReserved{
+    my ($borrowernumber, $biblionumber) = @_;
+
+    my $dbh           = C4::Context->dbh;
+    my $biblio        = GetBiblioData($biblionumber);
+    my $borrower      = C4::Members::GetMember($borrowernumber);
+    my $controlbranch = C4::Context->preference('ReservesControlBranch');
+    my $itype         = C4::Context->preference('item-level_itypes');
+    my $reservesrights= 0;
+    my $reservescount = 0;
+    
+    # we retrieve the user rights
+    my @args;
+    my $rightsquery = "SELECT categorycode, itemtype, branchcode, reservesallowed 
+                       FROM issuingrules 
+                       WHERE categorycode = ?";
+    push @args,$borrower->{categorycode};
+
+    if($controlbranch eq "ItemHomeLibrary"){
+        $rightsquery .= " AND branchcode = '*'";
+    }elsif($controlbranch eq "PatronLibrary"){
+        $rightsquery .= " AND branchcode IN (?,'*')";
+        push @args, $borrower->{branchcode};
+    }
+    
+    if(not $itype){
+        $rightsquery .= " AND itemtype IN (?,'*')";
+        push @args, $biblio->{itemtype};
+    }else{
+        $rightsquery .= " AND itemtype = '*'";
+    }
+    
+    $rightsquery .= " ORDER BY categorycode DESC, itemtype DESC, branchcode DESC";
+    
+    my $sthrights = $dbh->prepare($rightsquery);
+    $sthrights->execute(@args);
+    
+    if(my $row = $sthrights->fetchrow_hashref()){
+       $reservesrights = $row->{reservesallowed};
+    }
+    
+    @args = ();
+    # we count how many reserves the borrower have
+    my $countquery = "SELECT count(*) as count
+                      FROM reserves
+                      LEFT JOIN items USING (itemnumber)
+                      LEFT JOIN biblioitems ON (reserves.biblionumber=biblioitems.biblionumber)
+                      LEFT JOIN borrowers USING (borrowernumber)
+                      WHERE borrowernumber = ?
+                    ";
+    push @args, $borrowernumber;
+    
+    if(not $itype){
+           $countquery .= "AND itemtype = ?";
+           push @args, $biblio->{itemtype};
+    }
+    
+    if($controlbranch eq "PatronLibrary"){
+        $countquery .= " AND borrowers.branchcode = ? ";
+        push @args, $borrower->{branchcode};
+    }
+    
+    my $sthcount = $dbh->prepare($countquery);
+    $sthcount->execute(@args);
+    
+    if(my $row = $sthcount->fetchrow_hashref()){
+       $reservescount = $row->{count};
+    }
+    
+    if($reservescount < $reservesrights){
+        return 1;
+    }else{
+        return 0;
+    }
+    
+}
+
+=item CanItemBeReserved
+
+$error = &CanItemBeReserved($borrowernumber, $itemnumber)
+
+this function return 1 if an item can be issued by this borrower.
+
+=cut
+
+sub CanItemBeReserved{
+    my ($borrowernumber, $itemnumber) = @_;
+    
+    my $dbh             = C4::Context->dbh;
+    my $allowedreserves = 0;
+            
+    my $controlbranch = C4::Context->preference('ReservesControlBranch');
+    my $itype         = C4::Context->preference('item-level_itypes') ? "itype" : "itemtype";
+
+    # we retrieve borrowers and items informations #
+    my $item     = GetItem($itemnumber);
+    my $borrower = C4::Members::GetMember($borrowernumber);     
+    
+    # we retrieve user rights on this itemtype and branchcode
+    my $sth = $dbh->prepare("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 $querycount ="SELECT 
+                            count(*) as count
+                            FROM reserves
+                                LEFT JOIN items USING (itemnumber)
+                                LEFT JOIN biblioitems ON (reserves.biblionumber=biblioitems.biblionumber)
+                                LEFT JOIN borrowers USING (borrowernumber)
+                            WHERE borrowernumber = ?
+                                ";
+    
+    
+    my $itemtype     = $item->{$itype};
+    my $categorycode = $borrower->{categorycode};
+    my $branchcode   = "";
+    my $branchfield  = "reserves.branchcode";
+    
+    if( $controlbranch eq "ItemHomeLibrary" ){
+        $branchfield = "items.homebranch";
+        $branchcode = $item->{homebranch};
+    }elsif( $controlbranch eq "PatronLibrary" ){
+        $branchfield = "borrowers.branchcode";
+        $branchcode = $borrower->{branchcode};
+    }
+    
+    # we retrieve rights 
+    $sth->execute($categorycode, $itemtype, $branchcode);
+    if(my $rights = $sth->fetchrow_hashref()){
+        $itemtype        = $rights->{itemtype};
+        $allowedreserves = $rights->{reservesallowed}; 
+    }else{
+        $itemtype = '*';
+    }
+    
+    # we retrieve count
+    
+    $querycount .= "AND $branchfield = ?";
+    
+    $querycount .= " AND $itype = ?" if ($itemtype ne "*");
+    my $sthcount = $dbh->prepare($querycount);
+    
+    if($itemtype eq "*"){
+        $sthcount->execute($borrowernumber, $branchcode);
+    }else{
+        $sthcount->execute($borrowernumber, $branchcode, $itemtype);
+    }
+    
+    my $reservecount = "0";
+    if(my $rowcount = $sthcount->fetchrow_hashref()){
+        $reservecount = $rowcount->{count};
+    }
+    
+    # we check if it's ok or not
+    if( $reservecount < $allowedreserves ){
+        return 1;
+    }else{
+        return 0;
+    }
+}
+
 =item GetReserveCount
 
 $number = &GetReserveCount($borrowernumber);
index db5bca9..79cd0af 100755 (executable)
@@ -99,8 +99,8 @@ elsif ($op eq 'delete-branch-item') {
 # save the values entered
 elsif ($op eq 'add') {
     my $sth_search = $dbh->prepare("SELECT COUNT(*) AS total FROM issuingrules WHERE branchcode=? AND categorycode=? AND itemtype=?");
-    my $sth_insert = $dbh->prepare("INSERT INTO issuingrules (branchcode, categorycode, itemtype, maxissueqty, renewalsallowed, issuelength, fine, finedays, firstremind, chargeperiod) VALUES(?,?,?,?,?,?,?,?,?)");
-    my $sth_update=$dbh->prepare("UPDATE issuingrules SET fine=?, finedays=?, firstremind=?, chargeperiod=?, maxissueqty=?, renewalsallowed=?, issuelength=? WHERE branchcode=? AND categorycode=? AND itemtype=?");
+    my $sth_insert = $dbh->prepare("INSERT INTO issuingrules (branchcode, categorycode, itemtype, maxissueqty, renewalsallowed, reservesallowed, issuelength, fine, finedays,firstremind, chargeperiod) VALUES(?,?,?,?,?,?,?,?,?,?)");
+    my $sth_update=$dbh->prepare("UPDATE issuingrules SET fine=?, finedays=?, firstremind=?, chargeperiod=?, maxissueqty=?, renewalsallowed=?, reservesallowed=?, issuelength=? WHERE branchcode=? AND categorycode=? AND itemtype=?");
     
     my $br = $branch; # branch
     my $bor  = $input->param('categorycode'); # borrower category
@@ -111,6 +111,7 @@ elsif ($op eq 'add') {
     my $chargeperiod = $input->param('chargeperiod');
     my $maxissueqty  = $input->param('maxissueqty');
     my $renewalsallowed  = $input->param('renewalsallowed');
+    my $reservesallowed  = $input->param('reservesallowed');
     $maxissueqty =~ s/\s//g;
     $maxissueqty = undef if $maxissueqty !~ /^\d+/;
     my $issuelength  = $input->param('issuelength');
@@ -119,9 +120,9 @@ elsif ($op eq 'add') {
     $sth_search->execute($br,$bor,$cat);
     my $res = $sth_search->fetchrow_hashref();
     if ($res->{total}) {
-        $sth_update->execute($fine, $finedays, $firstremind, $chargeperiod, $maxissueqty,$renewalsallowed,$issuelength,$br,$bor,$cat);
+        $sth_update->execute($fine, $finedays, $firstremind, $chargeperiod, $maxissueqty,$renewalsallowed,$reservesallowed,$issuelength,$br,$bor,$cat);
     } else {
-        $sth_insert->execute($br,$bor,$cat,$maxissueqty,$renewalsallowed,$issuelength,$fine, $finedays,$firstremind,$chargeperiod);
+        $sth_insert->execute($br,$bor,$cat,$maxissueqty,$renewalsallowed,$reservesallowed,$issuelength,$fine,$finedays,$firstremind,$chargeperiod);
     }
 } 
 elsif ($op eq "set-branch-defaults") {
index a978fad..771e56e 100644 (file)
@@ -56,7 +56,6 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('MARCOrgCode','OSt','Define MARC Organization Code - http://www.loc.gov/marc/organizations/orgshome.html','','free');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('MaxFine',9999,'Maximum fine a patron can have for a single late return','','Integer');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('maxoutstanding',5,'maximum amount withstanding to be able make holds','','Integer');
-INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('maxreserves',50,'Define maximum number of holds a patron can place','','Integer');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('memberofinstitution',0,'If ON, patrons can be linked to institutions',NULL,'YesNo');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('MIME','EXCEL','Define the default application for exporting report data','EXCEL|OPENOFFICE.ORG','Choice');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('noissuescharge',5,'Define maximum amount withstanding before check outs are blocked','','Integer');
@@ -245,3 +244,4 @@ INSERT INTO systempreferences (variable,value,explanation,options,type)VALUES('v
 INSERT INTO systempreferences (variable,value,explanation,options,type)VALUES('viewLabeledMARC','0','Allow display of labeled MARC view of bibiographic records','','YesNo');
 INSERT INTO systempreferences (variable,value,explanation,options,type)VALUES('viewMARC','1','Allow display of MARC view of bibiographic records','','YesNo');
 INSERT INTO systempreferences (variable,value,explanation,options,type)VALUES('FilterBeforeOverdueReport','0','Do not run overdue report until filter selected','','YesNo');
+INSERT INTO systempreferences (variable,value, options, explanation, type) VALUES('ReservesControlBranch','PatronLibrary','ItemHomeLibrary|PatronLibrary','Branch checked for members reservations rights','Choice');
index b9b616e..64daa4f 100644 (file)
@@ -57,7 +57,6 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('MARCOrgCode', '0', 'Ce paramètre définit votre code organisme MARC. Utilisé en MARC21. Voir  - http://www.loc.gov/marc/organizations/orgshome.html', '', '');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('MaxFine','9999','Amende maximum qu''un ahdérent peut avoir pour un retour en retard','','Integer');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('maxoutstanding', '5', 'Ce paramètre définit le montant maximal des dettes au dela duquel le lecteur ne peut plus faire de réservation', '', 'Integer');
-INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('maxreserves', '2', 'Ce paramètre définit le nombre maximal de réservations qu''un lecteur peut faire.', '', 'Integer');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('memberofinstitution', '0', 'Vos adhérents sont ils membres d''une institution ?', NULL, 'YesNo');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('MIME', 'OPENOFFICE.ORG', 'Ce paramètre définit l''application par défaut à ouvrir lorsqu''on télécharge un fichier (OpenOffice.org ou MS-Excel habituellement)', 'EXCEL|OPENOFFICE.ORG', 'Choice');
 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('noissuescharge', '5', 'Ce paramètre définit le montant maximal des dettes au delà duquel le lecteur ne peut plus emprunter', '', 'Integer');
@@ -250,3 +249,4 @@ INSERT INTO systempreferences (variable,value,explanation,options,type)VALUES('v
 INSERT INTO systempreferences (variable,value,explanation,options,type)VALUES('viewLabeledMARC','0','Autoriser l''affichage MARC labellis des notices bibliographiques','','YesNo');
 INSERT INTO systempreferences (variable,value,explanation,options,type)VALUES('viewMARC','1','Autoriser l''affichage de la vue MARC des notices bibliographiques','','YesNo');
 INSERT INTO systempreferences (variable,value,explanation,options,type)VALUES('FilterBeforeOverdueReport','0','Ne pas lancer le rapport sur les retards tant qu''il n''y a pas de filtre','','YesNo');
+INSERT INTO systempreferences (variable,value, options, explanation, type) VALUES('ReservesControlBranch','PatronLibrary','ItemHomeLibrary|PatronLibrary','Site de controle pour les reservations','Choice');
index e2b62af..6c037e3 100644 (file)
@@ -1143,6 +1143,7 @@ CREATE TABLE `issuingrules` (
   `maxissueqty` int(4) default NULL,
   `issuelength` int(4) default NULL,
   `renewalsallowed` smallint(6) NOT NULL default "0",
+  `reservesallowed` smallint(6) NOT NULL default "0",
   `branchcode` varchar(10) NOT NULL default '',
   PRIMARY KEY  (`branchcode`,`categorycode`,`itemtype`),
   KEY `categorycode` (`categorycode`),
index dd0cf7d..d05dedb 100755 (executable)
@@ -2192,6 +2192,22 @@ if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
     print "Upgrade to $DBversion done (Moving allowed renewals from itemtypes to issuingrule)\n";
 }
 
+$DBversion = '3.01.00.040';
+if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
+    $dbh->do('ALTER TABLE issuingrules ADD COLUMN `reservesallowed` smallint(6) NOT NULL default "0" AFTER `renewalsallowed`;');
+    
+    my $maxreserves = C4::Context->preference('maxreserves');
+    $sth = $dbh->prepare('UPDATE issuingrules SET reservesallowed = ?;');
+    $sth->execute($maxreserves);
+    
+    $dbh->do('DELETE FROM systempreferences WHERE variable = "maxreserves";');
+
+    $dbh->do("INSERT INTO systempreferences (variable,value, options, explanation, type) VALUES('ReservesControlBranch','PatronLibrary','ItemHomeLibrary|PatronLibrary','Branch checked for members reservations rights','Choice')");
+    
+    SetVersion ($DBversion);
+    print "Upgrade to $DBversion done (Moving max allowed reserves from system preference to issuingrule)\n";
+}
+
 =item DropAllForeignKeys($table)
 
   Drop all foreign keys of the table $table
index 4f9aa99..f74b242 100644 (file)
@@ -70,6 +70,7 @@ $(document).ready(function() {
                 <th>Fine Charging Interval</th>
                 <th>Current Checkouts Allowed</th>
                 <th>Renewals Allowed</th>
+                <th>Reserves Allowed</th>
                 <th>Loan Period</th><th>&nbsp;</th>
             </tr>
             <!-- TMPL_LOOP NAME="rules" -->
@@ -105,6 +106,7 @@ $(document).ready(function() {
                         <!-- /TMPL_IF -->
                     </td>
                                        <td><!-- TMPL_IF NAME="renewalsallowed" --><!-- TMPL_VAR NAME="renewalsallowed" --> time(s)<!-- /TMPL_IF --></td>
+                                       <td><!-- TMPL_IF NAME="reservesallowed" --><!-- TMPL_VAR NAME="reservesallowed" --> time(s)<!-- /TMPL_IF --></td>
                     <td><!-- TMPL_IF NAME="issuelength" --><!-- TMPL_VAR NAME="issuelength" --> day(s)<!-- /TMPL_IF --></td>
                     <td>
                         <a class="button" href="/cgi-bin/koha/admin/smart-rules.pl?op=delete&amp;itemtype=<!-- TMPL_VAR NAME="itemtype" -->&amp;categorycode=<!-- TMPL_VAR NAME="categorycode" -->&amp;branch=<!-- TMPL_VAR NAME="branch" -->">Delete</a>
@@ -134,6 +136,7 @@ $(document).ready(function() {
                     <td><input name="chargeperiod" size="2" /> day(s)</td>
                     <td><input name="maxissueqty" size="3" /></td>
                     <td><input name="renewalsallowed" size="3" /></td>
+                    <td><input name="reservesallowed" size="3" /></td>
                     <td><input name="issuelength" size="3" /> day(s)</td>
                     <td><input type="hidden" name="branch" value="<!-- TMPL_VAR NAME="branch" -->"/><input type="submit" value="Add" class="submit" /></td>
                 </tr>
index 4395f38..1cfaa0b 100755 (executable)
@@ -32,8 +32,6 @@ use C4::Branch; # GetBranches
 use C4::Debug;
 # use Data::Dumper;
 
-my $MAXIMUM_NUMBER_OF_RESERVES = C4::Context->preference("maxreserves");
-
 my $query = new CGI;
 my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
     {
@@ -190,11 +188,13 @@ if ( $query->param('place_reserve') ) {
 
         my $biblioData = $biblioDataHash{$biblioNum};
         my $found;
+        my $canreserve = 0;
         
         # If a specific item was selected and the pickup branch is the same as the
         # holdingbranch, force the value $rank and $found.
         my $rank = $biblioData->{rank};
         if ($itemNum ne ''){
+            $canreserve = 1 if CanItemBeReserved($borrowernumber,$itemNum);
             $rank = '0' unless C4::Context->preference('ReservesNeedReturns');
             my $item = GetItem($itemNum);
             if ( $item->{'holdingbranch'} eq $branch ){
@@ -203,12 +203,13 @@ if ( $query->param('place_reserve') ) {
         }
         else {
             # Inserts a null into the 'itemnumber' field of 'reserves' table.
+            $canreserve = 1 if CanBookBeReserved($borrowernumber,$biblioNum);
             $itemNum = undef;
         }
         
         # Here we actually do the reserveration. Stage 3.
         AddReserve($branch, $borrowernumber, $biblioNum, 'a', [$biblioNum], $rank, $notes,
-                   $biblioData->{'title'}, $itemNum, $found);
+                   $biblioData->{'title'}, $itemNum, $found) if $canreserve;
     }
 
     print $query->redirect("/cgi-bin/koha/opac-user.pl#opac-user-holds");
@@ -253,11 +254,8 @@ if ( $borr->{debarred} && ($borr->{debarred} eq 1) ) {
 
 my @reserves = GetReservesFromBorrowernumber( $borrowernumber );
 $template->param( RESERVES => \@reserves );
-if ( scalar(@reserves) >= $MAXIMUM_NUMBER_OF_RESERVES ) {
-    $template->param( message => 1 );
-    $noreserves = 1;
-    $template->param( too_many_reserves => scalar(@reserves));
-}
+
+
 foreach my $res (@reserves) {
     foreach my $biblionumber (@biblionumbers) {
         if ( $res->{'biblionumber'} == $biblionumber && $res->{'borrowernumber'} == $borrowernumber) {
@@ -421,7 +419,7 @@ foreach my $biblioNum (@biblionumbers) {
             $policy_holdallowed = 0;
         }
 
-        if (IsAvailableForItemLevelRequest($itemNum) and $policy_holdallowed) {
+        if (IsAvailableForItemLevelRequest($itemNum) and $policy_holdallowed and CanItemBeReserved($borrowernumber,$itemNum)) {
             $itemLoopIter->{available} = 1;
             $numCopiesAvailable++;
         }
@@ -447,6 +445,10 @@ foreach my $biblioNum (@biblionumbers) {
         $biblioLoopIter{holdable} = undef;
     }
 
+    if(not CanBookBeReserved($borrowernumber,$biblioNum)){
+        $biblioLoopIter{holdable} = undef;
+    }
+    
     push @$biblioLoop, \%biblioLoopIter;
 }
 
index 9898a86..2b2c432 100755 (executable)
@@ -88,6 +88,7 @@ my $borrowerslist;
 my $messageborrower;
 my $warnings;
 my $messages;
+my $maxreserves;
 
 my $date = C4::Dates->today('iso');
 
@@ -115,24 +116,20 @@ if ($cardnumber) {
     my $diffbranch;
     my @getreservloop;
     my $count_reserv = 0;
-    my $maxreserves;
 
 #   we check the reserves of the borrower, and if he can reserv a document
 # FIXME At this time we have a simple count of reservs, but, later, we could improve the infos "title" ...
 
+    
+
     my $number_reserves =
       GetReserveCount( $borrowerinfo->{'borrowernumber'} );
-
-    if ( $number_reserves > C4::Context->preference('maxreserves') ) {
-               $warnings = 1;
-        $maxreserves = 1;
-    }
-
+    
     # we check the date expiry of the borrower (only if there is an expiry date, otherwise, set to 1 (warn)
     my $expiry_date = $borrowerinfo->{dateexpiry};
     my $expiry = 0; # flag set if patron account has expired
     if ($expiry_date and $expiry_date ne '0000-00-00' and
-            Date_to_Days(split /-/,$date) > Date_to_Days(split /-/,$expiry_date)) {
+            Date_to_Days(split (/-/,$date)) > Date_to_Days(split (/-/,$expiry_date))) {
                $messages = $expiry = 1;
     }else{
         $expiry = 0;
@@ -159,7 +156,6 @@ if ($cardnumber) {
                 borroweremailpro => $borrowerinfo->{'emailpro'},
                 borrowercategory => $borrowerinfo->{'category'},
                 borrowerreservs   => $count_reserv,
-                maxreserves       => $maxreserves,
                 expiry            => $expiry,
                 diffbranch        => $diffbranch,
                                messages => $messages,
@@ -215,6 +211,11 @@ if ($multihold) {
 my @biblioloop = ();
 foreach my $biblionumber (@biblionumbers) {
 
+    if ( not CanBookBeReserved($borrowerinfo->{borrowernumber}, $biblionumber) ) {
+               $warnings = 1;
+        $maxreserves = 1;
+    }
+
     my %biblioloopiter = ();
 
     my $dat          = GetBiblioData($biblionumber);
@@ -401,7 +402,7 @@ foreach my $biblionumber (@biblionumbers) {
                 $policy_holdallowed = 0;
             }
             
-            if (IsAvailableForItemLevelRequest($itemnumber) and not $item->{cantreserve}) {
+            if (IsAvailableForItemLevelRequest($itemnumber) and not $item->{cantreserve} and CanItemBeReserved($borrowerinfo->{borrowernumber}, $itemnumber) ) {
                 if ( not $policy_holdallowed and C4::Context->preference( 'AllowHoldPolicyOverride' ) ) {
                     $item->{override} = 1;
                     $num_override++;
@@ -547,6 +548,7 @@ foreach my $biblionumber (@biblionumbers) {
 
 $template->param( biblioloop => \@biblioloop );
 $template->param( biblionumbers => $biblionumbers );
+$template->param( maxreserves => $maxreserves );
 
 if ($multihold) {
     $template->param( multi_hold => 1 );