Merge remote branch 'kc/new/bug_6058' into kcmaster
[koha_fer] / C4 / Search.pm
index 16c6a55..24ed772 100644 (file)
@@ -16,7 +16,7 @@ package C4::Search;
 # Suite 330, Boston, MA  02111-1307 USA
 
 use strict;
-# use warnings; # FIXME
+#use warnings; FIXME - Bug 2505
 require Exporter;
 use C4::Context;
 use C4::Biblio;    # GetMarcFromKohaField, GetBiblioData
@@ -25,10 +25,11 @@ use Lingua::Stem;
 use C4::Search::PazPar2;
 use XML::Simple;
 use C4::Dates qw(format_date);
+use C4::Members qw(GetHideLostItemsPreference);
 use C4::XSLT;
 use C4::Branch;
+use C4::Reserves;    # CheckReserves
 use C4::Debug;
-use YAML;
 use URI::Escape;
 
 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG);
@@ -309,6 +310,7 @@ sub getRecords {
     my $facets_counter = ();
     my $facets_info    = ();
     my $facets         = getFacets();
+    my $facets_maxrecs = C4::Context->preference('maxRecordsForFacets')||20;
 
     my @facets_loop;    # stores the ref to array of hashes for template facets loop
 
@@ -363,10 +365,10 @@ sub getRecords {
                 $sort_by .= "1=9003 >i ";
             }
             elsif ( $sort eq "call_number_asc" ) {
-                $sort_by .= "1=20  <i ";
+                $sort_by .= "1=8007  <i ";
             }
             elsif ( $sort eq "call_number_dsc" ) {
-                $sort_by .= "1=20 >i ";
+                $sort_by .= "1=8007 >i ";
             }
             elsif ( $sort eq "pubdate_asc" ) {
                 $sort_by .= "1=31 <i ";
@@ -390,7 +392,7 @@ sub getRecords {
                 warn "Ignoring unrecognized sort '$sort' requested" if $sort_by;
             }
         }
-        if ($sort_by) {
+        if ($sort_by && !$scan) {
             if ( $results[$i]->sort( "yaz", $sort_by ) < 0 ) {
                 warn "WARNING sort $sort_by failed";
             }
@@ -418,7 +420,6 @@ sub getRecords {
                 for ( my $j = $offset ; $j < $times ; $j++ ) {
                     my $records_hash;
                     my $record;
-                    my $facet_record;
 
                     ## Check if it's an index scan
                     if ($scan) {
@@ -451,33 +452,55 @@ sub getRecords {
 
                         # warn "RECORD $j:".$record;
                         $results_hash->{'RECORDS'}[$j] = $record;
-
-            # Fill the facets while we're looping, but only for the biblioserver
-                        $facet_record = MARC::Record->new_from_usmarc($record)
-                          if $servers[ $i - 1 ] =~ /biblioserver/;
-
-                    #warn $servers[$i-1]."\n".$record; #.$facet_record->title();
-                        if ($facet_record) {
-                            for ( my $k = 0 ; $k <= @$facets ; $k++ ) {
-                                ($facets->[$k]) or next;
-                                my @fields = map {$facet_record->field($_)} @{$facets->[$k]->{'tags'}} ;
-                                for my $field (@fields) {
-                                    my @subfields = $field->subfields();
-                                    for my $subfield (@subfields) {
-                                        my ( $code, $data ) = @$subfield;
-                                        ($code eq $facets->[$k]->{'subfield'}) or next;
-                                        $facets_counter->{ $facets->[$k]->{'link_value'} }->{$data}++;
-                                    }
-                                }
-                                $facets_info->{ $facets->[$k]->{'link_value'} }->{'label_value'} =
-                                    $facets->[$k]->{'label_value'};
-                                $facets_info->{ $facets->[$k]->{'link_value'} }->{'expanded'} =
-                                    $facets->[$k]->{'expanded'};
-                            }
-                        }
                     }
+
                 }
                 $results_hashref->{ $servers[ $i - 1 ] } = $results_hash;
+
+                # Fill the facets while we're looping, but only for the biblioserver and not for a scan
+                if ( !$scan && $servers[ $i - 1 ] =~ /biblioserver/ ) {
+
+                    my $jmax = $size>$facets_maxrecs? $facets_maxrecs: $size;
+
+                    for ( my $k = 0 ; $k <= @$facets ; $k++ ) {
+                        ($facets->[$k]) or next;
+                        my @fcodes = @{$facets->[$k]->{'tags'}};
+                        my $sfcode = $facets->[$k]->{'subfield'};
+
+                               for ( my $j = 0 ; $j < $jmax ; $j++ ) {
+                                   my $render_record = $results[ $i - 1 ]->record($j)->render();
+                            my @used_datas = ();
+
+                            foreach my $fcode (@fcodes) {
+
+                                # avoid first line
+                                my $field_pattern = '\n'.$fcode.' ([^\n]+)';
+                                my @field_tokens = ( $render_record =~ /$field_pattern/g ) ;
+
+                                foreach my $field_token (@field_tokens) {
+                                    my $subfield_pattern = '\$'.$sfcode.' ([^\$]+)';
+                                    my @subfield_values = ( $field_token =~ /$subfield_pattern/g );
+
+                                    foreach my $subfield_value (@subfield_values) {
+
+                                        my $data = $subfield_value;
+                                        $data =~ s/^\s+//; # trim left
+                                        $data =~ s/\s+$//; # trim right
+
+                                        unless ( $data ~~ @used_datas ) {
+                                            $facets_counter->{ $facets->[$k]->{'link_value'} }->{$data}++;
+                                            push @used_datas, $data;
+                                        }
+                                    } # subfields
+                                } # fields
+                            } # field codes
+                        } # records
+
+                        $facets_info->{ $facets->[$k]->{'link_value'} }->{'label_value'} = $facets->[$k]->{'label_value'};
+                        $facets_info->{ $facets->[$k]->{'link_value'} }->{'expanded'} = $facets->[$k]->{'expanded'};
+                    } # facets
+                }
+                # End PROGILONE
             }
 
             # warn "connection ", $i-1, ": $size hits";
@@ -511,9 +534,11 @@ sub getRecords {
 
                             # fix the length that will display in the label,
                             my $facet_label_value = $one_facet;
+                            my $facet_max_length =
+                                C4::Context->preference('FacetLabelTruncationLength') || 20;
                             $facet_label_value =
-                              substr( $one_facet, 0, 20 ) . "..."
-                              unless length($facet_label_value) <= 20;
+                              substr( $one_facet, 0, $facet_max_length ) . "..."
+                                if length($facet_label_value) > $facet_max_length;
 
                             # if it's a branch, label by the name, not the code,
                             if ( $link_value =~ /branch/ ) {
@@ -650,7 +675,6 @@ sub _remove_stopwords {
 #
                foreach ( keys %{ C4::Context->stopwords } ) {
                        next if ( $_ =~ /(and|or|not)/ );    # don't remove operators
-                       $debug && warn "$_ Dump($operand)";
                        if ( my ($matched) = ($operand =~
                                /([^\X\p{isAlnum}]\Q$_\E[^\X\p{isAlnum}]|[^\X\p{isAlnum}]\Q$_\E$|^\Q$_\E[^\X\p{isAlnum}])/gi))
                        {
@@ -814,7 +838,7 @@ sub getIndexes{
                     'biblionumber',
                     'bio',
                     'biography',
-                    'callnum',          
+                    'callnum',
                     'cfn',
                     'Chronological-subdivision',
                     'cn-bib-source',
@@ -856,7 +880,9 @@ sub getIndexes{
                     'id-other',
                     'Illustration-code',
                     'ISBN',
+                    'isbn',
                     'ISSN',
+                    'issn',
                     'itemtype',
                     'kw',
                     'Koha-Auth-Number',
@@ -875,12 +901,14 @@ sub getIndexes{
                     'mc-itemtype',
                     'mc-rtype',
                     'mus',
+                    'name',
                     'Name-geographic',
                     'Name-geographic-heading',
                     'Name-geographic-see',
                     'Name-geographic-seealso',
                     'nb',
                     'Note',
+                    'notes',
                     'ns',
                     'nt',
                     'pb',
@@ -894,6 +922,8 @@ sub getIndexes{
                     'popularity',
                     'pubdate',
                     'Publisher',
+                    'Record-control-number',
+                    'rcn',
                     'Record-type',
                     'rtype',
                     'se',
@@ -927,7 +957,7 @@ sub getIndexes{
                     'Title-uniform-seealso',
                     'totalissues',
                     'yr',
-                    
+
                     # items indexes
                     'acqsource',
                     'barcode',
@@ -944,6 +974,7 @@ sub getIndexes{
                     'holdingbranch',
                     'homebranch',
                     'issues',
+                    'item',
                     'itemnumber',
                     'itype',
                     'Local-classification',
@@ -962,12 +993,14 @@ sub getIndexes{
                     'reserves',
                     'restricted',
                     'stack',
+                    'stocknumber',
+                    'inv',
                     'uri',
                     'withdrawn',
-                    
+
                     # subject related
                   );
-                  
+
     return \@indexes;
 }
 
@@ -1041,7 +1074,13 @@ sub buildQuery {
 # for handling ccl, cql, pqf queries in diagnostic mode, skip the rest of the steps
 # DIAGNOSTIC ONLY!!
     if ( $query =~ /^ccl=/ ) {
-        return ( undef, $', $', "q=ccl=$'", $', '', '', '', '', 'ccl' );
+        my $q=$';
+        # This is needed otherwise ccl= and &limit won't work together, and
+        # this happens when selecting a subject on the opac-detail page
+        if (@limits) {
+            $q .= ' and '.join(' and ', @limits);
+        }
+        return ( undef, $q, $q, "q=ccl=$q", $q, '', '', '', '', 'ccl' );
     }
     if ( $query =~ /^cql=/ ) {
         return ( undef, $', $', "q=cql=$'", $', '', '', '', '', 'cql' );
@@ -1077,15 +1116,18 @@ sub buildQuery {
 
             # COMBINE OPERANDS, INDEXES AND OPERATORS
             if ( $operands[$i] ) {
+               $operands[$i]=~s/^\s+//;
 
               # A flag to determine whether or not to add the index to the query
                 my $indexes_set;
 
 # If the user is sophisticated enough to specify an index, turn off field weighting, stemming, and stopword handling
-                if ( $operands[$i] =~ /(:|=)/ || $scan ) {
+                if ( $operands[$i] =~ /\w(:|=)/ || $scan ) {
                     $weight_fields    = 0;
                     $stemming         = 0;
                     $remove_stopwords = 0;
+                } else {
+                    $operands[$i] =~ s/\?/{?}/g; # need to escape question marks
                 }
                 my $operand = $operands[$i];
                 my $index   = $indexes[$i];
@@ -1114,20 +1156,20 @@ sub buildQuery {
                     ) = ( 0, 0, 0, 0, 0 );
 
                 }
-                
+
                 if(not $index){
                     $index = 'kw';
                 }
-                
+
                 # Set default structure attribute (word list)
-                my $struct_attr;
+                my $struct_attr = q{};
                 unless ( $indexes_set || !$index || $index =~ /(st-|phr|ext|wrdl)/ ) {
                     $struct_attr = ",wrdl";
                 }
 
                 # Some helpful index variants
-                my $index_plus       = $index . $struct_attr . ":" if $index;
-                my $index_plus_comma = $index . $struct_attr . "," if $index;
+                my $index_plus       = $index . $struct_attr . ':';
+                my $index_plus_comma = $index . $struct_attr . ',';
 
                 # Remove Stopwords
                 if ($remove_stopwords) {
@@ -1141,7 +1183,7 @@ sub buildQuery {
                 if ($auto_truncation){
                                        unless ( $index =~ /(st-|phr|ext)/ ) {
                                                #FIXME only valid with LTR scripts
-                                               $operand=join(" ",map{ 
+                                               $operand=join(" ",map{
                                                                                        (index($_,"*")>0?"$_":"$_*")
                                                                                         }split (/\s+/,$operand));
                                                warn $operand if $DEBUG;
@@ -1253,21 +1295,28 @@ sub buildQuery {
     my $group_OR_limits;
     my $availability_limit;
     foreach my $this_limit (@limits) {
-#        if ( $this_limit =~ /available/ ) {
+        if ( $this_limit =~ /available/ ) {
 #
 ## 'available' is defined as (items.onloan is NULL) and (items.itemlost = 0)
 ## In English:
 ## all records not indexed in the onloan register (zebra) and all records with a value of lost equal to 0
-#            $availability_limit .=
-#"( ( allrecords,AlwaysMatches='' not onloan,AlwaysMatches='') and (lost,st-numeric=0) )"; #or ( allrecords,AlwaysMatches='' not lost,AlwaysMatches='')) )";
-#            $limit_cgi  .= "&limit=available";
-#            $limit_desc .= "";
-#        }
-#
+            $availability_limit .=
+"( ( allrecords,AlwaysMatches='' not onloan,AlwaysMatches='') and (lost,st-numeric=0) )"; #or ( allrecords,AlwaysMatches='' not lost,AlwaysMatches='')) )";
+            $limit_cgi  .= "&limit=available";
+            $limit_desc .= "";
+        }
+
         # group_OR_limits, prefixed by mc-
         # OR every member of the group
-#        elsif ( $this_limit =~ /mc/ ) {
-        if ( $this_limit =~ /mc/ ) {
+        elsif ( $this_limit =~ /mc/ ) {
+        
+            if ( $this_limit =~ /mc-ccode:/ ) {
+                # in case the mc-ccode value has complicating chars like ()'s inside it we wrap in quotes
+                $this_limit =~ tr/"//d;
+                my ($k,$v) = split(/:/, $this_limit,2);
+                $this_limit = $k.":\"".$v."\"";
+            }
+
             $group_OR_limits .= " or " if $group_OR_limits;
             $limit_desc      .= " or " if $group_OR_limits;
             $group_OR_limits .= "$this_limit";
@@ -1305,10 +1354,13 @@ sub buildQuery {
     # Normalize the query and limit strings
     # This is flawed , means we can't search anything with : in it
     # if user wants to do ccl or cql, start the query with that
-    $query =~ s/:/=/g;
+#    $query =~ s/:/=/g;
+    $query =~ s/(?<=(ti|au|pb|su|an|kw|mc)):/=/g;
+    $query =~ s/(?<=(wrdl)):/=/g;
+    $query =~ s/(?<=(trn|phr)):/=/g;
     $limit =~ s/:/=/g;
     for ( $query, $query_desc, $limit, $limit_desc ) {
-        s/  / /g;    # remove extra spaces
+        s/  +/ /g;    # remove extra spaces
         s/^ //g;     # remove any beginning spaces
         s/ $//g;     # remove any ending spaces
         s/==/=/g;    # remove double == from query
@@ -1340,6 +1392,10 @@ sub buildQuery {
 
 =head2 searchResults
 
+  my @search_results = searchResults($search_context, $searchdesc, $hits, 
+                                     $results_per_page, $offset, $scan, 
+                                     @marcresults, $hidelostitems);
+
 Format results in a form suitable for passing to the template
 
 =cut
@@ -1347,10 +1403,12 @@ Format results in a form suitable for passing to the template
 # IMO this subroutine is pretty messy still -- it's responsible for
 # building the HTML output for the template
 sub searchResults {
-    my ( $searchdesc, $hits, $results_per_page, $offset, $scan, @marcresults, $hidelostitems ) = @_;
+    my ( $search_context, $searchdesc, $hits, $results_per_page, $offset, $scan, @marcresults, $hidelostitems ) = @_;
     my $dbh = C4::Context->dbh;
     my @newresults;
 
+    $search_context = 'opac' unless $search_context eq 'opac' or $search_context eq 'intranet';
+
     #Build branchnames hash
     #find branchname
     #get branch information.....
@@ -1417,20 +1475,19 @@ sub searchResults {
     # loop through all of the records we've retrieved
     for ( my $i = $offset ; $i <= $times - 1 ; $i++ ) {
         my $marcrecord = MARC::File::USMARC::decode( $marcresults[$i] );
-        if ($bibliotag<10){
-            $fw = GetFrameworkCode($marcrecord->field($bibliotag)->data);
-        }else{
-            $fw = GetFrameworkCode($marcrecord->subfield($bibliotag,$bibliosubf));
-        }
-
+        $fw = $scan
+             ? undef
+             : $bibliotag < 10
+               ? GetFrameworkCode($marcrecord->field($bibliotag)->data)
+               : GetFrameworkCode($marcrecord->subfield($bibliotag,$bibliosubf));
         my $oldbiblio = TransformMarcToKoha( $dbh, $marcrecord, $fw );
         $oldbiblio->{subtitle} = GetRecordValue('subtitle', $marcrecord, $fw);
         $oldbiblio->{result_number} = $i + 1;
 
         # add imageurl to itemtype if there is one
-        $oldbiblio->{imageurl} = getitemtypeimagelocation( 'opac', $itemtypes{ $oldbiblio->{itemtype} }->{imageurl} );
+        $oldbiblio->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $oldbiblio->{itemtype} }->{imageurl} );
 
-        $oldbiblio->{'authorised_value_images'}  = C4::Items::get_authorised_value_images( C4::Biblio::get_biblio_authorised_values( $oldbiblio->{'biblionumber'}, $marcrecord ) );
+        $oldbiblio->{'authorised_value_images'}  = ($search_context eq 'opac' && C4::Context->preference('AuthorisedValueImages')) || ($search_context eq 'intranet' && C4::Context->preference('StaffAuthorisedValueImages')) ? C4::Items::get_authorised_value_images( C4::Biblio::get_biblio_authorised_values( $oldbiblio->{'biblionumber'}, $marcrecord ) ) : [];
                $oldbiblio->{normalized_upc}  = GetNormalizedUPC(       $marcrecord,$marcflavour);
                $oldbiblio->{normalized_ean}  = GetNormalizedEAN(       $marcrecord,$marcflavour);
                $oldbiblio->{normalized_oclc} = GetNormalizedOCLCNumber($marcrecord,$marcflavour);
@@ -1513,6 +1570,7 @@ sub searchResults {
         my $itemdamaged_count     = 0;
         my $item_in_transit_count = 0;
         my $can_place_holds       = 0;
+       my $item_onhold_count     = 0;
         my $items_count           = scalar(@fields);
         my $maxitems =
           ( C4::Context->preference('maxItemsinSearchResults') )
@@ -1540,7 +1598,8 @@ sub searchResults {
 
                        my $prefix = $item->{$hbranch} . '--' . $item->{location} . $item->{itype} . $item->{itemcallnumber};
 # For each grouping of items (onloan, available, unavailable), we build a key to store relevant info about that item
-            if ( $item->{onloan} ) {
+            my $userenv = C4::Context->userenv;
+            if ( $item->{onloan} && !(C4::Members::GetHideLostItemsPreference($userenv->{'number'}) && $item->{itemlost}) ) {
                 $onloan_count++;
                                my $key = $prefix . $item->{onloan} . $item->{barcode};
                                $onloan_items->{$key}->{due_date} = format_date($item->{onloan});
@@ -1548,7 +1607,7 @@ sub searchResults {
                                $onloan_items->{$key}->{branchname} = $item->{branchname};
                                $onloan_items->{$key}->{location} = $shelflocations->{ $item->{location} };
                                $onloan_items->{$key}->{itemcallnumber} = $item->{itemcallnumber};
-                               $onloan_items->{$key}->{imageurl} = getitemtypeimagelocation( 'opac', $itemtypes{ $item->{itype} }->{imageurl} );
+                               $onloan_items->{$key}->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $item->{itype} }->{imageurl} );
                 # if something's checked out and lost, mark it as 'long overdue'
                 if ( $item->{itemlost} ) {
                     $onloan_items->{$prefix}->{longoverdue}++;
@@ -1570,6 +1629,10 @@ sub searchResults {
                 my $transfertwhen = '';
                 my ($transfertfrom, $transfertto);
 
+                # is item on the reserve shelf?
+               my $reservestatus = 0;
+               my $reserveitem;
+
                 unless ($item->{wthdrawn}
                         || $item->{itemlost}
                         || $item->{damaged}
@@ -1589,19 +1652,22 @@ sub searchResults {
                     #        should map transit status to record indexed in Zebra.
                     #
                     ($transfertwhen, $transfertfrom, $transfertto) = C4::Circulation::GetTransfers($item->{itemnumber});
+                   ($reservestatus, $reserveitem) = C4::Reserves::CheckReserves($item->{itemnumber});
                 }
 
                 # item is withdrawn, lost or damaged
                 if (   $item->{wthdrawn}
                     || $item->{itemlost}
                     || $item->{damaged}
-                    || $item->{notforloan}
+                    || $item->{notforloan} > 0
+                   || $reservestatus eq 'Waiting'
                     || ($transfertwhen ne ''))
                 {
                     $wthdrawn_count++        if $item->{wthdrawn};
                     $itemlost_count++        if $item->{itemlost};
                     $itemdamaged_count++     if $item->{damaged};
                     $item_in_transit_count++ if $transfertwhen ne '';
+                   $item_onhold_count++     if $reservestatus eq 'Waiting';
                     $item->{status} = $item->{wthdrawn} . "-" . $item->{itemlost} . "-" . $item->{damaged} . "-" . $item->{notforloan};
                     $other_count++;
 
@@ -1610,10 +1676,11 @@ sub searchResults {
                        $other_items->{$key}->{$_} = $item->{$_};
                                        }
                     $other_items->{$key}->{intransit} = ($transfertwhen ne '') ? 1 : 0;
+                    $other_items->{$key}->{onhold} = ($reservestatus) ? 1 : 0;
                                        $other_items->{$key}->{notforloan} = GetAuthorisedValueDesc('','',$item->{notforloan},'','',$notforloan_authorised_value) if $notforloan_authorised_value;
                                        $other_items->{$key}->{count}++ if $item->{$hbranch};
                                        $other_items->{$key}->{location} = $shelflocations->{ $item->{location} };
-                                       $other_items->{$key}->{imageurl} = getitemtypeimagelocation( 'opac', $itemtypes{ $item->{itype} }->{imageurl} );
+                                       $other_items->{$key}->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $item->{itype} }->{imageurl} );
                 }
                 # item is available
                 else {
@@ -1624,7 +1691,7 @@ sub searchResults {
                        $available_items->{$prefix}->{$_} = $item->{$_};
                                        }
                                        $available_items->{$prefix}->{location} = $shelflocations->{ $item->{location} };
-                                       $available_items->{$prefix}->{imageurl} = getitemtypeimagelocation( 'opac', $itemtypes{ $item->{itype} }->{imageurl} );
+                                       $available_items->{$prefix}->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $item->{itype} }->{imageurl} );
                 }
             }
         }    # notforloan, item level and biblioitem level
@@ -1647,18 +1714,24 @@ sub searchResults {
         }
 
         # XSLT processing of some stuff
-       my $debug=1;
        use C4::Charset;
        SetUTF8Flag($marcrecord);
        $debug && warn $marcrecord->as_formatted;
-        if (C4::Context->preference("XSLTResultsDisplay") && !$scan) {
-            $oldbiblio->{XSLTResultsRecord} = XSLTParse4Display(
-                $oldbiblio->{biblionumber}, $marcrecord, 'Results' );
+        if (!$scan && $search_context eq 'opac' && C4::Context->preference("OPACXSLTResultsDisplay")) {
+            # FIXME note that XSLTResultsDisplay (use of XSLT to format staff interface bib search results)
+            # is not implemented yet
+            $oldbiblio->{XSLTResultsRecord} = XSLTParse4Display($oldbiblio->{biblionumber}, $marcrecord, 'Results', 
+                                                                $search_context, 1);
+                # the last parameter tells Koha to clean up the problematic ampersand entities that Zebra outputs
+
         }
 
-        # last check for norequest : if itemtype is notforloan, it can't be reserved either, whatever the items
-        $can_place_holds = 0
-          if $itemtypes{ $oldbiblio->{itemtype} }->{notforloan};
+        # if biblio level itypes are used and itemtype is notforloan, it can't be reserved either
+        if (!C4::Context->preference("item-level_itypes")) {
+            if ($itemtypes{ $oldbiblio->{itemtype} }->{notforloan}) {
+                $can_place_holds = 0;
+            }
+        }
         $oldbiblio->{norequests} = 1 unless $can_place_holds;
         $oldbiblio->{itemsplural}          = 1 if $items_count > 1;
         $oldbiblio->{items_count}          = $items_count;
@@ -1675,9 +1748,39 @@ sub searchResults {
         $oldbiblio->{itemlostcount}        = $itemlost_count;
         $oldbiblio->{damagedcount}         = $itemdamaged_count;
         $oldbiblio->{intransitcount}       = $item_in_transit_count;
+        $oldbiblio->{onholdcount}          = $item_onhold_count;
         $oldbiblio->{orderedcount}         = $ordered_count;
         $oldbiblio->{isbn} =~
           s/-//g;    # deleting - in isbn to enable amazon content
+
+        if (C4::Context->preference("AlternateHoldingsField") && $items_count == 0) {
+            my $fieldspec = C4::Context->preference("AlternateHoldingsField");
+            my $subfields = substr $fieldspec, 3;
+            my $holdingsep = C4::Context->preference("AlternateHoldingsSeparator") || ' ';
+            my @alternateholdingsinfo = ();
+            my @holdingsfields = $marcrecord->field(substr $fieldspec, 0, 3);
+            my $alternateholdingscount = 0;
+
+            for my $field (@holdingsfields) {
+                my %holding = ( holding => '' );
+                my $havesubfield = 0;
+                for my $subfield ($field->subfields()) {
+                    if ((index $subfields, $$subfield[0]) >= 0) {
+                        $holding{'holding'} .= $holdingsep if (length $holding{'holding'} > 0);
+                        $holding{'holding'} .= $$subfield[1];
+                        $havesubfield++;
+                    }
+                }
+                if ($havesubfield) {
+                    push(@alternateholdingsinfo, \%holding);
+                    $alternateholdingscount++;
+                }
+            }
+
+            $oldbiblio->{'ALTERNATEHOLDINGS'} = \@alternateholdingsinfo;
+            $oldbiblio->{'alternateholdings_count'} = $alternateholdingscount;
+        }
+
         push( @newresults, $oldbiblio )
             if(not $hidelostitems
                or (($items_count > $itemlost_count )
@@ -1893,7 +1996,6 @@ sub NZanalyse {
         # depending of operand, intersect, union or exclude both lists
         # to get a result list
         if ( $operator eq ' and ' ) {
-            warn "NZAND";
             return NZoperatorAND($leftresult,$rightresult);
         }
         elsif ( $operator eq ' or ' ) {
@@ -2507,6 +2609,7 @@ OR adds a new authority record
 
 =item C<BUGS>
     * I had to add this to Search.pm (instead of the logical Biblio.pm) because of a circular dependency (this sub uses SimpleSearch, and Search.pm uses Biblio.pm)
+
 =back
 
 =cut
@@ -2553,7 +2656,7 @@ AND (authtypecode IS NOT NULL AND authtypecode<>\"\")|);
   #There are no results, build authority record, add it to Authorities, get authid and add it to 9
   ###NOTICE : This is only valid if a subfield is linked to one and only one authtypecode
   ###NOTICE : This can be a problem. We should also look into other types and rejected forms.
-         my $authtypedata=C4::AuthoritiesMarc->GetAuthType($data->{authtypecode});
+         my $authtypedata=C4::AuthoritiesMarc::GetAuthType($data->{authtypecode});
          next unless $authtypedata;
          my $marcrecordauth=MARC::Record->new();
          my $authfield=MARC::Field->new($authtypedata->{auth_tag_to_report},'','',"a"=>"".$field->subfield('a'));
@@ -2593,7 +2696,7 @@ sub GetDistinctValues {
     if ($fieldname=~/\./){
                        my ($table,$column)=split /\./, $fieldname;
                        my $dbh = C4::Context->dbh;
-                       warn "select DISTINCT($column) as value, count(*) as cnt from $table group by lib order by $column ";
+                       warn "select DISTINCT($column) as value, count(*) as cnt from $table group by lib order by $column " if $DEBUG;
                        my $sth = $dbh->prepare("select DISTINCT($column) as value, count(*) as cnt from $table ".($string?" where $column like \"$string%\"":"")."group by value order by $column ");
                        $sth->execute;
                        my $elements=$sth->fetchall_arrayref({});
@@ -2638,6 +2741,6 @@ __END__
 
 =head1 AUTHOR
 
-Koha Developement team <info@koha.org>
+Koha Development Team <http://koha-community.org/>
 
 =cut