Bug 15758: Koha::Libraries - Ultimate duel for C4::Branch
[koha.git] / opac / opac-detail.pl
1 #!/usr/bin/perl
2
3 # Copyright 2000-2002 Katipo Communications
4 # Copyright 2010 BibLibre
5 # Copyright 2011 KohaAloha, NZ
6 #
7 # This file is part of Koha.
8 #
9 # Koha is free software; you can redistribute it and/or modify it
10 # under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # Koha is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with Koha; if not, see <http://www.gnu.org/licenses>.
21
22
23 use Modern::Perl;
24
25 use CGI qw ( -utf8 );
26 use C4::Acquisition qw( SearchOrders );
27 use C4::Auth qw(:DEFAULT get_session);
28 use C4::Koha;
29 use C4::Serials;    #uses getsubscriptionfrom biblionumber
30 use C4::Output;
31 use C4::Biblio;
32 use C4::Items;
33 use C4::Circulation;
34 use C4::Tags qw(get_tags);
35 use C4::XISBN qw(get_xisbns get_biblionumber_from_isbn);
36 use C4::External::Amazon;
37 use C4::External::Syndetics qw(get_syndetics_index get_syndetics_summary get_syndetics_toc get_syndetics_excerpt get_syndetics_reviews get_syndetics_anotes );
38 use C4::Review;
39 use C4::Ratings;
40 use C4::Members;
41 use C4::XSLT;
42 use C4::ShelfBrowser;
43 use C4::Reserves;
44 use C4::Charset;
45 use MARC::Record;
46 use MARC::Field;
47 use List::MoreUtils qw/any none/;
48 use C4::Images;
49 use Koha::DateUtils;
50 use C4::HTML5Media;
51 use C4::CourseReserves qw(GetItemCourseReservesInfo);
52 use Koha::RecordProcessor;
53 use Koha::Virtualshelves;
54
55 BEGIN {
56         if (C4::Context->preference('BakerTaylorEnabled')) {
57                 require C4::External::BakerTaylor;
58                 import C4::External::BakerTaylor qw(&image_url &link_url);
59         }
60 }
61
62 my $query = new CGI;
63 my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
64     {
65         template_name   => "opac-detail.tt",
66         query           => $query,
67         type            => "opac",
68         authnotrequired => ( C4::Context->preference("OpacPublic") ? 1 : 0 ),
69     }
70 );
71
72 my $biblionumber = $query->param('biblionumber') || $query->param('bib') || 0;
73 $biblionumber = int($biblionumber);
74
75 my @all_items = GetItemsInfo($biblionumber);
76 my @hiddenitems;
77 if (scalar @all_items >= 1) {
78     push @hiddenitems, GetHiddenItemnumbers(@all_items);
79
80     if (scalar @hiddenitems == scalar @all_items ) {
81         print $query->redirect("/cgi-bin/koha/errors/404.pl"); # escape early
82         exit;
83     }
84 }
85
86 my $record = GetMarcBiblio($biblionumber);
87 if ( ! $record ) {
88     print $query->redirect("/cgi-bin/koha/errors/404.pl"); # escape early
89     exit;
90 }
91 my $framework = &GetFrameworkCode( $biblionumber );
92 my $record_processor = Koha::RecordProcessor->new({
93     filters => 'ViewPolicy',
94     options => {
95         interface => 'opac',
96         frameworkcode => $framework
97     }
98 });
99 $record_processor->process($record);
100
101 # redirect if opacsuppression is enabled and biblio is suppressed
102 if (C4::Context->preference('OpacSuppression')) {
103     # FIXME hardcoded; the suppression flag ought to be materialized
104     # as a column on biblio or the like
105     my $opacsuppressionfield = '942';
106     my $opacsuppressionfieldvalue = $record->field($opacsuppressionfield);
107     # redirect to opac-blocked info page or 404?
108     my $opacsuppressionredirect;
109     if ( C4::Context->preference("OpacSuppressionRedirect") ) {
110         $opacsuppressionredirect = "/cgi-bin/koha/opac-blocked.pl";
111     } else {
112         $opacsuppressionredirect = "/cgi-bin/koha/errors/404.pl";
113     }
114     if ( $opacsuppressionfieldvalue &&
115          $opacsuppressionfieldvalue->subfield("n") &&
116          $opacsuppressionfieldvalue->subfield("n") == 1) {
117         # if OPAC suppression by IP address
118         if (C4::Context->preference('OpacSuppressionByIPRange')) {
119             my $IPAddress = $ENV{'REMOTE_ADDR'};
120             my $IPRange = C4::Context->preference('OpacSuppressionByIPRange');
121             if ($IPAddress !~ /^$IPRange/)  {
122                 print $query->redirect($opacsuppressionredirect);
123                 exit;
124             }
125         } else {
126             print $query->redirect($opacsuppressionredirect);
127             exit;
128         }
129     }
130 }
131
132 $template->param( biblionumber => $biblionumber );
133
134 # get biblionumbers stored in the cart
135 my @cart_list;
136
137 if($query->cookie("bib_list")){
138     my $cart_list = $query->cookie("bib_list");
139     @cart_list = split(/\//, $cart_list);
140     if ( grep {$_ eq $biblionumber} @cart_list) {
141         $template->param( incart => 1 );
142     }
143 }
144
145
146 SetUTF8Flag($record);
147 my $marcflavour      = C4::Context->preference("marcflavour");
148 my $ean = GetNormalizedEAN( $record, $marcflavour );
149
150 # XSLT processing of some stuff
151 my $xslfile = C4::Context->preference('OPACXSLTDetailsDisplay');
152 my $lang   = $xslfile ? C4::Languages::getlanguage()  : undef;
153 my $sysxml = $xslfile ? C4::XSLT::get_xslt_sysprefs() : undef;
154
155 if ( $xslfile ) {
156     $template->param(
157         XSLTBloc => XSLTParse4Display(
158                         $biblionumber, $record, "OPACXSLTDetailsDisplay",
159                         1, undef, $sysxml, $xslfile, $lang
160                     )
161     );
162 }
163
164 my $OpacBrowseResults = C4::Context->preference("OpacBrowseResults");
165 $template->{VARS}->{'OpacBrowseResults'} = $OpacBrowseResults;
166
167 # We look for the busc param to build the simple paging from the search
168 if ($OpacBrowseResults) {
169 my $session = get_session($query->cookie("CGISESSID"));
170 my %paging = (previous => {}, next => {});
171 if ($session->param('busc')) {
172     use C4::Search;
173     use URI::Escape;
174
175     # Rebuild the string to store on session
176     # param value is URI encoded and params separator is HTML encode (&amp;)
177     sub rebuildBuscParam
178     {
179         my $arrParamsBusc = shift;
180
181         my $pasarParams = '';
182         my $j = 0;
183         for (keys %$arrParamsBusc) {
184             if ($_ =~ /^(?:query|listBiblios|newlistBiblios|query_type|simple_query|total|offset|offsetSearch|next|previous|count|expand|scan)/) {
185                 if (defined($arrParamsBusc->{$_})) {
186                     $pasarParams .= '&amp;' if ($j);
187                     $pasarParams .= $_ . '=' . Encode::decode('UTF-8', uri_escape_utf8( $arrParamsBusc->{$_} ));
188                     $j++;
189                 }
190             } else {
191                 for my $value (@{$arrParamsBusc->{$_}}) {
192                     $pasarParams .= '&amp;' if ($j);
193                     $pasarParams .= $_ . '=' . Encode::decode('UTF-8', uri_escape_utf8($value));
194                     $j++;
195                 }
196             }
197         }
198         return $pasarParams;
199     }#rebuildBuscParam
200
201     # Search given the current values from the busc param
202     sub searchAgain
203     {
204         my ($arrParamsBusc, $offset, $results_per_page) = @_;
205
206         my $expanded_facet = $arrParamsBusc->{'expand'};
207         my $itemtypes = GetItemTypes;
208         my @servers;
209         @servers = @{$arrParamsBusc->{'server'}} if $arrParamsBusc->{'server'};
210         @servers = ("biblioserver") unless (@servers);
211
212         my ($default_sort_by, @sort_by);
213         $default_sort_by = C4::Context->preference('OPACdefaultSortField')."_".C4::Context->preference('OPACdefaultSortOrder') if (C4::Context->preference('OPACdefaultSortField') && C4::Context->preference('OPACdefaultSortOrder'));
214         @sort_by = @{$arrParamsBusc->{'sort_by'}} if $arrParamsBusc->{'sort_by'};
215         $sort_by[0] = $default_sort_by if !$sort_by[0] && defined($default_sort_by);
216         my ($error, $results_hashref, $facets);
217         eval {
218             ($error, $results_hashref, $facets) = getRecords($arrParamsBusc->{'query'},$arrParamsBusc->{'simple_query'},\@sort_by,\@servers,$results_per_page,$offset,$expanded_facet,undef,$itemtypes,$arrParamsBusc->{'query_type'},$arrParamsBusc->{'scan'});
219         };
220         my $hits;
221         my @newresults;
222         for (my $i=0;$i<@servers;$i++) {
223             my $server = $servers[$i];
224             $hits = $results_hashref->{$server}->{"hits"};
225             @newresults = searchResults('opac', '', $hits, $results_per_page, $offset, $arrParamsBusc->{'scan'}, $results_hashref->{$server}->{"RECORDS"});
226         }
227         return \@newresults;
228     }#searchAgain
229
230     # Build the current list of biblionumbers in this search
231     sub buildListBiblios
232     {
233         my ($newresultsRef, $results_per_page) = @_;
234
235         my $listBiblios = '';
236         my $j = 0;
237         foreach (@$newresultsRef) {
238             my $bibnum = ($_->{biblionumber})?$_->{biblionumber}:0;
239             $listBiblios .= $bibnum . ',';
240             $j++;
241             last if ($j == $results_per_page);
242         }
243         chop $listBiblios if ($listBiblios =~ /,$/);
244         return $listBiblios;
245     }#buildListBiblios
246
247     my $busc = $session->param("busc");
248     my @arrBusc = split(/\&(?:amp;)?/, $busc);
249     my ($key, $value);
250     my %arrParamsBusc = ();
251     for (@arrBusc) {
252         ($key, $value) = split(/=/, $_, 2);
253         if ($key =~ /^(?:query|listBiblios|newlistBiblios|query_type|simple_query|next|previous|total|offset|offsetSearch|count|expand|scan)/) {
254             $arrParamsBusc{$key} = uri_unescape($value);
255         } else {
256             unless (exists($arrParamsBusc{$key})) {
257                 $arrParamsBusc{$key} = [];
258             }
259             push @{$arrParamsBusc{$key}}, uri_unescape($value);
260         }
261     }
262     my $searchAgain = 0;
263     my $count = C4::Context->preference('OPACnumSearchResults') || 20;
264     my $results_per_page = ($arrParamsBusc{'count'} && $arrParamsBusc{'count'} =~ /^[0-9]+?/)?$arrParamsBusc{'count'}:$count;
265     $arrParamsBusc{'count'} = $results_per_page;
266     my $offset = ($arrParamsBusc{'offset'} && $arrParamsBusc{'offset'} =~ /^[0-9]+?/)?$arrParamsBusc{'offset'}:0;
267     # The value OPACnumSearchResults has changed and the search has to be rebuild
268     if ($count != $results_per_page) {
269         if (exists($arrParamsBusc{'listBiblios'}) && $arrParamsBusc{'listBiblios'} =~ /^[0-9]+(?:,[0-9]+)*$/) {
270             my $indexBiblio = 0;
271             my @arrBibliosAux = split(',', $arrParamsBusc{'listBiblios'});
272             for (@arrBibliosAux) {
273                 last if ($_ == $biblionumber);
274                 $indexBiblio++;
275             }
276             $indexBiblio += $offset;
277             $offset = int($indexBiblio / $count) * $count;
278             $arrParamsBusc{'offset'} = $offset;
279         }
280         $arrParamsBusc{'count'} = $count;
281         $results_per_page = $count;
282         my $newresultsRef = searchAgain(\%arrParamsBusc, $offset, $results_per_page);
283         $arrParamsBusc{'listBiblios'} = buildListBiblios($newresultsRef, $results_per_page);
284         delete $arrParamsBusc{'previous'} if (exists($arrParamsBusc{'previous'}));
285         delete $arrParamsBusc{'next'} if (exists($arrParamsBusc{'next'}));
286         delete $arrParamsBusc{'offsetSearch'} if (exists($arrParamsBusc{'offsetSearch'}));
287         delete $arrParamsBusc{'newlistBiblios'} if (exists($arrParamsBusc{'newlistBiblios'}));
288         my $newbusc = rebuildBuscParam(\%arrParamsBusc);
289         $session->param("busc" => $newbusc);
290         @arrBusc = split(/\&(?:amp;)?/, $newbusc);
291     } else {
292         my $modifyListBiblios = 0;
293         # We come from a previous click
294         if (exists($arrParamsBusc{'previous'})) {
295             $modifyListBiblios = 1 if ($biblionumber == $arrParamsBusc{'previous'});
296             delete $arrParamsBusc{'previous'};
297         } elsif (exists($arrParamsBusc{'next'})) { # We come from a next click
298             $modifyListBiblios = 2 if ($biblionumber == $arrParamsBusc{'next'});
299             delete $arrParamsBusc{'next'};
300         }
301         if ($modifyListBiblios) {
302             if (exists($arrParamsBusc{'newlistBiblios'})) {
303                 my $listBibliosAux = $arrParamsBusc{'listBiblios'};
304                 $arrParamsBusc{'listBiblios'} = $arrParamsBusc{'newlistBiblios'};
305                 my @arrAux = split(',', $listBibliosAux);
306                 $arrParamsBusc{'newlistBiblios'} = $listBibliosAux;
307                 if ($modifyListBiblios == 1) {
308                     $arrParamsBusc{'next'} = $arrAux[0];
309                     $paging{'next'}->{biblionumber} = $arrAux[0];
310                 }else {
311                     $arrParamsBusc{'previous'} = $arrAux[$#arrAux];
312                     $paging{'previous'}->{biblionumber} = $arrAux[$#arrAux];
313                 }
314             } else {
315                 delete $arrParamsBusc{'listBiblios'};
316             }
317             my $offsetAux = $arrParamsBusc{'offset'};
318             $arrParamsBusc{'offset'} = $arrParamsBusc{'offsetSearch'};
319             $arrParamsBusc{'offsetSearch'} = $offsetAux;
320             $offset = $arrParamsBusc{'offset'};
321             my $newbusc = rebuildBuscParam(\%arrParamsBusc);
322             $session->param("busc" => $newbusc);
323             @arrBusc = split(/\&(?:amp;)?/, $newbusc);
324         }
325     }
326     my $buscParam = '';
327     my $j = 0;
328     # Rebuild the query for the button "back to results"
329     for (@arrBusc) {
330         unless ($_ =~ /^(?:query|listBiblios|newlistBiblios|query_type|simple_query|next|previous|total|count|offsetSearch)/) {
331             $buscParam .= '&amp;' unless ($j == 0);
332             $buscParam .= $_; # string already URI encoded
333             $j++;
334         }
335     }
336     $template->param('busc' => $buscParam);
337     my $offsetSearch;
338     my @arrBiblios;
339     # We are inside the list of biblios and we don't have to search
340     if (exists($arrParamsBusc{'listBiblios'}) && $arrParamsBusc{'listBiblios'} =~ /^[0-9]+(?:,[0-9]+)*$/) {
341         @arrBiblios = split(',', $arrParamsBusc{'listBiblios'});
342         if (@arrBiblios) {
343             # We are at the first item of the list
344             if ($arrBiblios[0] == $biblionumber) {
345                 if (@arrBiblios > 1) {
346                     for (my $j = 1; $j < @arrBiblios; $j++) {
347                         next unless ($arrBiblios[$j]);
348                         $paging{'next'}->{biblionumber} = $arrBiblios[$j];
349                         last;
350                     }
351                 }
352                 # search again if we are not at the first searching list
353                 if ($offset && !$arrParamsBusc{'previous'}) {
354                     $searchAgain = 1;
355                     $offsetSearch = $offset - $results_per_page;
356                 }
357             # we are at the last item of the list
358             } elsif ($arrBiblios[$#arrBiblios] == $biblionumber) {
359                 for (my $j = $#arrBiblios - 1; $j >= 0; $j--) {
360                     next unless ($arrBiblios[$j]);
361                     $paging{'previous'}->{biblionumber} = $arrBiblios[$j];
362                     last;
363                 }
364                 if (!$offset) {
365                     # search again if we are at the first list and there is more results
366                     $searchAgain = 1 if (!$arrParamsBusc{'next'} && $arrParamsBusc{'total'} != @arrBiblios);
367                 } else {
368                     # search again if we aren't at the first list and there is more results
369                     $searchAgain = 1 if (!$arrParamsBusc{'next'} && $arrParamsBusc{'total'} > ($offset + @arrBiblios));
370                 }
371                 $offsetSearch = $offset + $results_per_page if ($searchAgain);
372             } else {
373                 for (my $j = 1; $j < $#arrBiblios; $j++) {
374                     if ($arrBiblios[$j] == $biblionumber) {
375                         for (my $z = $j - 1; $z >= 0; $z--) {
376                             next unless ($arrBiblios[$z]);
377                             $paging{'previous'}->{biblionumber} = $arrBiblios[$z];
378                             last;
379                         }
380                         for (my $z = $j + 1; $z < @arrBiblios; $z++) {
381                             next unless ($arrBiblios[$z]);
382                             $paging{'next'}->{biblionumber} = $arrBiblios[$z];
383                             last;
384                         }
385                         last;
386                     }
387                 }
388             }
389         }
390         $offsetSearch = 0 if (defined($offsetSearch) && $offsetSearch < 0);
391     }
392     if ($searchAgain) {
393         my $newresultsRef = searchAgain(\%arrParamsBusc, $offsetSearch, $results_per_page);
394         my @newresults = @$newresultsRef;
395         # build the new listBiblios
396         my $listBiblios = buildListBiblios(\@newresults, $results_per_page);
397         unless (exists($arrParamsBusc{'listBiblios'})) {
398             $arrParamsBusc{'listBiblios'} = $listBiblios;
399             @arrBiblios = split(',', $arrParamsBusc{'listBiblios'});
400         } else {
401             $arrParamsBusc{'newlistBiblios'} = $listBiblios;
402         }
403         # From the new list we build again the next and previous result
404         if (@arrBiblios) {
405             if ($arrBiblios[0] == $biblionumber) {
406                 for (my $j = $#newresults; $j >= 0; $j--) {
407                     next unless ($newresults[$j]);
408                     $paging{'previous'}->{biblionumber} = $newresults[$j]->{biblionumber};
409                     $arrParamsBusc{'previous'} = $paging{'previous'}->{biblionumber};
410                     $arrParamsBusc{'offsetSearch'} = $offsetSearch;
411                    last;
412                 }
413             } elsif ($arrBiblios[$#arrBiblios] == $biblionumber) {
414                 for (my $j = 0; $j < @newresults; $j++) {
415                     next unless ($newresults[$j]);
416                     $paging{'next'}->{biblionumber} = $newresults[$j]->{biblionumber};
417                     $arrParamsBusc{'next'} = $paging{'next'}->{biblionumber};
418                     $arrParamsBusc{'offsetSearch'} = $offsetSearch;
419                     last;
420                 }
421             }
422         }
423         # build new busc param
424         my $newbusc = rebuildBuscParam(\%arrParamsBusc);
425         $session->param("busc" => $newbusc);
426     }
427     my ($numberBiblioPaging, $dataBiblioPaging);
428     # Previous biblio
429     $numberBiblioPaging = $paging{'previous'}->{biblionumber};
430     if ($numberBiblioPaging) {
431         $template->param( 'previousBiblionumber' => $numberBiblioPaging );
432         $dataBiblioPaging = GetBiblioData($numberBiblioPaging);
433         $template->param('previousTitle' => $dataBiblioPaging->{'title'}) if ($dataBiblioPaging);
434     }
435     # Next biblio
436     $numberBiblioPaging = $paging{'next'}->{biblionumber};
437     if ($numberBiblioPaging) {
438         $template->param( 'nextBiblionumber' => $numberBiblioPaging );
439         $dataBiblioPaging = GetBiblioData($numberBiblioPaging);
440         $template->param('nextTitle' => $dataBiblioPaging->{'title'}) if ($dataBiblioPaging);
441     }
442     # Partial list of biblio results
443     my @listResults;
444     for (my $j = 0; $j < @arrBiblios; $j++) {
445         next unless ($arrBiblios[$j]);
446         $dataBiblioPaging = GetBiblioData($arrBiblios[$j]) if ($arrBiblios[$j] != $biblionumber);
447         push @listResults, {index => $j + 1 + $offset, biblionumber => $arrBiblios[$j], title => ($arrBiblios[$j] == $biblionumber)?'':$dataBiblioPaging->{title}, author => ($arrBiblios[$j] != $biblionumber && $dataBiblioPaging->{author})?$dataBiblioPaging->{author}:'', url => ($arrBiblios[$j] == $biblionumber)?'':'opac-detail.pl?biblionumber=' . $arrBiblios[$j]};
448     }
449     $template->param('listResults' => \@listResults) if (@listResults);
450     $template->param('indexPag' => 1 + $offset, 'totalPag' => $arrParamsBusc{'total'}, 'indexPagEnd' => scalar(@arrBiblios) + $offset);
451 }
452 }
453
454
455 $template->param( 'ItemsIssued' => CountItemsIssued( $biblionumber ) );
456 $template->param('OPACShowCheckoutName' => C4::Context->preference("OPACShowCheckoutName") );
457 $template->param('OPACShowBarcode' => C4::Context->preference("OPACShowBarcode") );
458
459 # adding items linked via host biblios
460
461 my $analyticfield = '773';
462 if ($marcflavour eq 'MARC21' || $marcflavour eq 'NORMARC'){
463     $analyticfield = '773';
464 } elsif ($marcflavour eq 'UNIMARC') {
465     $analyticfield = '461';
466 }
467 foreach my $hostfield ( $record->field($analyticfield)) {
468     my $hostbiblionumber = $hostfield->subfield("0");
469     my $linkeditemnumber = $hostfield->subfield("9");
470     my @hostitemInfos = GetItemsInfo($hostbiblionumber);
471     foreach my $hostitemInfo (@hostitemInfos){
472         if ($hostitemInfo->{itemnumber} eq $linkeditemnumber){
473             push(@all_items, $hostitemInfo);
474         }
475     }
476 }
477
478 my @items;
479
480 # Are there items to hide?
481 my $hideitems;
482 $hideitems = 1 if C4::Context->preference('hidelostitems') or scalar(@hiddenitems) > 0;
483
484 # Hide items
485 if ($hideitems) {
486     for my $itm (@all_items) {
487         if  ( C4::Context->preference('hidelostitems') ) {
488             push @items, $itm unless $itm->{itemlost} or any { $itm->{'itemnumber'} eq $_ } @hiddenitems;
489         } else {
490             push @items, $itm unless any { $itm->{'itemnumber'} eq $_ } @hiddenitems;
491     }
492 }
493 } else {
494     # Or not
495     @items = @all_items;
496 }
497
498 my $branch = '';
499 if (C4::Context->userenv){
500     $branch = C4::Context->userenv->{branch};
501 }
502 if ( C4::Context->preference('HighlightOwnItemsOnOPAC') ) {
503     if (
504         ( ( C4::Context->preference('HighlightOwnItemsOnOPACWhich') eq 'PatronBranch' ) && $branch )
505         ||
506         C4::Context->preference('HighlightOwnItemsOnOPACWhich') eq 'OpacURLBranch'
507     ) {
508         my $branchcode;
509         if ( C4::Context->preference('HighlightOwnItemsOnOPACWhich') eq 'PatronBranch' ) {
510             $branchcode = $branch;
511         }
512         elsif (  C4::Context->preference('HighlightOwnItemsOnOPACWhich') eq 'OpacURLBranch' ) {
513             $branchcode = $ENV{'BRANCHCODE'};
514         }
515
516         my @our_items;
517         my @other_items;
518
519         foreach my $item ( @items ) {
520            if ( $item->{branchcode} eq $branchcode ) {
521                $item->{'this_branch'} = 1;
522                push( @our_items, $item );
523            } else {
524                push( @other_items, $item );
525            }
526         }
527
528         @items = ( @our_items, @other_items );
529     }
530 }
531
532 my $dat = &GetBiblioData($biblionumber);
533 my $HideMARC = $record_processor->filters->[0]->should_hide_marc(
534     {
535         frameworkcode => $dat->{'frameworkcode'},
536         interface     => 'opac',
537     } );
538
539 my $itemtypes = GetItemTypes();
540 # imageurl:
541 my $itemtype = $dat->{'itemtype'};
542 if ( $itemtype ) {
543     $dat->{'imageurl'}    = getitemtypeimagelocation( 'opac', $itemtypes->{$itemtype}->{'imageurl'} );
544     $dat->{'description'} = $itemtypes->{$itemtype}->{translated_description};
545 }
546 my $shelflocations =GetKohaAuthorisedValues('items.location',$dat->{'frameworkcode'}, 'opac');
547 my $collections =  GetKohaAuthorisedValues('items.ccode',$dat->{'frameworkcode'}, 'opac');
548 my $copynumbers = GetKohaAuthorisedValues('items.copynumber',$dat->{'frameworkcode'}, 'opac');
549
550 #coping with subscriptions
551 my $subscriptionsnumber = CountSubscriptionFromBiblionumber($biblionumber);
552 my @subscriptions       = SearchSubscriptions({ biblionumber => $biblionumber, orderby => 'title' });
553
554 my @subs;
555 $dat->{'serial'}=1 if $subscriptionsnumber;
556 foreach my $subscription (@subscriptions) {
557     my $serials_to_display;
558     my %cell;
559     $cell{subscriptionid}    = $subscription->{subscriptionid};
560     $cell{subscriptionnotes} = $subscription->{notes};
561     $cell{missinglist}       = $subscription->{missinglist};
562     $cell{opacnote}          = $subscription->{opacnote};
563     $cell{histstartdate}     = $subscription->{histstartdate};
564     $cell{histenddate}       = $subscription->{histenddate};
565     $cell{branchcode}        = $subscription->{branchcode};
566     $cell{hasalert}          = $subscription->{hasalert};
567     $cell{callnumber}        = $subscription->{callnumber};
568     $cell{closed}            = $subscription->{closed};
569     #get the three latest serials.
570     $serials_to_display = $subscription->{opacdisplaycount};
571     $serials_to_display = C4::Context->preference('OPACSerialIssueDisplayCount') unless $serials_to_display;
572         $cell{opacdisplaycount} = $serials_to_display;
573     $cell{latestserials} =
574       GetLatestSerials( $subscription->{subscriptionid}, $serials_to_display );
575     push @subs, \%cell;
576 }
577
578 $dat->{'count'} = scalar(@items);
579
580
581 my (%item_reserves, %priority);
582 my ($show_holds_count, $show_priority);
583 for ( C4::Context->preference("OPACShowHoldQueueDetails") ) {
584     m/holds/o and $show_holds_count = 1;
585     m/priority/ and $show_priority = 1;
586 }
587 my $has_hold;
588 if ( $show_holds_count || $show_priority) {
589     my $reserves = GetReservesFromBiblionumber({ biblionumber => $biblionumber, all_dates => 1 });
590     $template->param( holds_count  => scalar( @$reserves ) ) if $show_holds_count;
591     foreach (@$reserves) {
592         $item_reserves{ $_->{itemnumber} }++ if $_->{itemnumber};
593         if ($show_priority && $_->{borrowernumber} == $borrowernumber) {
594             $has_hold = 1;
595             $_->{itemnumber}
596                 ? ($priority{ $_->{itemnumber} } = $_->{priority})
597                 : ($template->param( priority => $_->{priority} ));
598         }
599     }
600 }
601 $template->param( show_priority => $has_hold ) ;
602
603 my $norequests = 1;
604 my %itemfields;
605 my (@itemloop, @otheritemloop);
606 my $currentbranch = C4::Context->userenv ? C4::Context->userenv->{branch} : undef;
607 if ($currentbranch and C4::Context->preference('OpacSeparateHoldings')) {
608     $template->param(SeparateHoldings => 1);
609 }
610 my $separatebranch = C4::Context->preference('OpacSeparateHoldingsBranch');
611 my $viewallitems = $query->param('viewallitems');
612 my $max_items_to_display = C4::Context->preference('OpacMaxItemsToDisplay') // 50;
613
614 # Get items on order
615 my ( @itemnumbers_on_order );
616 if ( C4::Context->preference('OPACAcquisitionDetails' ) ) {
617     my $orders = C4::Acquisition::SearchOrders({
618         biblionumber => $biblionumber,
619         ordered => 1,
620     });
621     my $total_quantity = 0;
622     for my $order ( @$orders ) {
623         if ( C4::Context->preference('AcqCreateItem') eq 'ordering' ) {
624             for my $itemnumber ( C4::Acquisition::GetItemnumbersFromOrder( $order->{ordernumber} ) ) {
625                 push @itemnumbers_on_order, $itemnumber;
626             }
627         }
628         $total_quantity += $order->{quantity};
629     }
630     $template->{VARS}->{acquisition_details} = {
631         total_quantity => $total_quantity,
632     };
633 }
634
635 if ( not $viewallitems and @items > $max_items_to_display ) {
636     $template->param(
637         too_many_items => 1,
638         items_count => scalar( @items ),
639     );
640 } else {
641   my $allow_onshelf_holds;
642   my $borrower = GetMember( 'borrowernumber' => $borrowernumber );
643   for my $itm (@items) {
644     $itm->{holds_count} = $item_reserves{ $itm->{itemnumber} };
645     $itm->{priority} = $priority{ $itm->{itemnumber} };
646     $norequests = 0
647       if $norequests
648         && !$itm->{'withdrawn'}
649         && !$itm->{'itemlost'}
650         && ($itm->{'itemnotforloan'}<0 || not $itm->{'itemnotforloan'})
651         && !$itemtypes->{$itm->{'itype'}}->{notforloan}
652         && $itm->{'itemnumber'};
653
654     $allow_onshelf_holds = C4::Reserves::OnShelfHoldsAllowed( $itm, $borrower )
655       unless $allow_onshelf_holds;
656
657     # get collection code description, too
658     my $ccode = $itm->{'ccode'};
659     $itm->{'ccode'} = $collections->{$ccode} if defined($ccode) && $collections && exists( $collections->{$ccode} );
660     my $copynumber = $itm->{'copynumber'};
661     $itm->{'copynumber'} = $copynumbers->{$copynumber} if ( defined($copynumbers) && defined($copynumber) && exists( $copynumbers->{$copynumber} ) );
662     if ( defined $itm->{'location'} ) {
663         $itm->{'location_description'} = $shelflocations->{ $itm->{'location'} };
664     }
665     if (exists $itm->{itype} && defined($itm->{itype}) && exists $itemtypes->{ $itm->{itype} }) {
666         $itm->{'imageurl'}    = getitemtypeimagelocation( 'opac', $itemtypes->{ $itm->{itype} }->{'imageurl'} );
667         $itm->{'description'} = $itemtypes->{ $itm->{itype} }->{translated_description};
668     }
669     foreach (qw(ccode enumchron copynumber itemnotes uri)) {
670         $itemfields{$_} = 1 if ($itm->{$_});
671     }
672
673      my $reserve_status = C4::Reserves::GetReserveStatus($itm->{itemnumber});
674       if( $reserve_status eq "Waiting"){ $itm->{'waiting'} = 1; }
675       if( $reserve_status eq "Reserved"){ $itm->{'onhold'} = 1; }
676     
677      my ( $transfertwhen, $transfertfrom, $transfertto ) = GetTransfers($itm->{itemnumber});
678      if ( defined( $transfertwhen ) && $transfertwhen ne '' ) {
679         $itm->{transfertwhen} = $transfertwhen;
680         $itm->{transfertfrom} = $transfertfrom;
681         $itm->{transfertto}   = $transfertto;
682      }
683     
684     if (    C4::Context->preference('OPACAcquisitionDetails')
685         and C4::Context->preference('AcqCreateItem') eq 'ordering' )
686     {
687         $itm->{on_order} = 1
688           if grep /^$itm->{itemnumber}$/, @itemnumbers_on_order;
689     }
690
691     my $itembranch = $itm->{$separatebranch};
692     if ($currentbranch and C4::Context->preference('OpacSeparateHoldings')) {
693         if ($itembranch and $itembranch eq $currentbranch) {
694             push @itemloop, $itm;
695         } else {
696             push @otheritemloop, $itm;
697         }
698     } else {
699         push @itemloop, $itm;
700     }
701   }
702   $template->param( 'AllowOnShelfHolds' => $allow_onshelf_holds );
703 }
704
705 # Display only one tab if one items list is empty
706 if (scalar(@itemloop) == 0 || scalar(@otheritemloop) == 0) {
707     $template->param(SeparateHoldings => 0);
708     if (scalar(@itemloop) == 0) {
709         @itemloop = @otheritemloop;
710     }
711 }
712
713 ## get notes and subjects from MARC record
714 if (!C4::Context->preference("OPACXSLTDetailsDisplay") ) {
715     my $marcisbnsarray   = GetMarcISBN    ($record,$marcflavour);
716     my $marcauthorsarray = GetMarcAuthors ($record,$marcflavour);
717     my $marcsubjctsarray = GetMarcSubjects($record,$marcflavour);
718     my $marcseriesarray  = GetMarcSeries  ($record,$marcflavour);
719     my $marcurlsarray    = GetMarcUrls    ($record,$marcflavour);
720     my $marchostsarray   = GetMarcHosts($record,$marcflavour);
721
722     $template->param(
723         MARCSUBJCTS => $marcsubjctsarray,
724         MARCAUTHORS => $marcauthorsarray,
725         MARCSERIES  => $marcseriesarray,
726         MARCURLS    => $marcurlsarray,
727         MARCISBNS   => $marcisbnsarray,
728         MARCHOSTS   => $marchostsarray,
729     );
730 }
731
732 my $marcnotesarray   = GetMarcNotes   ($record,$marcflavour);
733 my $subtitle         = GetRecordValue('subtitle', $record, GetFrameworkCode($biblionumber));
734
735     $template->param(
736                      MARCNOTES               => $marcnotesarray,
737                      norequests              => $norequests,
738                      RequestOnOpac           => C4::Context->preference("RequestOnOpac"),
739                      itemdata_ccode          => $itemfields{ccode},
740                      itemdata_enumchron      => $itemfields{enumchron},
741                      itemdata_uri            => $itemfields{uri},
742                      itemdata_copynumber     => $itemfields{copynumber},
743                      itemdata_itemnotes          => $itemfields{itemnotes},
744                      subtitle                => $subtitle,
745                      OpacStarRatings         => C4::Context->preference("OpacStarRatings"),
746     );
747
748 if (C4::Context->preference("AlternateHoldingsField") && scalar @items == 0) {
749     my $fieldspec = C4::Context->preference("AlternateHoldingsField");
750     my $subfields = substr $fieldspec, 3;
751     my $holdingsep = C4::Context->preference("AlternateHoldingsSeparator") || ' ';
752     my @alternateholdingsinfo = ();
753     my @holdingsfields = $record->field(substr $fieldspec, 0, 3);
754
755     for my $field (@holdingsfields) {
756         my %holding = ( holding => '' );
757         my $havesubfield = 0;
758         for my $subfield ($field->subfields()) {
759             if ((index $subfields, $$subfield[0]) >= 0) {
760                 $holding{'holding'} .= $holdingsep if (length $holding{'holding'} > 0);
761                 $holding{'holding'} .= $$subfield[1];
762                 $havesubfield++;
763             }
764         }
765         if ($havesubfield) {
766             push(@alternateholdingsinfo, \%holding);
767         }
768     }
769
770     $template->param(
771         ALTERNATEHOLDINGS   => \@alternateholdingsinfo,
772         );
773 }
774
775 # FIXME: The template uses this hash directly. Need to filter.
776 foreach ( keys %{$dat} ) {
777     next if ( $HideMARC->{$_} );
778     $template->param( "$_" => defined $dat->{$_} ? $dat->{$_} : '' );
779 }
780
781 # some useful variables for enhanced content;
782 # in each case, we're grabbing the first value we find in
783 # the record and normalizing it
784 my $upc = GetNormalizedUPC($record,$marcflavour);
785 my $oclc = GetNormalizedOCLCNumber($record,$marcflavour);
786 my $isbn = GetNormalizedISBN(undef,$record,$marcflavour);
787 my $content_identifier_exists;
788 if ( $isbn or $ean or $oclc or $upc ) {
789     $content_identifier_exists = 1;
790 }
791 $template->param(
792         normalized_upc => $upc,
793         normalized_ean => $ean,
794         normalized_oclc => $oclc,
795         normalized_isbn => $isbn,
796         content_identifier_exists =>  $content_identifier_exists,
797 );
798
799 # COinS format FIXME: for books Only
800 $template->param(
801     ocoins => GetCOinSBiblio($record),
802 );
803
804 my $libravatar_enabled = 0;
805 if ( C4::Context->preference('ShowReviewer') and C4::Context->preference('ShowReviewerPhoto')) {
806     eval {
807         require Libravatar::URL;
808         Libravatar::URL->import();
809     };
810     if (!$@ ) {
811         $libravatar_enabled = 1;
812     }
813 }
814
815 my $reviews = getreviews( $biblionumber, 1 );
816 my $loggedincommenter;
817
818
819
820
821 foreach ( @$reviews ) {
822     my $borrowerData   = GetMember('borrowernumber' => $_->{borrowernumber});
823     # setting some borrower info into this hash
824     $_->{title}     = $borrowerData->{'title'};
825     $_->{surname}   = $borrowerData->{'surname'};
826     $_->{firstname} = $borrowerData->{'firstname'};
827     if ($libravatar_enabled and $borrowerData->{'email'}) {
828         $_->{avatarurl} = libravatar_url(email => $borrowerData->{'email'}, https => $ENV{HTTPS});
829     }
830     $_->{userid}    = $borrowerData->{'userid'};
831     $_->{cardnumber}    = $borrowerData->{'cardnumber'};
832
833     if ($borrowerData->{'borrowernumber'} eq $borrowernumber) {
834                 $_->{your_comment} = 1;
835                 $loggedincommenter = 1;
836         }
837 }
838
839 if ( C4::Context->preference("OPACISBD") ) {
840     $template->param( ISBD => 1 );
841 }
842
843 $template->param(
844     itemloop            => \@itemloop,
845     otheritemloop       => \@otheritemloop,
846     subscriptionsnumber => $subscriptionsnumber,
847     biblionumber        => $biblionumber,
848     subscriptions       => \@subs,
849     subscriptionsnumber => $subscriptionsnumber,
850     reviews             => $reviews,
851     loggedincommenter   => $loggedincommenter
852 );
853
854 # Lists
855 if (C4::Context->preference("virtualshelves") ) {
856     my $shelves = Koha::Virtualshelves->search(
857         {
858             biblionumber => $biblionumber,
859             category => 2,
860         },
861         {
862             join => 'virtualshelfcontents',
863         }
864     );
865     $template->param( shelves => $shelves );
866 }
867
868 # XISBN Stuff
869 if (C4::Context->preference("OPACFRBRizeEditions")==1) {
870     eval {
871         $template->param(
872             XISBNS => get_xisbns($isbn)
873         );
874     };
875     if ($@) { warn "XISBN Failed $@"; }
876 }
877
878 # Serial Collection
879 my @sc_fields = $record->field(955);
880 my @lc_fields = $marcflavour eq 'UNIMARC'
881     ? $record->field(930)
882     : $record->field(852);
883 my @serialcollections = ();
884
885 foreach my $sc_field (@sc_fields) {
886     my %row_data;
887
888     $row_data{text}    = $sc_field->subfield('r');
889     $row_data{branch}  = $sc_field->subfield('9');
890     foreach my $lc_field (@lc_fields) {
891         $row_data{itemcallnumber} = $marcflavour eq 'UNIMARC'
892             ? $lc_field->subfield('a') # 930$a
893             : $lc_field->subfield('h') # 852$h
894             if ($sc_field->subfield('5') eq $lc_field->subfield('5'));
895     }
896
897     if ($row_data{text} && $row_data{branch}) { 
898         push (@serialcollections, \%row_data);
899     }
900 }
901
902 if (scalar(@serialcollections) > 0) {
903     $template->param(
904         serialcollection  => 1,
905         serialcollections => \@serialcollections);
906 }
907
908 # Local cover Images stuff
909 if (C4::Context->preference("OPACLocalCoverImages")){
910                 $template->param(OPACLocalCoverImages => 1);
911 }
912
913 # HTML5 Media
914 if ( (C4::Context->preference("HTML5MediaEnabled") eq 'both') or (C4::Context->preference("HTML5MediaEnabled") eq 'opac') ) {
915     $template->param( C4::HTML5Media->gethtml5media($record));
916 }
917
918 my $syndetics_elements;
919
920 if ( C4::Context->preference("SyndeticsEnabled") ) {
921     $template->param("SyndeticsEnabled" => 1);
922     $template->param("SyndeticsClientCode" => C4::Context->preference("SyndeticsClientCode"));
923         eval {
924             $syndetics_elements = &get_syndetics_index($isbn,$upc,$oclc);
925             for my $element (values %$syndetics_elements) {
926                 $template->param("Syndetics$element"."Exists" => 1 );
927                 #warn "Exists: "."Syndetics$element"."Exists";
928         }
929     };
930     warn $@ if $@;
931 }
932
933 if ( C4::Context->preference("SyndeticsEnabled")
934         && C4::Context->preference("SyndeticsSummary")
935         && ( exists($syndetics_elements->{'SUMMARY'}) || exists($syndetics_elements->{'AVSUMMARY'}) ) ) {
936         eval {
937             my $syndetics_summary = &get_syndetics_summary($isbn,$upc,$oclc, $syndetics_elements);
938             $template->param( SYNDETICS_SUMMARY => $syndetics_summary );
939         };
940         warn $@ if $@;
941
942 }
943
944 if ( C4::Context->preference("SyndeticsEnabled")
945         && C4::Context->preference("SyndeticsTOC")
946         && exists($syndetics_elements->{'TOC'}) ) {
947         eval {
948     my $syndetics_toc = &get_syndetics_toc($isbn,$upc,$oclc);
949     $template->param( SYNDETICS_TOC => $syndetics_toc );
950         };
951         warn $@ if $@;
952 }
953
954 if ( C4::Context->preference("SyndeticsEnabled")
955     && C4::Context->preference("SyndeticsExcerpt")
956     && exists($syndetics_elements->{'DBCHAPTER'}) ) {
957     eval {
958     my $syndetics_excerpt = &get_syndetics_excerpt($isbn,$upc,$oclc);
959     $template->param( SYNDETICS_EXCERPT => $syndetics_excerpt );
960     };
961         warn $@ if $@;
962 }
963
964 if ( C4::Context->preference("SyndeticsEnabled")
965     && C4::Context->preference("SyndeticsReviews")) {
966     eval {
967     my $syndetics_reviews = &get_syndetics_reviews($isbn,$upc,$oclc,$syndetics_elements);
968     $template->param( SYNDETICS_REVIEWS => $syndetics_reviews );
969     };
970         warn $@ if $@;
971 }
972
973 if ( C4::Context->preference("SyndeticsEnabled")
974     && C4::Context->preference("SyndeticsAuthorNotes")
975         && exists($syndetics_elements->{'ANOTES'}) ) {
976     eval {
977     my $syndetics_anotes = &get_syndetics_anotes($isbn,$upc,$oclc);
978     $template->param( SYNDETICS_ANOTES => $syndetics_anotes );
979     };
980     warn $@ if $@;
981 }
982
983 # LibraryThingForLibraries ID Code and Tabbed View Option
984 if( C4::Context->preference('LibraryThingForLibrariesEnabled') ) 
985
986 $template->param(LibraryThingForLibrariesID =>
987 C4::Context->preference('LibraryThingForLibrariesID') ); 
988 $template->param(LibraryThingForLibrariesTabbedView =>
989 C4::Context->preference('LibraryThingForLibrariesTabbedView') );
990
991
992 # Novelist Select
993 if( C4::Context->preference('NovelistSelectEnabled') ) 
994
995 $template->param(NovelistSelectProfile => C4::Context->preference('NovelistSelectProfile') ); 
996 $template->param(NovelistSelectPassword => C4::Context->preference('NovelistSelectPassword') ); 
997 $template->param(NovelistSelectView => C4::Context->preference('NovelistSelectView') ); 
998
999
1000
1001 # Babelthèque
1002 if ( C4::Context->preference("Babeltheque") ) {
1003     $template->param( 
1004         Babeltheque => 1,
1005         Babeltheque_url_js => C4::Context->preference("Babeltheque_url_js"),
1006     );
1007 }
1008
1009 # Social Networks
1010 if ( C4::Context->preference( "SocialNetworks" ) ) {
1011     $template->param( current_url => C4::Context->preference('OPACBaseURL') . "/cgi-bin/koha/opac-detail.pl?biblionumber=$biblionumber" );
1012     $template->param( SocialNetworks => 1 );
1013 }
1014
1015 # Shelf Browser Stuff
1016 if (C4::Context->preference("OPACShelfBrowser")) {
1017     my $starting_itemnumber = $query->param('shelfbrowse_itemnumber');
1018     if (defined($starting_itemnumber)) {
1019         $template->param( OpenOPACShelfBrowser => 1) if $starting_itemnumber;
1020         my $nearby = GetNearbyItems($starting_itemnumber);
1021
1022         $template->param(
1023             starting_itemnumber => $starting_itemnumber,
1024             starting_homebranch => $nearby->{starting_homebranch}->{description},
1025             starting_location => $nearby->{starting_location}->{description},
1026             starting_ccode => $nearby->{starting_ccode}->{description},
1027             shelfbrowser_prev_item => $nearby->{prev_item},
1028             shelfbrowser_next_item => $nearby->{next_item},
1029             shelfbrowser_items => $nearby->{items},
1030         );
1031
1032         # in which tab shelf browser should open ?
1033         if (grep { $starting_itemnumber == $_->{itemnumber} } @itemloop) {
1034             $template->param(shelfbrowser_tab => 'holdings');
1035         } else {
1036             $template->param(shelfbrowser_tab => 'otherholdings');
1037         }
1038     }
1039 }
1040
1041 $template->param( AmazonTld => get_amazon_tld() ) if ( C4::Context->preference("OPACAmazonCoverImages"));
1042
1043 if (C4::Context->preference("BakerTaylorEnabled")) {
1044         $template->param(
1045                 BakerTaylorEnabled  => 1,
1046                 BakerTaylorImageURL => &image_url(),
1047                 BakerTaylorLinkURL  => &link_url(),
1048                 BakerTaylorBookstoreURL => C4::Context->preference('BakerTaylorBookstoreURL'),
1049         );
1050         my ($bt_user, $bt_pass);
1051         if ($isbn and
1052                 $bt_user = C4::Context->preference('BakerTaylorUsername') and
1053                 $bt_pass = C4::Context->preference('BakerTaylorPassword')    )
1054         {
1055                 $template->param(
1056                 BakerTaylorContentURL   =>
1057                 sprintf("http://contentcafe2.btol.com/ContentCafeClient/ContentCafe.aspx?UserID=%s&Password=%s&ItemKey=%s&Options=Y",
1058                                 $bt_user,$bt_pass,$isbn)
1059                 );
1060         }
1061 }
1062
1063 my $tag_quantity;
1064 if (C4::Context->preference('TagsEnabled') and $tag_quantity = C4::Context->preference('TagsShowOnDetail')) {
1065         $template->param(
1066                 TagsEnabled => 1,
1067                 TagsShowOnDetail => $tag_quantity,
1068                 TagsInputOnDetail => C4::Context->preference('TagsInputOnDetail')
1069         );
1070         $template->param(TagLoop => get_tags({biblionumber=>$biblionumber, approved=>1,
1071                                                                 'sort'=>'-weight', limit=>$tag_quantity}));
1072 }
1073
1074 if (C4::Context->preference("OPACURLOpenInNewWindow")) {
1075     # These values are going to be read by Javascript, at least in the case
1076     # of the google covers
1077     $template->param(covernewwindow => 'true');
1078 } else {
1079     $template->param(covernewwindow => 'false');
1080 }
1081
1082 if ( C4::Context->preference('OpacStarRatings') !~ /disable/ ) {
1083     my $rating = GetRating( $biblionumber, $borrowernumber );
1084     $template->param(
1085         rating_value   => $rating->{'rating_value'},
1086         rating_total   => $rating->{'rating_total'},
1087         rating_avg     => $rating->{'rating_avg'},
1088         rating_avg_int => $rating->{'rating_avg_int'},
1089         borrowernumber => $borrowernumber
1090     );
1091 }
1092
1093 #Search for title in links
1094 my $marccontrolnumber   = GetMarcControlnumber ($record, $marcflavour);
1095 my $marcissns = GetMarcISSN ( $record, $marcflavour );
1096 my $issn = $marcissns->[0] || '';
1097
1098 if (my $search_for_title = C4::Context->preference('OPACSearchForTitleIn')){
1099     $dat->{title} =~ s/\/+$//; # remove trailing slash
1100     $dat->{title} =~ s/\s+$//; # remove trailing space
1101     $search_for_title = parametrized_url(
1102         $search_for_title,
1103         {
1104             TITLE         => $dat->{title},
1105             AUTHOR        => $dat->{author},
1106             ISBN          => $isbn,
1107             ISSN          => $issn,
1108             CONTROLNUMBER => $marccontrolnumber,
1109             BIBLIONUMBER  => $biblionumber,
1110         }
1111     );
1112     $template->param('OPACSearchForTitleIn' => $search_for_title);
1113 }
1114
1115 #IDREF
1116 if ( C4::Context->preference("IDREF") ) {
1117     # If the record comes from the SUDOC
1118     if ( $record->field('009') ) {
1119         my $unimarc3 = $record->field("009")->data;
1120         if ( $unimarc3 =~ /^\d+$/ ) {
1121             $template->param(
1122                 IDREF => 1,
1123             );
1124         }
1125     }
1126 }
1127
1128 # We try to select the best default tab to show, according to what
1129 # the user wants, and what's available for display
1130 my $opac_serial_default = C4::Context->preference('opacSerialDefaultTab');
1131 my $defaulttab = 
1132     $opac_serial_default eq 'subscriptions' && $subscriptionsnumber
1133         ? 'subscriptions' :
1134     $opac_serial_default eq 'serialcollection' && @serialcollections > 0
1135         ? 'serialcollection' :
1136     $opac_serial_default eq 'holdings' && scalar (@itemloop) > 0
1137         ? 'holdings' :
1138     $subscriptionsnumber
1139         ? 'subscriptions' :
1140     @serialcollections > 0 
1141         ? 'serialcollection' : 'subscriptions';
1142 $template->param('defaulttab' => $defaulttab);
1143
1144 if (C4::Context->preference('OPACLocalCoverImages') == 1) {
1145     my @images = ListImagesForBiblio($biblionumber);
1146     $template->{VARS}->{localimages} = \@images;
1147 }
1148
1149 $template->{VARS}->{IDreamBooksReviews} = C4::Context->preference('IDreamBooksReviews');
1150 $template->{VARS}->{IDreamBooksReadometer} = C4::Context->preference('IDreamBooksReadometer');
1151 $template->{VARS}->{IDreamBooksResults} = C4::Context->preference('IDreamBooksResults');
1152 $template->{VARS}->{OPACPopupAuthorsSearch} = C4::Context->preference('OPACPopupAuthorsSearch');
1153
1154 if (C4::Context->preference('OpacHighlightedWords')) {
1155     $template->{VARS}->{query_desc} = $query->param('query_desc');
1156 }
1157 $template->{VARS}->{'trackclicks'} = C4::Context->preference('TrackClicks');
1158
1159 if ( C4::Context->preference('UseCourseReserves') ) {
1160     foreach my $i ( @items ) {
1161         $i->{'course_reserves'} = GetItemCourseReservesInfo( itemnumber => $i->{'itemnumber'} );
1162     }
1163 }
1164
1165 $template->param(
1166     'OpacLocationBranchToDisplay'         => C4::Context->preference('OpacLocationBranchToDisplay') ,
1167     'OpacLocationBranchToDisplayShelving' => C4::Context->preference('OpacLocationBranchToDisplayShelving'),
1168 );
1169
1170 output_html_with_http_headers $query, $cookie, $template->output;