package C4::Reserves;
# Copyright 2000-2002 Katipo Communications
+# 2006 SAN Ouest Provence
+# 2007 BibLibre Paul POULAIN
#
# This file is part of Koha.
#
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307 USA
-# $Id$
use strict;
-require Exporter;
use C4::Context;
use C4::Biblio;
+use C4::Items;
use C4::Search;
use C4::Circulation;
+use C4::Accounts;
-our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,%EXPORT_TAGS);
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
my $library_name = C4::Context->preference("LibraryName");
-# set the version for version checking
-$VERSION = do { my @v = '$Revision$' =~ /\d+/g; shift(@v) . "." . join( "_", map { sprintf "%03d", $_ } @v ); };
-
=head1 NAME
C4::Reserves - Koha functions for dealing with reservation.
=head1 DESCRIPTION
this modules provides somes functions to deal with reservations.
-
+
+ Reserves are stored in reserves table.
+ The following columns contains important values :
+ - priority >0 : then the reserve is at 1st stage, and not yet affected to any item.
+ =0 : then the reserve is being dealed
+ - found : NULL : means the patron requested the 1st available, and we haven't choosen the item
+ W(aiting) : the reserve has an itemnumber affected, and is on the way
+ F(inished) : the reserve has been completed, and is done
+ - itemnumber : empty : the reserve is still unaffected to an item
+ filled: the reserve is attached to an item
+ The complete workflow is :
+ ==== 1st use case ====
+ patron request a document, 1st available : P >0, F=NULL, I=NULL
+ a library having it run "transfertodo", and clic on the list
+ if there is no transfer to do, the reserve waiting
+ patron can pick it up P =0, F=W, I=filled
+ if there is a transfer to do, write in branchtransfer P =0, F=NULL, I=filled
+ The pickup library recieve the book, it check in P =0, F=W, I=filled
+ The patron borrow the book P =0, F=F, I=filled
+
+ ==== 2nd use case ====
+ patron requests a document, a given item,
+ If pickup is holding branch P =0, F=W, I=filled
+ If transfer needed, write in branchtransfer P =0, F=NULL, I=filled
+ The pickup library recieve the book, it checks it in P =0, F=W, I=filled
+ The patron borrow the book P =0, F=F, I=filled
+
=head1 FUNCTIONS
=over 2
=cut
-@ISA = qw(Exporter);
-
-@EXPORT = qw(
- &AddReserve
+BEGIN {
+ # set the version for version checking
+ $VERSION = 3.02;
+ require Exporter;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(
+ &AddReserve
- &GetReservesFromItemnumber
- &GetReservesFromBiblionumber
- &GetReservesFromBorrowernumber
- &GetReservesForBranch
- &GetReservesToBranch
- &GetReserveCount
- &GetReserveFee
- &GetReservesForBranch
- &GetReservesToBranch
- &GetOtherReserves
-
- &ModReserveFill
- &ModReserveAffect
- &ModReserve
- &ModReserveStatus
- &ModReserveCancelAll
- &ModReserveMinusPriority
-
- &CheckReserves
- &CancelReserve
-);
-
+ &GetReservesFromItemnumber
+ &GetReservesFromBiblionumber
+ &GetReservesFromBorrowernumber
+ &GetReservesForBranch
+ &GetReservesToBranch
+ &GetReserveCount
+ &GetReserveFee
+ &GetReserveInfo
+
+ &GetOtherReserves
+
+ &ModReserveFill
+ &ModReserveAffect
+ &ModReserve
+ &ModReserveStatus
+ &ModReserveCancelAll
+ &ModReserveMinusPriority
+
+ &CheckReserves
+ &CancelReserve
+ );
+}
=item AddReserve
reservedate,
constrainttype,
found,
- itemnumber
+ itemnumber,
+ reservenotes
FROM reserves
- WHERE cancellationdate IS NULL
- AND (found <> \'F\' OR found IS NULL)
- AND biblionumber = ?
+ WHERE biblionumber = ?
ORDER BY priority";
my $sth = $dbh->prepare($query);
$sth->execute($biblionumber);
SELECT reservedate,borrowernumber,branchcode
FROM reserves
WHERE itemnumber=?
- AND cancellationdate IS NULL
- AND (found <> 'F' OR found IS NULL)
";
my $sth_res = $dbh->prepare($query);
$sth_res->execute($itemnumber);
SELECT *
FROM reserves
WHERE borrowernumber=?
- AND cancellationdate IS NULL
AND found =?
ORDER BY reservedate
");
SELECT *
FROM reserves
WHERE borrowernumber=?
- AND cancellationdate IS NULL
- AND (found != 'F' or found is null)
ORDER BY reservedate
");
$sth->execute($borrowernumber);
SELECT COUNT(*) AS counter
FROM reserves
WHERE borrowernumber = ?
- AND cancellationdate IS NULL
- AND (found != \'F\' OR found IS NULL)
';
my $sth = $dbh->prepare($query);
$sth->execute($borrowernumber);
my $dbh = C4::Context->dbh;
my $const = lc substr( $constraint, 0, 1 );
my $query = qq/
- SELECT * FROM borrowers,categories
+ SELECT * FROM borrowers
+ LEFT JOIN categories ON borrowers.categorycode = categories.categorycode
WHERE borrowernumber = ?
- AND borrowers.categorycode = categories.categorycode
/;
my $sth = $dbh->prepare($query);
$sth->execute($borrowernumber);
my $data = $sth->fetchrow_hashref;
$sth->finish();
my $fee = $data->{'reservefee'};
- my $cntitems = @- > $bibitems;
+ my $cntitems = @- > $bibitems; # FIXME: @- is a regexp match var. Unclear and probably INCORRECT usage here.
if ( $fee > 0 ) {
# first find biblioitem records
my @biblioitems;
my $sth1 = $dbh->prepare(
- "SELECT * FROM biblio,biblioitems
- WHERE (biblio.biblionumber = ?)
- AND (biblio.biblionumber = biblioitems.biblionumber)"
+ "SELECT * FROM biblio LEFT JOIN biblioitems on biblio.biblionumber = biblioitems.biblionumber
+ WHERE (biblio.biblionumber = ?)"
);
$sth1->execute($biblionumber);
while ( my $data1 = $sth1->fetchrow_hashref ) {
}
$x++;
}
- if ( $const eq 'o' ) {
- if ( $found == 1 ) {
- push @biblioitems, $data1;
- }
- }
- else {
- if ( $found == 0 ) {
- push @biblioitems, $data1;
- }
+ if ( $found == 0 or
+ ($found == 1 and $const eq 'o')) {
+ push @biblioitems, $data1;
}
}
}
my $allissued = 1;
while ( $x < $cntitemsfound ) {
my $bitdata = $biblioitems[$x];
- my $sth2 = $dbh->prepare(
- "SELECT * FROM items
- WHERE biblioitemnumber = ?"
- );
+ my $sth2 = $dbh->prepare("SELECT * FROM items WHERE biblioitemnumber = ?");
$sth2->execute( $bitdata->{'biblioitemnumber'} );
while ( my $itdata = $sth2->fetchrow_hashref ) {
- my $sth3 = $dbh->prepare(
- "SELECT * FROM issues
- WHERE itemnumber = ?
- AND returndate IS NULL"
- );
+ my $sth3 = $dbh->prepare("SELECT * FROM issues WHERE itemnumber = ?");
$sth3->execute( $itdata->{'itemnumber'} );
- if ( my $isdata = $sth3->fetchrow_hashref ) {
- }
- else {
+ unless ($sth3->rows()) {
$allissued = 0;
}
}
$x++;
}
if ( $allissued == 0 ) {
- my $rsth =
- $dbh->prepare("SELECT * FROM reserves WHERE biblionumber = ?");
+ my $rsth = $dbh->prepare("SELECT * FROM reserves WHERE biblionumber = ?");
$rsth->execute($biblionumber);
- if ( my $rdata = $rsth->fetchrow_hashref ) {
- }
- else {
+ unless ($rsth->rows()) {
$fee = 0;
}
}
my $sth = $dbh->prepare(
"SELECT borrowernumber,reservedate,itemnumber,timestamp
FROM reserves
- WHERE priority='0' AND cancellationdate is null
- AND branchcode=?
- AND found IS NULL "
+ WHERE priority='0'
+ AND branchcode=?"
);
$sth->execute( $frombranch );
my @transreserv;
sub GetReservesForBranch {
my ($frombranch) = @_;
my $dbh = C4::Context->dbh;
- my $sth = $dbh->prepare( "
- SELECT borrowernumber,reservedate,itemnumber,waitingdate
+ my $query = "SELECT borrowernumber,reservedate,itemnumber,waitingdate
FROM reserves
WHERE priority='0'
- AND cancellationdate IS NULL
- AND found='W'
- AND branchcode=?
- ORDER BY waitingdate" );
- $sth->execute($frombranch);
+ AND found='W' ";
+ if ($frombranch){
+ $query .= " AND branchcode=? ";
+ }
+ $query .= "ORDER BY waitingdate" ;
+ my $sth = $dbh->prepare($query);
+ if ($frombranch){
+ $sth->execute($frombranch);
+ }
+ else {
+ $sth->execute();
+ }
my @transreserv;
my $i = 0;
while ( my $data = $sth->fetchrow_hashref ) {
# Look up the item by itemnumber
my $query = "
SELECT items.biblionumber, items.biblioitemnumber, itemtypes.notforloan
- FROM items, biblioitems, itemtypes
- WHERE items.biblioitemnumber = biblioitems.biblioitemnumber
- AND biblioitems.itemtype = itemtypes.itemtype
- AND itemnumber=$qitem
+ FROM items
+ LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
+ LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
+ WHERE itemnumber=$qitem
";
$sth = $dbh->prepare($query);
}
# Look up the item by barcode
my $query = "
SELECT items.biblionumber, items.biblioitemnumber, itemtypes.notforloan
- FROM items, biblioitems, itemtypes
+ FROM items
+ LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
+ LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
WHERE items.biblioitemnumber = biblioitems.biblioitemnumber
AND biblioitems.itemtype = itemtypes.itemtype
AND barcode=$qbc
sub CancelReserve {
my ( $biblio, $item, $borr ) = @_;
my $dbh = C4::Context->dbh;
- if ( ( $item and $borr ) and ( not $biblio ) ) {
+ if ( $item and $borr ) {
# removing a waiting reserve record....
# update the database...
my $query = "
my $sth = $dbh->prepare($query);
$sth->execute( $item, $borr );
$sth->finish;
+ $query = "
+ INSERT INTO old_reserves
+ SELECT * FROM reserves
+ WHERE itemnumber = ?
+ AND borrowernumber = ?
+ ";
+ $sth = $dbh->prepare($query);
+ $sth->execute( $item, $borr );
+ $query = "
+ DELETE FROM reserves
+ WHERE itemnumber = ?
+ AND borrowernumber = ?
+ ";
+ $sth = $dbh->prepare($query);
+ $sth->execute( $item, $borr );
}
- if ( ( $biblio and $borr ) and ( not $item ) ) {
+ else {
# removing a reserve record....
# get the prioritiy on this record....
my $priority;
AND borrowernumber = ?
AND cancellationdate IS NULL
AND itemnumber IS NULL
- AND (found <> 'F' OR found IS NULL)
/;
my $sth = $dbh->prepare($query);
$sth->execute( $biblio, $borr );
priority = 0
WHERE biblionumber = ?
AND borrowernumber = ?
- AND cancellationdate IS NULL
- AND (found <> 'F' or found IS NULL)
/;
# update the database, removing the record...
$sth->execute( $biblio, $borr );
$sth->finish;
+ $query = qq/
+ INSERT INTO old_reserves
+ SELECT * FROM reserves
+ WHERE biblionumber = ?
+ AND borrowernumber = ?
+ /;
+ $sth = $dbh->prepare($query);
+ $sth->execute( $biblio, $borr );
+
+ $query = qq/
+ DELETE FROM reserves
+ WHERE biblionumber = ?
+ AND borrowernumber = ?
+ /;
+ $sth = $dbh->prepare($query);
+ $sth->execute( $biblio, $borr );
+
# now fix the priority on the others....
- _FixPriority( $priority, $biblio );
+ _FixPriority($biblio,$borr,$priority);
}
}
SET cancellationdate=now()
WHERE biblionumber = ?
AND borrowernumber = ?
- AND cancellationdate is NULL
- AND (found <> 'F' or found is NULL)
/;
my $sth = $dbh->prepare($query);
$sth->execute( $biblio, $borrower );
$sth->finish;
+ $query = qq/
+ INSERT INTO old_reserves
+ SELECT *
+ FROM reserves
+ WHERE biblionumber = ?
+ AND borrowernumber = ?
+ /;
+ $sth = $dbh->prepare($query);
+ $sth->execute( $biblio, $borrower );
+ $query = qq/
+ DELETE FROM reserves
+ WHERE biblionumber = ?
+ AND borrowernumber = ?
+ /;
+ $sth = $dbh->prepare($query);
+ $sth->execute( $biblio, $borrower );
}
else {
UPDATE reserves SET priority = ? ,branchcode = ?, itemnumber = ?, found = NULL
WHERE biblionumber = ?
AND borrowernumber = ?
- AND cancellationdate is NULL
- AND (found <> 'F' or found is NULL)
/;
my $sth = $dbh->prepare($query);
$sth->execute( $rank, $branch,$itemnumber, $biblio, $borrower);
$sth->execute( $biblionumber, $resdate, $borrowernumber );
$sth->finish;
+ # move to old_reserves
+ $query = "INSERT INTO old_reserves
+ SELECT * FROM reserves
+ WHERE biblionumber = ?
+ AND reservedate = ?
+ AND borrowernumber = ?
+ ";
+ $sth = $dbh->prepare($query);
+ $sth->execute( $biblionumber, $resdate, $borrowernumber );
+ $query = "DELETE FROM reserves
+ WHERE biblionumber = ?
+ AND reservedate = ?
+ AND borrowernumber = ?
+ ";
+ $sth = $dbh->prepare($query);
+ $sth->execute( $biblionumber, $resdate, $borrowernumber );
+
# now fix the priority on the others (if the priority wasn't
# already sorted!)....
unless ( $priority == 0 ) {
- _FixPriority( $priority, $biblionumber );
+ _FixPriority($biblionumber, $borrowernumber, $priority);
}
}
with the biblionumber & the borrowernumber, we can affect the itemnumber
to the correct reserve.
-if $transferToDo is set, then the status is set to "Waiting" as well.
+if $transferToDo is not set, then the status is set to "Waiting" as well.
otherwise, a transfer is on the way, and the end of the transfer will
take care of the waiting status
=cut
itemnumber = ?
WHERE borrowernumber = ?
AND biblionumber = ?
- AND reserves.cancellationdate IS NULL
- AND (reserves.found <> 'F' OR reserves.found IS NULL)
";
}
else {
itemnumber = ?
WHERE borrowernumber = ?
AND biblionumber = ?
- AND reserves.cancellationdate IS NULL
- AND (reserves.found <> 'F' OR reserves.found IS NULL)
";
}
$sth = $dbh->prepare($query);
$sth->execute( $itemnumber, $borrowernumber,$biblionumber);
$sth->finish;
-
- # now fix up the remaining priorities....
-# _FixPriority( $data->{'priority'}, $biblio ); # can't work, 1st parameter should be $biblionumbern NOT priority. FIXME : remove this line if no problem seen once it is commented.
return;
}
my $query = "
UPDATE reserves
SET priority = 0 , itemnumber = ?
- WHERE cancellationdate IS NULL
- AND borrowernumber=?
+ WHERE borrowernumber=?
AND biblionumber=?
";
my $sth_upd = $dbh->prepare($query);
SET priority = priority-1
WHERE biblionumber = ?
AND priority > 0
- AND cancellationdate IS NULL
";
$sth_upd = $dbh->prepare($query);
$sth_upd->execute( $biblionumber );
$sth_upd->finish;
}
+=item GetReserveInfo
+
+&GetReserveInfo($borrowernumber,$biblionumber);
+
+ Get item and borrower details for a current hold.
+ Current implementation this query should have a single result.
+=cut
+
+sub GetReserveInfo {
+ my ( $borrowernumber, $biblionumber ) = @_;
+ my $dbh = C4::Context->dbh;
+ my $strsth="SELECT reservedate, reservenotes, reserves.borrowernumber,
+ reserves.biblionumber, reserves.branchcode,
+ notificationdate, reminderdate, priority, found,
+ firstname, surname, phone,
+ email, address, address2,
+ cardnumber, city, zipcode,
+ biblio.title, biblio.author,
+ items.holdingbranch, items.itemcallnumber, items.itemnumber,
+ barcode, notes
+ FROM reserves left join items
+ ON items.itemnumber=reserves.itemnumber ,
+ borrowers, biblio
+ WHERE
+ reserves.borrowernumber=? &&
+ reserves.biblionumber=? &&
+ reserves.borrowernumber=borrowers.borrowernumber &&
+ reserves.biblionumber=biblio.biblionumber ";
+ my $sth = $dbh->prepare($strsth);
+ $sth->execute($borrowernumber,$biblionumber);
+
+ my $data = $sth->fetchrow_hashref;
+ return $data;
+
+}
+
=item _FixPriority
&_FixPriority($biblio,$borrowernumber,$rank);
SET priority = 0
WHERE biblionumber = ?
AND borrowernumber = ?
- AND cancellationdate IS NULL
AND found ='W'
/;
my $sth = $dbh->prepare($query);
# get whats left
# FIXME adding a new security in returned elements for changing priority,
# now, we don't care anymore any reservations with itemnumber linked (suppose a waiting reserve)
+ # This is wrong a waiting reserve has W set
+ # The assumption that having an itemnumber set means waiting is wrong and should be corrected any place it occurs
my $query = qq/
SELECT borrowernumber, reservedate, constrainttype
FROM reserves
WHERE biblionumber = ?
- AND cancellationdate IS NULL
- AND itemnumber IS NULL
- AND ((found <> 'F' and found <> 'W') or found is NULL)
+ AND ((found <> 'W') or found is NULL)
ORDER BY priority ASC
/;
my $sth = $dbh->prepare($query);
AND reserves.borrowernumber = reserveconstraints.borrowernumber
AND reserves.reservedate =reserveconstraints.reservedate )
OR reserves.constrainttype='a' )
- AND reserves.cancellationdate is NULL
- AND (reserves.found <> 'F' or reserves.found is NULL)
/;
my $sth = $dbh->prepare($query);
$sth->execute( $biblio, $bibitem );
- my @results;
- while ( my $data = $sth->fetchrow_hashref ) {
- push( @results, $data );
- }
- $sth->finish;
- return @results;
+ return $sth->fetchall_arrayref({});
}
=back
=cut
+1;