2 # NOTE: This file uses standard 8-character tabs
6 # Copyright 2000-2002 Katipo Communications
7 # 2006 SAN Ouest Provence
8 # 2007 BibLibre Paul POULAIN
10 # This file is part of Koha.
12 # Koha is free software; you can redistribute it and/or modify it under the
13 # terms of the GNU General Public License as published by the Free Software
14 # Foundation; either version 2 of the License, or (at your option) any later
17 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
18 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
19 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License along with
22 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23 # Suite 330, Boston, MA 02111-1307 USA
35 our ($VERSION,@ISA,@EXPORT,@EXPORT_OK,%EXPORT_TAGS);
37 my $library_name = C4::Context->preference("LibraryName");
39 # set the version for version checking
40 $VERSION = do { my @v = '$Revision$' =~ /\d+/g; shift(@v) . "." . join( "_", map { sprintf "%03d", $_ } @v ); };
44 C4::Reserves - Koha functions for dealing with reservation.
52 this modules provides somes functions to deal with reservations.
54 Reserves are stored in reserves table.
55 The following columns contains important values :
56 - priority >0 : then the reserve is at 1st stage, and not yet affected to any item.
57 =0 : then the reserve is being dealed
58 - found : NULL : means the patron requested the 1st available, and we haven't choosen the item
59 W(aiting) : the reserve has an itemnumber affected, and is on the way
60 F(inished) : the reserve has been completed, and is done
61 - itemnumber : empty : the reserve is still unaffected to an item
62 filled: the reserve is attached to an item
63 The complete workflow is :
64 ==== 1st use case ====
65 patron request a document, 1st available : P >0, F=NULL, I=NULL
66 a library having it run "transfertodo", and clic on the list
67 if there is no transfer to do, the reserve waiting
68 patron can pick it up P =0, F=W, I=filled
69 if there is a transfer to do, write in branchtransfer P =0, F=NULL, I=filled
70 The pickup library recieve the book, it check in P =0, F=W, I=filled
71 The patron borrow the book P =0, F=F, I=filled
73 ==== 2nd use case ====
74 patron requests a document, a given item,
75 If pickup is holding branch P =0, F=W, I=filled
76 If transfer needed, write in branchtransfer P =0, F=NULL, I=filled
77 The pickup library recieve the book, it checks it in P =0, F=W, I=filled
78 The patron borrow the book P =0, F=F, I=filled
91 &GetReservesFromItemnumber
92 &GetReservesFromBiblionumber
93 &GetReservesFromBorrowernumber
107 &ModReserveMinusPriority
116 AddReserve($branch,$borrowernumber,$biblionumber,$constraint,$bibitems,$priority,$notes,$title,$checkitem,$found)
122 $branch, $borrowernumber, $biblionumber,
123 $constraint, $bibitems, $priority, $notes,
124 $title, $checkitem, $found
127 GetReserveFee($borrowernumber, $biblionumber, $constraint,
129 my $dbh = C4::Context->dbh;
130 my $const = lc substr( $constraint, 0, 1 );
131 my @datearr = localtime(time);
133 ( 1900 + $datearr[5] ) . "-" . ( $datearr[4] + 1 ) . "-" . $datearr[3];
136 # If the reserv had the waiting status, we had the value of the resdate
137 if ( $found eq 'W' ) {
138 $waitingdate = $resdate;
142 # updates take place here
144 my $nextacctno = &getnextacctno( $borrowernumber );
146 INSERT INTO accountlines
147 (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding)
149 (?,?,now(),?,?,'Res',?)
151 my $usth = $dbh->prepare($query);
152 $usth->execute( $borrowernumber, $nextacctno, $fee,
153 "Reserve Charge - $title", $fee );
160 (borrowernumber,biblionumber,reservedate,branchcode,constrainttype,
161 priority,reservenotes,itemnumber,found,waitingdate)
166 my $sth = $dbh->prepare($query);
168 $borrowernumber, $biblionumber, $resdate, $branch,
169 $const, $priority, $notes, $checkitem,
175 if ( ( $const eq "o" ) || ( $const eq "e" ) ) {
176 my $numitems = @$bibitems;
178 while ( $i < $numitems ) {
179 my $biblioitem = @$bibitems[$i];
181 INSERT INTO reserveconstraints
182 (borrowernumber,biblionumber,reservedate,biblioitemnumber)
186 my $sth = $dbh->prepare("");
187 $sth->execute( $borrowernumber, $biblionumber, $resdate,
196 =item GetReservesFromBiblionumber
198 @borrowerreserv=&GetReserves($biblionumber,$itemnumber,$borrowernumber);
200 this function get the list of reservation for an C<$biblionumber>, C<$itemnumber> or C<$borrowernumber>
202 Only 1 argument has to be passed.
206 sub GetReservesFromBiblionumber {
207 my ( $biblionumber, $itemnumber, $borrowernumber ) = @_;
208 my $dbh = C4::Context->dbh;
210 # Find the desired items in the reserves
213 timestamp AS rtimestamp,
222 WHERE cancellationdate IS NULL
223 AND (found <> \'F\' OR found IS NULL)
226 my $sth = $dbh->prepare($query);
227 $sth->execute($biblionumber);
230 while ( my $data = $sth->fetchrow_hashref ) {
232 # FIXME - What is this if-statement doing? How do constraints work?
233 if ( $data->{constrainttype} eq 'o' ) {
235 SELECT biblioitemnumber
236 FROM reserveconstraints
237 WHERE biblionumber = ?
238 AND borrowernumber = ?
241 my $csth = $dbh->prepare($query);
242 $csth->execute( $data->{biblionumber}, $data->{borrowernumber},
243 $data->{reservedate}, );
246 while ( my $bibitemnos = $csth->fetchrow_array ) {
247 push( @bibitemno, $bibitemnos );
249 my $count = @bibitemno;
251 # if we have two or more different specific itemtypes
252 # reserved by same person on same day
255 $bdata = GetBiblioItemData( $bibitemno[$i] );
260 # Look up the book we just found.
261 $bdata = GetBiblioItemData( $bibitemno[0] );
265 # Add the results of this latest search to the current
267 # FIXME - An 'each' would probably be more efficient.
268 foreach my $key ( keys %$bdata ) {
269 $data->{$key} = $bdata->{$key};
272 push @results, $data;
275 return ( $#results + 1, \@results );
278 =item GetReservesFromItemnumber
280 ( $reservedate, $borrowernumber, $branchcode ) = GetReservesFromItemnumber($itemnumber);
282 TODO :: Description here
286 sub GetReservesFromItemnumber {
287 my ( $itemnumber ) = @_;
288 my $dbh = C4::Context->dbh;
290 SELECT reservedate,borrowernumber,branchcode
293 AND cancellationdate IS NULL
294 AND (found <> 'F' OR found IS NULL)
296 my $sth_res = $dbh->prepare($query);
297 $sth_res->execute($itemnumber);
298 my ( $reservedate, $borrowernumber,$branchcode ) = $sth_res->fetchrow_array;
299 return ( $reservedate, $borrowernumber, $branchcode );
302 =item GetReservesFromBorrowernumber
304 $borrowerreserv = GetReservesFromBorrowernumber($borrowernumber,$tatus);
310 sub GetReservesFromBorrowernumber {
311 my ( $borrowernumber, $status ) = @_;
312 my $dbh = C4::Context->dbh;
315 $sth = $dbh->prepare("
318 WHERE borrowernumber=?
319 AND cancellationdate IS NULL
323 $sth->execute($borrowernumber,$status);
325 $sth = $dbh->prepare("
328 WHERE borrowernumber=?
329 AND cancellationdate IS NULL
330 AND (found != 'F' or found is null)
333 $sth->execute($borrowernumber);
335 my $data = $sth->fetchall_arrayref({});
338 #-------------------------------------------------------------------------------------
340 =item GetReserveCount
342 $number = &GetReserveCount($borrowernumber);
344 this function returns the number of reservation for a borrower given on input arg.
348 sub GetReserveCount {
349 my ($borrowernumber) = @_;
351 my $dbh = C4::Context->dbh;
354 SELECT COUNT(*) AS counter
356 WHERE borrowernumber = ?
357 AND cancellationdate IS NULL
358 AND (found != \'F\' OR found IS NULL)
360 my $sth = $dbh->prepare($query);
361 $sth->execute($borrowernumber);
362 my $row = $sth->fetchrow_hashref;
365 return $row->{counter};
368 =item GetOtherReserves
370 ($messages,$nextreservinfo)=$GetOtherReserves(itemnumber);
372 Check queued list of this document and check if this document must be transfered
376 sub GetOtherReserves {
377 my ($itemnumber) = @_;
380 my ( $restype, $checkreserves ) = CheckReserves($itemnumber);
381 if ($checkreserves) {
382 my $iteminfo = GetItem($itemnumber);
383 if ( $iteminfo->{'holdingbranch'} ne $checkreserves->{'branchcode'} ) {
384 $messages->{'transfert'} = $checkreserves->{'branchcode'};
385 #minus priorities of others reservs
386 ModReserveMinusPriority(
388 $checkreserves->{'borrowernumber'},
389 $iteminfo->{'biblionumber'}
392 #launch the subroutine dotransfer
393 C4::Circulation::ModItemTransfer(
395 $iteminfo->{'holdingbranch'},
396 $checkreserves->{'branchcode'}
401 #step 2b : case of a reservation on the same branch, set the waiting status
403 $messages->{'waiting'} = 1;
404 ModReserveMinusPriority(
406 $checkreserves->{'borrowernumber'},
407 $iteminfo->{'biblionumber'}
409 ModReserveStatus($itemnumber,'W');
412 $nextreservinfo = $checkreserves->{'borrowernumber'};
415 return ( $messages, $nextreservinfo );
420 $fee = GetReserveFee($borrowernumber,$biblionumber,$constraint,$biblionumber);
422 Calculate the fee for a reserve
427 my ($borrowernumber, $biblionumber, $constraint, $bibitems ) = @_;
430 my $dbh = C4::Context->dbh;
431 my $const = lc substr( $constraint, 0, 1 );
433 SELECT * FROM borrowers,categories
434 WHERE borrowernumber = ?
435 AND borrowers.categorycode = categories.categorycode
437 my $sth = $dbh->prepare($query);
438 $sth->execute($borrowernumber);
439 my $data = $sth->fetchrow_hashref;
441 my $fee = $data->{'reservefee'};
442 my $cntitems = @- > $bibitems;
446 # check for items on issue
447 # first find biblioitem records
449 my $sth1 = $dbh->prepare(
450 "SELECT * FROM biblio,biblioitems
451 WHERE (biblio.biblionumber = ?)
452 AND (biblio.biblionumber = biblioitems.biblionumber)"
454 $sth1->execute($biblionumber);
455 while ( my $data1 = $sth1->fetchrow_hashref ) {
456 if ( $const eq "a" ) {
457 push @biblioitems, $data1;
462 while ( $x < $cntitems ) {
463 if ( @$bibitems->{'biblioitemnumber'} ==
464 $data->{'biblioitemnumber'} )
470 if ( $const eq 'o' ) {
472 push @biblioitems, $data1;
477 push @biblioitems, $data1;
483 my $cntitemsfound = @biblioitems;
487 while ( $x < $cntitemsfound ) {
488 my $bitdata = $biblioitems[$x];
489 my $sth2 = $dbh->prepare(
491 WHERE biblioitemnumber = ?"
493 $sth2->execute( $bitdata->{'biblioitemnumber'} );
494 while ( my $itdata = $sth2->fetchrow_hashref ) {
495 my $sth3 = $dbh->prepare(
496 "SELECT * FROM issues
498 AND returndate IS NULL"
500 $sth3->execute( $itdata->{'itemnumber'} );
501 if ( my $isdata = $sth3->fetchrow_hashref ) {
509 if ( $allissued == 0 ) {
511 $dbh->prepare("SELECT * FROM reserves WHERE biblionumber = ?");
512 $rsth->execute($biblionumber);
513 if ( my $rdata = $rsth->fetchrow_hashref ) {
523 =item GetReservesToBranch
525 @transreserv = GetReservesToBranch( $frombranch );
527 Get reserve list for a given branch
531 sub GetReservesToBranch {
532 my ( $frombranch ) = @_;
533 my $dbh = C4::Context->dbh;
534 my $sth = $dbh->prepare(
535 "SELECT borrowernumber,reservedate,itemnumber,timestamp
537 WHERE priority='0' AND cancellationdate is null
541 $sth->execute( $frombranch );
544 while ( my $data = $sth->fetchrow_hashref ) {
545 $transreserv[$i] = $data;
549 return (@transreserv);
552 =item GetReservesForBranch
554 @transreserv = GetReservesForBranch($frombranch);
558 sub GetReservesForBranch {
559 my ($frombranch) = @_;
560 my $dbh = C4::Context->dbh;
561 my $sth = $dbh->prepare( "
562 SELECT borrowernumber,reservedate,itemnumber,waitingdate
565 AND cancellationdate IS NULL
568 ORDER BY waitingdate" );
569 $sth->execute($frombranch);
572 while ( my $data = $sth->fetchrow_hashref ) {
573 $transreserv[$i] = $data;
577 return (@transreserv);
582 ($status, $reserve) = &CheckReserves($itemnumber);
584 Find a book in the reserves.
586 C<$itemnumber> is the book's item number.
588 As I understand it, C<&CheckReserves> looks for the given item in the
589 reserves. If it is found, that's a match, and C<$status> is set to
592 Otherwise, it finds the most important item in the reserves with the
593 same biblio number as this book (I'm not clear on this) and returns it
594 with C<$status> set to C<Reserved>.
596 C<&CheckReserves> returns a two-element list:
598 C<$status> is either C<Waiting>, C<Reserved> (see above), or 0.
600 C<$reserve> is the reserve item that matched. It is a
601 reference-to-hash whose keys are mostly the fields of the reserves
602 table in the Koha database.
607 my ( $item, $barcode ) = @_;
608 my $dbh = C4::Context->dbh;
611 my $qitem = $dbh->quote($item);
612 # Look up the item by itemnumber
614 SELECT items.biblionumber, items.biblioitemnumber, itemtypes.notforloan
615 FROM items, biblioitems, itemtypes
616 WHERE items.biblioitemnumber = biblioitems.biblioitemnumber
617 AND biblioitems.itemtype = itemtypes.itemtype
618 AND itemnumber=$qitem
620 $sth = $dbh->prepare($query);
623 my $qbc = $dbh->quote($barcode);
624 # Look up the item by barcode
626 SELECT items.biblionumber, items.biblioitemnumber, itemtypes.notforloan
627 FROM items, biblioitems, itemtypes
628 WHERE items.biblioitemnumber = biblioitems.biblioitemnumber
629 AND biblioitems.itemtype = itemtypes.itemtype
632 $sth = $dbh->prepare($query);
634 # FIXME - This function uses $item later on. Ought to set it here.
637 my ( $biblio, $bibitem, $notforloan ) = $sth->fetchrow_array;
640 # if item is not for loan it cannot be reserved either.....
641 return ( 0, 0 ) if $notforloan;
643 # get the reserves...
644 # Find this item in the reserves
645 my @reserves = _Findgroupreserve( $bibitem, $biblio );
646 my $count = scalar @reserves;
648 # $priority and $highest are used to find the most important item
649 # in the list returned by &_Findgroupreserve. (The lower $priority,
650 # the more important the item.)
651 # $highest is the most important item we've seen so far.
652 my $priority = 10000000;
655 foreach my $res (@reserves) {
656 # FIXME - $item might be undefined or empty: the caller
657 # might be searching by barcode.
658 if ( $res->{'itemnumber'} == $item ) {
660 return ( "Waiting", $res );
663 # See if this item is more important than what we've got
665 if ( $res->{'priority'} != 0 && $res->{'priority'} < $priority )
667 $priority = $res->{'priority'};
674 # If we get this far, then no exact match was found. Print the
675 # most important item on the list. I think this tells us who's
676 # next in line to get this book.
677 if ($highest) { # FIXME - $highest might be undefined
678 $highest->{'itemnumber'} = $item;
679 return ( "Reserved", $highest );
688 &CancelReserve($biblionumber, $itemnumber, $borrowernumber);
692 Use either C<$biblionumber> or C<$itemnumber> to specify the item to
693 cancel, but not both: if both are given, C<&CancelReserve> does
696 C<$borrowernumber> is the borrower number of the patron on whose
697 behalf the book was reserved.
699 If C<$biblionumber> was given, C<&CancelReserve> also adjusts the
700 priorities of the other people who are waiting on the book.
705 my ( $biblio, $item, $borr ) = @_;
706 my $dbh = C4::Context->dbh;
707 if ( ( $item and $borr ) and ( not $biblio ) ) {
708 # removing a waiting reserve record....
709 # update the database...
712 SET cancellationdate = now(),
716 AND borrowernumber = ?
718 my $sth = $dbh->prepare($query);
719 $sth->execute( $item, $borr );
722 if ( ( $biblio and $borr ) and ( not $item ) ) {
723 # removing a reserve record....
724 # get the prioritiy on this record....
727 SELECT priority FROM reserves
728 WHERE biblionumber = ?
729 AND borrowernumber = ?
730 AND cancellationdate IS NULL
731 AND itemnumber IS NULL
732 AND (found <> 'F' OR found IS NULL)
734 my $sth = $dbh->prepare($query);
735 $sth->execute( $biblio, $borr );
736 ($priority) = $sth->fetchrow_array;
740 SET cancellationdate = now(),
743 WHERE biblionumber = ?
744 AND borrowernumber = ?
745 AND cancellationdate IS NULL
746 AND (found <> 'F' or found IS NULL)
749 # update the database, removing the record...
750 $sth = $dbh->prepare($query);
751 $sth->execute( $biblio, $borr );
754 # now fix the priority on the others....
755 _FixPriority( $priority, $biblio );
761 &ModReserve($rank,$biblio,$borrower,$branch)
766 #subroutine to update a reserve
767 my ( $rank, $biblio, $borrower, $branch , $itemnumber) = @_;
768 return if $rank eq "W";
769 return if $rank eq "n";
770 my $dbh = C4::Context->dbh;
771 if ( $rank eq "del" ) {
774 SET cancellationdate=now()
775 WHERE biblionumber = ?
776 AND borrowernumber = ?
777 AND cancellationdate is NULL
778 AND (found <> 'F' or found is NULL)
780 my $sth = $dbh->prepare($query);
781 $sth->execute( $biblio, $borrower );
787 UPDATE reserves SET priority = ? ,branchcode = ?, itemnumber = ?, found = NULL
788 WHERE biblionumber = ?
789 AND borrowernumber = ?
790 AND cancellationdate is NULL
791 AND (found <> 'F' or found is NULL)
793 my $sth = $dbh->prepare($query);
794 $sth->execute( $rank, $branch,$itemnumber, $biblio, $borrower);
796 _FixPriority( $biblio, $borrower, $rank);
802 &ModReserveFill($reserve);
804 Fill a reserve. If I understand this correctly, this means that the
805 reserved book has been found and given to the patron who reserved it.
807 C<$reserve> specifies the reserve to fill. It is a reference-to-hash
808 whose keys are fields from the reserves table in the Koha database.
814 my $dbh = C4::Context->dbh;
815 # fill in a reserve record....
816 my $biblionumber = $res->{'biblionumber'};
817 my $borrowernumber = $res->{'borrowernumber'};
818 my $resdate = $res->{'reservedate'};
820 # get the priority on this record....
822 my $query = "SELECT priority
824 WHERE biblionumber = ?
825 AND borrowernumber = ?
826 AND reservedate = ?";
827 my $sth = $dbh->prepare($query);
828 $sth->execute( $biblionumber, $borrowernumber, $resdate );
829 ($priority) = $sth->fetchrow_array;
832 # update the database...
833 $query = "UPDATE reserves
836 WHERE biblionumber = ?
838 AND borrowernumber = ?
840 $sth = $dbh->prepare($query);
841 $sth->execute( $biblionumber, $resdate, $borrowernumber );
844 # now fix the priority on the others (if the priority wasn't
845 # already sorted!)....
846 unless ( $priority == 0 ) {
847 _FixPriority( $priority, $biblionumber );
851 =item ModReserveStatus
853 &ModReserveStatus($itemnumber, $newstatus);
855 Update the reserve status for the active (priority=0) reserve.
857 $itemnumber is the itemnumber the reserve is on
859 $newstatus is the new status.
863 sub ModReserveStatus {
865 #first : check if we have a reservation for this item .
866 my ($itemnumber, $newstatus) = @_;
867 my $dbh = C4::Context->dbh;
868 my $query = " UPDATE reserves
869 SET found=?,waitingdate = now()
874 my $sth_set = $dbh->prepare($query);
875 $sth_set->execute( $newstatus, $itemnumber );
879 =item ModReserveAffect
881 &ModReserveAffect($itemnumber,$borrowernumber,$diffBranchSend);
883 This function affect an item and a status for a given reserve
884 The itemnumber parameter is used to find the biblionumber.
885 with the biblionumber & the borrowernumber, we can affect the itemnumber
886 to the correct reserve.
888 if $transferToDo is not set, then the status is set to "Waiting" as well.
889 otherwise, a transfer is on the way, and the end of the transfer will
890 take care of the waiting status
893 sub ModReserveAffect {
894 my ( $itemnumber, $borrowernumber,$transferToDo ) = @_;
895 my $dbh = C4::Context->dbh;
897 # we want to attach $itemnumber to $borrowernumber, find the biblionumber
898 # attached to $itemnumber
899 my $sth = $dbh->prepare("SELECT biblionumber FROM items WHERE itemnumber=?");
900 $sth->execute($itemnumber);
901 my ($biblionumber) = $sth->fetchrow;
902 # If we affect a reserve that has to be transfered, don't set to Waiting
909 WHERE borrowernumber = ?
911 AND reserves.cancellationdate IS NULL
912 AND (reserves.found <> 'F' OR reserves.found IS NULL)
916 # affect the reserve to Waiting as well.
923 WHERE borrowernumber = ?
925 AND reserves.cancellationdate IS NULL
926 AND (reserves.found <> 'F' OR reserves.found IS NULL)
929 $sth = $dbh->prepare($query);
930 $sth->execute( $itemnumber, $borrowernumber,$biblionumber);
935 =item ModReserveCancelAll
937 ($messages,$nextreservinfo) = &ModReserveCancelAll($itemnumber,$borrowernumber);
939 function to cancel reserv,check other reserves, and transfer document if it's necessary
943 sub ModReserveCancelAll {
946 my ( $itemnumber, $borrowernumber ) = @_;
948 #step 1 : cancel the reservation
949 my $CancelReserve = CancelReserve( undef, $itemnumber, $borrowernumber );
951 #step 2 launch the subroutine of the others reserves
952 ( $messages, $nextreservinfo ) = GetOtherReserves($itemnumber);
954 return ( $messages, $nextreservinfo );
957 =item ModReserveMinusPriority
959 &ModReserveMinusPriority($itemnumber,$borrowernumber,$biblionumber)
961 Reduce the values of queuded list
965 sub ModReserveMinusPriority {
966 my ( $itemnumber, $borrowernumber, $biblionumber ) = @_;
968 #first step update the value of the first person on reserv
969 my $dbh = C4::Context->dbh;
972 SET priority = 0 , itemnumber = ?
973 WHERE cancellationdate IS NULL
977 my $sth_upd = $dbh->prepare($query);
978 $sth_upd->execute( $itemnumber, $borrowernumber, $biblionumber );
980 # second step update all others reservs
983 SET priority = priority-1
984 WHERE biblionumber = ?
986 AND cancellationdate IS NULL
988 $sth_upd = $dbh->prepare($query);
989 $sth_upd->execute( $biblionumber );
996 &_FixPriority($biblio,$borrowernumber,$rank);
998 Only used internally (so don't export it)
999 Changed how this functions works #
1000 Now just gets an array of reserves in the rank order and updates them with
1001 the array index (+1 as array starts from 0)
1002 and if $rank is supplied will splice item from the array and splice it back in again
1003 in new priority rank
1008 my ( $biblio, $borrowernumber, $rank ) = @_;
1009 my $dbh = C4::Context->dbh;
1010 if ( $rank eq "del" ) {
1011 CancelReserve( $biblio, undef, $borrowernumber );
1013 if ( $rank eq "W" || $rank eq "0" ) {
1015 # make sure priority for waiting items is 0
1019 WHERE biblionumber = ?
1020 AND borrowernumber = ?
1021 AND cancellationdate IS NULL
1024 my $sth = $dbh->prepare($query);
1025 $sth->execute( $biblio, $borrowernumber );
1031 # FIXME adding a new security in returned elements for changing priority,
1032 # now, we don't care anymore any reservations with itemnumber linked (suppose a waiting reserve)
1034 SELECT borrowernumber, reservedate, constrainttype
1036 WHERE biblionumber = ?
1037 AND cancellationdate IS NULL
1038 AND itemnumber IS NULL
1039 AND ((found <> 'F' and found <> 'W') or found is NULL)
1040 ORDER BY priority ASC
1042 my $sth = $dbh->prepare($query);
1043 $sth->execute($biblio);
1044 while ( my $line = $sth->fetchrow_hashref ) {
1045 push( @reservedates, $line );
1046 push( @priority, $line );
1049 # To find the matching index
1051 my $key = -1; # to allow for 0 to be a valid result
1052 for ( $i = 0 ; $i < @priority ; $i++ ) {
1053 if ( $borrowernumber == $priority[$i]->{'borrowernumber'} ) {
1054 $key = $i; # save the index
1059 # if index exists in array then move it to new position
1060 if ( $key > -1 && $rank ne 'del' && $rank > 0 ) {
1061 my $new_rank = $rank -
1062 1; # $new_rank is what you want the new index to be in the array
1063 my $moving_item = splice( @priority, $key, 1 );
1064 splice( @priority, $new_rank, 0, $moving_item );
1067 # now fix the priority on those that are left....
1071 WHERE biblionumber = ?
1072 AND borrowernumber = ?
1076 $sth = $dbh->prepare($query);
1077 for ( my $j = 0 ; $j < @priority ; $j++ ) {
1080 $priority[$j]->{'borrowernumber'},
1081 $priority[$j]->{'reservedate'}
1087 =item _Findgroupreserve
1089 @results = &_Findgroupreserve($biblioitemnumber, $biblionumber);
1092 I don't know what this does, because I don't understand how reserve
1093 constraints work. I think the idea is that you reserve a particular
1094 biblio, and the constraint allows you to restrict it to a given
1095 biblioitem (e.g., if you want to borrow the audio book edition of "The
1096 Prophet", rather than the first available publication).
1098 C<&_Findgroupreserve> returns :
1099 C<@results> is an array of references-to-hash whose keys are mostly
1100 fields from the reserves table of the Koha database, plus
1101 C<biblioitemnumber>.
1105 sub _Findgroupreserve {
1106 my ( $bibitem, $biblio ) = @_;
1107 my $dbh = C4::Context->dbh;
1109 SELECT reserves.biblionumber AS biblionumber,
1110 reserves.borrowernumber AS borrowernumber,
1111 reserves.reservedate AS reservedate,
1112 reserves.branchcode AS branchcode,
1113 reserves.cancellationdate AS cancellationdate,
1114 reserves.found AS found,
1115 reserves.reservenotes AS reservenotes,
1116 reserves.priority AS priority,
1117 reserves.timestamp AS timestamp,
1118 reserveconstraints.biblioitemnumber AS biblioitemnumber,
1119 reserves.itemnumber AS itemnumber
1121 LEFT JOIN reserveconstraints ON reserves.biblionumber = reserveconstraints.biblionumber
1122 WHERE reserves.biblionumber = ?
1123 AND ( ( reserveconstraints.biblioitemnumber = ?
1124 AND reserves.borrowernumber = reserveconstraints.borrowernumber
1125 AND reserves.reservedate =reserveconstraints.reservedate )
1126 OR reserves.constrainttype='a' )
1127 AND reserves.cancellationdate is NULL
1128 AND (reserves.found <> 'F' or reserves.found is NULL)
1130 my $sth = $dbh->prepare($query);
1131 $sth->execute( $biblio, $bibitem );
1133 while ( my $data = $sth->fetchrow_hashref ) {
1134 push( @results, $data );
1144 Koha Developement team <info@koha.org>