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.
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;
&ModReserveCancelAll
&ModReserveMinusPriority
+ &CanBookBeReserved
+ &CanItemBeReserved
&CheckReserves
&CancelReserve
}
#-------------------------------------------------------------------------------------
+=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);
# 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
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');
$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") {
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');
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');
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');
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');
`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`),
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
<th>Fine Charging Interval</th>
<th>Current Checkouts Allowed</th>
<th>Renewals Allowed</th>
+ <th>Reserves Allowed</th>
<th>Loan Period</th><th> </th>
</tr>
<!-- TMPL_LOOP NAME="rules" -->
<!-- /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&itemtype=<!-- TMPL_VAR NAME="itemtype" -->&categorycode=<!-- TMPL_VAR NAME="categorycode" -->&branch=<!-- TMPL_VAR NAME="branch" -->">Delete</a>
<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>
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(
{
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 ){
}
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");
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) {
$policy_holdallowed = 0;
}
- if (IsAvailableForItemLevelRequest($itemNum) and $policy_holdallowed) {
+ if (IsAvailableForItemLevelRequest($itemNum) and $policy_holdallowed and CanItemBeReserved($borrowernumber,$itemNum)) {
$itemLoopIter->{available} = 1;
$numCopiesAvailable++;
}
$biblioLoopIter{holdable} = undef;
}
+ if(not CanBookBeReserved($borrowernumber,$biblioNum)){
+ $biblioLoopIter{holdable} = undef;
+ }
+
push @$biblioLoop, \%biblioLoopIter;
}
my $messageborrower;
my $warnings;
my $messages;
+my $maxreserves;
my $date = C4::Dates->today('iso');
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;
borroweremailpro => $borrowerinfo->{'emailpro'},
borrowercategory => $borrowerinfo->{'category'},
borrowerreservs => $count_reserv,
- maxreserves => $maxreserves,
expiry => $expiry,
diffbranch => $diffbranch,
messages => $messages,
my @biblioloop = ();
foreach my $biblionumber (@biblionumbers) {
+ if ( not CanBookBeReserved($borrowerinfo->{borrowernumber}, $biblionumber) ) {
+ $warnings = 1;
+ $maxreserves = 1;
+ }
+
my %biblioloopiter = ();
my $dat = GetBiblioData($biblionumber);
$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++;
$template->param( biblioloop => \@biblioloop );
$template->param( biblionumbers => $biblionumbers );
+$template->param( maxreserves => $maxreserves );
if ($multihold) {
$template->param( multi_hold => 1 );