Bug 18936: Fix selenium/administration_tasks.t
[srvgit] / C4 / Search.pm
index 998e8e3..5d68165 100644 (file)
@@ -15,8 +15,7 @@ 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>.
 
-use strict;
-#use warnings; FIXME - Bug 2505
+use Modern::Perl;
 require Exporter;
 use C4::Context;
 use C4::Biblio;    # GetMarcFromKohaField, GetBiblioData
@@ -26,13 +25,14 @@ use Koha::Libraries;
 use Lingua::Stem;
 use C4::Search::PazPar2;
 use XML::Simple;
-use C4::Members qw(GetHideLostItemsPreference);
 use C4::XSLT;
 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;
@@ -160,7 +160,7 @@ sub FindDuplicate {
 
 =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
 
@@ -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.
+    * %options is optional. (e.g. "skip_normalize" allows you to skip changing : to = )
 
 
 =item C<Return:>
@@ -221,7 +222,7 @@ $template->param(result=>\@results);
 =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.
@@ -243,12 +244,12 @@ sub SimpleSearch {
         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 {
-                $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] );
@@ -310,26 +311,27 @@ sub SimpleSearch {
 ( 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
 
-See verbse embedded documentation.
+See verbose embedded documentation.
 
 =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;
+    $offset = 0 if $offset < 0;
 
     # Initialize variables for the ZOOM connection and results object
     my $zconn;
@@ -513,8 +515,6 @@ sub getRecords {
                         keys %$facets_counter
                       )
                     {
-                        my $expandable;
-                        my $number_of_facets;
                         my @this_facets_array;
                         for my $one_facet (
                             sort {
@@ -524,87 +524,80 @@ sub getRecords {
                             } 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
-                                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/ ) {
-                                    # 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 : '';
+                      # 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};
                                 }
+                            }
 
-                # 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,
@@ -613,8 +606,6 @@ sub getRecords {
                               . $facets_info->{$link_value}->{'label_value'} =>
                               1,
                             facets     => \@this_facets_array,
-                            expandable => $expandable,
-                            expand     => $link_value,
                           }
                           unless (
                             (
@@ -644,11 +635,9 @@ sub GetFacets {
     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;
 
-    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 );
@@ -844,7 +833,6 @@ sub _get_facets_info {
 
     for my $facet ( @$facets ) {
         $facets_info->{ $facet->{ idx } }->{ label_value } = $facet->{ label };
-        $facets_info->{ $facet->{ idx } }->{ expanded }    = $facet->{ expanded };
     }
 
     return $facets_info;
@@ -853,8 +841,8 @@ sub _get_facets_info {
 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 !
 
@@ -960,6 +948,9 @@ sub _build_stemmed_operand {
     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
@@ -1078,6 +1069,8 @@ sub getIndexes{
                     'an',
                     'Any',
                     'at',
+                    'arl',
+                    'arp',
                     'au',
                     'aub',
                     'aud',
@@ -1332,7 +1325,7 @@ sub _handle_exploding_index {
 
     ( $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
@@ -1478,12 +1471,12 @@ sub buildQuery {
         @limits = grep {!/^$/} @limits;
         my $original_q = $q; # without available part
         unless ( grep { /^available$/ } @limits ) {
-            $q =~ s| and \( \( allrecords,AlwaysMatches:'' not onloan,AlwaysMatches:''\) and \(lost,st-numeric=0\) \)||;
+            $q =~ s| and \( \(allrecords,AlwaysMatches=''\) and \(not-onloan-count,st-numeric >= 1\) and \(lost,st-numeric=0\) \)||;
             $original_q = $q;
         }
         if ( @limits ) {
             if ( grep { /^available$/ } @limits ) {
-                $q .= q| and ( ( allrecords,AlwaysMatches:'' not onloan,AlwaysMatches:'') and (lost,st-numeric=0) )|;
+                $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;
@@ -1529,7 +1522,7 @@ sub buildQuery {
         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
@@ -1570,7 +1563,7 @@ sub buildQuery {
                     $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
@@ -1674,7 +1667,7 @@ sub buildQuery {
                     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,
@@ -1697,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 .=
-"( ( 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 .= "";
         }
@@ -1845,9 +1838,9 @@ sub searchResults {
 
     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);
-    if ($search_context eq 'opac') {
+    if ($search_context->{'interface'} eq 'opac') {
         $hidelostitems = C4::Context->preference('hidelostitems');
         $is_opac       = 1;
     }
@@ -1862,21 +1855,22 @@ sub searchResults {
       { map { $_->{authorised_value} => $_->{lib} } Koha::AuthorisedValues->get_descriptions_by_koha_field( { frameworkcode => '', kohafield => 'items.location' } ) };
 
     # get notforloan authorised value list (see $shelflocations  FIXME)
-    my $av = Koha::MarcSubfieldStructures->search({ frameworkcode => '', kohafield => 'items.notforloan', authorised_value => { not => undef } });
+    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
-    my %itemtypes = %{ GetItemTypes() };
+    my $itemtypes = Koha::ItemTypes->search_with_localization;
+    my %itemtypes = map { $_->{itemtype} => $_ } @{ $itemtypes->unblessed };
 
     #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 ) =
-          &GetMarcFromKohaField( "items." . $column, "" );
+          &GetMarcFromKohaField( "items." . $column );
         if ( defined $tagsubfield ) {
             $subfieldstosearch{$column} = $tagsubfield;
         }
@@ -1893,15 +1887,28 @@ sub searchResults {
 
     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 $interface = $search_context eq 'opac' ? 'OPAC' : '';
-    my $xslsyspref = $interface . "XSLTResultsDisplay";
-    my $xslfile = C4::Context->preference($xslsyspref);
+    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++ ) {
 
@@ -1930,11 +1937,10 @@ sub searchResults {
 
         SetUTF8Flag($marcrecord);
         my $oldbiblio = TransformMarcToKoha( $marcrecord, $fw );
-        $oldbiblio->{subtitle} = GetRecordValue('subtitle', $marcrecord, $fw);
         $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->{normalized_upc}  = GetNormalizedUPC(       $marcrecord,$marcflavour);
                $oldbiblio->{normalized_ean}  = GetNormalizedEAN(       $marcrecord,$marcflavour);
@@ -1946,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)
- # 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();
 
@@ -1993,27 +2000,31 @@ sub searchResults {
         # Pull out the items fields
         my @fields = $marcrecord->field($itemtag);
         my $marcflavor = C4::Context->preference("marcflavour");
+
         # 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;
+                            }
                         }
                     }
                 }
@@ -2066,7 +2077,7 @@ sub searchResults {
                     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++;
@@ -2087,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 $userenv = C4::Context->userenv;
             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_items->{$key}->{due_date} = output_pref( { str => $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} =
-                  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} ) {
@@ -2190,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}->{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++;
-                                       $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
@@ -2232,7 +2243,6 @@ sub searchResults {
         # 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);
-        # the last parameter tells Koha to clean up the problematic ampersand entities that Zebra outputs
         }
 
         # if biblio level itypes are used and itemtype is notforloan, it can't be reserved either
@@ -2242,7 +2252,6 @@ sub searchResults {
             }
         }
         $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;
@@ -2289,6 +2298,8 @@ sub searchResults {
             $oldbiblio->{'alternateholdings_count'} = $alternateholdingscount;
         }
 
+        $oldbiblio->{biblio_object} = Koha::Biblios->find( $oldbiblio->{biblionumber} );
+
         push( @newresults, $oldbiblio );
     }
 
@@ -2499,7 +2510,7 @@ sub new_record_from_zebra {
     # Set the default indexing modes
     my $search_engine = C4::Context->preference("SearchEngine");
     if ($search_engine eq 'Elasticsearch') {
-        return $raw_data;
+        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'