Bug 24394: Typo when adding a new cash register
[koha-ffzg.git] / C4 / Search.pm
index a23fe13..5d68165 100644 (file)
@@ -15,32 +15,32 @@ package C4::Search;
 # You should have received a copy of the GNU General Public License
 # along with Koha; if not, see <http://www.gnu.org/licenses>.
 
 # You should have received a copy of the GNU General Public License
 # along with Koha; if not, see <http://www.gnu.org/licenses>.
 
-use strict;
-#use warnings; FIXME - Bug 2505
+use Modern::Perl;
 require Exporter;
 use C4::Context;
 use C4::Biblio;    # GetMarcFromKohaField, GetBiblioData
 use C4::Koha;      # getFacets
 use Koha::DateUtils;
 require Exporter;
 use C4::Context;
 use C4::Biblio;    # GetMarcFromKohaField, GetBiblioData
 use C4::Koha;      # getFacets
 use Koha::DateUtils;
+use Koha::Libraries;
 use Lingua::Stem;
 use C4::Search::PazPar2;
 use XML::Simple;
 use Lingua::Stem;
 use C4::Search::PazPar2;
 use XML::Simple;
-use C4::Members qw(GetHideLostItemsPreference);
 use C4::XSLT;
 use C4::XSLT;
-use C4::Branch;
 use C4::Reserves;    # GetReserveStatus
 use C4::Debug;
 use C4::Charset;
 use C4::Reserves;    # GetReserveStatus
 use C4::Debug;
 use C4::Charset;
+use Koha::AuthorisedValues;
+use Koha::ItemTypes;
+use Koha::Libraries;
+use Koha::Patrons;
 use YAML;
 use URI::Escape;
 use Business::ISBN;
 use MARC::Record;
 use MARC::Field;
 use YAML;
 use URI::Escape;
 use Business::ISBN;
 use MARC::Record;
 use MARC::Field;
-use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG);
+use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG);
 
 
-# set the version for version checking
 BEGIN {
 BEGIN {
-    $VERSION = 3.07.00.049;
     $DEBUG = ($ENV{DEBUG}) ? 1 : 0;
 }
 
     $DEBUG = ($ENV{DEBUG}) ? 1 : 0;
 }
 
