3 # Copyright 2000-2002 Katipo Communications
4 # This file is part of Koha.
6 # Koha is free software; you can redistribute it and/or modify it under the
7 # terms of the GNU General Public License as published by the Free Software
8 # Foundation; either version 2 of the License, or (at your option) any later
11 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
12 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License along with
16 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
17 # Suite 330, Boston, MA 02111-1307 USA
28 # FIXME - C4::Search uses C4::Reserves2, which uses C4::Search.
29 # So Perl complains that all of the functions here get redefined.
32 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
34 # set the version for version checking
35 $VERSION = do { my @v = '$Revision$' =~ /\d+/g;
36 shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
40 C4::Search - Functions for searching the Koha catalog and other databases
46 my ($count, @results) = catalogsearch4($env, $type, $search, $num, $offset);
50 This module provides the searching facilities for the Koha catalog and
63 &barcodes &ItemInfo &itemcount
64 &getcoverPhoto &add_query_line
65 &FindDuplicate &ZEBRAsearch_kohafields &convertPQF &sqlsearch &cataloguing_search
66 &getMARCnotes &getMARCsubjects &getMARCurls &parsefields);
67 # make all your functions, whether exported or not;
70 ZEBRAsearchkohafields is the underlying API for searching zebra for KOHA internal use
71 its kept similar to earlier version Koha Marc searches. instead of passing marc tags to the routine
72 you pass named kohafields
73 So you give an array of @kohafieldnames,@values, what relation they have @relations (equal, truncation etc) @and_or and
74 you receive an array of XML records.
75 The routine also has a flag $fordisplay and if it is set to 1 it will return the @results as an array of Perl hashes so that your previous
76 search results templates do actually work.
77 This routine will also take CCL,CQL or PQF queries and pass them straight to the server
78 See sub FindDuplicates for an example;
84 sub ZEBRAsearch_kohafields{
85 my ($kohafield,$value, $relation,$sort, $and_or, $fordisplay,$reorder,$startfrom,$number_of_results,$searchfrom,$searchtype)=@_;
86 return (0,undef) unless (@$value[0]);
87 my $server="biblioserver";
94 for ( $i=0; $i<=$#{$value}; $i++){
95 next if (@$value[$i] eq "");
97 my $keyattr=MARCfind_attr_from_kohafield(@$kohafield[$i]) if (@$kohafield[$i]);
98 if (!$keyattr){$keyattr=" \@attr 1=any";}
99 @$value[$i]=~ s/(\.|\?|\;|\=|\/|\\|\||\:|\*|\!|\,|\(|\)|\[|\]|\{|\}|\/)/ /g;
100 $query.=@$relation[$i]." ".$keyattr." \"".@$value[$i]."\" " if @$value[$i];
102 for (my $z= 0;$z<=$#{$and_or};$z++){
103 $query=@$and_or[$z]." ".$query if (@$value[$z+1] ne "");
110 ($oConnection[0])=C4::Context->Zconn($server);
113 (@sortpart)=split /,/,$reorder;
115 (@sortpart)=split /,/,$sort;
118 ##sortpart is expected to contain the form "title i<" notation or "title,1" both mean the same thing
120 push @sortpart," "; ##In case multisort variable is coming as a single query
122 if ($sortpart[1]==2){
123 $sortpart[1]=">i"; ##Descending
124 }elsif ($sortpart[1]==1){
125 $sortpart[1]="<i"; ##Ascending
128 unless($query=~/4=109/){ ###ranked sort not valid for numeric fields
130 $query="\@attr 2=102 ".$query;
135 $query=convertPQF($searchtype,$oConnection[0],$value);
137 $query=new ZOOM::Query::PQF($query);
139 goto EXITING unless $query;## erronous query coming in
140 $query->sortby($sortpart[0]." ".$sortpart[1]) if @sortpart;
148 $oResult= $oConnection[0]->search($query);
151 while (($i = ZOOM::event(\@oConnection)) != 0) {
152 $event = $oConnection[$i-1]->last_event();
153 last if $event == ZOOM::Event::ZEND;
156 my($error, $errmsg, $addinfo, $diagset) = $oConnection[0]->error_x();
157 if ($error==10007 && $tried<3) {## timeout --another 30 looonng seconds for this update
160 }elsif ($error==2 && $tried<2) {## timeout --temporary zebra error !whatever that means
164 warn "Error-$server /errcode:, $error, /MSG:,$errmsg,$addinfo \n";
166 $oConnection[0]->destroy();
167 return (undef,undef);
169 my $dbh=C4::Context->dbh;
170 $numresults=$oResult->size() ;
176 $ri=$startfrom if $startfrom;
177 for ( $ri; $ri<$numresults ; $ri++){
179 my $xmlrecord=$oResult->record($ri)->raw();
180 $xmlrecord=Encode::decode("utf8",$xmlrecord);
181 $xmlrecord=XML_xml2hash($xmlrecord);
184 push @results,$xmlrecord;
185 last if ($number_of_results && $z>=$number_of_results);
190 my ($facets,@parsed)=parsefields($dbh,$searchfrom,@results);
191 return ($numresults,$facets,@parsed) ;
196 $oConnection[0]->destroy();
197 return ($numresults,@results) ;
201 # Convert CCL, CQF or PQF to ZEBRA RPN queries,trap errors
202 my ($search_type,$zconn,$query)=@_;
205 if ($search_type eq "pqf"){
207 $pqf_query=new ZOOM::Query::PQF(@$query[0]);
209 }elsif ($search_type eq "ccl"){
211 my $cclfile=C4::Context->config("ccl2rpn");
212 $zconn->option(cclfile=>$cclfile);## CCL conversion file path
214 $pqf_query=new ZOOM::Query::CCL2RPN(@$query[0],$zconn);
216 }elsif ($search_type eq "cql"){
218 $pqf_query=new ZOOM::Query::CQL(@$query[0]);
229 =item add_bold_fields
230 After a search the searched keyword is <b>boldened</b> in the displayed search results if it exists in the title or author
231 It is now depreceated
233 sub add_html_bold_fields {
234 my ($type, $data, $search) = @_;
235 foreach my $key ('title', 'author') {
238 $new_key = 'bold_' . $key;
239 $data->{$new_key} = $data->{$key};
247 if ($type eq 'keyword') {
248 my $newkey=$search->{'keyword'};
250 @keys = split " ", $newkey;
253 for ($i = 0; $i < $count ; $i++) {
255 if (($data->{$new_key} =~ /($keys[$i])/i) && (lc($keys[$i]) ne 'b') ) {
257 $data->{$new_key} =~ s/$word/<b>$word<\/b>/;
266 ## This searches the SQL database only for biblionumber,itemnumber,barcode
267 ### Not very useful on production but as a debug tool useful during system maturing for ZEBRA operations
269 my ($dbh,$search)=@_;
271 if ($search->{'barcode'} ne '') {
272 $sth=$dbh->prepare("SELECT biblionumber from items where barcode=?");
273 $sth->execute($search->{'barcode'});
274 }elsif ($search->{'itemnumber'} ne '') {
275 $sth=$dbh->prepare("SELECT biblionumber from items where itemnumber=?");
276 $sth->execute($search->{'itemnumber'});
277 }elsif ($search->{'biblionumber'} ne '') {
278 $sth=$dbh->prepare("SELECT biblionumber from biblio where biblionumber=?");
279 $sth->execute($search->{'biblionumber'});
281 return (undef,undef);
284 my $result=$sth->fetchrow_hashref;
285 return (1,$result) if $result;
288 sub cataloguing_search{
289 ## This is an SQL based search designed to be used when adding a new biblio incase library sets
290 ## preference zebraorsql to sql when adding a new biblio
291 my ($search,$num,$offset) = @_;
292 my ($count,@results);
293 my $dbh=C4::Context->dbh;
296 my $condition="select SQL_CALC_FOUND_ROWS marcxml from biblio where ";
297 if ($search->{'isbn'} ne''){
298 $search->{'isbn'}=$search->{'isbn'}."%";
299 $query=$search->{'isbn'};
300 $condition.= " isbn like ? ";
302 return (0,undef) unless $search->{title};
303 $query=$search->{'title'};
304 $condition.= " MATCH (title) AGAINST(? in BOOLEAN MODE ) ";
306 my $sth=$dbh->prepare($condition);
307 $sth->execute($query);
308 my $nbresult=$dbh->prepare("SELECT FOUND_ROWS()");
310 my $count=$nbresult->fetchrow;
311 my $limit = $num + $offset;
312 my $startfrom = $offset;
315 while (my $marc=$sth->fetchrow){
316 if (($i >= $startfrom) && ($i < $limit)) {
317 my $record=XML_xml2hash_onerecord($marc);
318 my $data=XMLmarc2koha_onerecord($dbh,$record,"biblios");
324 return ($count,@results);
331 my $dbh=C4::Context->dbh;
332 my ($result) = XMLmarc2koha_onerecord($dbh,$xml,"biblios");
338 # search duplicate on ISBN, easy and fast..
340 if ($result->{isbn}) {
341 push @kohafield,"isbn";
342 ###Temporary fix for ISBN
343 my $isbn=$result->{isbn};
344 $isbn=~ s/(\.|\?|\;|\=|\/|\\|\||\:|\!|\'|,|\-|\"|\*|\(|\)|\[|\]|\{|\}|\/)//g;
347 $result->{title}=~s /\\//g;
348 $result->{title}=~s /\"//g;
349 $result->{title}=~ s/(\.|\?|\;|\=|\/|\\|\||\:|\*|\!|\,|\-|\(|\)|\[|\]|\{|\}|\/)/ /g;
351 push @kohafield,"title";
352 push @value,$result->{title};
353 push @relation,"\@attr 6=3 \@attr 4=1 \@attr 5=1"; ## right truncated,phrase,whole field
356 my ($total,@result)=ZEBRAsearch_kohafields(\@kohafield,\@value,\@relation,"",\@and_or,0,"",0,1);
358 my $title=XML_readline($result[0],"title","biblios") ;
359 my $biblionumber=XML_readline($result[0],"biblionumber","biblios") ;
360 return $biblionumber,$title ;
368 my ($type,$search,$results)=@_;
369 my $dbh = C4::Context->dbh;
372 my $borrowernumber = $search->{'borrowernumber'};
373 my $remote_IP = $search->{'remote_IP'};
374 my $remote_URL= $search->{'remote_URL'};
375 my $searchdesc = $search->{'searchdesc'};
377 my $sth = $dbh->prepare("INSERT INTO phrase_log(phr_phrase,phr_resultcount,phr_ip,user,actual) VALUES(?,?,?,?,?)");
380 $sth->execute($searchdesc,$results,$remote_IP,$borrowernumber,$remote_URL);
388 @results = &ItemInfo($env, $biblionumber, $type);
390 Returns information about books with the given biblionumber.
392 C<$type> may be either C<intra> or anything else. If it is not set to
393 C<intra>, then the search will exclude lost, very overdue, and
398 C<&ItemInfo> returns a list of references-to-hash. Each element
399 contains a number of keys. Most of them are table items from the
400 C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
401 Koha database. Other keys include:
405 =item C<$data-E<gt>{branchname}>
407 The name (not the code) of the branch to which the book belongs.
409 =item C<$data-E<gt>{datelastseen}>
411 This is simply C<items.datelastseen>, except that while the date is
412 stored in YYYY-MM-DD format in the database, here it is converted to
413 DD/MM/YYYY format. A NULL date is returned as C<//>.
415 =item C<$data-E<gt>{datedue}>
417 =item C<$data-E<gt>{class}>
419 This is the concatenation of C<biblioitems.classification>, the book's
420 Dewey code, and C<biblioitems.subclass>.
422 =item C<$data-E<gt>{ocount}>
424 I think this is the number of copies of the book available.
426 =item C<$data-E<gt>{order}>
428 If this is set, it is set to C<One Order>.
435 my ($dbh,$data) = @_;
438 my ($date_due, $count_reserves);
440 my $isth=$dbh->prepare("Select issues.*,borrowers.cardnumber from issues,borrowers where itemnumber = ? and returndate is null and issues.borrowernumber=borrowers.borrowernumber");
441 $isth->execute($data->{'itemnumber'});
442 if (my $idata=$isth->fetchrow_hashref){
443 $data->{borrowernumber} = $idata->{borrowernumber};
444 $data->{cardnumber} = $idata->{cardnumber};
445 $datedue = format_date($idata->{'date_due'});
447 if ($datedue eq '' || $datedue eq "0000-00-00"){
449 my ($restype,$reserves)=C4::Reserves2::CheckReserves($data->{'itemnumber'});
451 $count_reserves = $restype;
455 #get branch information.....
456 my $bsth=$dbh->prepare("SELECT * FROM branches WHERE branchcode = ?");
457 $bsth->execute($data->{'holdingbranch'});
458 if (my $bdata=$bsth->fetchrow_hashref){
459 $data->{'branchname'} = $bdata->{'branchname'};
461 my $date=substr($data->{'datelastseen'},0,8);
462 $data->{'datelastseen'}=format_date($date);
463 $data->{'datedue'}=$datedue;
464 $data->{'count_reserves'} = $count_reserves;
465 # get notforloan complete status if applicable
466 my ($tagfield,$tagsub)=MARCfind_marc_from_kohafield("notforloan","holdings");
467 my $sthnflstatus = $dbh->prepare("select authorised_value from holdings_subfield_structure where tagfield='$tagfield' and tagsubfield='$tagsub'");
468 $sthnflstatus->execute;
469 my ($authorised_valuecode) = $sthnflstatus->fetchrow;
470 if ($authorised_valuecode) {
471 $sthnflstatus = $dbh->prepare("select lib from authorised_values where category=? and authorised_value=?");
472 $sthnflstatus->execute($authorised_valuecode,$data->{itemnotforloan});
473 my ($lib) = $sthnflstatus->fetchrow;
474 $data->{notforloan} = $lib;
477 # my shelf procedures
478 my ($tagfield,$tagsubfield)=MARCfind_marc_from_kohafield("shelf","holdings");
480 my $shelfstatus = $dbh->prepare("select authorised_value from holdings_subfield_structure where tagfield='$tagfield' and tagsubfield='$tagsubfield'");
481 $shelfstatus->execute;
482 $authorised_valuecode = $shelfstatus->fetchrow;
483 if ($authorised_valuecode) {
484 $shelfstatus = $dbh->prepare("select lib from authorised_values where category=? and authorised_value=?");
485 $shelfstatus->execute($authorised_valuecode,$data->{shelf});
487 my ($lib) = $shelfstatus->fetchrow;
488 $data->{shelf} = $lib;
502 @barcodes = &barcodes($biblioitemnumber);
504 Given a biblioitemnumber, looks up the corresponding items.
506 Returns an array of references-to-hash; the keys are C<barcode> and
509 The returned items include very overdue items, but not lost ones.
514 #called from request.pl
515 my ($biblionumber)=@_;
517 my $dbh = C4::Context->dbh;
524 push @kohafields, "biblionumber";
525 push @values,$biblionumber;
526 push @relations, " "," \@attr 2=1"; ## selecting wthdrawn less then 1
527 push @and_or, "\@and";
529 my ($count,@results)=ZEBRAsearch_kohafields(\@kohafields,\@values,\@relations,$sort,\@and_or,"","");
530 push @fields,"barcode","itemlost","itemnumber","date_due","wthdrawn","notforloan";
531 my ($biblio,@items)=XMLmarc2koha($dbh,$results[0],"holdings", @fields);
540 ##Requires a MARCXML as $record
541 my ($dbh, $record, $marcflavour) = @_;
543 my ($mintag, $maxtag);
544 if (uc($marcflavour) eq uc"MARC21" || uc($marcflavour) eq "USMARC") {
547 } else { # assume unimarc if not marc21
553 foreach my $field ($mintag..$maxtag) {
555 my @values=XML_readline_asarray($record,"","",$field,"");
556 foreach my $value (@values){
557 $line{MARCNOTE}=$value if $value;
558 push @marcnotes,\%line if $line{MARCNOTE};
562 my $marcnotesarray=\@marcnotes;
563 return $marcnotesarray;
568 sub getMARCsubjects {
570 my ($dbh, $record, $marcflavour) = @_;
571 my ($mintag, $maxtag);
572 if (uc($marcflavour) eq uc"MARC21" || uc($marcflavour) eq "USMARC") {
575 } else { # assume unimarc if not marc21
584 foreach my $field ($mintag..$maxtag) {
585 my @value =XML_readline_asarray($record,"","",$field,"a");
586 foreach my $subject (@value){
587 $marcsubjct = {MARCSUBJCT => $subject,};
588 push @marcsubjcts, $marcsubjct;
592 my $marcsubjctsarray=\@marcsubjcts;
593 return $marcsubjctsarray;
594 } #end getMARCsubjects
598 ### This code is wrong only works with MARC21
599 my ($dbh, $record, $marcflavour) = @_;
600 my ($mintag, $maxtag);
601 if (uc($marcflavour) eq uc"MARC21" || uc($marcflavour) eq "USMARC") {
604 } else { # assume unimarc if not marc21
614 foreach my $field ($mintag..$maxtag) {
615 my @value =XML_readline_asarray($record,"","",$field,"u");
616 foreach my $url (@value){
617 if ( $value ne $url) {
618 $marcurl = {MARCURL => $url,};
619 push @marcurls, $marcurl;
626 my $marcurlsarray=\@marcurls;
627 return $marcurlsarray;
633 #pass this a MARC record and it will parse it for display purposes
634 my ($dbh,$intranet,@marcrecords)=@_;
637 my $retrieve_from=C4::Context->preference('retrieve_from');
638 #Build brancnames hash for displaying in OPAC - more user friendly
640 #get branch information.....
642 my $bsth=$dbh->prepare("SELECT branchcode,branchname FROM branches");
644 while (my $bdata=$bsth->fetchrow_hashref){
645 $branches{$bdata->{'branchcode'}}= $bdata->{'branchname'};
648 #Building shelving hash if library has shelves defined like junior section, non-fiction, audio-visual room etc
651 my ($tagfield,$tagsubfield)=MARCfind_marc_from_kohafield("shelf","holdings");
652 my $shelfstatus = $dbh->prepare("select authorised_value from holdings_subfield_structure where tagfield='$tagfield' and tagsubfield='$tagsubfield'");
653 $shelfstatus->execute;
654 my ($authorised_valuecode) = $shelfstatus->fetchrow;
655 if ($authorised_valuecode) {
656 $shelfstatus = $dbh->prepare("select lib,authorised_value from authorised_values where category=? ");
657 $shelfstatus->execute($authorised_valuecode);
658 while (my $lib = $shelfstatus->fetchrow_hashref){
659 $shelves{$lib->{'authorised_value'}} = $lib->{'lib'};
664 my $facets_counter = ();
665 my $facets_info = ();
666 my @facets_loop; # stores the ref to array of hashes for template
668 foreach my $xml(@marcrecords){
670 if (C4::Context->preference('useFacets')){
671 ($facets_counter,$facets_info)=FillFacets($xml,$facets_counter,$facets_info);
673 my @kohafields; ## just name those necessary for the result page
674 push @kohafields, "biblionumber","title","author","publishercode","classification","itemtype","copyrightdate", "holdingbranch","date_due","location","shelf","itemcallnumber","notforloan","itemlost","wthdrawn";
675 my ($oldbiblio,@itemrecords) = XMLmarc2koha($dbh,$xml,"",@kohafields);
683 ##Loop for each item field
685 foreach my $item (@itemrecords) {
686 $norequests = 0 unless $item->{'itemnotforloan'};
689 #renaming some fields according to templates
690 $item->{'branchname'}=$branches{$item->{'holdingbranch'}};
691 $item->{'shelves'}=$shelves{$item->{'shelf'}};
692 $status="Lost" if ($item->{'itemlost'}>0);
693 $status="Withdrawn" if ($item->{'wthdrawn'}>0);
694 if ($intranet eq "intranet"){ ## we give full itemcallnumber detail in intranet
695 $status="Due:".format_date($item->{'date_due'}) if ($item->{'date_due'} gt "0000-00-00");
696 $status = $item->{'holdingbranch'}."-".$item->{'shelf'}."[".$item->{'itemcallnumber'}."]" unless defined $status;
698 $status="On Loan" if ($item->{'date_due'} gt "0000-00-00");
699 $status = $item->{'branchname'}."[".$item->{'shelves'}."]" unless defined $status;
705 $oldbiblio->{'noitems'} = $noitems;
706 $oldbiblio->{'norequests'} = $norequests;
707 $oldbiblio->{'even'} = $even;
710 $oldbiblio->{'toggle'}="#ffffcc";
712 $oldbiblio->{'toggle'}="white";
713 } ; ## some forms seems to use toggle
715 $oldbiblio->{'itemcount'} = $counts{'total'};
716 my $totalitemcounts = 0;
717 foreach my $key (keys %counts){
718 if ($key ne 'total'){
719 $totalitemcounts+= $counts{$key};
720 $oldbiblio->{'locationhash'}->{$key}=$counts{$key};
724 my ($locationtext, $locationtextonly, $notavailabletext) = ('','','');
725 foreach (sort keys %{$oldbiblio->{'locationhash'}}) {
727 if ($_ eq 'notavailable') {
728 $notavailabletext="Not available";
729 my $c=$oldbiblio->{'locationhash'}->{$_};
730 $oldbiblio->{'not-available-p'}=$c;
733 my $c=$oldbiblio->{'locationhash'}->{$_};
735 $oldbiblio->{'lost-p'} = $c;
736 } elsif ($_ eq 'Withdrawn') {
737 $oldbiblio->{'withdrawn-p'} = $c;
738 } elsif ($_ =~/\^Due:/) {
740 $oldbiblio->{'on-loan-p'} = $c;
742 $locationtextonly.= $_;
743 $locationtextonly.= " ($c)<br> " if $totalitemcounts > 1;
745 if ($totalitemcounts>1) {
746 $locationtext.=" ($c)<br> ";
750 if ($notavailabletext) {
751 $locationtext.= $notavailabletext;
753 $locationtext=~s/, $//;
755 $oldbiblio->{'location'} = $locationtext;
756 $oldbiblio->{'location-only'} = $locationtextonly;
757 $oldbiblio->{'use-location-flags-p'} = 1;
758 push @results,$oldbiblio;
760 }## For each record received
761 @facets_loop=BuildFacets($facets_counter,$facets_info,%branches);
763 return(@facets_loop,@results);
767 my ($facet_record,$facets_counter,$facets_info)=@_;
768 my $facets = C4::Koha::getFacets();
769 for (my $k=0; $k<@$facets;$k++) {
770 my $tags=@$facets->[$k]->{tags};
771 my $subfields=@$facets->[$k]->{subfield};
773 for (my $i=0; $i<@$tags;$i++) {
775 $type="holdings" if @$facets->[$k]->{'link_value'} =~/branch/; ## if using other facets from items add them here
776 if ($type eq "holdings"){
777 ###Read each item record
778 my $holdings=$facet_record->{holdings}->[0]->{record};
779 foreach my $holding(@$holdings){
780 my $data=XML_readline($holding,"","holdings",@$tags[$i],@$subfields[$i]);
781 $facets_counter->{ @$facets->[$k]->{'link_value'} }->{ $data }++ if $data;
784 my $data=XML_readline($facet_record,"","biblios",@$tags[$i],@$subfields[$i]);
785 $facets_counter->{ @$facets->[$k]->{'link_value'} }->{ $data }++ if $data;
788 $facets_info->{ @$facets->[$k]->{'link_value'} }->{ 'label_value' } = @$facets->[$k]->{'label_value'};
789 $facets_info->{ @$facets->[$k]->{'link_value'} }->{ 'expanded' } = @$facets->[$k]->{'expanded'};
791 return ($facets_counter,$facets_info);
795 my ($facets_counter, $facets_info,%branches) = @_;
797 my @facets_loop; # stores the ref to array of hashes for template
799 foreach my $link_value ( sort { $facets_counter->{$b} <=> $facets_counter->{$a} } keys %$facets_counter) {
801 my $number_of_facets;
802 my @this_facets_array;
803 foreach my $one_facet ( sort { $facets_counter->{ $link_value }->{$b} <=> $facets_counter->{ $link_value }->{$a} } keys %{$facets_counter->{$link_value}} ) {
805 if (($number_of_facets < 11) || ($facets_info->{ $link_value }->{ 'expanded'})) {
807 # sanitize the link value ), ( will cause errors with CCL
808 my $facet_link_value = $one_facet;
809 $facet_link_value =~ s/(\(|\))/ /g;
811 # fix the length that will display in the label
812 my $facet_label_value = $one_facet;
813 $facet_label_value = substr($one_facet,0,20)."..." unless length($facet_label_value)<=20;
814 # well, if it's a branch, label by the name, not the code
815 if ($link_value =~/branch/) {
816 $facet_label_value = $branches{$one_facet};
819 # but we're down with the whole label being in the link's title
820 my $facet_title_value = $one_facet;
822 push @this_facets_array ,
823 ( { facet_count => $facets_counter->{ $link_value }->{ $one_facet },
824 facet_label_value => $facet_label_value,
825 facet_title_value => $facet_title_value,
826 facet_link_value => $facet_link_value,
827 type_link_value => $link_value,
830 }## if $number_of_facets
832 unless ($facets_info->{ $link_value }->{ 'expanded'}) {
833 $expandable=1 if ($number_of_facets > 10);
836 { type_link_value => $link_value,
837 type_id => $link_value."_id",
838 type_label => $facets_info->{ $link_value }->{ 'label_value' },
839 facets => \@this_facets_array,
840 expandable => $expandable,
841 expand => $link_value,
846 return \@facets_loop;
851 ## return the address of a cover image if defined otherwise the amazon cover images
854 my $image=XML_readline_onerecord($record,"coverphoto","biblios");
858 # if there is no image put the amazon cover image adress
860 my $isbn=XML_readline_onerecord($record,"isbn","biblios");
861 return "http://images.amazon.com/images/P/".$isbn.".01.MZZZZZZZ.jpg";
866 ($count, $lcount, $nacount, $fcount, $scount, $lostcount,
867 $mending, $transit,$ocount) =
868 &itemcount($env, $biblionumber, $type);
870 Counts the number of items with the given biblionumber, broken down by
875 If C<$type> is not set to C<intra>, lost, very overdue, and withdrawn
876 items will not be counted.
878 C<&itemcount> returns a nine-element list:
880 C<$count> is the total number of items with the given biblionumber.
882 C<$lcount> is the number of items at the Levin branch.
884 C<$nacount> is the number of items that are neither borrowed, lost,
885 nor withdrawn (and are therefore presumably on a shelf somewhere).
887 C<$fcount> is the number of items at the Foxton branch.
889 C<$scount> is the number of items at the Shannon branch.
891 C<$lostcount> is the number of lost and very overdue items.
893 C<$mending> is the number of items at the Mending branch (being
896 C<$transit> is the number of items at the Transit branch (in transit
899 C<$ocount> is the number of items that haven't arrived yet
900 (aqorders.quantity - aqorders.quantityreceived).
908 my ($env,$bibnum,$type)=@_;
909 my $dbh = C4::Context->dbh;
915 my $query="Select * from items where
917 push @kohafield,"biblionumber";
920 my ($total,@result)=ZEBRAsearch_kohafields(\@kohafield,\@value, \@relation,"", \@and_or, 0);## there is only one record no need for $num or $offset
921 my @fields;## extract only the fields required
922 push @fields,"itemnumber","itemlost","wthdrawn","holdingbranch","date_due";
923 my ($biblio,@items)=XMLmarc2koha ($dbh,$result[0],"holdings",\@fields);
933 foreach my $data(@items){
934 if ($type ne "intra"){
935 next if ($data->{itemlost} || $data->{wthdrawn});
936 } ## Probably trying to hide lost item from opac ?
939 ## Now it seems we want to find those which are onloan
942 if ( $data->{date_due} gt "0000-00-00"){
946 ### The rest of this code is hardcoded for Foxtrot Shanon etc. We urgently need a global understanding of these terms--TG
947 if ($data->{'holdingbranch'} eq 'C' || $data->{'holdingbranch'} eq 'LT'){
950 if ($data->{'holdingbranch'} eq 'F' || $data->{'holdingbranch'} eq 'FP'){
953 if ($data->{'holdingbranch'} eq 'S' || $data->{'holdingbranch'} eq 'SP'){
956 if ($data->{'itemlost'} eq '1'){
959 if ($data->{'itemlost'} eq '2'){
962 if ($data->{'holdingbranch'} eq 'FM'){
965 if ($data->{'holdingbranch'} eq 'TR'){
971 my $sth2=$dbh->prepare("Select * from aqorders where biblionumber=?");
972 $sth2->execute($bibnum);
973 if (my $data=$sth2->fetchrow_hashref){
974 $ocount=$data->{'quantity'} - $data->{'quantityreceived'};
978 return ($count,$lcount,$nacount,$fcount,$scount,$lostcount,$mending,$transit,$ocount);
981 END { } # module clean-up code here (global destructor)
990 Koha Developement team <info@koha.org>
991 # New functions to comply with ZEBRA search and new KOHA 3 API added 2006 Tumer Garip tgarip@neu.edu.tr