adding POD from Andres Arensburger
[koha.git] / C4 / Search.pm
1 package C4::Search; #assumes C4/Search
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::Database;
25 use C4::Reserves2;
26 use Set::Scalar;
27
28 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
29   
30 # set the version for version checking
31 $VERSION = 0.02;
32     
33 =head1 NAME
34
35 C4::Search - Functions for searching the Koha catalog and other databases
36
37 =head1 SYNOPSIS
38
39   use C4::Search;
40
41   my ($count, @results) = catalogsearch($env, $type, $search, $num, $offset);
42
43 =head1 DESCRIPTION
44
45 This module provides the searching facilities for the Koha catalog and
46 other databases.
47
48 C<&catalogsearch> is a front end to all the other searches. Depending
49 on what is passed to it, it calls the appropriate search function.
50
51 =head1 FUNCTIONS
52
53 =over 2
54
55 =cut
56
57 @ISA = qw(Exporter);
58 @EXPORT = qw(&CatSearch &BornameSearch &ItemInfo &KeywordSearch &subsearch
59 &itemdata &bibdata &GetItems &borrdata &itemnodata &itemcount
60 &borrdata2 &NewBorrowerNumber &bibitemdata &borrissues
61 &getboracctrecord &ItemType &itemissues &subject &subtitle
62 &addauthor &bibitems &barcodes &findguarantees &allissues &systemprefs
63 &findguarantor &getwebsites &getwebbiblioitems &catalogsearch &itemcount2);
64 # make all your functions, whether exported or not;
65
66 =item findguarantees
67
68   ($num_children, $children_arrayref) = &findguarantees($parent_borrno);
69   $child0_cardno = $children_arrayref->[0]{"cardnumber"};
70   $child0_borrno = $children_arrayref->[0]{"borrowernumber"};
71
72 C<&findguarantees> takes a borrower number (e.g., that of a patron
73 with children) and looks up the borrowers who are guaranteed by that
74 borrower (i.e., the patron's children).
75
76 C<&findguarantees> returns two values: an integer giving the number of
77 borrowers guaranteed by C<$parent_borrno>, and a reference to an array
78 of references to hash, which gives the actual results.
79
80 =cut
81 #'
82 sub findguarantees{         
83   my ($bornum)=@_;         
84   my $dbh=C4Connect;           
85   my $query="select cardnumber,borrowernumber from borrowers where    
86   guarantor='$bornum'";               
87   my $sth=$dbh->prepare($query);                 
88   $sth->execute;                   
89   my @dat;                     
90   my $i=0;                       
91   while (my $data=$sth->fetchrow_hashref){    
92     $dat[$i]=$data;                           
93     $i++;                               
94   }                                   
95   $sth->finish; 
96   $dbh->disconnect;         
97   return($i,\@dat);             
98 }
99
100 =item findguarantor
101
102   $guarantor = &findguarantor($borrower_no);
103   $guarantor_cardno = $guarantor->{"cardnumber"};
104   $guarantor_surname = $guarantor->{"surname"};
105   ...
106
107 C<&findguarantor> takes a borrower number (presumably that of a child
108 patron), finds the guarantor for C<$borrower_no> (the child's parent),
109 and returns the record for the guarantor.
110
111 C<&findguarantor> returns a reference-to-hash. Its keys are the fields
112 from the C<borrowers> database table;
113
114 =cut
115 #'
116 sub findguarantor{  
117   my ($bornum)=@_;  
118   my $dbh=C4Connect;    
119   my $query="select guarantor from borrowers where      
120   borrowernumber='$bornum'";        
121   my $sth=$dbh->prepare($query);          
122   $sth->execute;            
123   my $data=$sth->fetchrow_hashref;              
124   $sth->finish;                
125   $query="Select * from borrowers where
126   borrowernumber='$data->{'guarantor'}'";  
127   $sth=$dbh->prepare($query);  
128   $sth->execute;    
129   $data=$sth->fetchrow_hashref;      
130   $sth->finish;        
131   $dbh->disconnect;          
132   return($data);            
133 }
134
135 =item systemprefs
136
137   %prefs = &systemprefs();
138
139 Returns a hash giving the system preferences. This is basically just a
140 dump of the C<systempreferences> database table.
141
142 =cut
143 #'
144 sub systemprefs {
145     my %systemprefs;
146     my $dbh=C4Connect;
147     my $sth=$dbh->prepare("select variable,value from systempreferences");
148     $sth->execute;
149     while (my ($variable,$value)=$sth->fetchrow) {
150         $systemprefs{$variable}=$value;
151     }
152     $sth->finish;
153     $dbh->disconnect;
154     return(%systemprefs);
155 }
156
157 =item NewBorrowerNumber
158
159   $num = &NewBorrowerNumber();
160
161 Allocates a new, unused borrower number, and returns it.
162
163 =cut
164 #'
165 sub NewBorrowerNumber {           
166   my $dbh=C4Connect;        
167   my $sth=$dbh->prepare("Select max(borrowernumber) from borrowers");     
168   $sth->execute;            
169   my $data=$sth->fetchrow_hashref;                                  
170   $sth->finish;                   
171   $data->{'max(borrowernumber)'}++;         
172   $dbh->disconnect;
173   return($data->{'max(borrowernumber)'}); 
174 }    
175
176 =item catalogsearch
177
178   ($count, @results) = &catalogsearch($env, $type, $search, $num, $offset);
179
180 This is primarily a front-end to other, more specialized catalog
181 search functions: if C<$search-E<gt>{itemnumber}> or
182 C<$search-E<gt>{isbn}> is given, C<&catalogsearch> uses a precise
183 C<&CatSearch>. If $search->{subject} is given, it runs a subject
184 C<&CatSearch>. If C<$search-E<gt>{keyword}> is given, it runs a
185 C<&KeywordSearch>. Otherwise, it runs a loose C<&CatSearch>.
186
187 If C<$env-E<gt>{itemcount}> is 1, then C<&catalogsearch> also counts
188 the items for each result, and adds several keys:
189
190 =over 4
191
192 =item C<itemcount>
193
194 The total number of copies of this book.
195
196 =item C<locationhash>
197
198 This is a reference-to-hash; the keys are the names of branches where
199 this book may be found, and the values are the number of copies at
200 that branch.
201
202 =item C<location>
203
204 A descriptive string saying where the book is located, and how many
205 copies there are, if greater than 1.
206
207 =item C<subject2>
208
209 The book's subject, with spaces replaced with C<%20>, presumably for
210 HTML.
211
212 =back
213
214 =cut
215 #'
216 sub catalogsearch {
217   my ($env,$type,$search,$num,$offset)=@_;
218   my $dbh = C4Connect();
219 #  foreach my $key (%$search){
220 #    $search->{$key}=$dbh->quote($search->{$key});
221 #  }
222   my ($count,@results);
223 #  print STDERR "Doing a search \n";
224   # FIXME - Use "elsif" to avoid this sort of deep nesting
225   if ($search->{'itemnumber'} ne '' || $search->{'isbn'} ne ''){
226         print STDERR "Doing a precise search\n";
227     ($count,@results)=CatSearch($env,'precise',$search,$num,$offset);
228
229   } else {
230     if ($search->{'subject'} ne ''){
231       ($count,@results)=CatSearch($env,'subject',$search,$num,$offset);
232     } else {
233       if ($search->{'keyword'} ne ''){
234          ($count,@results)=&KeywordSearch($env,'keyword',$search,$num,$offset);
235        } else {
236         ($count,@results)=CatSearch($env,'loose',$search,$num,$offset);
237
238       }
239     }
240   }
241   if ($env->{itemcount} eq '1') {
242     foreach my $data (@results){
243       my ($counts) = itemcount2($env, $data->{'biblionumber'}, 'intra');
244       my $subject2=$data->{'subject'};
245       $subject2=~ s/ /%20/g;
246       $data->{'itemcount'}=$counts->{'total'};
247       my $totalitemcounts=0;
248       foreach my $key (keys %$counts){
249         if ($key ne 'total'){   # FIXME - Should ignore 'order', too.
250           #$data->{'location'}.="$key $counts->{$key} ";
251           $totalitemcounts+=$counts->{$key};
252           $data->{'locationhash'}->{$key}=$counts->{$key};
253          }
254       }
255       my $locationtext='';
256       my $notavailabletext='';
257       foreach (sort keys %{$data->{'locationhash'}}) {
258           if ($_ eq 'notavailable') {
259               $notavailabletext="Not available";
260               my $c=$data->{'locationhash'}->{$_};
261               if ($totalitemcounts>1) {
262                   $notavailabletext.=" ($c)";
263               }
264           } else {
265               $locationtext.="$_";
266               my $c=$data->{'locationhash'}->{$_};
267               if ($totalitemcounts>1) {
268                   $locationtext.=" ($c), ";
269               }
270           }
271       }
272       if ($notavailabletext) {
273           $locationtext.=$notavailabletext;
274       } else {
275           $locationtext=~s/, $//;
276       }
277       $data->{'location'}=$locationtext;
278       $data->{'subject2'}=$subject2;
279     }
280   }
281   return ($count,@results);
282 }
283
284 =item KeywordSearch
285
286   $search = { "keyword" => "One or more keywords",
287               "class"   => "VID|CD",    # Limit search to fiction and CDs
288               "dewey"   => "813",
289          };
290   ($count, @results) = &KeywordSearch($env, $type, $search, $num, $offset);
291
292 C<&KeywordSearch> searches the catalog by keyword: given a string
293 (C<$search-E<gt>{"keyword"}> consisting of a space-separated list of
294 keywords, it looks for books that contain any of those keywords in any
295 of a number of places.
296
297 C<&KeywordSearch> looks for keywords in the book title (and subtitle),
298 series name, notes (both C<biblio.notes> and C<biblioitems.notes>),
299 and subjects.
300
301 C<$search-E<gt>{"class"}> can be set to a C<|> (pipe)-separated list of
302 item class codes (e.g., "F" for fiction, "JNF" for junior nonfiction,
303 etc.). In this case, the search will be restricted to just those
304 classes.
305
306 If C<$search-E<gt>{"class"}> is not specified, you may specify
307 C<$search-E<gt>{"dewey"}>. This will restrict the search to that
308 particular Dewey Decimal Classification category. Setting
309 C<$search-E<gt>{"dewey"}> to "513" will return books about arithmetic,
310 whereas setting it to "5" will return all books with Dewey code 5I<xx>
311 (Science and Mathematics).
312
313 C<$env> and C<$type> are ignored.
314
315 C<$offset> and C<$num> specify the subset of results to return.
316 C<$num> specifies the number of results to return, and C<$offset> is
317 the number of the first result. Thus, setting C<$offset> to 100 and
318 C<$num> to 5 will return results 100 through 104 inclusive.
319
320 =cut
321 #'
322
323 # FIXME - Everything that's being done here with Set::Scalar can be
324 # done with hashes: to add a result to the set, just use:
325 #       $results{$foo} = 1;
326 # To get the list of results, just use
327 #       @biblionumbers = sort keys %results;
328 # This would remove the dependency on Set::Scalar, which means one
329 # fewer package that people have to install.
330   
331 sub KeywordSearch {
332   my ($env,$type,$search,$num,$offset)=@_;
333   my $dbh = &C4Connect;
334   $search->{'keyword'}=~ s/ +$//;
335   $search->{'keyword'}=~ s/'/\\'/;
336   my @key=split(' ',$search->{'keyword'});
337   my $count=@key;
338   my $i=1;
339   my @results;
340
341   # Look for keywords in table 'biblio'.
342
343   # FIXME - The next 15 lines can be rewritten in somewhat Lisp-ish
344   # fashion as follows:
345   #
346   # my $query = "select biblionumber from biblio where (" .
347   #     join(") or (",
348   #          map {
349   #                  my $field = $_;
350   #                  join (" and ",
351   #                        map {
352   #                          "($field like '$_\%' or $field like '\% $_\%')"
353   #                        }
354   #                        @key)
355   #          }
356   #          qw( title biblio.notes seriestitle )) .
357   #     ")";
358   # FIXME - Also,
359   #     field like 'string%' or field like '% string%'
360   # can be rewritten (in MySQL, at least) as
361   #     field regexp '(^| )string';
362   my $query="Select biblionumber from biblio
363   where ((title like '$key[0]%' or title like '% $key[0]%')";
364   while ($i < $count){                                                  
365       $query=$query." and (title like '$key[$i]%' or title like '% $key[$i]%')";                                                   
366       $i++;                                                  
367   }
368   $query.= ") or ((biblio.notes like '$key[0]%' or biblio.notes like '% $key[0]%')";                                             
369   for ($i=1;$i<$count;$i++){                                                  
370       $query.=" and (biblio.notes like '$key[$i]%' or biblio.notes like '% $key[$i]%')";                                           
371   }
372    $query.= ") or ((seriestitle like '$key[0]%' or seriestitle like '% $key[0]%')";                                               
373   for ($i=1;$i<$count;$i++){                                                  
374       $query.=" and (seriestitle like '$key[$i]%' or seriestitle like '% $key[$i]%')";                                             
375   }
376   $query.=" )";
377 #  print $query;
378   my $sth=$dbh->prepare($query);
379   $sth->execute;
380   $i=0;
381   while (my @res=$sth->fetchrow_array){
382     $results[$i]=$res[0];
383     $i++;
384   }
385   $sth->finish;
386   my $set1=Set::Scalar->new(@results);
387
388   # Now look for keywords in the 'bibliosubtitle' table.
389   $query="Select biblionumber from bibliosubtitle where
390   ((subtitle like '$key[0]%' or subtitle like '% $key[0]%')";                 
391   for ($i=1;$i<$count;$i++){   
392         $query.= " and (subtitle like '$key[$i]%' or subtitle like '% $key[$i]%')";                                                  
393   }                   
394   $query.=" )";
395 #  print $query;
396   $sth=$dbh->prepare($query);
397   $sth->execute;
398   $i=0;
399   while (my @res=$sth->fetchrow_array){
400     $results[$i]=$res[0];
401     $i++;
402   }
403   $sth->finish;
404   my $set2=Set::Scalar->new(@results);
405   if ($i > 0){
406     $set1=$set1+$set2;
407   }
408
409   # Look for the keywords in the notes for individual items
410   # ('biblioitems.notes')
411   $query ="Select biblionumber from biblioitems where
412   ((biblioitems.notes like '$key[0]%' or biblioitems.notes like '% $key[0]%')";                                   
413   for ($i=1;$i<$count;$i++){                                                  
414       $query.=" and (biblioitems.notes like '$key[$i]%' or biblioitems.notes like '% $key[$i]%')";                                 
415   }            
416   $query.=" )";
417 #  print $query;
418   $sth=$dbh->prepare($query);
419   $sth->execute;
420   $i=0;
421   while (my @res=$sth->fetchrow_array){
422     $results[$i]=$res[0];
423     $i++;
424   }
425   $sth->finish;
426   my $set3=Set::Scalar->new(@results);    
427   if ($i > 0){
428     $set1=$set1+$set3;
429   }
430
431   # Look for keywords in the 'bibliosubject' table.
432   $sth=$dbh->prepare("Select biblionumber from bibliosubject where subject
433   like '%$search->{'keyword'}%' group by biblionumber");
434   $sth->execute;
435   $i=0;
436   while (my @res=$sth->fetchrow_array){
437     $results[$i]=$res[0];
438     $i++;
439   }
440   $sth->finish;
441   my $set4=Set::Scalar->new(@results);    
442   if ($i > 0){
443     $set1=$set1+$set4;
444   }
445   my $i2=0;
446   my $i3=0;
447   my $i4=0;
448
449   my @res2;
450   my @res = $set1->members;
451   $count=@res;
452 #  print $set1;
453   $i=0;
454 #  print "count $count";
455   if ($search->{'class'} ne ''){ 
456     while ($i2 <$count){
457       my $query="select * from biblio,biblioitems where 
458       biblio.biblionumber='$res[$i2]' and     
459       biblio.biblionumber=biblioitems.biblionumber ";         
460       if ($search->{'class'} ne ''){    # FIXME - Redundant
461       my @temp=split(/\|/,$search->{'class'});
462       my $count=@temp;                       
463       $query.= "and ( itemtype='$temp[0]'";     
464       for (my $i=1;$i<$count;$i++){     
465         $query.=" or itemtype='$temp[$i]'";                                     
466       } 
467       $query.=")"; 
468       }
469        my $sth=$dbh->prepare($query);    
470        #    print $query;        
471        $sth->execute;        
472        if (my $data2=$sth->fetchrow_hashref){            
473          my $dewey= $data2->{'dewey'};                
474          my $subclass=$data2->{'subclass'};          
475          # FIXME - This next bit is bogus, because it assumes that the
476          # Dewey code is a floating-point number. It isn't. It's
477          # actually a string that mainly consists of numbers. In
478          # particular, "4" is not a valid Dewey code, although "004"
479          # is ("Data processing; Computer science"). Likewise, zeros
480          # after the decimal are significant ("575" is not the same as
481          # "575.0"; the latter is more specific). And "000" is a
482          # perfectly good Dewey code ("General works; computer
483          # science") and should not be interpreted to mean "this
484          # database entry does not have a Dewey code". That's what
485          # NULL is for.
486          $dewey=~s/\.*0*$//;           
487          ($dewey == 0) && ($dewey=''); 
488          ($dewey) && ($dewey.=" $subclass") ;                                    
489           $sth->finish;
490           my $end=$offset +$num;
491           if ($i4 <= $offset){
492             $i4++;
493           }
494 #         print $i4;
495           if ($i4 <=$end && $i4 > $offset){
496             $data2->{'dewey'}=$dewey;
497             $res2[$i3]=$data2;
498             
499 #           $res2[$i3]="$data2->{'author'}\t$data2->{'title'}\t$data2->{'biblionumber'}\t$data2->{'copyrightdate'}\t$dewey";    
500             $i3++;
501             $i4++;
502 #           print "in here $i3<br>";
503           } else {
504 #           print $end;
505           }
506           $i++; 
507         }         
508      $i2++;
509      }
510      $count=$i;
511   
512    } else {
513   # $search->{'class'} was not specified
514   while ($i2 < $num && $i2 < $count){
515     my $query="select * from biblio,biblioitems where
516     biblio.biblionumber='$res[$i2+$offset]' and        
517     biblio.biblionumber=biblioitems.biblionumber ";
518
519     if ($search->{'class'} ne ''){      # FIXME - Ignored: we already know
520                                         # that $search->{'class'} eq '';
521       my @temp=split(/\|/,$search->{'class'});
522       my $count=@temp;
523       $query.= "and ( itemtype='$temp[0]'";
524       for (my $i=1;$i<$count;$i++){
525         $query.=" or itemtype='$temp[$i]'";
526       }
527       $query.=")"; 
528     }
529     if ($search->{'dewey'} ne ''){
530       $query.= "and (dewey like '$search->{'dewey'}%') ";
531     }
532
533     my $sth=$dbh->prepare($query);
534 #    print $query;
535     $sth->execute;
536     if (my $data2=$sth->fetchrow_hashref){
537         my $dewey= $data2->{'dewey'};               
538         my $subclass=$data2->{'subclass'};                   
539         $dewey=~s/\.*0*$//;     
540         ($dewey == 0) && ($dewey='');               
541         ($dewey) && ($dewey.=" $subclass") ;                      
542         $sth->finish;                                             
543         $data2->{'dewey'}=$dewey;
544         
545         $res2[$i]=$data2;
546 #       $res2[$i]="$data2->{'author'}\t$data2->{'title'}\t$data2->{'biblionumber'}\t$data2->{'copyrightdate'}\t$dewey";
547         $i++;
548     }
549     $i2++;
550     
551   }
552   }
553   $dbh->disconnect;
554
555   #$count=$i;
556   return($count,@res2);
557 }
558
559 sub KeywordSearch2 {
560   my ($env,$type,$search,$num,$offset)=@_;
561   my $dbh = &C4Connect;
562   $search->{'keyword'}=~ s/ +$//;
563   $search->{'keyword'}=~ s/'/\\'/;
564   my @key=split(' ',$search->{'keyword'});
565   my $count=@key;
566   my $i=1;
567   my @results;
568   my $query ="Select * from biblio,bibliosubtitle,biblioitems where
569   biblio.biblionumber=biblioitems.biblionumber and
570   biblio.biblionumber=bibliosubtitle.biblionumber and
571   (((title like '$key[0]%' or title like '% $key[0]%')";
572   while ($i < $count){
573     $query=$query." and (title like '$key[$i]%' or title like '% $key[$i]%')";
574     $i++;
575   }
576   $query.= ") or ((subtitle like '$key[0]%' or subtitle like '% $key[0]%')";
577   for ($i=1;$i<$count;$i++){
578     $query.= " and (subtitle like '$key[$i]%' or subtitle like '% $key[$i]%')";
579   }
580   $query.= ") or ((seriestitle like '$key[0]%' or seriestitle like '% $key[0]%')";
581   for ($i=1;$i<$count;$i++){
582     $query.=" and (seriestitle like '$key[$i]%' or seriestitle like '% $key[$i]%')";
583   }
584   $query.= ") or ((biblio.notes like '$key[0]%' or biblio.notes like '% $key[0]%')";
585   for ($i=1;$i<$count;$i++){
586     $query.=" and (biblio.notes like '$key[$i]%' or biblio.notes like '% $key[$i]%')";
587   }
588   $query.= ") or ((biblioitems.notes like '$key[0]%' or biblioitems.notes like '% $key[0]%')";
589   for ($i=1;$i<$count;$i++){
590     $query.=" and (biblioitems.notes like '$key[$i]%' or biblioitems.notes like '% $key[$i]%')";
591   }
592   if ($search->{'keyword'} =~ /new zealand/i){
593     $query.= "or (title like 'nz%' or title like '% nz %' or title like '% nz' or subtitle like 'nz%'
594     or subtitle like '% nz %' or subtitle like '% nz' or author like 'nz %' 
595     or author like '% nz %' or author like '% nz')"
596   }
597   if ($search->{'keyword'} eq  'nz' || $search->{'keyword'} eq 'NZ' ||
598   $search->{'keyword'} =~ /nz /i || $search->{'keyword'} =~ / nz /i ||
599   $search->{'keyword'} =~ / nz/i){
600     $query.= "or (title like 'new zealand%' or title like '% new zealand %'
601     or title like '% new zealand' or subtitle like 'new zealand%' or
602     subtitle like '% new zealand %'
603     or subtitle like '% new zealand' or author like 'new zealand%' 
604     or author like '% new zealand %' or author like '% new zealand' or 
605     seriestitle like 'new zealand%' or seriestitle like '% new zealand %'
606     or seriestitle like '% new zealand')"
607   }
608   $query=$query."))";
609   if ($search->{'class'} ne ''){
610     my @temp=split(/\|/,$search->{'class'});
611     my $count=@temp;
612     $query.= "and ( itemtype='$temp[0]'";
613     for (my $i=1;$i<$count;$i++){
614       $query.=" or itemtype='$temp[$i]'";
615      }
616   $query.=")"; 
617   }
618   if ($search->{'dewey'} ne ''){
619     $query.= "and (dewey like '$search->{'dewey'}%') ";
620   }
621    $query.="group by biblio.biblionumber";
622    #$query.=" order by author,title";
623 #  print $query;
624   my $sth=$dbh->prepare($query);
625   $sth->execute;
626   $i=0;
627   while (my $data=$sth->fetchrow_hashref){
628 #    my $sti=$dbh->prepare("select dewey,subclass from biblioitems where biblionumber=$data->{'biblionumber'}
629 #    ");
630 #    $sti->execute;
631 #    my ($dewey, $subclass) = $sti->fetchrow;
632     my $dewey=$data->{'dewey'};
633     my $subclass=$data->{'subclass'};
634     $dewey=~s/\.*0*$//;
635     ($dewey == 0) && ($dewey='');
636     ($dewey) && ($dewey.=" $subclass");
637 #    $sti->finish;
638     $results[$i]="$data->{'author'}\t$data->{'title'}\t$data->{'biblionumber'}\t$data->{'copyrightdate'}\t$dewey";
639 #      print $results[$i];
640     $i++;
641   }
642   $sth->finish;
643   $sth=$dbh->prepare("Select biblionumber from bibliosubject where subject
644   like '%$search->{'keyword'}%' group by biblionumber");
645   $sth->execute;
646   while (my $data=$sth->fetchrow_hashref){
647     $query="Select * from biblio,biblioitems where
648     biblio.biblionumber=$data->{'biblionumber'} and
649     biblio.biblionumber=biblioitems.biblionumber ";
650     if ($search->{'class'} ne ''){
651       my @temp=split(/\|/,$search->{'class'});
652       my $count=@temp;
653       $query.= " and ( itemtype='$temp[0]'";
654       for (my $i=1;$i<$count;$i++){
655         $query.=" or itemtype='$temp[$i]'";
656       }
657       $query.=")"; 
658       
659     }
660     if ($search->{'dewey'} ne ''){
661       $query.= "and (dewey like '$search->{'dewey'}%') ";
662     }
663     my $sth2=$dbh->prepare($query);
664     $sth2->execute;
665 #    print $query;
666     while (my $data2=$sth2->fetchrow_hashref){
667       my $dewey= $data2->{'dewey'};
668       my $subclass=$data2->{'subclass'};
669       $dewey=~s/\.*0*$//;          
670       ($dewey == 0) && ($dewey='');              
671       ($dewey) && ($dewey.=" $subclass") ;                  
672 #      $sti->finish;              
673        $results[$i]="$data2->{'author'}\t$data2->{'title'}\t$data2->{'biblionumber'}\t$data2->{'copyrightdate'}\t$dewey";
674 #      print $results[$i];
675       $i++;   
676     }
677     $sth2->finish;
678   }    
679   my $i2=1;
680   @results=sort @results;
681   my @res;
682   $count=@results;
683   $i=1;
684   if ($count > 0){
685     $res[0]=$results[0];
686   }
687   while ($i2 < $count){
688     if ($results[$i2] ne $res[$i-1]){
689       $res[$i]=$results[$i2];
690       $i++;
691     }
692     $i2++;
693   }
694   $i2=0;
695   my @res2;
696   $count=@res;
697   while ($i2 < $num && $i2 < $count){
698     $res2[$i2]=$res[$i2+$offset];
699 #    print $res2[$i2];
700     $i2++;
701   }
702   $sth->finish;
703   $dbh->disconnect;
704 #  $i--;
705 #  $i++;
706   return($i,@res2);
707 }
708
709 =item CatSearch
710
711   ($count, @results) = &CatSearch($env, $type, $search, $num, $offset);
712
713 C<&CatSearch> searches the Koha catalog. It returns a list whose first
714 element is the number of returned results, and whose subsequent
715 elements are the results themselves.
716
717 Each returned element is a reference-to-hash. Most of the keys are
718 simply the fields from the C<biblio> table in the Koha database, but
719 the following keys may also be present:
720
721 =over 4
722
723 =item C<illustrator>
724
725 The book's illustrator.
726
727 =item C<publisher>
728
729 The publisher.
730
731 =back
732
733 C<$env> is ignored.
734
735 C<$type> may be C<subject>, C<loose>, or C<precise>. This controls the
736 high-level behavior of C<&CatSearch>, as described below.
737
738 In many cases, the description below says that a certain field in the
739 database must match the search string. In these cases, it means that
740 the beginning of some word in the field must match the search string.
741 Thus, an author search for "sm" will return books whose author is
742 "John Smith" or "Mike Smalls", but not "Paul Grossman", since the "sm"
743 does not occur at the beginning of a word.
744
745 Note that within each search mode, the criteria are and-ed together.
746 That is, if you perform a loose search on the author "Jerome" and the
747 title "Boat", the search will only return books by Jerome containing
748 "Boat" in the title.
749
750 It is not possible to cross modes, e.g., set the author to "Asimov"
751 and the subject to "Math" in hopes of finding books on math by Asimov.
752
753 =head2 Loose search
754
755 If C<$type> is set to C<loose>, the following search criteria may be
756 used:
757
758 =over 4
759
760 =item C<$search-E<gt>{author}>
761
762 The search string is a space-separated list of words. Each word must
763 match either the C<author> or C<additionalauthors> field.
764
765 =item C<$search-E<gt>{title}>
766
767 Each word in the search string must match the book title. If no author
768 is specified, the book subtitle will also be searched.
769
770 =item C<$search-E<gt>{abstract}>
771
772 Searches for the given search string in the book's abstract.
773
774 =item C<$search-E<gt>{'date-before'}>
775
776 Searches for books whose copyright date matches the search string.
777 That is, setting C<$search-E<gt>{'date-before'}> to "1985" will find
778 books written in 1985, and setting it to "198" will find books written
779 between 1980 and 1989.
780
781 =item C<$search-E<gt>{title}>
782
783 Searches by title are also affected by the value of
784 C<$search-E<gt>{"ttype"}>; if it is set to C<exact>, then the book
785 title, (one of) the series titleZ<>(s), or (one of) the unititleZ<>(s) must
786 match the search string exactly (the subtitle is not searched).
787
788 If C<$search-E<gt>{"ttype"}> is set to anything other than C<exact>,
789 each word in the search string must match the title, subtitle,
790 unititle, or series title.
791
792 =item C<$search-E<gt>{class}>
793
794 Restricts the search to certain item classes. The value of
795 C<$search-E<gt>{"class"}> is a | (pipe)-separated list of item types.
796 Thus, setting it to "F" restricts the search to fiction, and setting
797 it to "CD|CAS" will only look in compact disks and cassettes.
798
799 =item C<$search-E<gt>{dewey}>
800
801 Searches for books whose Dewey Decimal Classification code matches the
802 search string. That is, setting C<$search-E<gt>{"dewey"}> to "5" will
803 search for all books in 5I<xx> (Science and mathematics), setting it
804 to "54" will search for all books in 54I<x> (Chemistry), and setting
805 it to "546" will search for books on inorganic chemistry.
806
807 =item C<$search-E<gt>{publisher}>
808
809 Searches for books whose publisher contains the search string (unlike
810 other search criteria, C<$search-E<gt>{publisher}> is a string, not a
811 set of words.
812
813 =back
814
815 =head2 Subject search
816
817 If C<$type> is set to C<subject>, the following search criteria may be
818 used:
819
820 =over 4
821
822 =item C<$search-E<gt>{subject}>
823
824 The search string is a space-separated list of words, each of which
825 must match the book's subject.
826
827 Special case: if C<$search-E<gt>{subject}> is set to C<nz>,
828 C<&CatSearch> will search for books whose subject is "New Zealand".
829 However, setting C<$search-E<gt>{subject}> to C<"nz football"> will
830 search for books on "nz" and "football", not books on "New Zealand"
831 and "football".
832
833 =back
834
835 =head2 Precise search
836
837 If C<$type> is set to C<precise>, the following search criteria may be
838 used:
839
840 =over 4
841
842 =item C<$search-E<gt>{item}>
843
844 Searches for books whose barcode exactly matches the search string.
845
846 =item C<$search-E<gt>{isbn}>
847
848 Searches for books whose ISBN exactly matches the search string.
849
850 =back
851
852 For a loose search, if an author was specified, the results are
853 ordered by author and title. If no author was specified, the results
854 are ordered by title.
855
856 For other (non-loose) searches, if a subject was specified, the
857 results are ordered alphabetically by subject.
858
859 In all other cases (e.g., loose search by keyword), the results are
860 not ordered.
861
862 =cut
863 #'
864 sub CatSearch  {
865   my ($env,$type,$search,$num,$offset)=@_;
866   my $dbh = &C4Connect;
867   my $query = '';
868     my @results;
869   # FIXME - Why not just
870   #     $search->{'title'} = quotemeta($search->{'title'})
871   # to escape all questionable characters, not just single-quotes?
872   $search->{'title'}=~ s/'/\\'/g;
873   $search->{'author'}=~ s/'/\\'/g;
874   $search->{'illustrator'}=~ s/'/\\'/g;
875   my $title = lc($search->{'title'}); 
876   
877   if ($type eq 'loose') {
878       if ($search->{'author'} ne ''){
879         my @key=split(' ',$search->{'author'});
880         my $count=@key;
881         my $i=1;
882         $query="select *,biblio.author,biblio.biblionumber from
883          biblio
884          left join additionalauthors
885          on additionalauthors.biblionumber =biblio.biblionumber
886          where
887          ((biblio.author like '$key[0]%' or biblio.author like '% $key[0]%' or
888          additionalauthors.author like '$key[0]%' or additionalauthors.author 
889          like '% $key[0]%'
890                  )";    
891          while ($i < $count){ 
892            $query=$query." and (
893            biblio.author like '$key[$i]%' or biblio.author like '% $key[$i]%' or
894            additionalauthors.author like '$key[$i]%' or additionalauthors.author like '% $key[$i]%'
895            )";
896            $i++;       
897          }   
898          $query=$query.")";
899          if ($search->{'title'} ne ''){ 
900            my @key=split(' ',$search->{'title'});
901            my $count=@key;
902            my $i=0;
903            $query.= " and (((title like '$key[0]%' or title like '% $key[0]%' or title like '% $key[0]')";
904             while ($i<$count){            
905               $query=$query." and (title like '$key[$i]%' or title like '% $key[$i]%' or title like '% $key[$i]')";
906               $i++; 
907             }                       
908 #           $query.=") or ((subtitle like '$key[0]%' or subtitle like '% $key[0] %' or subtitle like '% $key[0]')"; 
909 #            for ($i=1;$i<$count;$i++){
910 #             $query.=" and (subtitle like '$key[$i]%' or subtitle like '% $key[$i] %' or subtitle like '% $key[$i]')";   
911 #            }
912             $query.=") or ((seriestitle like '$key[0]%' or seriestitle like '% $key[0]%' or seriestitle like '% $key[0]')";  
913             for ($i=1;$i<$count;$i++){                    
914                 $query.=" and (seriestitle like '$key[$i]%' or seriestitle like '% $key[$i]%')";
915             }                                                             
916             $query.=") or ((unititle like '$key[0]%' or unititle like '% $key[0]%' or unititle like '% $key[0]')";                         
917             for ($i=1;$i<$count;$i++){                    
918                 $query.=" and (unititle like '$key[$i]%' or unititle like '% $key[$i]%')";   
919             }                                                             
920             $query=$query."))"; 
921            #$query=$query. " and (title like '%$search->{'title'}%' 
922            #or seriestitle like '%$search->{'title'}%')";
923          }
924          if ($search->{'abstract'} ne ''){
925             $query.= " and (abstract like '%$search->{'abstract'}%')";
926          }
927          if ($search->{'date-before'} ne ''){
928             $query.= " and (copyrightdate like '%$search->{'date-before'}%')";
929            }
930
931          $query.=" group by biblio.biblionumber";
932       } else {
933           if ($search->{'title'} ne '') {
934            if ($search->{'ttype'} eq 'exact'){
935              $query="select * from biblio
936              where                            
937              (biblio.title='$search->{'title'}' or (biblio.unititle = '$search->{'title'}'
938              or biblio.unititle like '$search->{'title'} |%' or 
939              biblio.unititle like '%| $search->{'title'} |%' or
940              biblio.unititle like '%| $search->{'title'}') or
941              (biblio.seriestitle = '$search->{'title'}' or
942              biblio.seriestitle like '$search->{'title'} |%' or
943              biblio.seriestitle like '%| $search->{'title'} |%' or
944              biblio.seriestitle like '%| $search->{'title'}')
945              )";
946            } else {
947             my @key=split(' ',$search->{'title'});
948             my $count=@key;
949             my $i=1;
950             $query="select * from biblio
951             left join bibliosubtitle on
952             biblio.biblionumber=bibliosubtitle.biblionumber
953             where
954             (((title like '$key[0]%' or title like '% $key[0]%' or title like '% $key[0]')";
955             while ($i<$count){
956               $query=$query." and (title like '$key[$i]%' or title like '% $key[$i]%' or title like '% $key[$i]')";
957               $i++;
958             }
959             $query.=") or ((subtitle like '$key[0]%' or subtitle like '% $key[0]%' or subtitle like '% $key[0]')";
960             for ($i=1;$i<$count;$i++){
961               $query.=" and (subtitle like '$key[$i]%' or subtitle like '% $key[$i]%' or subtitle like '% $key[$i]')";
962             }
963             $query.=") or ((seriestitle like '$key[0]%' or seriestitle like '% $key[0]%' or seriestitle like '% $key[0]')";
964             for ($i=1;$i<$count;$i++){
965               $query.=" and (seriestitle like '$key[$i]%' or seriestitle like '% $key[$i]%')";
966             }
967             $query.=") or ((unititle like '$key[0]%' or unititle like '% $key[0]%' or unititle like '% $key[0]')";
968             for ($i=1;$i<$count;$i++){
969               $query.=" and (unititle like '$key[$i]%' or unititle like '% $key[$i]%')";
970             }
971             $query=$query."))";
972            }
973            if ($search->{'abstract'} ne ''){
974             $query.= " and (abstract like '%$search->{'abstract'}%')";
975            }
976            if ($search->{'date-before'} ne ''){
977             $query.= " and (copyrightdate like '%$search->{'date-before'}%')";
978            }
979           } elsif ($search->{'class'} ne ''){
980              $query="select * from biblioitems,biblio where biblio.biblionumber=biblioitems.biblionumber";
981              my @temp=split(/\|/,$search->{'class'});
982               my $count=@temp;
983               $query.= " and ( itemtype='$temp[0]'";
984               for (my $i=1;$i<$count;$i++){
985                $query.=" or itemtype='$temp[$i]'";
986               }
987               $query.=")";
988               if ($search->{'illustrator'} ne ''){
989                 $query.=" and illus like '%".$search->{'illustrator'}."%' ";
990               }
991               if ($search->{'dewey'} ne ''){
992                 $query.=" and biblioitems.dewey like '$search->{'dewey'}%'";
993               }
994           } elsif ($search->{'dewey'} ne ''){
995              $query="select * from biblioitems,biblio 
996              where biblio.biblionumber=biblioitems.biblionumber
997              and biblioitems.dewey like '$search->{'dewey'}%'";
998           } elsif ($search->{'illustrator'} ne '') {
999              $query="select * from biblioitems,biblio 
1000              where biblio.biblionumber=biblioitems.biblionumber
1001              and biblioitems.illus like '%".$search->{'illustrator'}."%'";
1002           } elsif ($search->{'publisher'} ne ''){
1003             $query.= "Select * from biblio,biblioitems where biblio.biblionumber
1004             =biblioitems.biblionumber and (publishercode like '%$search->{'publisher'}%')";
1005           } elsif ($search->{'abstract'} ne ''){
1006             $query.= "Select * from biblio where abstract like '%$search->{'abstract'}%'";
1007           
1008           } elsif ($search->{'date-before'} ne ''){
1009             $query.= "Select * from biblio where copyrightdate like '%$search->{'date-before'}%'";
1010           }
1011           $query .=" group by biblio.biblionumber";      
1012       }
1013   } 
1014   if ($type eq 'subject'){
1015     my @key=split(' ',$search->{'subject'});
1016     my $count=@key;
1017     my $i=1;
1018     $query="select distinct(subject) from bibliosubject where( subject like
1019     '$key[0]%' or subject like '% $key[0]%' or subject like '% $key[0]' or subject like '%($key[0])%')";
1020     while ($i<$count){
1021       $query.=" and (subject like '$key[$i]%' or subject like '% $key[$i]%'
1022       or subject like '% $key[$i]'
1023       or subject like '%($key[$i])%')";
1024       $i++;
1025     }
1026
1027     # FIXME - Wouldn't it be better to fix the database so that if a
1028     # book has a subject "NZ", then it also gets added the subject
1029     # "New Zealand"?
1030     # This can also be generalized by adding a table of subject
1031     # synonyms to the database: just declare "NZ" to be a synonym for
1032     # "New Zealand", "SF" a synonym for both "Science fiction" and
1033     # "Fantastic fiction", etc.
1034
1035     # FIXME - This can be rewritten as
1036     #   if (lc($search->{"subject"}) eq "nz") {
1037     if ($search->{'subject'} eq 'NZ' || $search->{'subject'} eq 'nz'){ 
1038       $query.= " or (subject like 'NEW ZEALAND %' or subject like '% NEW ZEALAND %'
1039       or subject like '% NEW ZEALAND' or subject like '%(NEW ZEALAND)%' ) ";
1040     } elsif ( $search->{'subject'} =~ /^nz /i || $search->{'subject'} =~ / nz /i || $search->{'subject'} =~ / nz$/i){
1041       $query=~ s/ nz/ NEW ZEALAND/ig;
1042       $query=~ s/nz /NEW ZEALAND /ig;
1043       $query=~ s/\(nz\)/\(NEW ZEALAND\)/gi;
1044     }  
1045   }
1046   if ($type eq 'precise'){
1047       
1048       if ($search->{'item'} ne ''){
1049         $query="select * from items,biblio ";
1050         my $search2=uc $search->{'item'};
1051         $query=$query." where 
1052         items.biblionumber=biblio.biblionumber 
1053         and barcode='$search2'";
1054       }
1055       if ($search->{'isbn'} ne ''){
1056         my $search2=uc $search->{'isbn'};
1057         my $query1 = "select * from biblioitems where isbn='$search2'";
1058         my $sth1=$dbh->prepare($query1);
1059 #       print STDERR "$query1\n";
1060         $sth1->execute;
1061         my $i2=0;
1062         while (my $data=$sth1->fetchrow_hashref) {
1063            $query="select * from biblioitems,biblio where
1064            biblio.biblionumber = $data->{'biblionumber'}
1065            and biblioitems.biblionumber = biblio.biblionumber";
1066            my $sth=$dbh->prepare($query);
1067            $sth->execute;
1068            my $data=$sth->fetchrow_hashref;
1069            my ($dewey, $subclass) = ($data->{'dewey'}, $data->{'subclass'});
1070            # FIXME - The following assumes that the Dewey code is a
1071            # floating-point number. It isn't: it's a string.
1072            $dewey=~s/\.*0*$//;
1073            ($dewey == 0) && ($dewey='');
1074            ($dewey) && ($dewey.=" $subclass");
1075            $data->{'dewey'}=$dewey;
1076            $results[$i2]=$data;
1077 #           $results[$i2]="$data->{'author'}\t$data->{'title'}\t$data->{'biblionumber'}\t$data->{'copyrightdate'}\t$dewey\t$data->{'isbn'}\t$data->{'itemtype'}";
1078            $i2++; 
1079            $sth->finish;
1080         }
1081         $sth1->finish;
1082       }
1083   }
1084 #print $query;
1085 if ($type ne 'precise' && $type ne 'subject'){
1086   if ($search->{'author'} ne ''){   
1087       $query=$query." order by biblio.author,title";
1088   } else {
1089       $query=$query." order by title";
1090   }
1091 } else {
1092   if ($type eq 'subject'){
1093       $query=$query." order by subject";
1094   }
1095 }
1096 #print STDERR "$query\n";
1097 my $sth=$dbh->prepare($query);
1098 $sth->execute;
1099 my $count=1;
1100 my $i=0;
1101 my $limit= $num+$offset;
1102 while (my $data=$sth->fetchrow_hashref){
1103   my $query="select dewey,subclass,publishercode from biblioitems where biblionumber=$data->{'biblionumber'}";
1104             if ($search->{'class'} ne ''){
1105               my @temp=split(/\|/,$search->{'class'});
1106               my $count=@temp;
1107               $query.= " and ( itemtype='$temp[0]'";
1108               for (my $i=1;$i<$count;$i++){
1109                $query.=" or itemtype='$temp[$i]'";
1110               }
1111               $query.=")";
1112             }
1113             if ($search->{'dewey'} ne ''){
1114               $query.=" and dewey='$search->{'dewey'}' ";
1115             }
1116             if ($search->{'illustrator'} ne ''){
1117               $query.=" and illus like '%".$search->{'illustrator'}."%' ";
1118             }
1119             if ($search->{'publisher'} ne ''){
1120             $query.= " and (publishercode like '%$search->{'publisher'}%')";
1121             }
1122
1123   my $sti=$dbh->prepare($query);
1124   $sti->execute;
1125   my $dewey;
1126   my $subclass;
1127   my $true=0;
1128   my $publishercode;
1129   my $bibitemdata;
1130   if ($bibitemdata = $sti->fetchrow_hashref() || $type eq 'subject'){
1131     $true=1;
1132     $dewey=$bibitemdata->{'dewey'};
1133     $subclass=$bibitemdata->{'subclass'};
1134     $publishercode=$bibitemdata->{'publishercode'};
1135   }
1136   print STDERR "$dewey $subclass $publishercode\n";
1137   $dewey=~s/\.*0*$//;
1138   ($dewey == 0) && ($dewey='');
1139   ($dewey) && ($dewey.=" $subclass");
1140   $data->{'dewey'}=$dewey;
1141   $data->{'publishercode'}=$publishercode;
1142   $sti->finish;
1143   if ($true == 1){
1144     if ($count > $offset && $count <= $limit){
1145       $results[$i]=$data;
1146       $i++;
1147     }
1148     $count++;
1149   }
1150 }
1151 $sth->finish;
1152 #if ($type ne 'precise'){
1153   $count--;
1154 #}
1155 #$count--;
1156 return($count,@results);
1157 }
1158
1159 sub updatesearchstats{
1160   my ($dbh,$query)=@_;
1161   
1162 }
1163
1164 =item subsearch
1165
1166   @results = &subsearch($env, $subject);
1167
1168 Searches for books that have a subject that exactly matches
1169 C<$subject>.
1170
1171 C<&subsearch> returns an array of results. Each element of this array
1172 is a string, containing the book's title, author, and biblionumber,
1173 separated by tabs.
1174
1175 C<$env> is ignored.
1176
1177 =cut
1178 #'
1179 sub subsearch {
1180   my ($env,$subject)=@_;
1181   my $dbh=C4Connect();
1182   $subject=$dbh->quote($subject);
1183   my $query="Select * from biblio,bibliosubject where
1184   biblio.biblionumber=bibliosubject.biblionumber and
1185   bibliosubject.subject=$subject group by biblio.biblionumber
1186   order by biblio.title";
1187   my $sth=$dbh->prepare($query);
1188   $sth->execute;
1189   my $i=0;
1190 #  print $query;
1191   my @results;
1192   while (my $data=$sth->fetchrow_hashref){
1193     $results[$i]="$data->{'title'}\t$data->{'author'}\t$data->{'biblionumber'}";
1194     $i++;
1195   }
1196   $sth->finish;
1197   $dbh->disconnect;
1198   return(@results);
1199 }
1200
1201 =item ItemInfo
1202
1203   @results = &ItemInfo($env, $biblionumber, $type);
1204
1205 Returns information about books with the given biblionumber.
1206
1207 C<$type> may be either C<intra> or anything else. If it is not set to
1208 C<intra>, then the search will exclude lost, very overdue, and
1209 withdrawn items.
1210
1211 C<$env> is ignored.
1212
1213 C<&ItemInfo> returns a list of references-to-hash. Each element
1214 contains a number of keys. Most of them are table items from the
1215 C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
1216 Koha database. Other keys include:
1217
1218 =over 4
1219
1220 =item C<$data-E<gt>{branchname}>
1221
1222 The name (not the code) of the branch to which the book belongs.
1223
1224 =item C<$data-E<gt>{datelastseen}>
1225
1226 This is simply C<items.datelastseen>, except that while the date is
1227 stored in YYYY-MM-DD format in the database, here it is converted to
1228 DD/MM/YYYY format. A NULL date is returned as C<//>.
1229
1230 =item C<$data-E<gt>{datedue}>
1231
1232 =item C<$data-E<gt>{class}>
1233
1234 This is the concatenation of C<biblioitems.classification>, the book's
1235 Dewey code, and C<biblioitems.subclass>.
1236
1237 =item C<$data-E<gt>{ocount}>
1238
1239 I think this is the number of copies of the book available.
1240
1241 =item C<$data-E<gt>{order}>
1242
1243 If this is set, it is set to C<One Order>.
1244
1245 =cut
1246 #'
1247 sub ItemInfo {
1248     my ($env,$biblionumber,$type) = @_;
1249     my $dbh   = &C4Connect;
1250     my $query = "SELECT * FROM items, biblio, biblioitems, itemtypes
1251                   WHERE items.biblionumber = ?
1252                     AND biblioitems.biblioitemnumber = items.biblioitemnumber
1253                     AND biblioitems.itemtype = itemtypes.itemtype
1254                     AND biblio.biblionumber = items.biblionumber";
1255   if ($type ne 'intra'){
1256     $query .= " and ((items.itemlost<>1 and items.itemlost <> 2)
1257     or items.itemlost is NULL)
1258     and (wthdrawn <> 1 or wthdrawn is NULL)";
1259   }
1260   $query .= " order by items.dateaccessioned desc";
1261     #warn $query;
1262   my $sth=$dbh->prepare($query);
1263   $sth->execute($biblionumber);
1264   my $i=0;
1265   my @results;
1266 #  print $query;
1267   while (my $data=$sth->fetchrow_hashref){
1268     my $iquery = "Select * from issues
1269     where itemnumber = '$data->{'itemnumber'}'
1270     and returndate is null";
1271     my $datedue = '';
1272     my $isth=$dbh->prepare($iquery);
1273     $isth->execute;
1274     if (my $idata=$isth->fetchrow_hashref){
1275       # FIXME - The date ought to be properly parsed, and printed
1276       # according to local convention.
1277       my @temp=split('-',$idata->{'date_due'});
1278       $datedue = "$temp[2]/$temp[1]/$temp[0]";
1279     }
1280     if ($data->{'itemlost'} eq '2'){
1281         $datedue='Very Overdue';
1282     }
1283     if ($data->{'itemlost'} eq '1'){
1284         $datedue='Lost';
1285     }
1286     if ($data->{'wthdrawn'} eq '1'){
1287         $datedue="Cancelled";
1288     }
1289     if ($datedue eq ''){
1290         $datedue="Available";
1291         my ($restype,$reserves)=CheckReserves($data->{'itemnumber'});
1292         if ($restype){
1293             $datedue=$restype;
1294         }
1295     }
1296     $isth->finish;
1297 #get branch information.....
1298     my $bquery = "SELECT * FROM branches
1299                           WHERE branchcode = '$data->{'holdingbranch'}'";
1300     my $bsth=$dbh->prepare($bquery);
1301     $bsth->execute;
1302     if (my $bdata=$bsth->fetchrow_hashref){
1303         $data->{'branchname'} = $bdata->{'branchname'};
1304     }
1305
1306     my $class = $data->{'classification'};
1307     my $dewey = $data->{'dewey'};
1308     $dewey =~ s/0+$//;
1309     if ($dewey eq "000.") { $dewey = "";};      # FIXME - "000" is general
1310                                                 # books about computer science
1311     if ($dewey < 10){$dewey='00'.$dewey;}
1312     if ($dewey < 100 && $dewey > 10){$dewey='0'.$dewey;}
1313     if ($dewey <= 0){
1314       $dewey='';
1315     }
1316     $dewey=~ s/\.$//;
1317     $class = $class.$dewey;
1318     if ($dewey ne ''){
1319       $class = $class.$data->{'subclass'};
1320     }
1321  #   $results[$i]="$data->{'title'}\t$data->{'barcode'}\t$datedue\t$data->{'branchname'}\t$data->{'dewey'}";
1322     # FIXME - If $data->{'datelastseen'} is NULL, perhaps it'd be prettier
1323     # to leave it empty, rather than convert it to "//".
1324     # Also ideally this should use the local format for displaying dates.
1325     my @temp=split('-',$data->{'datelastseen'});
1326     my $date="$temp[2]/$temp[1]/$temp[0]";
1327     $data->{'datelastseen'}=$date;
1328     $data->{'datedue'}=$datedue;
1329     $data->{'class'}=$class;
1330     $results[$i]=$data;
1331     $i++;
1332   }
1333  $sth->finish;
1334   my $query2="Select * from aqorders where biblionumber=$biblionumber";
1335   my $sth2=$dbh->prepare($query2);         
1336   $sth2->execute;                                        
1337   my $data;
1338   my $ocount;
1339   if ($data=$sth2->fetchrow_hashref){                   
1340     $ocount=$data->{'quantity'} - $data->{'quantityreceived'};                                                  
1341     if ($ocount > 0){
1342       $data->{'ocount'}=$ocount;
1343       $data->{'order'}="One Order";
1344       $results[$i]=$data;
1345     }
1346   } 
1347   $sth2->finish;
1348
1349   $dbh->disconnect;
1350   return(@results);
1351 }
1352
1353 =item GetItems
1354
1355   @results = &GetItems($env, $biblionumber);
1356
1357 Returns information about books with the given biblionumber.
1358
1359 C<$env> is ignored.
1360
1361 C<&GetItems> returns an array of strings. Each element is a
1362 tab-separated list of values: biblioitemnumber, itemtype,
1363 classification, Dewey number, subclass, ISBN, volume, number, and
1364 itemdata.
1365
1366 Itemdata, in turn, is a string of the form
1367 "I<barcode>C<[>I<holdingbranch>C<[>I<flags>" where I<flags> contains
1368 the string C<NFL> if the item is not for loan, and C<LOST> if the item
1369 is lost.
1370
1371 =cut
1372 #'
1373 sub GetItems {
1374    my ($env,$biblionumber)=@_;
1375    #debug_msg($env,"GetItems");
1376    my $dbh = &C4Connect;
1377    my $query = "Select * from biblioitems where (biblionumber = $biblionumber)";
1378    #debug_msg($env,$query);
1379    my $sth=$dbh->prepare($query);
1380    $sth->execute;
1381    #debug_msg($env,"executed query");      
1382    my $i=0;
1383    my @results;
1384    while (my $data=$sth->fetchrow_hashref) {
1385       #debug_msg($env,$data->{'biblioitemnumber'});
1386       my $dewey = $data->{'dewey'};
1387       $dewey =~ s/0+$//; 
1388       my $line = $data->{'biblioitemnumber'}."\t".$data->{'itemtype'};
1389       $line = $line."\t$data->{'classification'}\t$dewey";
1390       $line = $line."\t$data->{'subclass'}\t$data->{isbn}";
1391       $line = $line."\t$data->{'volume'}\t$data->{number}";
1392       my $isth= $dbh->prepare("select * from items where biblioitemnumber = $data->{'biblioitemnumber'}");
1393       $isth->execute;
1394       while (my $idata = $isth->fetchrow_hashref) {
1395         my $iline = $idata->{'barcode'}."[".$idata->{'holdingbranch'}."[";
1396         if ($idata->{'notforloan'} == 1) {
1397           $iline = $iline."NFL ";
1398         }
1399         if ($idata->{'itemlost'} == 1) {
1400           $iline = $iline."LOST ";
1401         }        
1402         $line = $line."\t$iline"; 
1403       }
1404       $isth->finish;
1405       $results[$i] = $line;
1406       $i++;      
1407    }
1408    $sth->finish;
1409    $dbh->disconnect;
1410    return(@results);
1411 }            
1412   
1413 =item itemdata
1414
1415   $item = &itemdata($barcode);
1416
1417 Looks up the item with the given barcode, and returns a
1418 reference-to-hash containing information about that item. The keys of
1419 the hash are the fields from the C<items> and C<biblioitems> tables in
1420 the Koha database.
1421
1422 =cut
1423 #'
1424 sub itemdata {
1425   my ($barcode)=@_;
1426   my $dbh=C4Connect;
1427   my $query="Select * from items,biblioitems where barcode='$barcode'
1428   and items.biblioitemnumber=biblioitems.biblioitemnumber";
1429 #  print $query;
1430   my $sth=$dbh->prepare($query);
1431   $sth->execute;
1432   my $data=$sth->fetchrow_hashref;
1433   $sth->finish;
1434   $dbh->disconnect;
1435   return($data);
1436 }
1437
1438 =item bibdata
1439
1440   $data = &bibdata($biblionumber, $type);
1441
1442 Returns information about the book with the given biblionumber.
1443
1444 C<$type> is ignored.
1445
1446 C<&bibdata> returns a reference-to-hash. The keys are the fields in
1447 the C<biblio>, C<biblioitems>, and C<bibliosubtitle> tables in the
1448 Koha database.
1449
1450 In addition, C<$data-E<gt>{subject}> is the list of the book's
1451 subjects, separated by C<" , "> (space, comma, space).
1452
1453 If there are multiple biblioitems with the given biblionumber, only
1454 the first one is considered.
1455
1456 =cut
1457 #'
1458 sub bibdata {
1459     my ($bibnum, $type) = @_;
1460     my $dbh   = C4Connect;
1461     my $query = "Select *, biblio.notes  
1462     from biblio, biblioitems 
1463     left join bibliosubtitle on
1464     biblio.biblionumber = bibliosubtitle.biblionumber
1465     where biblio.biblionumber = $bibnum
1466     and biblioitems.biblionumber = $bibnum";
1467     my $sth   = $dbh->prepare($query);
1468     my $data;
1469
1470     $sth->execute;
1471     $data  = $sth->fetchrow_hashref;
1472     $sth->finish;
1473
1474     $query = "Select * from bibliosubject where biblionumber = '$bibnum'";
1475     $sth   = $dbh->prepare($query);
1476     $sth->execute;
1477     while (my $dat = $sth->fetchrow_hashref){
1478         $data->{'subject'} .= " , $dat->{'subject'}";
1479     } # while
1480
1481     $sth->finish;
1482     $dbh->disconnect;
1483     return($data);
1484 } # sub bibdata
1485
1486 =item bibitemdata
1487
1488   $itemdata = &bibitemdata($biblioitemnumber);
1489
1490 Looks up the biblioitem with the given biblioitemnumber. Returns a
1491 reference-to-hash. The keys are the fields from the C<biblio>,
1492 C<biblioitems>, and C<itemtypes> tables in the Koha database, except
1493 that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
1494
1495 =cut
1496 #'
1497 sub bibitemdata {
1498     my ($bibitem) = @_;
1499     my $dbh   = C4Connect;
1500     my $query = "Select *,biblioitems.notes as bnotes from biblio, biblioitems,itemtypes
1501 where biblio.biblionumber = biblioitems.biblionumber
1502 and biblioitemnumber = $bibitem
1503 and biblioitems.itemtype = itemtypes.itemtype";
1504     my $sth   = $dbh->prepare($query);
1505     my $data;
1506
1507     $sth->execute;
1508
1509     $data = $sth->fetchrow_hashref;
1510
1511     $sth->finish;
1512     $dbh->disconnect;
1513     return($data);
1514 } # sub bibitemdata
1515
1516 =item subject
1517
1518   ($count, $subjects) = &subject($biblionumber);
1519
1520 Looks up the subjects of the book with the given biblionumber. Returns
1521 a two-element list. C<$subjects> is a reference-to-array, where each
1522 element is a subject of the book, and C<$count> is the number of
1523 elements in C<$subjects>.
1524
1525 =cut
1526 #'
1527 sub subject {
1528   my ($bibnum)=@_;
1529   my $dbh=C4Connect;
1530   my $query="Select * from bibliosubject where biblionumber=$bibnum";
1531   my $sth=$dbh->prepare($query);
1532   $sth->execute;
1533   my @results;
1534   my $i=0;
1535   while (my $data=$sth->fetchrow_hashref){
1536     $results[$i]=$data;
1537     $i++;
1538   }
1539   $sth->finish;
1540   $dbh->disconnect;
1541   return($i,\@results);
1542 }
1543
1544 =item addauthor
1545
1546   ($count, $authors) = &addauthors($biblionumber);
1547
1548 Looks up the additional authors for the book with the given
1549 biblionumber.
1550
1551 Returns a two-element list. C<$authors> is a reference-to-array, where
1552 each element is an additional author, and C<$count> is the number of
1553 elements in C<$authors>.
1554
1555 =cut
1556 #'
1557 sub addauthor {
1558   my ($bibnum)=@_;
1559   my $dbh=C4Connect;
1560   my $query="Select * from additionalauthors where biblionumber=$bibnum";
1561   my $sth=$dbh->prepare($query);
1562   $sth->execute;
1563   my @results;
1564   my $i=0;
1565   while (my $data=$sth->fetchrow_hashref){
1566     $results[$i]=$data;
1567     $i++;
1568   }
1569   $sth->finish;
1570   $dbh->disconnect;
1571   return($i,\@results);
1572 }
1573
1574 =item subtitle
1575
1576   ($count, $subtitles) = &subtitle($biblionumber);
1577
1578 Looks up the subtitles for the book with the given biblionumber.
1579
1580 Returns a two-element list. C<$subtitles> is a reference-to-array,
1581 where each element is a subtitle, and C<$count> is the number of
1582 elements in C<$subtitles>.
1583
1584 =cut
1585 #'
1586 sub subtitle {
1587   my ($bibnum)=@_;
1588   my $dbh=C4Connect;
1589   my $query="Select * from bibliosubtitle where biblionumber=$bibnum";
1590   my $sth=$dbh->prepare($query);
1591   $sth->execute;
1592   my @results;
1593   my $i=0;
1594   while (my $data=$sth->fetchrow_hashref){
1595     $results[$i]=$data;
1596     $i++;
1597   }
1598   $sth->finish;
1599   $dbh->disconnect;
1600   return($i,\@results);
1601 }
1602
1603 =item itemissues
1604
1605   @issues = &itemissues($biblioitemnumber, $biblio);
1606
1607 Looks up information about who has borrowed the bookZ<>(s) with the
1608 given biblioitemnumber.
1609
1610 C<$biblio> is ignored.
1611
1612 C<&itemissues> returns an array of references-to-hash. The keys
1613 include the fields from the C<items> table in the Koha database.
1614 Additional keys include:
1615
1616 =over 4
1617
1618 =item C<date_due>
1619
1620 If the item is currently on loan, this gives the due date.
1621
1622 If the item is not on loan, then this is either "Available" or
1623 "Cancelled", if the item has been withdrawn.
1624
1625 =item C<card>
1626
1627 If the item is currently on loan, this gives the card number of the
1628 patron who currently has the item.
1629
1630 =item C<timestamp0>, C<timestamp1>, C<timestamp2>
1631
1632 These give the timestamp for the last three times the item was
1633 borrowed.
1634
1635 =item C<card0>, C<card1>, C<card2>
1636
1637 The card number of the last three patrons who borrowed this item.
1638
1639 =item C<borrower0>, C<borrower1>, C<borrower2>
1640
1641 The borrower number of the last three patrons who borrowed this item.
1642
1643 =back
1644
1645 =cut
1646 #'
1647 sub itemissues {
1648     my ($bibitem, $biblio)=@_;
1649     my $dbh   = C4Connect;
1650     my $query = "Select * from items where 
1651 items.biblioitemnumber = '$bibitem'";
1652     # FIXME - If this function die()s, the script will abort, and the
1653     # user won't get anything; depending on how far the script has
1654     # gotten, the user might get a blank page. It would be much better
1655     # to at least print an error message. The easiest way to do this
1656     # is to set $SIG{__DIE__}.
1657     my $sth   = $dbh->prepare($query)
1658       || die $dbh->errstr;
1659     my $i     = 0;
1660     my @results;
1661   
1662     $sth->execute
1663       || die $sth->errstr;
1664
1665     while (my $data = $sth->fetchrow_hashref) {
1666         # Find out who currently has this item.
1667         # FIXME - Wouldn't it be better to do this as a left join of
1668         # some sort? Currently, this code assumes that if
1669         # fetchrow_hashref() fails, then the book is on the shelf.
1670         # fetchrow_hashref() can fail for any number of reasons (e.g.,
1671         # database server crash), not just because no items match the
1672         # search criteria.
1673         my $query2 = "select * from issues,borrowers
1674 where itemnumber = $data->{'itemnumber'}
1675 and returndate is NULL
1676 and issues.borrowernumber = borrowers.borrowernumber";
1677         my $sth2   = $dbh->prepare($query2);
1678
1679         $sth2->execute; 
1680         if (my $data2 = $sth2->fetchrow_hashref) {
1681             $data->{'date_due'} = $data2->{'date_due'};
1682             $data->{'card'}     = $data2->{'cardnumber'};
1683         } else {
1684             if ($data->{'wthdrawn'} eq '1') {
1685                 $data->{'date_due'} = 'Cancelled';
1686             } else {
1687                 $data->{'date_due'} = 'Available';
1688             } # else
1689         } # else
1690
1691         $sth2->finish;
1692
1693         # Find the last 3 people who borrowed this item.
1694         $query2 = "select * from issues, borrowers
1695 where itemnumber = '$data->{'itemnumber'}'
1696 and issues.borrowernumber = borrowers.borrowernumber 
1697 and returndate is not NULL
1698 order by returndate desc,timestamp desc";
1699         $sth2 = $dbh->prepare($query2)
1700           || die $dbh->errstr;
1701         $sth2->execute
1702           || die $sth2->errstr;
1703
1704         for (my $i2 = 0; $i2 < 2; $i2++) {
1705             if (my $data2 = $sth2->fetchrow_hashref) {
1706                 $data->{"timestamp$i2"} = $data2->{'timestamp'};
1707                 $data->{"card$i2"}      = $data2->{'cardnumber'};
1708                 $data->{"borrower$i2"}  = $data2->{'borrowernumber'};
1709             } # if
1710         } # for
1711
1712         $sth2->finish;
1713         $results[$i] = $data;
1714         $i++;
1715     }
1716
1717     $sth->finish;
1718     $dbh->disconnect;
1719     return(@results);
1720 }
1721
1722 =item itemnodata
1723
1724   $item = &itemnodata($env, $dbh, $biblioitemnumber);
1725
1726 Looks up the item with the given biblioitemnumber.
1727
1728 C<$env> and C<$dbh> are ignored.
1729
1730 C<&itemnodata> returns a reference-to-hash whose keys are the fields
1731 from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
1732 database.
1733
1734 =cut
1735 #'
1736 sub itemnodata {
1737   my ($env,$dbh,$itemnumber) = @_;
1738   $dbh=C4Connect;
1739   my $query="Select * from biblio,items,biblioitems
1740     where items.itemnumber = '$itemnumber'
1741     and biblio.biblionumber = items.biblionumber
1742     and biblioitems.biblioitemnumber = items.biblioitemnumber";
1743   my $sth=$dbh->prepare($query);
1744 #  print $query;
1745   $sth->execute;
1746   my $data=$sth->fetchrow_hashref;
1747   $sth->finish;  
1748   $dbh->disconnect;
1749   return($data);               
1750 }
1751
1752 =item BornameSearch
1753
1754   ($count, $borrowers) = &BornameSearch($env, $searchstring, $type);
1755
1756 Looks up patrons (borrowers) by name.
1757
1758 C<$env> and C<$type> are ignored.
1759
1760 C<$searchstring> is a space-separated list of search terms. Each term
1761 must match the beginning a borrower's surname, first name, or other
1762 name.
1763
1764 C<&BornameSearch> returns a two-element list. C<$borrowers> is a
1765 reference-to-array; each element is a reference-to-hash, whose keys
1766 are the fields of the C<borrowers> table in the Koha database.
1767 C<$count> is the number of elements in C<$borrowers>.
1768
1769 =cut
1770 #'
1771 #used by member enquiries from the intranet
1772 #called by member.pl
1773 sub BornameSearch  {
1774   my ($env,$searchstring,$type)=@_;
1775   my $dbh = &C4Connect;
1776   $searchstring=~ s/\'/\\\'/g;
1777   my @data=split(' ',$searchstring);
1778   my $count=@data;
1779   my $query="Select * from borrowers 
1780   where ((surname like \"$data[0]%\" or surname like \"% $data[0]%\" 
1781   or firstname  like \"$data[0]%\" or firstname like \"% $data[0]%\" 
1782   or othernames like \"$data[0]%\" or othernames like \"% $data[0]%\")
1783   ";
1784   for (my $i=1;$i<$count;$i++){
1785     $query=$query." and (surname like \"$data[$i]%\" or surname like \"% $data[$i]%\"                  
1786     or firstname  like \"$data[$i]%\" or firstname like \"% $data[$i]%\"                    
1787     or othernames like \"$data[$i]%\" or othernames like \"% $data[$i]%\")";
1788   }
1789   $query=$query.") or cardnumber = \"$searchstring\"
1790   order by surname,firstname";
1791 #  print $query,"\n";
1792   my $sth=$dbh->prepare($query);
1793   $sth->execute;
1794   my @results;
1795   my $cnt=0;
1796   while (my $data=$sth->fetchrow_hashref){
1797     push(@results,$data);
1798     $cnt ++;
1799   }
1800 #  $sth->execute;
1801   $sth->finish;
1802   $dbh->disconnect;
1803   return ($cnt,\@results);
1804 }
1805
1806 =item borrdata
1807
1808   $borrower = &borrdata($cardnumber, $borrowernumber);
1809
1810 Looks up information about a patron (borrower) by either card number
1811 or borrower number. If $borrowernumber is specified, C<&borrdata>
1812 searches by borrower number; otherwise, it searches by card number.
1813
1814 C<&borrdata> returns a reference-to-hash whose keys are the fields of
1815 the C<borrowers> table in the Koha database.
1816
1817 =cut
1818 #'
1819 sub borrdata {
1820   my ($cardnumber,$bornum)=@_;
1821   $cardnumber = uc $cardnumber;
1822   my $dbh=C4Connect;
1823   my $query;
1824   if ($bornum eq ''){
1825     $query="Select * from borrowers where cardnumber='$cardnumber'";
1826   } else {
1827       $query="Select * from borrowers where borrowernumber='$bornum'";
1828   }
1829   #print $query;
1830   my $sth=$dbh->prepare($query);
1831   $sth->execute;
1832   my $data=$sth->fetchrow_hashref;
1833   $sth->finish;
1834   $dbh->disconnect;
1835   return($data);
1836 }
1837
1838 =item borrissues
1839
1840   ($count, $issues) = &borrissues($borrowernumber);
1841
1842 Looks up what the patron with the given borrowernumber has borrowed.
1843
1844 C<&borrissues> returns a two-element array. C<$issues> is a
1845 reference-to-array, where each element is a reference-to-hash; the
1846 keys are the fields from the C<issues>, C<biblio>, and C<items> tables
1847 in the Koha database. C<$count> is the number of elements in
1848 C<$issues>.
1849
1850 =cut
1851 #'
1852 sub borrissues {
1853   my ($bornum)=@_;
1854   my $dbh=C4Connect;
1855   my $query;
1856   $query="Select * from issues,biblio,items where borrowernumber='$bornum' and
1857 items.itemnumber=issues.itemnumber and
1858 items.biblionumber=biblio.biblionumber and issues.returndate is NULL order
1859 by date_due";
1860   #print $query;
1861   my $sth=$dbh->prepare($query);
1862     $sth->execute;
1863   my @result;
1864   my $i=0;
1865   while (my $data=$sth->fetchrow_hashref){
1866     $result[$i]=$data;;
1867     $i++;
1868   }
1869   $sth->finish;
1870   $dbh->disconnect;
1871   return($i,\@result);
1872 }
1873
1874 =item allissues
1875
1876   ($count, $issues) = &allissues($borrowernumber, $sortkey, $limit);
1877
1878 Looks up what the patron with the given borrowernumber has borrowed,
1879 and sorts the results.
1880
1881 C<$sortkey> is the name of a field on which to sort the results. This
1882 should be the name of a field in the C<issues>, C<biblio>,
1883 C<biblioitems>, or C<items> table in the Koha database.
1884
1885 C<$limit> is the maximum number of results to return.
1886
1887 C<&allissues> returns a two-element array. C<$issues> is a
1888 reference-to-array, where each element is a reference-to-hash; the
1889 keys are the fields from the C<issues>, C<biblio>, C<biblioitems>, and
1890 C<items> tables of the Koha database. C<$count> is the number of
1891 elements in C<$issues>
1892
1893 =cut
1894 #'
1895 sub allissues { 
1896   my ($bornum,$order,$limit)=@_; 
1897   my $dbh=C4Connect;   
1898   my $query;     
1899   $query="Select * from issues,biblio,items,biblioitems       
1900   where borrowernumber='$bornum' and         
1901   items.biblioitemnumber=biblioitems.biblioitemnumber and           
1902   items.itemnumber=issues.itemnumber and             
1903   items.biblionumber=biblio.biblionumber";               
1904   $query.=" order by $order";                 
1905   if ($limit !=0){                   
1906     $query.=" limit $limit";                     
1907   }                         
1908   #print $query;                           
1909   my $sth=$dbh->prepare($query);          
1910   $sth->execute;
1911   my @result;   
1912   my $i=0;    
1913   while (my $data=$sth->fetchrow_hashref){                                      
1914     $result[$i]=$data;; 
1915     $i++;     
1916   }         
1917   $sth->finish;           
1918   $dbh->disconnect;             
1919   return($i,\@result);               
1920 }
1921
1922 =item borrdata2
1923
1924   ($borrowed, $due, $fine) = &borrdata2($env, $borrowernumber);
1925
1926 Returns aggregate data about items borrowed by the patron with the
1927 given borrowernumber.
1928
1929 C<$env> is ignored.
1930
1931 C<&borrdata2> returns a three-element array. C<$borrowed> is the
1932 number of books the patron currently has borrowed. C<$due> is the
1933 number of overdue items the patron currently has borrowed. C<$fine> is
1934 the total fine currently due by the borrower.
1935
1936 =cut
1937 #'
1938 sub borrdata2 {
1939   my ($env,$bornum)=@_;
1940   my $dbh=C4Connect;
1941   my $query="Select count(*) from issues where borrowernumber='$bornum' and
1942     returndate is NULL";
1943     # print $query;
1944   my $sth=$dbh->prepare($query);
1945   $sth->execute;
1946   my $data=$sth->fetchrow_hashref;
1947   $sth->finish;
1948   $sth=$dbh->prepare("Select count(*) from issues where
1949     borrowernumber='$bornum' and date_due < now() and returndate is NULL");
1950   $sth->execute;
1951   my $data2=$sth->fetchrow_hashref;
1952   $sth->finish;
1953   $sth=$dbh->prepare("Select sum(amountoutstanding) from accountlines where
1954     borrowernumber='$bornum'");
1955   $sth->execute;
1956   my $data3=$sth->fetchrow_hashref;
1957   $sth->finish;
1958   $dbh->disconnect;
1959
1960 return($data2->{'count(*)'},$data->{'count(*)'},$data3->{'sum(amountoutstanding)'});
1961 }
1962         
1963 =item getboracctrecord
1964
1965   ($count, $acctlines, $total) = &getboracctrecord($env, $borrowernumber);
1966
1967 Looks up accounting data for the patron with the given borrowernumber.
1968
1969 C<$env> is ignored.
1970
1971 (FIXME - I'm not at all sure what this is about.)
1972
1973 C<&getboracctrecord> returns a three-element array. C<$acctlines> is a
1974 reference-to-array, where each element is a reference-to-hash; the
1975 keys are the fields of the C<accountlines> table in the Koha database.
1976 C<$count> is the number of elements in C<$acctlines>. C<$total> is the
1977 total amount outstanding for all of the account lines.
1978
1979 =cut
1980 #'
1981 sub getboracctrecord {
1982    my ($env,$params) = @_;
1983    my $dbh=C4Connect;
1984    my @acctlines;
1985    my $numlines=0;
1986    my $query= "Select * from accountlines where
1987 borrowernumber=$params->{'borrowernumber'} order by date desc,timestamp desc";
1988    my $sth=$dbh->prepare($query);
1989 #   print $query;
1990    $sth->execute;
1991    my $total=0;
1992    while (my $data=$sth->fetchrow_hashref){
1993 #      if ($data->{'itemnumber'} ne ''){
1994 #        $query="Select * from items,biblio where items.itemnumber=
1995 #       '$data->{'itemnumber'}' and biblio.biblionumber=items.biblionumber";
1996 #       my $sth2=$dbh->prepare($query);
1997 #       $sth2->execute;
1998 #       my $data2=$sth2->fetchrow_hashref;
1999 #       $sth2->finish;
2000 #       $data=$data2;
2001  #     }
2002       $acctlines[$numlines] = $data;
2003       $numlines++;
2004       $total = $total+ $data->{'amountoutstanding'};
2005    }
2006    $sth->finish;
2007    $dbh->disconnect;
2008    return ($numlines,\@acctlines,$total);
2009 }
2010
2011 =item itemcount
2012
2013   ($count, $lcount, $nacount, $fcount, $scount, $lostcount,
2014   $mending, $transit,$ocount) =
2015     &itemcount($env, $biblionumber, $type);
2016
2017 Counts the number of items with the given biblionumber, broken down by
2018 category.
2019
2020 C<$env> is ignored.
2021
2022 If C<$type> is not set to C<intra>, lost, very overdue, and withdrawn
2023 items will not be counted.
2024
2025 C<&itemcount> returns a nine-element list:
2026
2027 C<$count> is the total number of items with the given biblionumber.
2028
2029 C<$lcount> is the number of items at the Levin branch.
2030
2031 C<$nacount> is the number of items that are neither borrowed, lost,
2032 nor withdrawn (and are therefore presumably on a shelf somewhere).
2033
2034 C<$fcount> is the number of items at the Foxton branch.
2035
2036 C<$scount> is the number of items at the Shannon branch.
2037
2038 C<$lostcount> is the number of lost and very overdue items.
2039
2040 C<$mending> is the number of items at the Mending branch (being
2041 mended?).
2042
2043 C<$transit> is the number of items at the Transit branch (in transit
2044 between branches?).
2045
2046 C<$ocount> is the number of items that haven't arrived yet
2047 (aqorders.quantity - aqorders.quantityreceived).
2048
2049 =cut
2050 #'
2051 sub itemcount { 
2052   my ($env,$bibnum,$type)=@_; 
2053   my $dbh=C4Connect;   
2054   my $query="Select * from items where     
2055   biblionumber=$bibnum ";
2056   if ($type ne 'intra'){
2057     $query.=" and ((itemlost <>1 and itemlost <> 2) or itemlost is NULL) and
2058     (wthdrawn <> 1 or wthdrawn is NULL)";      
2059   }
2060   my $sth=$dbh->prepare($query);         
2061   #  print $query;           
2062   $sth->execute;           
2063   my $count=0;             
2064   my $lcount=0;               
2065   my $nacount=0;                 
2066   my $fcount=0;
2067   my $scount=0;
2068   my $lostcount=0;
2069   my $mending=0;
2070   my $transit=0;
2071   my $ocount=0;
2072   while (my $data=$sth->fetchrow_hashref){
2073     $count++;                     
2074     my $query2="select * from issues,items where issues.itemnumber=                          
2075     '$data->{'itemnumber'}' and returndate is NULL
2076     and items.itemnumber=issues.itemnumber and ((items.itemlost <>1 and
2077     items.itemlost <> 2) or items.itemlost is NULL) 
2078     and (wthdrawn <> 1 or wthdrawn is NULL)"; 
2079     
2080     my $sth2=$dbh->prepare($query2);     
2081     $sth2->execute;         
2082     if (my $data2=$sth2->fetchrow_hashref){         
2083        $nacount++;         
2084     } else {         
2085       if ($data->{'holdingbranch'} eq 'C' || $data->{'holdingbranch'} eq 'LT'){         
2086         $lcount++;               
2087       }                       
2088       if ($data->{'holdingbranch'} eq 'F' || $data->{'holdingbranch'} eq 'FP'){         
2089         $fcount++;               
2090       }                       
2091       if ($data->{'holdingbranch'} eq 'S' || $data->{'holdingbranch'} eq 'SP'){         
2092         $scount++;               
2093       }                       
2094       if ($data->{'itemlost'} eq '1'){
2095         $lostcount++;
2096       }
2097       if ($data->{'itemlost'} eq '2'){
2098         $lostcount++;
2099       }
2100       if ($data->{'holdingbranch'} eq 'FM'){
2101         $mending++;
2102       }
2103       if ($data->{'holdingbranch'} eq 'TR'){
2104         $transit++;
2105       }
2106     }                             
2107     $sth2->finish;     
2108   } 
2109 #  if ($count == 0){
2110     my $query2="Select * from aqorders where biblionumber=$bibnum";
2111     my $sth2=$dbh->prepare($query2);
2112     $sth2->execute;
2113     if (my $data=$sth2->fetchrow_hashref){
2114       $ocount=$data->{'quantity'} - $data->{'quantityreceived'};
2115     }
2116 #    $count+=$ocount;
2117     $sth2->finish;
2118   $sth->finish; 
2119   $dbh->disconnect;                   
2120   return ($count,$lcount,$nacount,$fcount,$scount,$lostcount,$mending,$transit,$ocount); 
2121 }
2122
2123 =item itemcount2
2124
2125   $counts = &itemcount2($env, $biblionumber, $type);
2126
2127 Counts the number of items with the given biblionumber, broken down by
2128 category.
2129
2130 C<$env> is ignored.
2131
2132 C<$type> may be either C<intra> or anything else. If it is not set to
2133 C<intra>, then the search will exclude lost, very overdue, and
2134 withdrawn items.
2135
2136 C<$&itemcount2> returns a reference-to-hash, with the following fields:
2137
2138 =over 4
2139
2140 =item C<total>
2141
2142 The total number of items with this biblionumber.
2143
2144 =item C<order>
2145
2146 The number of items on order (aqorders.quantity -
2147 aqorders.quantityreceived).
2148
2149 =item I<branchname>
2150
2151 For each branch that has at least one copy of the book, C<$counts>
2152 will have a key with the branch name, giving the number of copies at
2153 that branch.
2154
2155 =back
2156
2157 =cut
2158 #'
2159 sub itemcount2 { 
2160   my ($env,$bibnum,$type)=@_; 
2161   my $dbh=C4Connect;   
2162   my $query="Select * from items,branches where     
2163   biblionumber=$bibnum and items.holdingbranch=branches.branchcode";
2164   if ($type ne 'intra'){
2165     $query.=" and ((itemlost <>1 and itemlost <> 2) or itemlost is NULL) and
2166     (wthdrawn <> 1 or wthdrawn is NULL)";      
2167   }
2168   my $sth=$dbh->prepare($query);         
2169   #  print $query;           
2170   $sth->execute;           
2171   my %counts;
2172   $counts{'total'}=0;
2173   while (my $data=$sth->fetchrow_hashref){
2174     $counts{'total'}++;                     
2175     my $query2="select * from issues,items where issues.itemnumber=                          
2176     '$data->{'itemnumber'}' and returndate is NULL
2177     and items.itemnumber=issues.itemnumber and ((items.itemlost <>1 and
2178     items.itemlost <> 2) or items.itemlost is NULL) 
2179     and (wthdrawn <> 1 or wthdrawn is NULL)"; 
2180     
2181     my $sth2=$dbh->prepare($query2);     
2182     $sth2->execute;         
2183     # FIXME - fetchrow_hashref() can fail for any number of reasons
2184     # (e.g., a database server crash). Perhaps use a left join of some
2185     # sort for this?
2186     if (my $data2=$sth2->fetchrow_hashref){         
2187        $counts{'not available'}++;         
2188     } else {         
2189        $counts{$data->{'branchname'}}++;
2190     }                             
2191     $sth2->finish;     
2192   } 
2193   my $query2="Select * from aqorders where biblionumber=$bibnum and
2194   datecancellationprinted is NULL and quantity > quantityreceived";
2195   my $sth2=$dbh->prepare($query2);
2196   $sth2->execute;
2197   if (my $data=$sth2->fetchrow_hashref){
2198       $counts{'order'}=$data->{'quantity'} - $data->{'quantityreceived'};
2199   }
2200   $sth2->finish;
2201   $sth->finish; 
2202   $dbh->disconnect;                   
2203   return (\%counts); 
2204 }
2205
2206 =item ItemType
2207
2208   $description = &ItemType($itemtype);
2209
2210 Given an item type code, returns the description for that type.
2211
2212 =cut
2213 #'
2214
2215 # FIXME - I'm pretty sure that after the initial setup, the list of
2216 # item types doesn't change very often. Hence, it seems slow and
2217 # inefficient to make yet another database call to look up information
2218 # that'll only change every few months or years.
2219 #
2220 # Much better, I think, to automatically build a Perl file that can be
2221 # included in those scripts that require it, e.g.:
2222 #       @itemtypes = qw( ART BCD CAS CD F ... );
2223 #       %itemtypedesc = (
2224 #               ART     => "Art Prints",
2225 #               BCD     => "CD-ROM from book",
2226 #               CD      => "Compact disc (WN)",
2227 #               F       => "Free Fiction",
2228 #               ...
2229 #       );
2230 # The web server can then run a cron job to rebuild this file from the
2231 # database every hour or so.
2232 #
2233 # The same thing goes for branches, book funds, book sellers, currency
2234 # rates, printers, stopwords, and perhaps others.
2235 sub ItemType {
2236   my ($type)=@_;
2237   my $dbh=C4Connect;
2238   my $query="select description from itemtypes where itemtype='$type'";
2239   my $sth=$dbh->prepare($query);
2240   $sth->execute;
2241   my $dat=$sth->fetchrow_hashref;
2242   $sth->finish;
2243   $dbh->disconnect;
2244   return ($dat->{'description'});
2245 }
2246
2247 =item bibitems
2248
2249   ($count, @results) = &bibitems($biblionumber);
2250
2251 Given the biblionumber for a book, C<&bibitems> looks up that book's
2252 biblioitems (different publications of the same book, the audio book
2253 and film versions, etc.).
2254
2255 C<$count> is the number of elements in C<@results>.
2256
2257 C<@results> is an array of references-to-hash; the keys are the fields
2258 of the C<biblioitems> and C<itemtypes> tables of the Koha database. In
2259 addition, C<itemlost> indicates the availability of the item: if it is
2260 "2", then all copies of the item are long overdue; if it is "1", then
2261 all copies are lost; otherwise, there is at least one copy available.
2262
2263 =cut
2264 #'
2265 sub bibitems {
2266     my ($bibnum) = @_;
2267     my $dbh   = C4Connect;
2268     my $query = "SELECT biblioitems.*, 
2269                         itemtypes.*, 
2270                         MIN(items.itemlost)        as itemlost,
2271                         MIN(items.dateaccessioned) as dateaccessioned
2272                           FROM biblioitems, itemtypes, items
2273                          WHERE biblioitems.biblionumber     = ?
2274                            AND biblioitems.itemtype         = itemtypes.itemtype
2275                            AND biblioitems.biblioitemnumber = items.biblioitemnumber
2276                       GROUP BY items.biblioitemnumber";
2277     my $sth   = $dbh->prepare($query);
2278     my $count = 0;
2279     my @results;
2280     $sth->execute($bibnum);
2281     while (my $data = $sth->fetchrow_hashref) {
2282         $results[$count] = $data;
2283         $count++;
2284     } # while    
2285     $sth->finish;
2286     $dbh->disconnect;
2287     return($count, @results);
2288 } # sub bibitems
2289
2290 =item barcodes
2291
2292   @barcodes = &barcodes($biblioitemnumber);
2293
2294 Given a biblioitemnumber, looks up the corresponding items.
2295
2296 Returns an array of references-to-hash; the keys are C<barcode> and
2297 C<itemlost>.
2298
2299 The returned items include very overdue items, but not lost ones.
2300
2301 =cut
2302 #'
2303 sub barcodes{
2304     #called from request.pl
2305     my ($biblioitemnumber)=@_;
2306     my $dbh=C4Connect;
2307     my $query="SELECT barcode, itemlost FROM items
2308                            WHERE biblioitemnumber = ?
2309                              AND (wthdrawn <> 1 OR wthdrawn IS NULL)";
2310     my $sth=$dbh->prepare($query);
2311     $sth->execute($biblioitemnumber);
2312     my @barcodes;
2313     my $i=0;
2314     while (my $data=$sth->fetchrow_hashref){
2315         $barcodes[$i]=$data;
2316         $i++;
2317     }
2318     $sth->finish;
2319     $dbh->disconnect;
2320     return(@barcodes);
2321 }
2322
2323 =item getwebsites
2324
2325   ($count, @websites) = &getwebsites($biblionumber);
2326
2327 Looks up the web sites pertaining to the book with the given
2328 biblionumber.
2329
2330 C<$count> is the number of elements in C<@websites>.
2331
2332 C<@websites> is an array of references-to-hash; the keys are the
2333 fields from the C<websites> table in the Koha database.
2334
2335 =cut
2336 #'
2337 sub getwebsites {
2338     my ($biblionumber) = @_;
2339     my $dbh   = C4Connect;
2340     my $query = "Select * from websites where biblionumber = $biblionumber";
2341     my $sth   = $dbh->prepare($query);
2342     my $count = 0;
2343     my @results;
2344
2345     $sth->execute;
2346     while (my $data = $sth->fetchrow_hashref) {
2347         # FIXME - The URL scheme shouldn't be stripped off, at least
2348         # not here, since it's part of the URL, and will be useful in
2349         # constructing a link to the site. If you don't want the user
2350         # to see the "http://" part, strip that off when building the
2351         # HTML code.
2352         $data->{'url'} =~ s/^http:\/\///;       # FIXME - Leaning toothpick
2353                                                 # syndrome
2354         $results[$count] = $data;
2355         $count++;
2356     } # while
2357
2358     $sth->finish;
2359     $dbh->disconnect;
2360     return($count, @results);
2361 } # sub getwebsites
2362
2363 =item getwebbiblioitems
2364
2365   ($count, @results) = &getwebbiblioitems($biblionumber);
2366
2367 Given a book's biblionumber, looks up the web versions of the book
2368 (biblioitems with itemtype C<WEB>).
2369
2370 C<$count> is the number of items in C<@results>. C<@results> is an
2371 array of references-to-hash; the keys are the items from the
2372 C<biblioitems> table of the Koha database.
2373
2374 =cut
2375 #'
2376 sub getwebbiblioitems {
2377     my ($biblionumber) = @_;
2378     my $dbh   = C4Connect;
2379     my $query = "Select * from biblioitems where biblionumber = $biblionumber
2380 and itemtype = 'WEB'";
2381     my $sth   = $dbh->prepare($query);
2382     my $count = 0;
2383     my @results;
2384     
2385     $sth->execute;
2386     while (my $data = $sth->fetchrow_hashref) {
2387         $data->{'url'} =~ s/^http:\/\///;
2388         $results[$count] = $data;
2389         $count++;
2390     } # while
2391     
2392     $sth->finish;
2393     $dbh->disconnect;
2394     return($count, @results);
2395 } # sub getwebbiblioitems
2396
2397
2398 END { }       # module clean-up code here (global destructor)
2399
2400 1;
2401 __END__
2402
2403 =back
2404
2405 =head1 AUTHOR
2406
2407 Koha Developement team <info@koha.org>
2408
2409 =head1 SEE ALSO
2410
2411 L<perl>.
2412
2413 =cut