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