@@ -84,7 +84,7 @@ This function attempts to find duplicate records using a hard-coded, fairly simp
 sub FindDuplicate {
     my ($record) = @_;
     my $dbh = C4::Context->dbh;
 sub FindDuplicate {
     my ($record) = @_;
     my $dbh = C4::Context->dbh;
-    my $result = TransformMarcToKoha( $dbh, $record, '' );
+    my $result = TransformMarcToKoha( $record, '' );
     my $sth;
     my $query;
     my $search;
     my $sth;
     my $query;
     my $search;
@@ -146,7 +146,7 @@ sub FindDuplicate {
                 $possible_duplicate_record
             );
 
                 $possible_duplicate_record
             );
 
-            my $result = TransformMarcToKoha( $dbh, $marcrecord, '' );
+            my $result = TransformMarcToKoha( $marcrecord, '' );
 
             # FIXME :: why 2 $biblionumber ?
             if ($result) {
 
             # FIXME :: why 2 $biblionumber ?
             if ($result) {
@@ -160,7 +160,7 @@ sub FindDuplicate {
 
 =head2 SimpleSearch
 
 
 =head2 SimpleSearch
 
-( $error, $results, $total_hits ) = SimpleSearch( $query, $offset, $max_results, [@servers] );
+( $error, $results, $total_hits ) = SimpleSearch( $query, $offset, $max_results, [@servers], [%options] );
 
 This function provides a simple search API on the bibliographic catalog
 
 
 This function provides a simple search API on the bibliographic catalog
 
@@ -172,6 +172,7 @@ This function provides a simple search API on the bibliographic catalog
     * @servers is optional. Defaults to biblioserver as found in koha-conf.xml
     * $offset - If present, represents the number of records at the beginning to omit. Defaults to 0
     * $max_results - if present, determines the maximum number of records to fetch. undef is All. defaults to undef.
     * @servers is optional. Defaults to biblioserver as found in koha-conf.xml
     * $offset - If present, represents the number of records at the beginning to omit. Defaults to 0
     * $max_results - if present, determines the maximum number of records to fetch. undef is All. defaults to undef.
+    * %options is optional. (e.g. "skip_normalize" allows you to skip changing : to = )
 
 
 =item C<Return:>
 
 
 =item C<Return:>
@@ -202,7 +203,7 @@ my @results;
 
 for my $r ( @{$marcresults} ) {
     my $marcrecord = MARC::File::USMARC::decode($r);
 
 for my $r ( @{$marcresults} ) {
     my $marcrecord = MARC::File::USMARC::decode($r);
-    my $biblio = TransformMarcToKoha(C4::Context->dbh,$marcrecord,q{});
+    my $biblio = TransformMarcToKoha($marcrecord,q{});
 
     #build the iarray of hashs for the template.
     push @results, {
 
     #build the iarray of hashs for the template.
     push @results, {
@@ -221,7 +222,7 @@ $template->param(result=>\@results);
 =cut
 
 sub SimpleSearch {
 =cut
 
 sub SimpleSearch {
-    my ( $query, $offset, $max_results, $servers )  = @_;
+    my ( $query, $offset, $max_results, $servers, %options )  = @_;
 
     return ( 'No query entered', undef, undef ) unless $query;
     # FIXME hardcoded value. See catalog/search.pl & opac-search.pl too.
 
     return ( 'No query entered', undef, undef ) unless $query;
     # FIXME hardcoded value. See catalog/search.pl & opac-search.pl too.
@@ -243,12 +244,12 @@ sub SimpleSearch {
         eval {
             $zconns[$i] = C4::Context->Zconn( $servers[$i], 1 );
             if ($QParser) {
         eval {
             $zconns[$i] = C4::Context->Zconn( $servers[$i], 1 );
             if ($QParser) {
-                $query =~ s/=/:/g;
+                $query =~ s/=/:/g unless $options{skip_normalize};
                 $QParser->parse( $query );
                 $query = $QParser->target_syntax($servers[$i]);
                 $zoom_queries[$i] = new ZOOM::Query::PQF( $query, $zconns[$i]);
             } else {
                 $QParser->parse( $query );
                 $query = $QParser->target_syntax($servers[$i]);
                 $zoom_queries[$i] = new ZOOM::Query::PQF( $query, $zconns[$i]);
             } else {
-                $query =~ s/:/=/g;
+                $query =~ s/:/=/g unless $options{skip_normalize};
                 $zoom_queries[$i] = new ZOOM::Query::CCL2RPN( $query, $zconns[$i]);
             }
             $tmpresults[$i] = $zconns[$i]->search( $zoom_queries[$i] );
                 $zoom_queries[$i] = new ZOOM::Query::CCL2RPN( $query, $zconns[$i]);
             }
             $tmpresults[$i] = $zconns[$i]->search( $zoom_queries[$i] );
@@ -310,26 +311,27 @@ sub SimpleSearch {
 ( undef, $results_hashref, \@facets_loop ) = getRecords (
 
         $koha_query,       $simple_query, $sort_by_ref,    $servers_ref,
 ( undef, $results_hashref, \@facets_loop ) = getRecords (
 
         $koha_query,       $simple_query, $sort_by_ref,    $servers_ref,
-        $results_per_page, $offset,       $expanded_facet, $branches,$itemtypes,
-        $query_type,       $scan
+        $results_per_page, $offset,       $branches,       $itemtypes,
+        $query_type,       $scan,         $opac
     );
 
 The all singing, all dancing, multi-server, asynchronous, scanning,
 searching, record nabbing, facet-building
 
     );
 
 The all singing, all dancing, multi-server, asynchronous, scanning,
 searching, record nabbing, facet-building
 
-See verbse embedded documentation.
+See verbose embedded documentation.
 
 =cut
 
 sub getRecords {
     my (
         $koha_query,       $simple_query, $sort_by_ref,    $servers_ref,
 
 =cut
 
 sub getRecords {
     my (
         $koha_query,       $simple_query, $sort_by_ref,    $servers_ref,
-        $results_per_page, $offset,       $expanded_facet, $branches,
-        $itemtypes,        $query_type,   $scan,           $opac
+        $results_per_page, $offset,       $branches,         $itemtypes,
+        $query_type,       $scan,         $opac
     ) = @_;
 
     my @servers = @$servers_ref;
     my @sort_by = @$sort_by_ref;
     ) = @_;
 
     my @servers = @$servers_ref;
     my @sort_by = @$sort_by_ref;
+    $offset = 0 if $offset < 0;
 
     # Initialize variables for the ZOOM connection and results object
     my $zconn;
 
     # Initialize variables for the ZOOM connection and results object
     my $zconn;
@@ -337,6 +339,9 @@ sub getRecords {
     my @results;
     my $results_hashref = ();
 
     my @results;
     my $results_hashref = ();
 
+    # TODO simplify this structure ( { branchcode => $branchname } is enought) and remove this parameter
+    $branches ||= { map { $_->branchcode => { branchname => $_->branchname } } Koha::Libraries->search };
+
     # Initialize variables for the faceted results objects
     my $facets_counter = {};
     my $facets_info    = {};
     # Initialize variables for the faceted results objects
     my $facets_counter = {};
     my $facets_info    = {};
@@ -510,8 +515,6 @@ sub getRecords {
                         keys %$facets_counter
                       )
                     {
                         keys %$facets_counter
                       )
                     {
-                        my $expandable;
-                        my $number_of_facets;
                         my @this_facets_array;
                         for my $one_facet (
                             sort {
                         my @this_facets_array;
                         for my $one_facet (
                             sort {
@@ -521,87 +524,80 @@ sub getRecords {
                             } keys %{ $facets_counter->{$link_value} }
                           )
                         {
                             } keys %{ $facets_counter->{$link_value} }
                           )
                         {
-                            $number_of_facets++;
-                            if (   ( $number_of_facets <= 5 )
-                                || ( $expanded_facet eq $link_value )
-                                || ( $facets_info->{$link_value}->{'expanded'} )
-                              )
-                            {
-
 # Sanitize the link value : parenthesis, question and exclamation mark will cause errors with CCL
 # Sanitize the link value : parenthesis, question and exclamation mark will cause errors with CCL
-                                my $facet_link_value = $one_facet;
-                                $facet_link_value =~ s/[()!?¡¿؟]/ /g;
-
-                                # 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, $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/ ) {
-                                    if (   defined $branches
-                                        && ref($branches) eq "HASH"
-                                        && defined $branches->{$one_facet}
-                                        && ref( $branches->{$one_facet} ) eq
-                                        "HASH" )
-                                    {
-                                        $facet_label_value =
-                                          $branches->{$one_facet}
-                                          ->{'branchname'};
-                                    }
-                                    else {
-                                        $facet_label_value = "*";
-                                    }
+                            my $facet_link_value = $one_facet;
+                            $facet_link_value =~ s/[()!?¡¿؟]/ /g;
+
+                            # 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, $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/ ) {
+                                if (   defined $branches
+                                    && ref($branches) eq "HASH"
+                                    && defined $branches->{$one_facet}
+                                    && ref( $branches->{$one_facet} ) eq
+                                    "HASH" )
+                                {
+                                    $facet_label_value =
+                                      $branches->{$one_facet}
+                                      ->{'branchname'};
                                 }
                                 }
-
-                          # if it's a itemtype, label by the name, not the code,
-                                if ( $link_value =~ /itype/ ) {
-                                    if (   defined $itemtypes
-                                        && ref($itemtypes) eq "HASH"
-                                        && defined $itemtypes->{$one_facet}
-                                        && ref( $itemtypes->{$one_facet} ) eq
-                                        "HASH" )
-                                    {
-                                        $facet_label_value =
-                                          $itemtypes->{$one_facet}
-                                          ->{translated_description};
-                                    }
+                                else {
+                                    $facet_label_value = "*";
                                 }
                                 }
+                            }
 
 
-               # also, if it's a location code, use the name instead of the code
-                                if ( $link_value =~ /location/ ) {
+                      # if it's a itemtype, label by the name, not the code,
+                            if ( $link_value =~ /itype/ ) {
+                                if (   defined $itemtypes
+                                    && ref($itemtypes) eq "HASH"
+                                    && defined $itemtypes->{$one_facet}
+                                    && ref( $itemtypes->{$one_facet} ) eq
+                                    "HASH" )
+                                {
                                     $facet_label_value =
                                     $facet_label_value =
-                                      GetKohaAuthorisedValueLib( 'LOC',
-                                        $one_facet, $opac );
+                                      $itemtypes->{$one_facet}
+                                      ->{translated_description};
                                 }
                                 }
+                            }
 
 
-                # but we're down with the whole label being in the link's title.
-                                push @this_facets_array,
-                                  {
-                                    facet_count =>
-                                      $facets_counter->{$link_value}
-                                      ->{$one_facet},
-                                    facet_label_value => $facet_label_value,
-                                    facet_title_value => $one_facet,
-                                    facet_link_value  => $facet_link_value,
-                                    type_link_value   => $link_value,
-                                  }
-                                  if ($facet_label_value);
+           # also, if it's a location code, use the name instead of the code
+                            if ( $link_value =~ /location/ ) {
+                                # TODO Retrieve all authorised values at once, instead of 1 query per entry
+                                my $av = Koha::AuthorisedValues->search({ category => 'LOC', authorised_value => $one_facet });
+                                $facet_label_value = $av->count ? $av->next->opac_description : '';
                             }
                             }
-                        }
 
 
-                        # handle expanded option
-                        unless ( $facets_info->{$link_value}->{'expanded'} ) {
-                            $expandable = 1
-                              if ( ( $number_of_facets > 5 )
-                                && ( $expanded_facet ne $link_value ) );
+                            # also, if it's a collection code, use the name instead of the code
+                            if ( $link_value =~ /ccode/ ) {
+                                # TODO Retrieve all authorised values at once, instead of 1 query per entry
+                                my $av = Koha::AuthorisedValues->search({ category => 'CCODE', authorised_value => $one_facet });
+                                $facet_label_value = $av->count ? $av->next->opac_description : '';
+                            }
+
+            # but we're down with the whole label being in the link's title.
+                            push @this_facets_array,
+                              {
+                                facet_count =>
+                                  $facets_counter->{$link_value}
+                                  ->{$one_facet},
+                                facet_label_value => $facet_label_value,
+                                facet_title_value => $one_facet,
+                                facet_link_value  => $facet_link_value,
+                                type_link_value   => $link_value,
+                              }
+                              if ($facet_label_value);
                         }
                         }
+
                         push @facets_loop,
                           {
                             type_link_value => $link_value,
                         push @facets_loop,
                           {
                             type_link_value => $link_value,
@@ -610,20 +606,27 @@ sub getRecords {
                               . $facets_info->{$link_value}->{'label_value'} =>
                               1,
                             facets     => \@this_facets_array,
                               . $facets_info->{$link_value}->{'label_value'} =>
                               1,
                             facets     => \@this_facets_array,
-                            expandable => $expandable,
-                            expand     => $link_value,
                           }
                           unless (
                             (
                                 $facets_info->{$link_value}->{'label_value'} =~
                                 /Libraries/
                             )
                           }
                           unless (
                             (
                                 $facets_info->{$link_value}->{'label_value'} =~
                                 /Libraries/
                             )
-                            and ( C4::Context->preference('singleBranchMode') )
+                            and ( Koha::Libraries->search->count == 1 )
                           );
                     }
                 }
             }
         );
                           );
                     }
                 }
             }
         );
+
+    # This sorts the facets into alphabetical order
+    if (@facets_loop) {
+        foreach my $f (@facets_loop) {
+            $f->{facets} = [ sort { uc($a->{facet_label_value}) cmp uc($b->{facet_label_value}) } @{ $f->{facets} } ];
+        }
+        @facets_loop = sort {$a->{expand} cmp $b->{expand}} @facets_loop;
+    }
+
     return ( undef, $results_hashref, \@facets_loop );
 }
 
     return ( undef, $results_hashref, \@facets_loop );
 }
 
@@ -632,11 +635,9 @@ sub GetFacets {
     my $rs = shift;
     my $facets;
 
     my $rs = shift;
     my $facets;
 
-    my $indexing_mode    = C4::Context->config('zebra_bib_index_mode') // 'dom';
     my $use_zebra_facets = C4::Context->config('use_zebra_facets') // 0;
 
     my $use_zebra_facets = C4::Context->config('use_zebra_facets') // 0;
 
-    if ( $indexing_mode eq 'dom' &&
-         $use_zebra_facets ) {
+    if ( $use_zebra_facets ) {
         $facets = _get_facets_from_zebra( $rs );
     } else {
         $facets = _get_facets_from_records( $rs );
         $facets = _get_facets_from_zebra( $rs );
     } else {
         $facets = _get_facets_from_records( $rs );
@@ -832,7 +833,6 @@ sub _get_facets_info {
 
     for my $facet ( @$facets ) {
         $facets_info->{ $facet->{ idx } }->{ label_value } = $facet->{ label };
 
     for my $facet ( @$facets ) {
         $facets_info->{ $facet->{ idx } }->{ label_value } = $facet->{ label };
-        $facets_info->{ $facet->{ idx } }->{ expanded }    = $facet->{ expanded };
     }
 
     return $facets_info;
     }
 
     return $facets_info;
@@ -841,9 +841,10 @@ sub _get_facets_info {
 sub pazGetRecords {
     my (
         $koha_query,       $simple_query, $sort_by_ref,    $servers_ref,
 sub pazGetRecords {
     my (
         $koha_query,       $simple_query, $sort_by_ref,    $servers_ref,
-        $results_per_page, $offset,       $expanded_facet, $branches,
-        $query_type,       $scan
+        $results_per_page, $offset,       $branches,       $query_type,
+        $scan
     ) = @_;
     ) = @_;
+    #NOTE: Parameter $branches is not used here !
 
     my $paz = C4::Search::PazPar2->new(C4::Context->config('pazpar2url'));
     $paz->init();
 
     my $paz = C4::Search::PazPar2->new(C4::Context->config('pazpar2url'));
     $paz->init();
@@ -947,6 +948,9 @@ sub _build_stemmed_operand {
     require Lingua::Stem::Snowball ;
     my $stemmed_operand=q{};
 
     require Lingua::Stem::Snowball ;
     my $stemmed_operand=q{};
 
+    # Stemmer needs language
+    return $operand unless $lang;
+
     # If operand contains a digit, it is almost certainly an identifier, and should
     # not be stemmed.  This is particularly relevant for ISBNs and ISSNs, which
     # can contain the letter "X" - for example, _build_stemmend_operand would reduce
     # If operand contains a digit, it is almost certainly an identifier, and should
     # not be stemmed.  This is particularly relevant for ISBNs and ISSNs, which
     # can contain the letter "X" - for example, _build_stemmend_operand would reduce
@@ -1021,6 +1025,11 @@ sub _build_weighted_query {
         $weighted_query .= "an=\"$operand\"";
     }
 
         $weighted_query .= "an=\"$operand\"";
     }
 
+    # If the index is numeric, don't autoquote it.
+    elsif ( $index =~ /,st-numeric$/ ) {
+        $weighted_query .= " $index=$operand";
+    }
+
     # If the index already has more than one qualifier, wrap the operand
     # in quotes and pass it back (assumption is that the user knows what they
     # are doing and won't appreciate us mucking up their query
     # If the index already has more than one qualifier, wrap the operand
     # in quotes and pass it back (assumption is that the user knows what they
     # are doing and won't appreciate us mucking up their query
@@ -1060,6 +1069,8 @@ sub getIndexes{
                     'an',
                     'Any',
                     'at',
                     'an',
                     'Any',
                     'at',
+                    'arl',
+                    'arp',
                     'au',
                     'aub',
                     'aud',
                     'au',
                     'aub',
                     'aud',
@@ -1104,9 +1115,11 @@ sub getIndexes{
                     'date-entered-on-file',
                     'Date-of-acquisition',
                     'Date-of-publication',
                     'date-entered-on-file',
                     'Date-of-acquisition',
                     'Date-of-publication',
+                    'Date-time-last-modified',
                     'Dewey-classification',
                     'Dissertation-information',
                     'diss',
                     'Dewey-classification',
                     'Dissertation-information',
                     'diss',
+                    'dtlm',
                     'EAN',
                     'extent',
                     'fic',
                     'EAN',
                     'extent',
                     'fic',
@@ -1121,9 +1134,13 @@ sub getIndexes{
                     'Heading-use-subject-added-entry',
                     'Host-item',
                     'id-other',
                     'Heading-use-subject-added-entry',
                     'Host-item',
                     'id-other',
+                    'ident',
+                    'Identifier-standard',
                     'Illustration-code',
                     'Index-term-genre',
                     'Index-term-uncontrolled',
                     'Illustration-code',
                     'Index-term-genre',
                     'Index-term-uncontrolled',
+                    'Interest-age-level',
+                    'Interest-grade-level',
                     'ISBN',
                     'isbn',
                     'ISSN',
                     'ISBN',
                     'isbn',
                     'ISSN',
@@ -1138,6 +1155,7 @@ sub getIndexes{
                     'LC-card-number',
                     'lcn',
                     'lex',
                     'LC-card-number',
                     'lcn',
                     'lex',
+                    'lexile-number',
                     'llength',
                     'ln',
                     'ln-audio',
                     'llength',
                     'ln',
                     'ln-audio',
@@ -1161,6 +1179,7 @@ sub getIndexes{
                     'notes',
                     'ns',
                     'nt',
                     'notes',
                     'ns',
                     'nt',
+                    'Other-control-number',
                     'pb',
                     'Personal-name',
                     'Personal-name-heading',
                     'pb',
                     'Personal-name',
                     'Personal-name-heading',
@@ -1174,6 +1193,7 @@ sub getIndexes{
                     'Publisher',
                     'Provider',
                     'pv',
                     'Publisher',
                     'Provider',
                     'pv',
+                    'Reading-grade-level',
                     'Record-control-number',
                     'rcn',
                     'Record-type',
                     'Record-control-number',
                     'rcn',
                     'Record-type',
@@ -1305,12 +1325,13 @@ sub _handle_exploding_index {
 
     ( $operators, $operands, $indexes, $limits,
       $sort_by, $scan, $lang ) =
 
     ( $operators, $operands, $indexes, $limits,
       $sort_by, $scan, $lang ) =
-            buildQuery ( $operators, $operands, $indexes, $limits, $sort_by, $scan, $lang);
+            parseQuery ( $operators, $operands, $indexes, $limits, $sort_by, $scan, $lang);
 
 Shim function to ease the transition from buildQuery to a new QueryParser.
 This function is called at the beginning of buildQuery, and modifies
 buildQuery's input. If it can handle the input, it returns a query that
 buildQuery will not try to parse.
 
 Shim function to ease the transition from buildQuery to a new QueryParser.
 This function is called at the beginning of buildQuery, and modifies
 buildQuery's input. If it can handle the input, it returns a query that
 buildQuery will not try to parse.
+
 =cut
 
 sub parseQuery {
 =cut
 
 sub parseQuery {
@@ -1448,10 +1469,19 @@ sub buildQuery {
         # This is needed otherwise ccl= and &limit won't work together, and
         # this happens when selecting a subject on the opac-detail page
         @limits = grep {!/^$/} @limits;
         # This is needed otherwise ccl= and &limit won't work together, and
         # this happens when selecting a subject on the opac-detail page
         @limits = grep {!/^$/} @limits;
+        my $original_q = $q; # without available part
+        unless ( grep { /^available$/ } @limits ) {
+            $q =~ s| and \( \(allrecords,AlwaysMatches=''\) and \(not-onloan-count,st-numeric >= 1\) and \(lost,st-numeric=0\) \)||;
+            $original_q = $q;
+        }
         if ( @limits ) {
         if ( @limits ) {
-            $q .= ' and '.join(' and ', @limits);
+            if ( grep { /^available$/ } @limits ) {
+                $q .= q| and ( (allrecords,AlwaysMatches='') and (not-onloan-count,st-numeric >= 1) and (lost,st-numeric=0) )|;
+                delete $limits['available'];
+            }
+            $q .= ' and '.join(' and ', @limits) if @limits;
         }
         }
-        return ( undef, $q, $q, "q=ccl=".uri_escape_utf8($q), $q, '', '', '', 'ccl' );
+        return ( undef, $q, $q, "q=ccl=".uri_escape_utf8($q), $original_q, '', '', '', 'ccl' );
     }
     if ( $query =~ /^cql=/ ) {
         return ( undef, $', $', "q=cql=".uri_escape_utf8($'), $', '', '', '', 'cql' );
     }
     if ( $query =~ /^cql=/ ) {
         return ( undef, $', $', "q=cql=".uri_escape_utf8($'), $', '', '', '', 'cql' );
@@ -1492,7 +1522,7 @@ sub buildQuery {
         for ( my $i = 0 ; $i <= @operands ; $i++ ) {
 
             # COMBINE OPERANDS, INDEXES AND OPERATORS
         for ( my $i = 0 ; $i <= @operands ; $i++ ) {
 
             # COMBINE OPERANDS, INDEXES AND OPERATORS
-            if ( $operands[$i] ) {
+            if ( ($operands[$i] // '') ne '' ) {
                $operands[$i]=~s/^\s+//;
 
               # A flag to determine whether or not to add the index to the query
                $operands[$i]=~s/^\s+//;
 
               # A flag to determine whether or not to add the index to the query
@@ -1515,8 +1545,8 @@ sub buildQuery {
                 #which is processed higher up in this sub. Other than that, year searches are typically
                 #handled as limits which are not processed her either.
 
                 #which is processed higher up in this sub. Other than that, year searches are typically
                 #handled as limits which are not processed her either.
 
-                # Date of Publication
-                if ( $index =~ /yr/ ) {
+                # Search ranges: Date of Publication, st-numeric
+                if ( $index =~ /(yr|st-numeric)/ ) {
                     #weight_fields/relevance search causes errors with date ranges
                     #In the case of YYYY-, it will only return records with a 'yr' of YYYY (not the range)
                     #In the case of YYYY-YYYY, it will return no results
                     #weight_fields/relevance search causes errors with date ranges
                     #In the case of YYYY-, it will only return records with a 'yr' of YYYY (not the range)
                     #In the case of YYYY-YYYY, it will return no results
@@ -1533,7 +1563,7 @@ sub buildQuery {
                     $stemming = $auto_truncation = $weight_fields = $fuzzy_enabled = 0;
                 }
                 # ISBN,ISSN,Standard Number, don't need special treatment
                     $stemming = $auto_truncation = $weight_fields = $fuzzy_enabled = 0;
                 }
                 # ISBN,ISSN,Standard Number, don't need special treatment
-                elsif ( $index eq 'nb' || $index eq 'ns' ) {
+                elsif ( $index eq 'nb' || $index eq 'ns' || $index eq 'hi' ) {
                     (
                         $stemming,      $auto_truncation,
                         $weight_fields, $fuzzy_enabled
                     (
                         $stemming,      $auto_truncation,
                         $weight_fields, $fuzzy_enabled
@@ -1637,7 +1667,7 @@ sub buildQuery {
                     query_desc => $query_desc,
                     operator => ($operators[ $i - 1 ]) ? $operators[ $i - 1 ] : '',
                     parsed_operand => $operand,
                     query_desc => $query_desc,
                     operator => ($operators[ $i - 1 ]) ? $operators[ $i - 1 ] : '',
                     parsed_operand => $operand,
-                    original_operand => ($operands[$i]) ? $operands[$i] : '',
+                    original_operand => $operands[$i] // '',
                     index => $index,
                     index_plus => $index_plus,
                     indexes_set => $indexes_set,
                     index => $index,
                     index_plus => $index_plus,
                     indexes_set => $indexes_set,
@@ -1660,7 +1690,7 @@ sub buildQuery {
 ## In English:
 ## all records not indexed in the onloan register (zebra) and all records with a value of lost equal to 0
             $availability_limit .=
 ## 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='')) )";
+"( (allrecords,AlwaysMatches='') and (not-onloan-count,st-numeric >= 1) and (lost,st-numeric=0) )";
             $limit_cgi  .= "&limit=available";
             $limit_desc .= "";
         }
             $limit_cgi  .= "&limit=available";
             $limit_desc .= "";
         }
@@ -1689,9 +1719,9 @@ sub buildQuery {
             $limit_cgi  .= "&limit=" . uri_escape_utf8($this_limit);
             if ($this_limit =~ /^branch:(.+)/) {
                 my $branchcode = $1;
             $limit_cgi  .= "&limit=" . uri_escape_utf8($this_limit);
             if ($this_limit =~ /^branch:(.+)/) {
                 my $branchcode = $1;
-                my $branchname = GetBranchName($branchcode);
-                if (defined $branchname) {
-                    $limit_desc .= " branch:$branchname";
+                my $library = Koha::Libraries->find( $branchcode );
+                if (defined $library) {
+                    $limit_desc .= " branch:" . $library->branchname;
                 } else {
                     $limit_desc .= " $this_limit";
                 }
                 } else {
                     $limit_desc .= " $this_limit";
                 }
@@ -1745,6 +1775,7 @@ sub buildQuery {
         warn "LIMIT DESC:" . $limit_desc;
         warn "---------\nLeave buildQuery\n---------";
     }
         warn "LIMIT DESC:" . $limit_desc;
         warn "---------\nLeave buildQuery\n---------";
     }
+
     return (
         undef,              $query, $simple_query, $query_cgi,
         $query_desc,        $limit, $limit_cgi,    $limit_desc,
     return (
         undef,              $query, $simple_query, $query_cgi,
         $query_desc,        $limit, $limit_cgi,    $limit_desc,
@@ -1807,42 +1838,39 @@ sub searchResults {
 
     require C4::Items;
 
 
     require C4::Items;
 
-    $search_context = 'opac' if !$search_context || $search_context ne 'intranet';
+    $search_context->{'interface'} = 'opac' if !$search_context->{'interface'} || $search_context->{'interface'} ne 'intranet';
     my ($is_opac, $hidelostitems);
     my ($is_opac, $hidelostitems);
-    if ($search_context eq 'opac') {
+    if ($search_context->{'interface'} eq 'opac') {
         $hidelostitems = C4::Context->preference('hidelostitems');
         $is_opac       = 1;
     }
 
     #Build branchnames hash
         $hidelostitems = C4::Context->preference('hidelostitems');
         $is_opac       = 1;
     }
 
     #Build branchnames hash
-    #find branchname
-    #get branch information.....
-    my %branches;
-    my $bsth =$dbh->prepare("SELECT branchcode,branchname FROM branches"); # FIXME : use C4::Branch::GetBranches
-    $bsth->execute();
-    while ( my $bdata = $bsth->fetchrow_hashref ) {
-        $branches{ $bdata->{'branchcode'} } = $bdata->{'branchname'};
-    }
+    my %branches = map { $_->branchcode => $_->branchname } Koha::Libraries->search({}, { order_by => 'branchname' });
+
 # FIXME - We build an authorised values hash here, using the default framework
 # though it is possible to have different authvals for different fws.
 
 # FIXME - We build an authorised values hash here, using the default framework
 # though it is possible to have different authvals for different fws.
 
-    my $shelflocations =GetKohaAuthorisedValues('items.location','');
+    my $shelflocations =
+      { map { $_->{authorised_value} => $_->{lib} } Koha::AuthorisedValues->get_descriptions_by_koha_field( { frameworkcode => '', kohafield => 'items.location' } ) };
 
     # get notforloan authorised value list (see $shelflocations  FIXME)
 
     # get notforloan authorised value list (see $shelflocations  FIXME)
-    my $notforloan_authorised_value = GetAuthValCode('items.notforloan','');
+    my $av = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.notforloan', authorised_value => [ -and => {'!=' => undef }, {'!=' => ''}] });
+    my $notforloan_authorised_value = $av->count ? $av->next->authorised_value : undef;
 
     #Get itemtype hash
 
     #Get itemtype hash
-    my %itemtypes = %{ GetItemTypes() };
+    my $itemtypes = Koha::ItemTypes->search_with_localization;
+    my %itemtypes = map { $_->{itemtype} => $_ } @{ $itemtypes->unblessed };
 
     #search item field code
 
     #search item field code
-    my ($itemtag, undef) = &GetMarcFromKohaField( "items.itemnumber", "" );
+    my ($itemtag, undef) = &GetMarcFromKohaField( "items.itemnumber" );
 
     ## find column names of items related to MARC
     my %subfieldstosearch;
     my @columns = Koha::Database->new()->schema()->resultset('Item')->result_source->columns;
     for my $column ( @columns ) {
         my ( $tagfield, $tagsubfield ) =
 
     ## find column names of items related to MARC
     my %subfieldstosearch;
     my @columns = Koha::Database->new()->schema()->resultset('Item')->result_source->columns;
     for my $column ( @columns ) {
         my ( $tagfield, $tagsubfield ) =
-          &GetMarcFromKohaField( "items." . $column, "" );
+          &GetMarcFromKohaField( "items." . $column );
         if ( defined $tagsubfield ) {
             $subfieldstosearch{$column} = $tagsubfield;
         }
         if ( defined $tagsubfield ) {
             $subfieldstosearch{$column} = $tagsubfield;
         }
@@ -1859,7 +1887,27 @@ sub searchResults {
 
     my $marcflavour = C4::Context->preference("marcflavour");
     # We get the biblionumber position in MARC
 
     my $marcflavour = C4::Context->preference("marcflavour");
     # We get the biblionumber position in MARC
-    my ($bibliotag,$bibliosubf)=GetMarcFromKohaField('biblio.biblionumber','');
+    my ($bibliotag,$bibliosubf)=GetMarcFromKohaField( 'biblio.biblionumber' );
+
+    # set stuff for XSLT processing here once, not later again for every record we retrieved
+    my $xslfile;
+    my $xslsyspref;
+    if( $is_opac ){
+        $xslsyspref = "OPACXSLTResultsDisplay";
+        $xslfile = C4::Context->preference( $xslsyspref );
+    } else {
+        $xslsyspref = "XSLTResultsDisplay";
+        $xslfile = C4::Context->preference( $xslsyspref ) || "default";
+    }
+    my $lang   = $xslfile ? C4::Languages::getlanguage()  : undef;
+    my $sysxml = $xslfile ? C4::XSLT::get_xslt_sysprefs() : undef;
+
+    my $userenv = C4::Context->userenv;
+    my $logged_in_user
+        = ( defined $userenv and $userenv->{number} )
+        ? Koha::Patrons->find( $userenv->{number} )
+        : undef;
+    my $patron_category_hide_lost_items = ($logged_in_user) ? $logged_in_user->category->hidelostitems : 0;
 
     # loop through all of the records we've retrieved
     for ( my $i = $offset ; $i <= $times - 1 ; $i++ ) {
 
     # loop through all of the records we've retrieved
     for ( my $i = $offset ; $i <= $times - 1 ; $i++ ) {
@@ -1888,14 +1936,12 @@ sub searchResults {
                : GetFrameworkCode($marcrecord->subfield($bibliotag,$bibliosubf));
 
         SetUTF8Flag($marcrecord);
                : GetFrameworkCode($marcrecord->subfield($bibliotag,$bibliosubf));
 
         SetUTF8Flag($marcrecord);
-        my $oldbiblio = TransformMarcToKoha( $dbh, $marcrecord, $fw );
-        $oldbiblio->{subtitle} = GetRecordValue('subtitle', $marcrecord, $fw);
+        my $oldbiblio = TransformMarcToKoha( $marcrecord, $fw );
         $oldbiblio->{result_number} = $i + 1;
 
         # add imageurl to itemtype if there is one
         $oldbiblio->{result_number} = $i + 1;
 
         # add imageurl to itemtype if there is one
-        $oldbiblio->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $oldbiblio->{itemtype} }->{imageurl} );
+        $oldbiblio->{imageurl} = getitemtypeimagelocation( $search_context->{'interface'}, $itemtypes{ $oldbiblio->{itemtype} }->{imageurl} );
 
 
-        $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);
                $oldbiblio->{normalized_upc}  = GetNormalizedUPC(       $marcrecord,$marcflavour);
                $oldbiblio->{normalized_ean}  = GetNormalizedEAN(       $marcrecord,$marcflavour);
                $oldbiblio->{normalized_oclc} = GetNormalizedOCLCNumber($marcrecord,$marcflavour);
@@ -1906,8 +1952,9 @@ sub searchResults {
         $oldbiblio->{edition} = $oldbiblio->{editionstatement};
         $oldbiblio->{description} = $itemtypes{ $oldbiblio->{itemtype} }->{translated_description};
  # Build summary if there is one (the summary is defined in the itemtypes table)
         $oldbiblio->{edition} = $oldbiblio->{editionstatement};
         $oldbiblio->{description} = $itemtypes{ $oldbiblio->{itemtype} }->{translated_description};
  # Build summary if there is one (the summary is defined in the itemtypes table)
- # FIXME: is this used anywhere, I think it can be commented out? -- JF
-        if ( $itemtypes{ $oldbiblio->{itemtype} }->{summary} ) {
+
+        # FIXME: this is only used in the deprecated non-XLST opac results
+        if ( !$xslfile && $is_opac && $itemtypes{ $oldbiblio->{itemtype} }->{summary} ) {
             my $summary = $itemtypes{ $oldbiblio->{itemtype} }->{summary};
             my @fields  = $marcrecord->fields();
 
             my $summary = $itemtypes{ $oldbiblio->{itemtype} }->{summary};
             my @fields  = $marcrecord->fields();
 
@@ -1953,27 +2000,31 @@ sub searchResults {
         # Pull out the items fields
         my @fields = $marcrecord->field($itemtag);
         my $marcflavor = C4::Context->preference("marcflavour");
         # Pull out the items fields
         my @fields = $marcrecord->field($itemtag);
         my $marcflavor = C4::Context->preference("marcflavour");
+
         # adding linked items that belong to host records
         # adding linked items that belong to host records
-        my $analyticsfield = '773';
-        if ($marcflavor eq 'MARC21' || $marcflavor eq 'NORMARC') {
-            $analyticsfield = '773';
-        } elsif ($marcflavor eq 'UNIMARC') {
-            $analyticsfield = '461';
-        }
-        foreach my $hostfield ( $marcrecord->field($analyticsfield)) {
-            my $hostbiblionumber = $hostfield->subfield("0");
-            my $linkeditemnumber = $hostfield->subfield("9");
-            if(!$hostbiblionumber eq undef){
-                my $hostbiblio = GetMarcBiblio($hostbiblionumber, 1);
-                my ($itemfield, undef) = GetMarcFromKohaField( 'items.itemnumber', GetFrameworkCode($hostbiblionumber) );
-                if(!$hostbiblio eq undef){
-                    my @hostitems = $hostbiblio->field($itemfield);
-                    foreach my $hostitem (@hostitems){
-                        if ($hostitem->subfield("9") eq $linkeditemnumber){
-                            my $linkeditem =$hostitem;
-                            # append linked items if they exist
-                            if (!$linkeditem eq undef){
-                                push (@fields, $linkeditem);}
+        if ( C4::Context->preference('EasyAnalyticalRecords') ) {
+            my $analyticsfield = '773';
+            if ($marcflavor eq 'MARC21' || $marcflavor eq 'NORMARC') {
+                $analyticsfield = '773';
+            } elsif ($marcflavor eq 'UNIMARC') {
+                $analyticsfield = '461';
+            }
+            foreach my $hostfield ( $marcrecord->field($analyticsfield)) {
+                my $hostbiblionumber = $hostfield->subfield("0");
+                my $linkeditemnumber = $hostfield->subfield("9");
+                if( $hostbiblionumber ) {
+                    my $hostbiblio = GetMarcBiblio({
+                        biblionumber => $hostbiblionumber,
+                        embed_items  => 1 });
+                    my ($itemfield, undef) = GetMarcFromKohaField( 'items.itemnumber' );
+                    if( $hostbiblio ) {
+                        my @hostitems = $hostbiblio->field($itemfield);
+                        foreach my $hostitem (@hostitems){
+                            if ($hostitem->subfield("9") eq $linkeditemnumber){
+                                my $linkeditem =$hostitem;
+                                # append linked items if they exist
+                                push @fields, $linkeditem if $linkeditem;
+                            }
                         }
                     }
                 }
                         }
                     }
                 }
@@ -2026,7 +2077,7 @@ sub searchResults {
                     next;
                 }
                 # hidden based on OpacHiddenItems syspref
                     next;
                 }
                 # hidden based on OpacHiddenItems syspref
-                my @hi = C4::Items::GetHiddenItemnumbers($item);
+                my @hi = C4::Items::GetHiddenItemnumbers({ items=> [ $item ], borcat => $search_context->{category} });
                 if (scalar @hi) {
                     push @hiddenitems, @hi;
                     $hideatopac_count++;
                 if (scalar @hi) {
                     push @hiddenitems, @hi;
                     $hideatopac_count++;
@@ -2047,20 +2098,20 @@ 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
 
                        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
-            my $userenv = C4::Context->userenv;
             if ( $item->{onloan}
             if ( $item->{onloan}
-                && !( C4::Members::GetHideLostItemsPreference( $userenv->{'number'} ) && $item->{itemlost} ) )
+                and $logged_in_user
+                and !( $patron_category_hide_lost_items and $item->{itemlost} ) )
             {
                 $onloan_count++;
                 my $key = $prefix . $item->{onloan} . $item->{barcode};
             {
                 $onloan_count++;
                 my $key = $prefix . $item->{onloan} . $item->{barcode};
-                $onloan_items->{$key}->{due_date} = output_pref( { dt => dt_from_string( $item->{onloan} ), dateonly => 1 } );
+                $onloan_items->{$key}->{due_date} = $item->{onloan};
                 $onloan_items->{$key}->{count}++ if $item->{$hbranch};
                 $onloan_items->{$key}->{branchname}     = $item->{branchname};
                 $onloan_items->{$key}->{location}       = $shelflocations->{ $item->{location} };
                 $onloan_items->{$key}->{itemcallnumber} = $item->{itemcallnumber};
                 $onloan_items->{$key}->{description}    = $item->{description};
                 $onloan_items->{$key}->{imageurl} =
                 $onloan_items->{$key}->{count}++ if $item->{$hbranch};
                 $onloan_items->{$key}->{branchname}     = $item->{branchname};
                 $onloan_items->{$key}->{location}       = $shelflocations->{ $item->{location} };
                 $onloan_items->{$key}->{itemcallnumber} = $item->{itemcallnumber};
                 $onloan_items->{$key}->{description}    = $item->{description};
                 $onloan_items->{$key}->{imageurl} =
-                  getitemtypeimagelocation( $search_context, $itemtypes{ $item->{itype} }->{imageurl} );
+                  getitemtypeimagelocation( $search_context->{'interface'}, $itemtypes{ $item->{itype} }->{imageurl} );
 
                 # if something's checked out and lost, mark it as 'long overdue'
                 if ( $item->{itemlost} ) {
 
                 # if something's checked out and lost, mark it as 'long overdue'
                 if ( $item->{itemlost} ) {
@@ -2095,7 +2146,8 @@ sub searchResults {
                         || $item->{itemlost}
                         || $item->{damaged}
                         || $item->{notforloan}
                         || $item->{itemlost}
                         || $item->{damaged}
                         || $item->{notforloan}
-                        || $items_count > C4::Context->preference('MaxSearchResultsItemsPerRecordStatusCheck') ) {
+                        || ( C4::Context->preference('MaxSearchResultsItemsPerRecordStatusCheck')
+                        && $items_count > C4::Context->preference('MaxSearchResultsItemsPerRecordStatusCheck') ) ) {
 
                     # A couple heuristics to limit how many times
                     # we query the database for item transfer information, sacrificing
 
                     # A couple heuristics to limit how many times
                     # we query the database for item transfer information, sacrificing
@@ -2149,21 +2201,21 @@ sub searchResults {
                     $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 and $item->{notforloan};
                     $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 and $item->{notforloan};
-                                       $other_items->{$key}->{count}++ if $item->{$hbranch};
-                                       $other_items->{$key}->{location} = $shelflocations->{ $item->{location} };
-                                       $other_items->{$key}->{description} = $item->{description};
-                                       $other_items->{$key}->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $item->{itype} }->{imageurl} );
+                    $other_items->{$key}->{count}++ if $item->{$hbranch};
+                    $other_items->{$key}->{location} = $shelflocations->{ $item->{location} };
+                    $other_items->{$key}->{description} = $item->{description};
+                    $other_items->{$key}->{imageurl} = getitemtypeimagelocation( $search_context->{'interface'}, $itemtypes{ $item->{itype} }->{imageurl} );
                 }
                 # item is available
                 else {
                     $can_place_holds = 1;
                     $available_count++;
                 }
                 # item is available
                 else {
                     $can_place_holds = 1;
                     $available_count++;
-                                       $available_items->{$prefix}->{count}++ if $item->{$hbranch};
-                                       foreach (qw(branchname itemcallnumber description)) {
-                       $available_items->{$prefix}->{$_} = $item->{$_};
-                                       }
-                                       $available_items->{$prefix}->{location} = $shelflocations->{ $item->{location} };
-                                       $available_items->{$prefix}->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $item->{itype} }->{imageurl} );
+                    $available_items->{$prefix}->{count}++ if $item->{$hbranch};
+                    foreach (qw(branchname itemcallnumber description)) {
+                        $available_items->{$prefix}->{$_} = $item->{$_};
+                    }
+                    $available_items->{$prefix}->{location} = $shelflocations->{ $item->{location} };
+                    $available_items->{$prefix}->{imageurl} = getitemtypeimagelocation( $search_context->{'interface'}, $itemtypes{ $item->{itype} }->{imageurl} );
                 }
             }
         }    # notforloan, item level and biblioitem level
                 }
             }
         }    # notforloan, item level and biblioitem level
@@ -2188,10 +2240,9 @@ sub searchResults {
         }
 
         # XSLT processing of some stuff
         }
 
         # XSLT processing of some stuff
-        my $interface = $search_context eq 'opac' ? 'OPAC' : '';
-        if (!$scan && C4::Context->preference($interface . "XSLTResultsDisplay")) {
-            $oldbiblio->{XSLTResultsRecord} = XSLTParse4Display($oldbiblio->{biblionumber}, $marcrecord, $interface."XSLTResultsDisplay", 1, \@hiddenitems);
-        # the last parameter tells Koha to clean up the problematic ampersand entities that Zebra outputs
+        # we fetched the sysprefs already before the loop through all retrieved record!
+        if (!$scan && $xslfile) {
+            $oldbiblio->{XSLTResultsRecord} = XSLTParse4Display($oldbiblio->{biblionumber}, $marcrecord, $xslsyspref, 1, \@hiddenitems, $sysxml, $xslfile, $lang);
         }
 
         # if biblio level itypes are used and itemtype is notforloan, it can't be reserved either
         }
 
         # if biblio level itypes are used and itemtype is notforloan, it can't be reserved either
@@ -2201,7 +2252,6 @@ sub searchResults {
             }
         }
         $oldbiblio->{norequests} = 1 unless $can_place_holds;
             }
         }
         $oldbiblio->{norequests} = 1 unless $can_place_holds;
-        $oldbiblio->{itemsplural}          = 1 if $items_count > 1;
         $oldbiblio->{items_count}          = $items_count;
         $oldbiblio->{available_items_loop} = \@available_items_loop;
         $oldbiblio->{onloan_items_loop}    = \@onloan_items_loop;
         $oldbiblio->{items_count}          = $items_count;
         $oldbiblio->{available_items_loop} = \@available_items_loop;
         $oldbiblio->{onloan_items_loop}    = \@onloan_items_loop;
@@ -2248,101 +2298,14 @@ sub searchResults {
             $oldbiblio->{'alternateholdings_count'} = $alternateholdingscount;
         }
 
             $oldbiblio->{'alternateholdings_count'} = $alternateholdingscount;
         }
 
+        $oldbiblio->{biblio_object} = Koha::Biblios->find( $oldbiblio->{biblionumber} );
+
         push( @newresults, $oldbiblio );
     }
 
     return @newresults;
 }
 
         push( @newresults, $oldbiblio );
     }
 
     return @newresults;
 }
 
-=head2 SearchAcquisitions
-    Search for acquisitions
-=cut
-
-sub SearchAcquisitions{
-    my ($datebegin, $dateend, $itemtypes,$criteria, $orderby) = @_;
-
-    my $dbh=C4::Context->dbh;
-    # Variable initialization
-    my $str=qq|
-    SELECT marcxml
-    FROM biblio
-    LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber
-    LEFT JOIN items ON items.biblionumber=biblio.biblionumber
-    WHERE dateaccessioned BETWEEN ? AND ?
-    |;
-
-    my (@params,@loopcriteria);
-
-    push @params, $datebegin->output("iso");
-    push @params, $dateend->output("iso");
-
-    if (scalar(@$itemtypes)>0 and $criteria ne "itemtype" ){
-        if(C4::Context->preference("item-level_itypes")){
-            $str .= "AND items.itype IN (?".( ',?' x scalar @$itemtypes - 1 ).") ";
-        }else{
-            $str .= "AND biblioitems.itemtype IN (?".( ',?' x scalar @$itemtypes - 1 ).") ";
-        }
-        push @params, @$itemtypes;
-    }
-
-    if ($criteria =~/itemtype/){
-        if(C4::Context->preference("item-level_itypes")){
-            $str .= "AND items.itype=? ";
-        }else{
-            $str .= "AND biblioitems.itemtype=? ";
-        }
-
-        if(scalar(@$itemtypes) == 0){
-            my $itypes = GetItemTypes();
-            for my $key (keys %$itypes){
-                push @$itemtypes, $key;
-            }
-        }
-
-        @loopcriteria= @$itemtypes;
-    }elsif ($criteria=~/itemcallnumber/){
-        $str .= "AND (items.itemcallnumber LIKE CONCAT(?,'%')
-                 OR items.itemcallnumber is NULL
-                 OR items.itemcallnumber = '')";
-
-        @loopcriteria = ("AA".."ZZ", "") unless (scalar(@loopcriteria)>0);
-    }else {
-        $str .= "AND biblio.title LIKE CONCAT(?,'%') ";
-        @loopcriteria = ("A".."z") unless (scalar(@loopcriteria)>0);
-    }
-
-    if ($orderby =~ /date_desc/){
-        $str.=" ORDER BY dateaccessioned DESC";
-    } else {
-        $str.=" ORDER BY title";
-    }
-
-    my $qdataacquisitions=$dbh->prepare($str);
-
-    my @loopacquisitions;
-    foreach my $value(@loopcriteria){
-        push @params,$value;
-        my %cell;
-        $cell{"title"}=$value;
-        $cell{"titlecode"}=$value;
-
-        eval{$qdataacquisitions->execute(@params);};
-
-        if ($@){ warn "recentacquisitions Error :$@";}
-        else {
-            my @loopdata;
-            while (my $data=$qdataacquisitions->fetchrow_hashref){
-                push @loopdata, {"summary"=>GetBiblioSummary( $data->{'marcxml'} ) };
-            }
-            $cell{"loopdata"}=\@loopdata;
-        }
-        push @loopacquisitions,\%cell if (scalar(@{$cell{loopdata}})>0);
-        pop @params;
-    }
-    $qdataacquisitions->finish;
-    return \@loopacquisitions;
-}
-
 =head2 enabled_staff_search_views
 
 %hash = enabled_staff_search_views()
 =head2 enabled_staff_search_views
 
 %hash = enabled_staff_search_views()
@@ -2526,7 +2489,7 @@ sub _ZOOM_event_loop {
 
 =head2 new_record_from_zebra
 
 
 =head2 new_record_from_zebra
 
-Given raw data from a Zebra result set, return a MARC::Record object
+Given raw data from a searchengine result set, return a MARC::Record object
 
 This helper function is needed to take into account all the involved
 system preferences and configuration variables to properly create the
 
 This helper function is needed to take into account all the involved
 system preferences and configuration variables to properly create the
@@ -2535,6 +2498,9 @@ MARC::Record object.
 If we are using GRS-1, then the raw data we get from Zebra should be USMARC
 data. If we are using DOM, then it has to be MARCXML.
 
 If we are using GRS-1, then the raw data we get from Zebra should be USMARC
 data. If we are using DOM, then it has to be MARCXML.
 
+If we are using elasticsearch, it'll already be a MARC::Record and this
+function needs a new name.
+
 =cut
 
 sub new_record_from_zebra {
 =cut
 
 sub new_record_from_zebra {
@@ -2542,6 +2508,10 @@ sub new_record_from_zebra {
     my $server   = shift;
     my $raw_data = shift;
     # Set the default indexing modes
     my $server   = shift;
     my $raw_data = shift;
     # Set the default indexing modes
+    my $search_engine = C4::Context->preference("SearchEngine");
+    if ($search_engine eq 'Elasticsearch') {
+        return ref $raw_data eq 'MARC::Record' ? $raw_data : MARC::Record->new_from_xml( $raw_data, 'UTF-8' );
+    }
     my $index_mode = ( $server eq 'biblioserver' )
                         ? C4::Context->config('zebra_bib_index_mode') // 'dom'
                         : C4::Context->config('zebra_auth_index_mode') // 'dom';
     my $index_mode = ( $server eq 'biblioserver' )
                         ? C4::Context->config('zebra_bib_index_mode') // 'dom'
                         : C4::Context->config('zebra_auth_index_mode') // 'dom';