Added a FIXME comment.
[koha.git] / C4 / Reserves2.pm
1 package C4::Reserves2; #assumes C4/Reserves2
2
3
4 # Copyright 2000-2002 Katipo Communications
5 #
6 # This file is part of Koha.
7 #
8 # Koha is free software; you can redistribute it and/or modify it under the
9 # terms of the GNU General Public License as published by the Free Software
10 # Foundation; either version 2 of the License, or (at your option) any later
11 # version.
12 #
13 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
14 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License along with
18 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
19 # Suite 330, Boston, MA  02111-1307 USA
20
21 use strict;
22 require Exporter;
23 use DBI;
24 use C4::Context;
25 use C4::Search;
26         # FIXME - C4::Reserves2 uses C4::Search, which uses C4::Reserves2.
27         # So Perl complains that all of the functions here get redefined.
28 #use C4::Accounts;
29
30 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
31   
32 # set the version for version checking
33 $VERSION = 0.01;
34     
35 @ISA = qw(Exporter);
36 @EXPORT = qw(&FindReserves &CheckReserves &CheckWaiting &CancelReserve &FillReserve &ReserveWaiting &CreateReserve &updatereserves &UpdateReserve &getreservetitle &Findgroupreserve);
37                                                     
38 # make all your functions, whether exported or not;
39
40 sub FindReserves {
41   my ($bib,$bor)=@_;
42   my $dbh = C4::Context->dbh;
43   my $query="SELECT *,reserves.branchcode,biblio.title AS btitle
44                       FROM reserves,borrowers,biblio ";
45   if ($bib ne ''){
46       $bib = $dbh->quote($bib);
47       if ($bor ne ''){
48           $bor = $dbh->quote($bor);
49           $query .=  " where reserves.biblionumber   = $bib
50                          and borrowers.borrowernumber = $bor 
51                          and reserves.borrowernumber = borrowers.borrowernumber 
52                          and biblio.biblionumber     = $bib 
53                          and cancellationdate is NULL 
54                          and (found <> 'F' or found is NULL)";
55       } else {
56           $query .= " where reserves.borrowernumber = borrowers.borrowernumber
57                         and biblio.biblionumber     = $bib 
58                         and reserves.biblionumber   = $bib
59                         and cancellationdate is NULL 
60                         and (found <> 'F' or found is NULL)";
61       }
62   } else {
63       $query .= " where borrowers.borrowernumber = $bor 
64                     and reserves.borrowernumber  = borrowers.borrowernumber 
65                     and reserves.biblionumber    = biblio.biblionumber 
66                     and cancellationdate is NULL and 
67                     (found <> 'F' or found is NULL)";
68   }
69   $query.=" order by priority";
70   my $sth=$dbh->prepare($query);
71   $sth->execute;
72   my $i=0;
73   my @results;
74   while (my $data=$sth->fetchrow_hashref){
75       if ($data->{'constrainttype'} eq 'o') {
76           my $conquery = "SELECT biblioitemnumber FROM reserveconstraints 
77                            WHERE biblionumber   = ? 
78                              AND borrowernumber = ?
79                              AND reservedate    = ?";
80           my $csth=$dbh->prepare($conquery);
81           my $bibn = $data->{'biblionumber'};
82           my $born = $data->{'borrowernumber'};
83           my $resd = $data->{'reservedate'};
84           $csth->execute($bibn, $born, $resd);
85           my ($bibitemno) = $csth->fetchrow_array;
86           $csth->finish;
87           my $bdata = C4::Search::bibitemdata($bibitemno);
88           foreach my $key (keys %$bdata) {
89               $data->{$key} = $bdata->{$key};
90           }
91       }
92       $results[$i]=$data;
93       $i++;
94   }
95 #  print $query;
96   $sth->finish;
97   return($i,\@results);
98 }
99
100 sub CheckReserves {
101     my ($item, $barcode) = @_;
102 #    warn "In CheckReserves: itemnumber = $item";
103     my $dbh = C4::Context->dbh;
104     my $sth;
105     if ($item) {
106         my $qitem=$dbh->quote($item);
107 # get the biblionumber...
108         $sth=$dbh->prepare("SELECT items.biblionumber, items.biblioitemnumber, itemtypes.notforloan
109                              FROM items, biblioitems, itemtypes 
110                             WHERE items.biblioitemnumber = biblioitems.biblioitemnumber
111                               AND biblioitems.itemtype = itemtypes.itemtype
112                               AND itemnumber=$qitem");
113     } else {
114         my $qbc=$dbh->quote($barcode);
115 # get the biblionumber...
116         $sth=$dbh->prepare("SELECT items.biblionumber, items.biblioitemnumber, itemtypes.notforloan
117                              FROM items, biblioitems, itemtypes 
118                             WHERE items.biblioitemnumber = biblioitems.biblioitemnumber
119                               AND biblioitems.itemtype = itemtypes.itemtype
120                               AND barcode=$qbc");
121     }
122     $sth->execute;
123     my ($biblio, $bibitem, $notforloan) = $sth->fetchrow_array;
124     $sth->finish;
125 # if item is not for loan it cannot be reserved either.....
126     return (0, 0) if ($notforloan);
127 # get the reserves...
128     my ($count, @reserves) = Findgroupreserve($bibitem, $biblio);
129     my $priority = 10000000; 
130     my $highest;
131     if ($count) {
132         foreach my $res (@reserves) {
133             if ($res->{'itemnumber'} == $item) {
134                 return ("Waiting", $res);
135             } else {
136                 if ($res->{'priority'} != 0 && $res->{'priority'} < $priority) {
137                     $priority = $res->{'priority'};
138                     $highest = $res;
139                 }
140             }
141         }
142     }
143     if ($highest) {
144         $highest->{'itemnumber'} = $item;
145         return ("Reserved", $highest);
146     } else {
147         return (0, 0);
148     }
149 }
150
151 sub CancelReserve {
152     my ($biblio, $item, $borr) = @_;
153     my $dbh = C4::Context->dbh;
154     #warn "In CancelReserve";
155     if (($item and $borr) and (not $biblio)) {
156 # removing a waiting reserve record....
157         $item = $dbh->quote($item);
158         $borr = $dbh->quote($borr);
159 # update the database...
160         my $query = "update reserves set cancellationdate = now(), 
161                                          found            = Null, 
162                                          priority         = 0 
163                                    where itemnumber       = $item 
164                                      and borrowernumber   = $borr";
165         my $sth = $dbh->prepare($query);
166         $sth->execute;
167         $sth->finish;
168     }
169     if (($biblio and $borr) and (not $item)) {
170 # removing a reserve record....
171         my $q_biblio = $dbh->quote($biblio);
172         $borr = $dbh->quote($borr);
173 # get the prioritiy on this record....
174         my $query = "SELECT priority FROM reserves 
175                                     WHERE biblionumber   = $q_biblio 
176                                       AND borrowernumber = $borr
177                                       AND cancellationdate is NULL 
178                                       AND (found <> 'F' or found is NULL)";
179         my $sth=$dbh->prepare($query);
180         $sth->execute;
181         my ($priority) = $sth->fetchrow_array;
182         $sth->finish;
183 # update the database, removing the record...
184         # FIXME - There's already a $query in this scope.
185         my $query = "update reserves set cancellationdate = now(), 
186                                          found            = Null, 
187                                          priority         = 0 
188                                    where biblionumber     = $q_biblio 
189                                      and borrowernumber   = $borr
190                                      and cancellationdate is NULL 
191                                      and (found <> 'F' or found is NULL)";
192                 # FIXME - There's already a $query in this scope.
193         # FIXME - There's already a $sth in this scope.
194         my $sth = $dbh->prepare($query);
195                 # FIXME - There's already a $sth in this scope.
196         $sth->execute;
197         $sth->finish;
198 # now fix the priority on the others....
199         fixpriority($priority, $biblio);
200     }
201 }
202
203
204 sub FillReserve {
205     my ($res) = @_;
206     my $dbh = C4::Context->dbh;
207 # fillinf a reserve record....
208     my $biblio = $res->{'biblionumber'}; my $qbiblio = $dbh->quote($biblio);
209     my $borr = $res->{'borrowernumber'}; $borr = $dbh->quote($borr);
210     my $resdate = $res->{'reservedate'}; $resdate = $dbh->quote($resdate);
211 # get the prioritiy on this record....
212     my $query = "SELECT priority FROM reserves 
213                                 WHERE biblionumber   = $qbiblio 
214                                   AND borrowernumber = $borr
215                                   AND reservedate    = $resdate)";
216     my $sth=$dbh->prepare($query);
217     $sth->execute;
218     my ($priority) = $sth->fetchrow_array;
219     $sth->finish;
220 # update the database...
221     # FIXME - There's already a $query in this scope.
222     my $query = "UPDATE reserves SET found            = 'F', 
223                                      priority         = 0 
224                                WHERE biblionumber     = $qbiblio
225                                  AND reservedate      = $resdate
226                                  AND borrowernumber   = $borr";
227                 # FIXME - There's already a $query in this scope.
228     # FIXME - There's already a $sth in this scope.
229     my $sth = $dbh->prepare($query);
230                 # FIXME - There's already a $sth in this scope.
231     $sth->execute;
232     $sth->finish;
233 # now fix the priority on the others (if the priority wasnt already sorted!)....
234     unless ($priority == 0) {
235         fixpriority($priority, $biblio);
236     }
237 }
238
239 sub fixpriority {
240     my ($priority, $biblio) =  @_;
241     my $dbh = C4::Context->dbh;
242     my ($count, $reserves) = FindReserves($biblio);
243     foreach my $rec (@$reserves) {
244         if ($rec->{'priority'} > $priority) {
245             my $newpr = $rec->{'priority'};      $newpr = $dbh->quote($newpr - 1);
246             my $nbib = $rec->{'biblionumber'};   $nbib = $dbh->quote($nbib);
247             my $nbor = $rec->{'borrowernumber'}; $nbor = $dbh->quote($nbor);
248             my $nresd = $rec->{'reservedate'};   $nresd = $dbh->quote($nresd);
249             my $query = "UPDATE reserves SET priority = $newpr 
250                                WHERE biblionumber     = $nbib 
251                                  AND borrowernumber   = $nbor
252                                  AND reservedate      = $nresd";
253             #warn $query;
254             my $sth = $dbh->prepare($query);
255             $sth->execute;
256             $sth->finish;
257         } 
258     }
259 }
260
261
262
263 sub ReserveWaiting {
264     my ($item, $borr) = @_;
265     my $dbh = C4::Context->dbh;
266     $item = $dbh->quote($item);
267     $borr = $dbh->quote($borr);
268 # get priority and biblionumber....
269     my $query = "SELECT reserves.priority     as priority, 
270                         reserves.biblionumber as biblionumber,
271                         reserves.branchcode   as branchcode, 
272                         reserves.timestamp     as timestamp
273                       FROM reserves,items 
274                      WHERE reserves.biblionumber   = items.biblionumber 
275                        AND items.itemnumber        = $item 
276                        AND reserves.borrowernumber = $borr 
277                        AND reserves.cancellationdate is NULL
278                        AND (reserves.found <> 'F' or reserves.found is NULL)";
279     my $sth = $dbh->prepare($query);
280     $sth->execute;
281     my $data = $sth->fetchrow_hashref;
282     $sth->finish;
283     my $biblio = $data->{'biblionumber'};
284     my $timestamp = $data->{'timestamp'};
285     my $q_biblio = $dbh->quote($biblio);
286     my $q_timestamp = $dbh->quote($timestamp);
287     warn "Timestamp: ".$timestamp."\n";
288 # update reserves record....
289     $query = "UPDATE reserves SET priority = 0, found = 'W', itemnumber = $item 
290                             WHERE borrowernumber = $borr 
291                               AND biblionumber = $q_biblio 
292                               AND timestamp = $q_timestamp";
293     warn "Query: ".$query."\n";
294     $sth = $dbh->prepare($query);
295     $sth->execute;
296     $sth->finish;
297 # now fix up the remaining priorities....
298     fixpriority($data->{'priority'}, $biblio);
299     my $branchcode = $data->{'branchcode'};
300     return $branchcode;
301 }
302
303 sub CheckWaiting {
304     my ($borr)=@_;
305     my $dbh = C4::Context->dbh;
306     $borr = $dbh->quote($borr);
307     my @itemswaiting;
308     my $query = "SELECT * FROM reserves
309                          WHERE borrowernumber = $borr
310                            AND reserves.found = 'W' 
311                            AND cancellationdate is NULL";
312     my $sth = $dbh->prepare($query);
313     $sth->execute();
314     # FIXME - Use 'push'
315     my $cnt=0;
316     if (my $data=$sth->fetchrow_hashref) {
317         $itemswaiting[$cnt] =$data;
318         $cnt ++;
319     }
320     $sth->finish;
321     return ($cnt,\@itemswaiting);
322 }
323
324 sub Findgroupreserve {
325   my ($bibitem,$biblio)=@_;
326   my $dbh = C4::Context->dbh;
327   $bibitem=$dbh->quote($bibitem);
328   my $query = "SELECT reserves.biblionumber               AS biblionumber, 
329                       reserves.borrowernumber             AS borrowernumber, 
330                       reserves.reservedate                AS reservedate, 
331                       reserves.branchcode                 AS branchcode, 
332                       reserves.cancellationdate           AS cancellationdate, 
333                       reserves.found                      AS found, 
334                       reserves.reservenotes               AS reservenotes, 
335                       reserves.priority                   AS priority, 
336                       reserves.timestamp                  AS timestamp, 
337                       reserveconstraints.biblioitemnumber AS biblioitemnumber, 
338                       reserves.itemnumber                 AS itemnumber 
339                  FROM reserves LEFT JOIN reserveconstraints
340                    ON reserves.biblionumber = reserveconstraints.biblionumber
341                 WHERE reserves.biblionumber = $biblio
342                   AND ( ( reserveconstraints.biblioitemnumber = $bibitem 
343                       AND reserves.borrowernumber = reserveconstraints.borrowernumber
344                       AND reserves.reservedate    =reserveconstraints.reservedate )
345                    OR reserves.constrainttype='a' )
346                   AND reserves.cancellationdate is NULL
347                   AND (reserves.found <> 'F' or reserves.found is NULL)";
348   my $sth=$dbh->prepare($query);
349   $sth->execute;
350   my $i=0;
351   my @results;
352   while (my $data=$sth->fetchrow_hashref){
353     $results[$i]=$data;
354     $i++;
355   }
356   $sth->finish;
357   return($i,@results);
358 }
359
360 sub CreateReserve {                                                           
361   my
362 ($env,$branch,$borrnum,$biblionumber,$constraint,$bibitems,$priority,$notes,$title)= @_;   
363   my $fee=CalcReserveFee($env,$borrnum,$biblionumber,$constraint,$bibitems);
364   my $dbh = C4::Context->dbh;
365   my $const = lc substr($constraint,0,1);       
366   my @datearr = localtime(time);                                
367   my $resdate =(1900+$datearr[5])."-".($datearr[4]+1)."-".$datearr[3];                   
368   #eval {                                                           
369   # updates take place here             
370   if ($fee > 0) {           
371 #    print $fee;
372     my $nextacctno = &getnextacctno($env,$borrnum,$dbh);   
373     my $updquery = "insert into accountlines       
374     (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding)
375                                                           values
376     ($borrnum,$nextacctno,now(),$fee,'Reserve Charge - $title','Res',$fee)";          
377     my $usth = $dbh->prepare($updquery);                      
378     $usth->execute;             
379     $usth->finish;                        
380   }                     
381   #if ($const eq 'a'){
382     my $query="insert into reserves
383    (borrowernumber,biblionumber,reservedate,branchcode,constrainttype,priority,reservenotes)
384     values
385 ('$borrnum','$biblionumber','$resdate','$branch','$const','$priority','$notes')";   
386     my $sth = $dbh->prepare($query);                        
387     $sth->execute();                
388     $sth->finish;
389   #}
390   if (($const eq "o") || ($const eq "e")) {     
391     my $numitems = @$bibitems;             
392     my $i = 0;                                        
393     while ($i < $numitems) {   
394       my $biblioitem = @$bibitems[$i];   
395       my $query = "insert into
396       reserveconstraints                          
397       (borrowernumber,biblionumber,reservedate,biblioitemnumber)         
398       values
399       ('$borrnum','$biblionumber','$resdate','$biblioitem')";                 
400       my $sth = $dbh->prepare($query);                    
401       $sth->execute();
402       $sth->finish;
403       $i++;                         
404     }                                   
405   } 
406 #  print $query;
407   return();   
408 }             
409
410 sub CalcReserveFee {
411   my ($env,$borrnum,$biblionumber,$constraint,$bibitems) = @_;        
412   #check for issues;    
413   my $dbh = C4::Context->dbh;           
414   my $const = lc substr($constraint,0,1); 
415   my $query = "SELECT * FROM borrowers,categories 
416                 WHERE (borrowernumber = ?)         
417                   AND (borrowers.categorycode = categories.categorycode)";   
418   my $sth = $dbh->prepare($query);                       
419   $sth->execute($borrnum);                                    
420   my $data = $sth->fetchrow_hashref;                  
421   $sth->finish();
422   my $fee = $data->{'reservefee'};       
423   my $cntitems = @->$bibitems;   
424   if ($fee > 0) {                         
425     # check for items on issue      
426     # first find biblioitem records       
427     my @biblioitems;    
428     my $query1 = "SELECT * FROM biblio,biblioitems                           
429                    WHERE (biblio.biblionumber = ?)     
430                      AND (biblio.biblionumber = biblioitems.biblionumber)";
431     my $sth1 = $dbh->prepare($query1);                   
432     $sth1->execute($biblionumber);                                     
433     while (my $data1=$sth1->fetchrow_hashref) { 
434       if ($const eq "a") {    
435         push @biblioitems,$data1;       
436       } else {                     
437         my $found = 0;        
438         my $x = 0;
439         while ($x < $cntitems) {                                             
440           if (@$bibitems->{'biblioitemnumber'} == $data->{'biblioitemnumber'}) {         
441             $found = 1;   
442           }               
443           $x++;                                       
444         }               
445         if ($const eq 'o') {
446           if ( $found == 1) {
447             push @biblioitems,$data1;
448           }                            
449         } else {
450           if ($found == 0) {
451             push @biblioitems,$data1;
452           } 
453         }     
454       }   
455     }             
456     $sth1->finish;                                  
457     my $cntitemsfound = @biblioitems; 
458     my $issues = 0;                 
459     my $x = 0;                   
460     my $allissued = 1; 
461     while ($x < $cntitemsfound) { 
462       my $bitdata = $biblioitems[$x];                                       
463       my $query2 = "SELECT * FROM items                   
464                      WHERE biblioitemnumber = ?";     
465       my $sth2 = $dbh->prepare($query2);                       
466       $sth2->execute($bitdata->{'biblioitemnumber'});   
467       while (my $itdata=$sth2->fetchrow_hashref) { 
468         my $query3 = "SELECT * FROM issues
469                        WHERE itemnumber = ? 
470                          AND returndate IS NULL";
471         
472         my $sth3 = $dbh->prepare($query3);                      
473         $sth3->execute($itdata->{'itemnumber'});                     
474         if (my $isdata=$sth3->fetchrow_hashref) {
475         } else {
476           $allissued = 0; 
477         }  
478       }                                                           
479       $x++;   
480     }         
481     if ($allissued == 0) { 
482       my $rquery = "SELECT * FROM reserves WHERE biblionumber = ?"; 
483       my $rsth = $dbh->prepare($rquery);   
484       $rsth->execute($biblionumber);   
485       if (my $rdata = $rsth->fetchrow_hashref) { 
486       } else {                                     
487         $fee = 0;                                                           
488       }   
489     }             
490   }                   
491 #  print "fee $fee";
492   return $fee;                                      
493 }                   
494
495 sub getnextacctno {                                                           
496   my ($env,$bornumber,$dbh)=@_;           
497   my $nextaccntno = 1;      
498   my $query = "select * from accountlines                             
499   where (borrowernumber = '$bornumber')                               
500   order by accountno desc";                       
501   my $sth = $dbh->prepare($query);                                  
502   $sth->execute;                    
503   if (my $accdata=$sth->fetchrow_hashref){    
504     $nextaccntno = $accdata->{'accountno'} + 1;           
505   }                       
506   $sth->finish;                                       
507   return($nextaccntno);                   
508 }              
509
510 sub updatereserves{
511   #subroutine to update a reserve 
512   my ($rank,$biblio,$borrower,$del,$branch)=@_;
513   my $dbh = C4::Context->dbh;
514   my $query="Update reserves ";
515   if ($del == 0){
516     $query.="set  priority='$rank',branchcode='$branch' where
517     biblionumber=$biblio and borrowernumber=$borrower";
518   } else {
519     $query="Select * from reserves where biblionumber=$biblio and
520     borrowernumber=$borrower";
521     my $sth=$dbh->prepare($query);
522     $sth->execute;
523     my $data=$sth->fetchrow_hashref;
524     $sth->finish;
525     $query="Select * from reserves where biblionumber=$biblio and 
526     priority > '$data->{'priority'}' and cancellationdate is NULL 
527     order by priority";
528     my $sth2=$dbh->prepare($query) || die $dbh->errstr;
529     $sth2->execute || die $sth2->errstr;
530     while (my $data=$sth2->fetchrow_hashref){
531       $data->{'priority'}--;
532       $query="Update reserves set priority=$data->{'priority'} where
533       biblionumber=$data->{'biblionumber'} and
534       borrowernumber=$data->{'borrowernumber'}";
535       my $sth3=$dbh->prepare($query);
536       $sth3->execute || die $sth3->errstr;
537       $sth3->finish;
538     }
539     $sth2->finish;
540     $query="update reserves set cancellationdate=now() where biblionumber=$biblio 
541     and borrowernumber=$borrower";    
542   }
543   my $sth=$dbh->prepare($query);
544   $sth->execute;
545   $sth->finish;
546 }
547 sub UpdateReserve {
548     #subroutine to update a reserve 
549     my ($rank,$biblio,$borrower,$branch)=@_;
550     return if $rank eq "W";
551     my $dbh = C4::Context->dbh;
552     if ($rank eq "del") {
553         my $query = "UPDATE reserves SET cancellationdate=now() 
554                                    WHERE biblionumber   = ? 
555                                      AND borrowernumber = ?    
556                                      AND cancellationdate is NULL
557                                      AND (found <> 'F' or found is NULL)";
558         my $sth=$dbh->prepare($query);
559         $sth->execute($biblio, $borrower);
560         $sth->finish;  
561     } else {
562         my $query = "UPDATE reserves SET priority = ? ,branchcode = ?, itemnumber = NULL, found = NULL 
563                                    WHERE biblionumber   = ? 
564                                      AND borrowernumber = ?
565                                      AND cancellationdate is NULL
566                                      AND (found <> 'F' or found is NULL)";
567         my $sth=$dbh->prepare($query);
568         $sth->execute($rank, $branch, $biblio, $borrower);
569         $sth->finish;  
570     }
571 }
572
573 sub getreservetitle {
574  my ($biblio,$bor,$date,$timestamp)=@_;
575  my $dbh = C4::Context->dbh;
576  my $query="Select * from reserveconstraints,biblioitems where
577  reserveconstraints.biblioitemnumber=biblioitems.biblioitemnumber
578  and reserveconstraints.biblionumber=$biblio and reserveconstraints.borrowernumber
579  = $bor and reserveconstraints.reservedate='$date' and
580  reserveconstraints.timestamp=$timestamp";
581  my $sth=$dbh->prepare($query);
582  $sth->execute;
583  my $data=$sth->fetchrow_hashref;
584  $sth->finish;
585 # print $query;
586  return($data);
587 }
588
589
590
591
592
593                         
594 END { }       # module clean-up code here (global destructor)