bug fix :syntax error in variable name
[koha.git] / C4 / Reserves2.pm
1 # -*- tab-width: 8 -*-
2 # NOTE: This file uses standard 8-character tabs
3
4 package C4::Reserves2;
5
6 # $Id$
7
8 # Copyright 2000-2002 Katipo Communications
9 #
10 # This file is part of Koha.
11 #
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
15 # version.
16 #
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.
20 #
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
24
25 use strict;
26 require Exporter;
27 use DBI;
28 use C4::Context;
29 use C4::Biblio;
30
31 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
32
33 # set the version for version checking
34 $VERSION = 0.01;
35
36 =head1 NAME
37
38 C4::Reserves2 - FIXME
39
40 =head1 SYNOPSIS
41
42   use C4::Reserves2;
43
44 =head1 DESCRIPTION
45
46 FIXME
47
48 =head1 FUNCTIONS
49
50 =over 2
51
52 =cut
53
54 @ISA = qw(Exporter);
55 # FIXME Take out CalcReserveFee after it can be removed from opac-reserves.pl
56 @EXPORT = qw(
57     &FindReserves
58     &CheckReserves
59     &CheckWaiting
60     &CancelReserve
61     &CalcReserveFee
62     &FillReserve
63     &ReserveWaiting
64     &CreateReserve
65     &updatereserves
66     &UpdateReserve
67     &getreservetitle
68     &Findgroupreserve
69     &FastFindReserves
70     &SetWaitingStatus
71     &GlobalCancel
72     &MinusPriority
73     &OtherReserves
74     GetFirstReserveDateFromItem
75     GetNumberReservesFromBorrower
76 );
77
78 # make all your functions, whether exported or not;
79 =item GlobalCancel
80         New op dev for the circulation based on item, global is a function to cancel reserv,check other reserves, and transfer document if it's necessary
81 =cut
82 #'
83 sub GlobalCancel {
84         my $messages;
85         my $nextreservinfo;
86         my ($itemnumber,$borrowernumber)=@_;
87         
88 #       step 1 : cancel the reservation
89         my $CancelReserve = CancelReserve(0,$itemnumber,$borrowernumber);
90
91 #       step 2 launch the subroutine of the others reserves
92         my ($messages,$nextreservinfo) = OtherReserves($itemnumber);
93
94 return ($messages,$nextreservinfo);
95 }
96
97 =item OtherReserves
98         New op dev: check queued list of this document and check if this document must be  transfered
99 =cut
100 #'
101 sub OtherReserves {
102         my ($itemnumber)=@_;
103         my $messages;
104         my $nextreservinfo;
105         my ($restype,$checkreserves) = CheckReserves($itemnumber);
106         if ($checkreserves){
107                 my %env;
108                 my $iteminfo = C4::Circulation::Circ2::getiteminformation(\%env,$itemnumber);
109                 if ($iteminfo->{'holdingbranch'} ne $checkreserves->{'branchcode'}){
110                 $messages->{'transfert'} = $checkreserves->{'branchcode'};
111
112 #               minus priorities of others reservs
113                 MinusPriority($itemnumber,$checkreserves->{'borrowernumber'},$iteminfo->{'biblionumber'});
114 #               launch the subroutine dotransfer
115                 C4::Circulation::Circ2::dotransfer($itemnumber,$iteminfo->{'holdingbranch'},$checkreserves->{'branchcode'}),
116                 }
117
118 #       step 2b : case of a reservation on the same branch, set the waiting status
119                 else{
120                 $messages->{'waiting'} = 1;
121                 MinusPriority($itemnumber,$checkreserves->{'borrowernumber'},$iteminfo->{'biblionumber'});
122                 SetWaitingStatus($itemnumber);
123                 }
124
125                 $nextreservinfo = $checkreserves->{'borrowernumber'};
126         }
127
128         return ($messages,$nextreservinfo);     
129 }
130
131 =item MinusPriority
132         Reduce the values of queuded list       
133 =cut
134 #'
135 sub MinusPriority{
136         my ($itemnumber,$borrowernumber,$biblionumber)=@_;
137 #       first step update the value of the first person on reserv
138         my $dbh = C4::Context->dbh;
139         my $sth_upd=$dbh->prepare("UPDATE reserves SET priority = 0 , itemnumber = ? 
140         WHERE cancellationdate is NULL 
141         AND borrowernumber=?
142         AND biblionumber=?");
143         $sth_upd->execute($itemnumber,$borrowernumber,$biblionumber);
144         $sth_upd->finish;
145
146 # second step update all others reservs
147         my $sth_oth=$dbh->prepare("SELECT priority,borrowernumber,biblionumber,reservedate FROM reserves WHERE priority !='0' AND cancellationdate is NULL");
148         $sth_oth->execute();
149         while (my ($priority,$borrowernumber,$biblionumber,$reservedate)=$sth_oth->fetchrow_array){
150                 $priority--;
151                  my $sth_upd_oth = $dbh->prepare("UPDATE reserves SET priority = ?
152                                WHERE biblionumber     = ?
153                                  AND borrowernumber   = ?
154                                  AND reservedate      = ?");
155                 $sth_upd_oth->execute($priority,$biblionumber,$borrowernumber,$reservedate);
156                 $sth_upd_oth->finish;
157         }
158         $sth_oth->finish;
159
160 }
161
162
163 =item GlobalCancel
164         New op dev for the circulation based on item, global is a function to cancel reserv,check other reserves, and transfer document if it's necessary
165 =cut
166 #'
167 # New op dev :
168 # we check if we have a reserves with itemnumber (New op system of reserves), if we found one, we update the status of the reservation when we have : 'priority' = 0, and we have an itemnumber 
169 sub SetWaitingStatus{
170 #       first : check if we have a reservation for this item .
171         my ($itemnumber)=@_;
172         my $dbh = C4::Context->dbh;
173         my $sth_find=$dbh->prepare("SELECT priority,borrowernumber from reserves WHERE itemnumber=? and cancellationdate is NULL and found is NULL and priority='0'");
174         $sth_find->execute($itemnumber);
175         my ($priority,$borrowernumber) = $sth_find->fetchrow_array;
176         $sth_find->finish;
177         if (not $borrowernumber){
178                 return();
179         }
180         else{
181 #               step 2 : if we have a borrowernumber, we update the value found to 'W' for notify the borrower
182                 my $sth_set=$dbh->prepare("UPDATE reserves SET found='W',waitingdate = now() where borrowernumber=? AND itemnumber=? AND found is null");
183         $sth_set->execute($borrowernumber,$itemnumber);
184         $sth_set->finish;
185         }
186
187 }
188
189 sub FastFindReserves {
190         my ($itemnumber,$borrowernumber)=@_;
191         if ($itemnumber){
192                 my $dbh = C4::Context->dbh;
193                 my $sth_res=$dbh->prepare("SELECT reservedate,borrowernumber from reserves WHERE itemnumber=? and cancellationdate is NULL AND (found != 'F' or found is null)");
194                 $sth_res->execute($itemnumber);
195                 my ($reservedate,$borrowernumber)=$sth_res->fetchrow_array;
196                 $sth_res->finish;
197                 return($reservedate,$borrowernumber);
198         }
199         if ($borrowernumber){
200                 my $dbh = C4::Context->dbh;
201                 my $sth_find=$dbh->prepare("SELECT * from reserves WHERE borrowernumber=? and cancellationdate is NULL and (found != 'F' or found is null) order by reservedate");
202                 $sth_find->execute($borrowernumber);    
203                 my @borrowerreserv;
204                 my $i=0;
205                 while (my $data=$sth_find->fetchrow_hashref){
206                         $borrowerreserv[$i]=$data;
207                         $i++;
208                 }
209                 $sth_find->finish;
210                 return (@borrowerreserv);
211         }
212
213 }
214
215
216
217 =item FindReserves
218
219   ($count, $results) = &FindReserves($biblionumber, $borrowernumber);
220
221 Looks books up in the reserves. C<$biblionumber> is the biblionumber
222 of the book to look up. C<$borrowernumber> is the borrower number of a
223 patron whose books to look up.
224
225 Either C<$biblionumber> or C<$borrowernumber> may be the empty string,
226 but not both. If both are specified, C<&FindReserves> looks up the
227 given book for the given patron. If only C<$biblionumber> is
228 specified, C<&FindReserves> looks up that book for all patrons. If
229 only C<$borrowernumber> is specified, C<&FindReserves> looks up all of
230 that patron's reserves. If neither is specified, C<&FindReserves>
231 barfs.
232
233 For each book thus found, C<&FindReserves> checks the reserve
234 constraints and does something I don't understand.
235
236 C<&FindReserves> returns a two-element array:
237
238 C<$count> is the number of elements in C<$results>.
239
240 C<$results> is a reference to an array of references of hashes. Each hash
241 has for keys a list of column from reserves table (see details in function).
242
243 =cut
244 #'
245 sub FindReserves {
246     my ($bib, $bor) = @_;
247     my $dbh = C4::Context->dbh;
248     my @bind;
249
250     # Find the desired items in the reserves
251     my $query = '
252 SELECT branchcode,
253        timestamp AS rtimestamp,
254        priority,
255        biblionumber,
256        borrowernumber,
257        reservedate,
258        constrainttype,
259        found
260   FROM reserves
261   WHERE cancellationdate IS NULL
262     AND (found <> \'F\' OR found IS NULL)
263 ';
264
265     if ($bib ne '') {
266         $query.= '
267     AND biblionumber = ?
268 ';
269         push @bind, $bib;
270     }
271
272     if ($bor ne '') {
273         $query.= '
274     AND borrowernumber = ?
275 ';
276         push @bind, $bor;
277     }
278
279     $query.= '
280   ORDER BY priority
281 ';
282     my $sth=$dbh->prepare($query);
283     $sth->execute(@bind);
284     my @results;
285     while (my $data = $sth->fetchrow_hashref){
286         # FIXME - What is this if-statement doing? How do constraints work?
287         if ($data->{constrainttype} eq 'o') {
288             $query = '
289 SELECT biblioitemnumber
290   FROM reserveconstraints
291   WHERE biblionumber   = ?
292     AND borrowernumber = ?
293     AND reservedate    = ?
294 ';
295             my $csth=$dbh->prepare($query);
296             $csth->execute(
297                 $data->{biblionumber},
298                 $data->{borrowernumber},
299                 $data->{reservedate},
300             );
301             my ($bibitemno) = $csth->fetchrow_array;
302             $csth->finish;
303             # Look up the book we just found.
304             my $bdata = bibitemdata($bibitemno);
305             # Add the results of this latest search to the current
306             # results.
307             # FIXME - An 'each' would probably be more efficient.
308             foreach my $key (keys %$bdata) {
309                 $data->{$key} = $bdata->{$key};
310             }
311         }
312         push @results, $data;
313     }
314     $sth->finish;
315
316     return($#results+1,\@results);
317 }
318
319 sub GetNumberReservesFromBorrower {
320     my ($borrowernumber) = @_;
321
322     my $dbh = C4::Context->dbh;
323
324     my $query = '
325 SELECT COUNT(*) AS counter
326   FROM reserves
327   WHERE borrowernumber = ?
328     AND cancellationdate IS NULL
329     AND (found != \'F\' OR found IS NULL)
330 ';
331     my $sth = $dbh->prepare($query);
332     $sth->execute($borrowernumber);
333     my $row = $sth->fetchrow_hashref;
334     $sth->finish;
335
336     return $row->{counter};
337 }
338
339 sub GetFirstReserveDateFromItem {
340     my ($itemnumber) = @_;
341
342     my $dbh = C4::Context->dbh;
343
344     my $query = '
345 SELECT reservedate
346   FROM reserves
347   WHERE itemnumber = ?
348     AND cancellationdate IS NULL
349     AND (found != \'F\' OR found IS NULL)
350 ';
351     my $sth = $dbh->prepare($query);
352     $sth->execute($itemnumber);
353     my $row = $sth->fetchrow_hashref;
354     $sth->finish;
355
356     return $row->{reservedate};
357 }
358
359 =item CheckReserves
360
361   ($status, $reserve) = &CheckReserves($itemnumber, $barcode);
362
363 Find a book in the reserves.
364
365 C<$itemnumber> is the book's item number. C<$barcode> is its barcode.
366 Either one, but not both, may be false. If both are specified,
367 C<&CheckReserves> uses C<$itemnumber>.
368
369 $itemnubmer can be false, in which case uses the barcode. (Never uses
370 both. $itemnumber gets priority).
371
372 As I understand it, C<&CheckReserves> looks for the given item in the
373 reserves. If it is found, that's a match, and C<$status> is set to
374 C<Waiting>.
375
376 Otherwise, it finds the most important item in the reserves with the
377 same biblio number as this book (I'm not clear on this) and returns it
378 with C<$status> set to C<Reserved>.
379
380 C<&CheckReserves> returns a two-element list:
381
382 C<$status> is either C<Waiting>, C<Reserved> (see above), or 0.
383
384 C<$reserve> is the reserve item that matched. It is a
385 reference-to-hash whose keys are mostly the fields of the reserves
386 table in the Koha database.
387
388 =cut
389 #'
390 sub CheckReserves {
391     my ($item, $barcode) = @_;
392 #    warn "In CheckReserves: itemnumber = $item";
393     my $dbh = C4::Context->dbh;
394     my $sth;
395     if ($item) {
396         my $qitem=$dbh->quote($item);
397         # Look up the item by itemnumber
398         $sth=$dbh->prepare("SELECT items.biblionumber, items.biblioitemnumber, itemtypes.notforloan
399                              FROM items, biblioitems, itemtypes
400                             WHERE items.biblioitemnumber = biblioitems.biblioitemnumber
401                               AND biblioitems.itemtype = itemtypes.itemtype
402                               AND itemnumber=$qitem");
403     } else {
404         my $qbc=$dbh->quote($barcode);
405         # Look up the item by barcode
406         $sth=$dbh->prepare("SELECT items.biblionumber, items.biblioitemnumber, itemtypes.notforloan
407                              FROM items, biblioitems, itemtypes
408                             WHERE items.biblioitemnumber = biblioitems.biblioitemnumber
409                               AND biblioitems.itemtype = itemtypes.itemtype
410                               AND barcode=$qbc");
411         # FIXME - This function uses $item later on. Ought to set it here.
412     }
413     $sth->execute;
414     my ($biblio, $bibitem, $notforloan) = $sth->fetchrow_array;
415     $sth->finish;
416 # if item is not for loan it cannot be reserved either.....
417     return (0, 0) if ($notforloan);
418 # get the reserves...
419     # Find this item in the reserves
420     my ($count, @reserves) = Findgroupreserve($bibitem, $biblio);
421     # $priority and $highest are used to find the most important item
422     # in the list returned by &Findgroupreserve. (The lower $priority,
423     # the more important the item.)
424     # $highest is the most important item we've seen so far.
425     my $priority = 10000000;
426     my $highest;
427     if ($count) {
428         foreach my $res (@reserves) {
429             # FIXME - $item might be undefined or empty: the caller
430             # might be searching by barcode.
431             if ($res->{'itemnumber'} == $item) {
432                 # Found it
433                 return ("Waiting", $res);
434             } else {
435                 # See if this item is more important than what we've got
436                 # so far.
437                 if ($res->{'priority'} != 0 && $res->{'priority'} < $priority) {
438                     $priority = $res->{'priority'};
439                     $highest = $res;
440                 }
441             }
442         }
443     }
444
445     # If we get this far, then no exact match was found. Print the
446     # most important item on the list. I think this tells us who's
447     # next in line to get this book.
448     if ($highest) {     # FIXME - $highest might be undefined
449         $highest->{'itemnumber'} = $item;
450         return ("Reserved", $highest);
451     } else {
452         return (0, 0);
453     }
454 }
455
456 =item CancelReserve
457
458   &CancelReserve($biblionumber, $itemnumber, $borrowernumber);
459
460 Cancels a reserve.
461
462 Use either C<$biblionumber> or C<$itemnumber> to specify the item to
463 cancel, but not both: if both are given, C<&CancelReserve> does
464 nothing.
465
466 C<$borrowernumber> is the borrower number of the patron on whose
467 behalf the book was reserved.
468
469 If C<$biblionumber> was given, C<&CancelReserve> also adjusts the
470 priorities of the other people who are waiting on the book.
471
472 =cut
473 #'
474 sub CancelReserve {
475     my ($biblio, $item, $borr) = @_;
476     my $dbh = C4::Context->dbh;
477     #warn "In CancelReserve";
478     if (($item and $borr) and (not $biblio)) {
479                 # removing a waiting reserve record....
480                 # update the database...
481                 my $sth = $dbh->prepare("update reserves set cancellationdate = now(),
482                                                                                         found            = Null,
483                                                                                         priority         = 0
484                                                                         where itemnumber       = ?
485                                                                                 and borrowernumber   = ?");
486                 $sth->execute($item,$borr);
487                 $sth->finish;
488     }
489     if (($biblio and $borr) and (not $item)) {
490                 # removing a reserve record....
491                 # get the prioritiy on this record....
492                 my $priority;
493                 my $sth=$dbh->prepare("SELECT priority FROM reserves
494                                                                                 WHERE biblionumber   = ?
495                                                                                 AND borrowernumber = ?
496                                                                                 AND cancellationdate is NULL
497                                                                                 AND (found <> 'F' or found is NULL)");
498                 $sth->execute($biblio,$borr);
499                 ($priority) = $sth->fetchrow_array;
500                 $sth->finish;
501
502                 # update the database, removing the record...
503                 $sth = $dbh->prepare("update reserves set cancellationdate = now(),
504                                                                                         found            = Null,
505                                                                                         priority         = 0
506                                                                         where biblionumber     = ?
507                                                                                 and borrowernumber   = ?
508                                                                                 and cancellationdate is NULL
509                                                                                 and (found <> 'F' or found is NULL)");
510                 $sth->execute($biblio,$borr);
511                 $sth->finish;
512                 # now fix the priority on the others....
513                 fixpriority($priority, $biblio);
514     }
515 }
516
517 =item FillReserve
518
519   &FillReserve($reserve);
520
521 Fill a reserve. If I understand this correctly, this means that the
522 reserved book has been found and given to the patron who reserved it.
523
524 C<$reserve> specifies the reserve to fill. It is a reference-to-hash
525 whose keys are fields from the reserves table in the Koha database.
526
527 =cut
528 #'
529 sub FillReserve {
530     my ($res) = @_;
531     my $dbh = C4::Context->dbh;
532
533     # fill in a reserve record....
534     # FIXME - Remove some of the redundancy here
535     my $biblio = $res->{'biblionumber'}; my $qbiblio =$biblio;
536     my $borr = $res->{'borrowernumber'}; 
537     my $resdate = $res->{'reservedate'}; 
538
539     # get the priority on this record....
540     my $priority;
541     {
542     my $query = "SELECT priority FROM reserves
543                                 WHERE biblionumber   = ?
544                                   AND borrowernumber = ?
545                                   AND reservedate    = ?";
546     my $sth=$dbh->prepare($query);
547     $sth->execute($qbiblio,$borr,$resdate);
548     ($priority) = $sth->fetchrow_array;
549     $sth->finish;
550     }
551
552     # update the database...
553     {
554     my $query = "UPDATE reserves SET found            = 'F',
555                                      priority         = 0
556                                WHERE biblionumber     = ?
557                                  AND reservedate      = ?
558                                  AND borrowernumber   = ?";
559     my $sth = $dbh->prepare($query);
560     $sth->execute($qbiblio,$resdate,$borr);
561     $sth->finish;
562     }
563
564     # now fix the priority on the others (if the priority wasn't
565     # already sorted!)....
566     unless ($priority == 0) {
567         fixpriority($priority, $biblio);
568     }
569 }
570
571 # Only used internally
572 # Decrements (makes more important) the reserves for all of the
573 # entries waiting on the given book, if their priority is > $priority.
574 sub fixpriority {
575     my ($priority, $biblio) =  @_;
576     my $dbh = C4::Context->dbh;
577     my ($count, $reserves) = FindReserves($biblio);
578     foreach my $rec (@$reserves) {
579         if ($rec->{'priority'} > $priority) {
580             my $sth = $dbh->prepare("UPDATE reserves SET priority = ?
581                                WHERE biblionumber     = ?
582                                  AND borrowernumber   = ?
583                                  AND reservedate      = ?");
584             $sth->execute($rec->{'priority'},$rec->{'biblionumber'},$rec->{'borrowernumber'},$rec->{'reservedate'});
585             $sth->finish;
586         }
587     }
588 }
589
590 # XXX - POD
591 sub ReserveWaiting {
592     my ($item, $borr) = @_;
593     my $dbh = C4::Context->dbh;
594 # get priority and biblionumber....
595     my $sth = $dbh->prepare("SELECT reserves.priority     as priority,
596                         reserves.biblionumber as biblionumber,
597                         reserves.branchcode   as branchcode,
598                         reserves.timestamp     as timestamp
599                       FROM reserves,items
600                      WHERE reserves.biblionumber   = items.biblionumber
601                        AND items.itemnumber        = ?
602                        AND reserves.borrowernumber = ?
603                        AND reserves.cancellationdate is NULL
604                        AND (reserves.found <> 'F' or reserves.found is NULL)");
605     $sth->execute($item,$borr);
606     my $data = $sth->fetchrow_hashref;
607     $sth->finish;
608     my $biblio = $data->{'biblionumber'};
609     my $timestamp = $data->{'timestamp'};
610 # update reserves record....
611     $sth = $dbh->prepare("UPDATE reserves SET priority = 0, found = 'W', itemnumber = ?
612                             WHERE borrowernumber = ?
613                               AND biblionumber = ?
614                               AND timestamp = ?");
615     $sth->execute($item,$borr,$biblio,$timestamp);
616     $sth->finish;
617 # now fix up the remaining priorities....
618     fixpriority($data->{'priority'}, $biblio);
619     my $branchcode = $data->{'branchcode'};
620     return $branchcode;
621 }
622
623 # XXX - POD
624 sub CheckWaiting {
625     my ($borr)=@_;
626     my $dbh = C4::Context->dbh;
627     my @itemswaiting;
628     my $sth = $dbh->prepare("SELECT * FROM reserves
629                          WHERE borrowernumber = ?
630                            AND reserves.found = 'W'
631                            AND cancellationdate is NULL");
632     $sth->execute($borr);
633     while (my $data=$sth->fetchrow_hashref) {
634           push(@itemswaiting,$data);
635     }
636     $sth->finish;
637     return (scalar(@itemswaiting),\@itemswaiting);
638 }
639
640 =item Findgroupreserve
641
642   ($count, @results) = &Findgroupreserve($biblioitemnumber, $biblionumber);
643
644 I don't know what this does, because I don't understand how reserve
645 constraints work. I think the idea is that you reserve a particular
646 biblio, and the constraint allows you to restrict it to a given
647 biblioitem (e.g., if you want to borrow the audio book edition of "The
648 Prophet", rather than the first available publication).
649
650 C<&Findgroupreserve> returns a two-element array:
651
652 C<$count> is the number of elements in C<@results>.
653
654 C<@results> is an array of references-to-hash whose keys are mostly
655 fields from the reserves table of the Koha database, plus
656 C<biblioitemnumber>.
657
658 =cut
659 #'
660 sub Findgroupreserve {
661   my ($bibitem,$biblio)=@_;
662   my $dbh = C4::Context->dbh;
663   my $sth=$dbh->prepare("SELECT reserves.biblionumber               AS biblionumber,
664                       reserves.borrowernumber             AS borrowernumber,
665                       reserves.reservedate                AS reservedate,
666                       reserves.branchcode                 AS branchcode,
667                       reserves.cancellationdate           AS cancellationdate,
668                       reserves.found                      AS found,
669                       reserves.reservenotes               AS reservenotes,
670                       reserves.priority                   AS priority,
671                       reserves.timestamp                  AS timestamp,
672                       reserveconstraints.biblioitemnumber AS biblioitemnumber,
673                       reserves.itemnumber                 AS itemnumber
674                  FROM reserves LEFT JOIN reserveconstraints
675                    ON reserves.biblionumber = reserveconstraints.biblionumber
676                 WHERE reserves.biblionumber = ?
677                   AND ( ( reserveconstraints.biblioitemnumber = ?
678                       AND reserves.borrowernumber = reserveconstraints.borrowernumber
679                       AND reserves.reservedate    =reserveconstraints.reservedate )
680                    OR reserves.constrainttype='a' )
681                   AND reserves.cancellationdate is NULL
682                   AND (reserves.found <> 'F' or reserves.found is NULL)");
683   $sth->execute($biblio, $bibitem);
684   my @results;
685   while (my $data=$sth->fetchrow_hashref){
686     push(@results,$data);
687   }
688   $sth->finish;
689   return(scalar(@results),@results);
690 }
691
692 # FIXME - A somewhat different version of this function appears in
693 # C4::Reserves. Pick one and stick with it.
694 # XXX - POD
695 sub CreateReserve {
696   my ($env,$branch,$borrnum,$biblionumber,$constraint,$bibitems,$priority,$notes,$title,$checkitem,$found)= @_;
697   my $fee=CalcReserveFee($env,$borrnum,$biblionumber,$constraint,$bibitems);
698   my $dbh = C4::Context->dbh;
699   my $const = lc substr($constraint,0,1);
700   my @datearr = localtime(time);
701   my $resdate =(1900+$datearr[5])."-".($datearr[4]+1)."-".$datearr[3];
702   my $waitingdate;
703 # If the reserv had the waiting status, we had the value of the resdate
704   if ($found eq 'W'){
705   $waitingdate = $resdate;
706   }
707   #eval {
708   # updates take place here
709   if ($fee > 0) {
710 #    print $fee;
711     my $nextacctno = &getnextacctno($env,$borrnum,$dbh);
712     my $usth = $dbh->prepare("insert into accountlines
713     (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding)
714                                                           values
715     (?,?,now(),?,?,'Res',?)");
716     $usth->execute($borrnum,$nextacctno,$fee,"Reserve Charge - $title",$fee);
717     $usth->finish;
718   }
719   #if ($const eq 'a'){
720     my $sth = $dbh->prepare("insert into reserves
721    (borrowernumber,biblionumber,reservedate,branchcode,constrainttype,priority,reservenotes,itemnumber,found,waitingdate)
722     values (?,?,?,?,?,?,?,?,?,?)");
723     $sth->execute($borrnum,$biblionumber,$resdate,$branch,$const,$priority,$notes,$checkitem,$found,$waitingdate);
724     $sth->finish;
725   #}
726   if (($const eq "o") || ($const eq "e")) {
727     my $numitems = @$bibitems;
728     my $i = 0;
729     while ($i < $numitems) {
730       my $biblioitem = @$bibitems[$i];
731       my $sth = $dbh->prepare("insert into
732       reserveconstraints
733       (borrowernumber,biblionumber,reservedate,biblioitemnumber)
734       values (?,?,?,?)");
735       $sth->execute($borrnum,$biblionumber,$resdate,$biblioitem);
736       $sth->finish;
737       $i++;
738     }
739   }
740 #  print $query;
741   return();
742 }
743
744 # FIXME - A functionally identical version of this function appears in
745 # C4::Reserves. Pick one and stick with it.
746 # XXX - Internal use only
747 # FIXME - opac-reserves.pl need to use it, temporarily put into @EXPORT
748 sub CalcReserveFee {
749   my ($env,$borrnum,$biblionumber,$constraint,$bibitems) = @_;
750   #check for issues;
751   my $dbh = C4::Context->dbh;
752   my $const = lc substr($constraint,0,1);
753   my $sth = $dbh->prepare("SELECT * FROM borrowers,categories
754                 WHERE (borrowernumber = ?)
755                   AND (borrowers.categorycode = categories.categorycode)");
756   $sth->execute($borrnum);
757   my $data = $sth->fetchrow_hashref;
758   $sth->finish();
759   my $fee = $data->{'reservefee'};
760   my $cntitems = @->$bibitems;
761   if ($fee > 0) {
762     # check for items on issue
763     # first find biblioitem records
764     my @biblioitems;
765     my $sth1 = $dbh->prepare("SELECT * FROM biblio,biblioitems
766                    WHERE (biblio.biblionumber = ?)
767                      AND (biblio.biblionumber = biblioitems.biblionumber)");
768     $sth1->execute($biblionumber);
769     while (my $data1=$sth1->fetchrow_hashref) {
770       if ($const eq "a") {
771         push @biblioitems,$data1;
772       } else {
773         my $found = 0;
774         my $x = 0;
775         while ($x < $cntitems) {
776           if (@$bibitems->{'biblioitemnumber'} == $data->{'biblioitemnumber'}) {
777             $found = 1;
778           }
779           $x++;
780         }
781         if ($const eq 'o') {
782           if ( $found == 1) {
783             push @biblioitems,$data1;
784           }
785         } else {
786           if ($found == 0) {
787             push @biblioitems,$data1;
788           }
789         }
790       }
791     }
792     $sth1->finish;
793     my $cntitemsfound = @biblioitems;
794     my $issues = 0;
795     my $x = 0;
796     my $allissued = 1;
797     while ($x < $cntitemsfound) {
798       my $bitdata = $biblioitems[$x];
799       my $sth2 = $dbh->prepare("SELECT * FROM items
800                      WHERE biblioitemnumber = ?");
801       $sth2->execute($bitdata->{'biblioitemnumber'});
802       while (my $itdata=$sth2->fetchrow_hashref) {
803         my $sth3 = $dbh->prepare("SELECT * FROM issues
804                        WHERE itemnumber = ?
805                          AND returndate IS NULL");
806         $sth3->execute($itdata->{'itemnumber'});
807         if (my $isdata=$sth3->fetchrow_hashref) {
808         } else {
809           $allissued = 0;
810         }
811       }
812       $x++;
813     }
814     if ($allissued == 0) {
815       my $rsth = $dbh->prepare("SELECT * FROM reserves WHERE biblionumber = ?");
816       $rsth->execute($biblionumber);
817       if (my $rdata = $rsth->fetchrow_hashref) {
818       } else {
819         $fee = 0;
820       }
821     }
822   }
823 #  print "fee $fee";
824   return $fee;
825 }
826
827 # XXX - Internal use
828 sub getnextacctno {
829   my ($env,$bornumber,$dbh)=@_;
830   my $nextaccntno = 1;
831   my $sth = $dbh->prepare("select * from accountlines
832   where (borrowernumber = ?)
833   order by accountno desc");
834   $sth->execute($bornumber);
835   if (my $accdata=$sth->fetchrow_hashref){
836     $nextaccntno = $accdata->{'accountno'} + 1;
837   }
838   $sth->finish;
839   return($nextaccntno);
840 }
841
842 # XXX - POD
843 sub updatereserves{
844   #subroutine to update a reserve
845   my ($rank,$biblio,$borrower,$del,$branch)=@_;
846   my $dbh = C4::Context->dbh;
847   if ($del == 0){
848     my $sth = $dbh->prepare("Update reserves set priority=?,branchcode=? where
849     biblionumber=? and borrowernumber=?");
850     $sth->execute($rank,$branch,$biblio,$borrower);
851     $sth->finish();
852   } else {
853     my $sth=$dbh->prepare("Select * from reserves where biblionumber=? and
854     borrowernumber=?");
855     $sth->execute($biblio,$borrower);
856     my $data=$sth->fetchrow_hashref;
857     $sth->finish();
858     $sth=$dbh->prepare("Select * from reserves where biblionumber=? and
859     priority > ? and cancellationdate is NULL
860     order by priority") || die $dbh->errstr;
861     $sth->execute($biblio,$data->{'priority'}) || die $sth->errstr;
862     while (my $data=$sth->fetchrow_hashref){
863       $data->{'priority'}--;
864       my $sth3=$dbh->prepare("Update reserves set priority=?
865       where biblionumber=? and borrowernumber=?");
866       $sth3->execute($data->{'priority'},$data->{'biblionumber'},$data->{'borrowernumber'}) || die $sth3->errstr;
867       $sth3->finish();
868     }
869     $sth->finish();
870     $sth=$dbh->prepare("update reserves set cancellationdate=now() where biblionumber=?
871     and borrowernumber=?");
872     $sth->execute($biblio,$borrower);
873     $sth->finish;
874   }
875 }
876
877 # XXX - POD
878 sub UpdateReserve {
879     #subroutine to update a reserve
880     my ($rank,$biblio,$borrower,$branch)=@_;
881     return if $rank eq "W";
882     return if $rank eq "n";
883     my $dbh = C4::Context->dbh;
884     if ($rank eq "del") {
885         my $sth=$dbh->prepare("UPDATE reserves SET cancellationdate=now()
886                                    WHERE biblionumber   = ?
887                                      AND borrowernumber = ?
888                                      AND cancellationdate is NULL
889                                      AND (found <> 'F' or found is NULL)");
890         $sth->execute($biblio, $borrower);
891         $sth->finish;
892     } else {
893         my $sth=$dbh->prepare("UPDATE reserves SET priority = ? ,branchcode = ?, itemnumber = NULL, found = NULL
894                                    WHERE biblionumber   = ?
895                                      AND borrowernumber = ?
896                                      AND cancellationdate is NULL
897                                      AND (found <> 'F' or found is NULL)");
898         $sth->execute($rank, $branch, $biblio, $borrower);
899         $sth->finish;
900     }
901 }
902
903 # XXX - POD
904 sub getreservetitle {
905  my ($biblio,$bor,$date,$timestamp)=@_;
906  my $dbh = C4::Context->dbh;
907  my $sth=$dbh->prepare("Select * from reserveconstraints,biblioitems where
908  reserveconstraints.biblioitemnumber=biblioitems.biblioitemnumber
909  and reserveconstraints.biblionumber=? and reserveconstraints.borrowernumber
910  = ? and reserveconstraints.reservedate=? and
911  reserveconstraints.timestamp=?");
912  $sth->execute($biblio,$bor,$date,$timestamp);
913  my $data=$sth->fetchrow_hashref;
914  $sth->finish;
915  return($data);
916 }