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