use C4::Search::PazPar2;
use XML::Simple;
use C4::Dates qw(format_date);
+use C4::Members qw(GetHideLostItemsPreference);
use C4::XSLT;
use C4::Branch;
use C4::Reserves; # CheckReserves
use C4::Debug;
+use C4::Charset;
+use YAML;
use URI::Escape;
+use Business::ISBN;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG);
# set the version for version checking
BEGIN {
- $VERSION = 3.01;
+ $VERSION = 3.07.00.049;
$DEBUG = ($ENV{DEBUG}) ? 1 : 0;
}
&NZgetRecords
&AddSearchHistory
&GetDistinctValues
- &BiblioAddAuthorities
+ &enabled_staff_search_views
+ &SimpleSearch
);
-#FIXME: i had to add BiblioAddAuthorities here because in Biblios.pm it caused circular dependencies (C4::Search uses C4::Biblio, and BiblioAddAuthorities uses SimpleSearch from C4::Search)
# make all your functions, whether exported or not;
}
}
- # FIXME: add error handling
- my ( $error, $searchresults ) = SimpleSearch($query); # FIXME :: hardcoded !
+ my ( $error, $searchresults, undef ) = SimpleSearch($query); # FIXME :: hardcoded !
my @results;
- foreach my $possible_duplicate_record (@$searchresults) {
- my $marcrecord =
- MARC::Record->new_from_usmarc($possible_duplicate_record);
- my $result = TransformMarcToKoha( $dbh, $marcrecord, '' );
-
- # FIXME :: why 2 $biblionumber ?
- if ($result) {
- push @results, $result->{'biblionumber'};
- push @results, $result->{'title'};
+ if (!defined $error) {
+ foreach my $possible_duplicate_record (@{$searchresults}) {
+ my $marcrecord =
+ MARC::Record->new_from_usmarc($possible_duplicate_record);
+ my $result = TransformMarcToKoha( $dbh, $marcrecord, '' );
+
+ # FIXME :: why 2 $biblionumber ?
+ if ($result) {
+ push @results, $result->{'biblionumber'};
+ push @results, $result->{'title'};
+ }
}
}
return @results;
* $max_results - if present, determines the maximum number of records to fetch. undef is All. defaults to undef.
-=item C<Output:>
+=item C<Return:>
- * $error is a empty unless an error is detected
- * \@results is an array of records.
+ Returns an array consisting of three elements
+ * $error is undefined unless an error is detected
+ * $results is a reference to an array of records.
* $total_hits is the number of hits that would have been returned with no limit
+ If an error is returned the two other return elements are undefined. If error itself is undefined
+ the other two elements are always defined
+
=item C<usage in the script:>
=back
exit;
}
-my $hits = scalar @$marcresults;
+my $hits = @{$marcresults};
my @results;
-for my $i (0..$hits) {
- my %resultsloop;
- my $marcrecord = MARC::File::USMARC::decode($marcresults->[$i]);
- my $biblio = TransformMarcToKoha(C4::Context->dbh,$marcrecord,'');
-
- #build the hash for the template.
- $resultsloop{title} = $biblio->{'title'};
- $resultsloop{subtitle} = $biblio->{'subtitle'};
- $resultsloop{biblionumber} = $biblio->{'biblionumber'};
- $resultsloop{author} = $biblio->{'author'};
- $resultsloop{publishercode} = $biblio->{'publishercode'};
- $resultsloop{publicationyear} = $biblio->{'publicationyear'};
+for my $r ( @{$marcresults} ) {
+ my $marcrecord = MARC::File::USMARC::decode($r);
+ my $biblio = TransformMarcToKoha(C4::Context->dbh,$marcrecord,q{});
+
+ #build the iarray of hashs for the template.
+ push @results, {
+ title => $biblio->{'title'},
+ subtitle => $biblio->{'subtitle'},
+ biblionumber => $biblio->{'biblionumber'},
+ author => $biblio->{'author'},
+ publishercode => $biblio->{'publishercode'},
+ publicationyear => $biblio->{'publicationyear'},
+ };
- push @results, \%resultsloop;
}
$template->param(result=>\@results);
return ( undef, $search_result, scalar($result->{hits}) );
}
else {
+ return ( 'No query entered', undef, undef ) unless $query;
# FIXME hardcoded value. See catalog/search.pl & opac-search.pl too.
- my @servers = defined ( $servers ) ? @$servers : ( "biblioserver" );
- my @results;
+ my @servers = defined ( $servers ) ? @$servers : ( 'biblioserver' );
my @zoom_queries;
my @tmpresults;
my @zconns;
- my $total_hits;
- return ( "No query entered", undef, undef ) unless $query;
+ my $results = [];
+ my $total_hits = 0;
# Initialize & Search Zebra
for ( my $i = 0 ; $i < @servers ; $i++ ) {
for my $j ( $first_record..$last_record ) {
my $record = $tmpresults[ $i - 1 ]->record( $j-1 )->raw(); # 0 indexed
- push @results, $record;
+ push @{$results}, $record;
}
}
}
$zoom_query->destroy();
}
- return ( undef, \@results, $total_hits );
+ return ( undef, $results, $total_hits );
}
}
( undef, $results_hashref, \@facets_loop ) = getRecords (
$koha_query, $simple_query, $sort_by_ref, $servers_ref,
- $results_per_page, $offset, $expanded_facet, $branches,
+ $results_per_page, $offset, $expanded_facet, $branches,$itemtypes,
$query_type, $scan
);
sub getRecords {
my (
$koha_query, $simple_query, $sort_by_ref, $servers_ref,
- $results_per_page, $offset, $expanded_facet, $branches,
+ $results_per_page, $offset, $expanded_facet, $branches,$itemtypes,
$query_type, $scan
) = @_;
# Note: sort will override rank
my $sort_by;
foreach my $sort (@sort_by) {
- if ( $sort eq "author_az" ) {
+ if ( $sort eq "author_az" || $sort eq "author_asc" ) {
$sort_by .= "1=1003 <i ";
}
- elsif ( $sort eq "author_za" ) {
+ elsif ( $sort eq "author_za" || $sort eq "author_dsc" ) {
$sort_by .= "1=1003 >i ";
}
elsif ( $sort eq "popularity_asc" ) {
$sort_by .= "1=9003 >i ";
}
elsif ( $sort eq "call_number_asc" ) {
- $sort_by .= "1=20 <i ";
+ $sort_by .= "1=8007 <i ";
}
elsif ( $sort eq "call_number_dsc" ) {
- $sort_by .= "1=20 >i ";
+ $sort_by .= "1=8007 >i ";
}
elsif ( $sort eq "pubdate_asc" ) {
$sort_by .= "1=31 <i ";
elsif ( $sort eq "acqdate_dsc" ) {
$sort_by .= "1=32 >i ";
}
- elsif ( $sort eq "title_az" ) {
+ elsif ( $sort eq "title_az" || $sort eq "title_asc" ) {
$sort_by .= "1=4 <i ";
}
- elsif ( $sort eq "title_za" ) {
+ elsif ( $sort eq "title_za" || $sort eq "title_dsc" ) {
$sort_by .= "1=4 >i ";
}
else {
warn "Ignoring unrecognized sort '$sort' requested" if $sort_by;
}
}
- if ($sort_by) {
+ if ($sort_by && !$scan) {
if ( $results[$i]->sort( "yaz", $sort_by ) < 0 ) {
warn "WARNING sort $sort_by failed";
}
if ( !$scan && $servers[ $i - 1 ] =~ /biblioserver/ ) {
my $jmax = $size>$facets_maxrecs? $facets_maxrecs: $size;
-
- for ( my $k = 0 ; $k <= @$facets ; $k++ ) {
- ($facets->[$k]) or next;
- my @fcodes = @{$facets->[$k]->{'tags'}};
- my $sfcode = $facets->[$k]->{'subfield'};
-
+ for my $facet ( @$facets ) {
for ( my $j = 0 ; $j < $jmax ; $j++ ) {
my $render_record = $results[ $i - 1 ]->record($j)->render();
my @used_datas = ();
-
- foreach my $fcode (@fcodes) {
-
+ foreach my $tag ( @{$facet->{tags}} ) {
# avoid first line
- my $field_pattern = '\n'.$fcode.' ([^\n]+)';
+ my $tag_num = substr($tag, 0, 3);
+ my $letters = substr($tag, 3);
+ my $field_pattern = '\n' . $tag_num . ' ([^\n]+)';
my @field_tokens = ( $render_record =~ /$field_pattern/g ) ;
-
foreach my $field_token (@field_tokens) {
- my $subfield_pattern = '\$'.$sfcode.' ([^\$]+)';
- my @subfield_values = ( $field_token =~ /$subfield_pattern/g );
-
- foreach my $subfield_value (@subfield_values) {
-
- my $data = $subfield_value;
- $data =~ s/^\s+//; # trim left
- $data =~ s/\s+$//; # trim right
-
- unless ( $data ~~ @used_datas ) {
- $facets_counter->{ $facets->[$k]->{'link_value'} }->{$data}++;
- push @used_datas, $data;
+ my @subf = ( $field_token =~ /\$([a-zA-Z0-9]) ([^\$]+)/g );
+ my @values;
+ for (my $i = 0; $i < @subf; $i += 2) {
+ if ( $letters =~ $subf[$i] ) {
+ my $value = $subf[$i+1];
+ $value =~ s/^ *//;
+ $value =~ s/ *$//;
+ push @values, $value;
}
- } # subfields
+ }
+ my $data = join($facet->{sep}, @values);
+ unless ( $data ~~ @used_datas ) {
+ $facets_counter->{ $facet->{idx} }->{$data}++;
+ push @used_datas, $data;
+ }
} # fields
} # field codes
} # records
-
- $facets_info->{ $facets->[$k]->{'link_value'} }->{'label_value'} = $facets->[$k]->{'label_value'};
- $facets_info->{ $facets->[$k]->{'link_value'} }->{'expanded'} = $facets->[$k]->{'expanded'};
+ $facets_info->{ $facet->{idx} }->{label_value} = $facet->{label};
+ $facets_info->{ $facet->{idx} }->{expanded} = $facet->{expanded};
} # facets
}
- # End PROGILONE
}
# warn "connection ", $i-1, ": $size hits";
# fix the length that will display in the label,
my $facet_label_value = $one_facet;
+ my $facet_max_length =
+ C4::Context->preference('FacetLabelTruncationLength') || 20;
$facet_label_value =
- substr( $one_facet, 0, 20 ) . "..."
- unless length($facet_label_value) <= 20;
+ substr( $one_facet, 0, $facet_max_length ) . "..."
+ if length($facet_label_value) > $facet_max_length;
# if it's a branch, label by the name, not the code,
if ( $link_value =~ /branch/ ) {
$facet_label_value = "*";
}
}
+ # if it's a itemtype, label by the name, not the code,
+ if ( $link_value =~ /itype/ ) {
+ if (defined $itemtypes
+ && ref($itemtypes) eq "HASH"
+ && defined $itemtypes->{$one_facet}
+ && ref ($itemtypes->{$one_facet}) eq "HASH")
+ {
+ $facet_label_value =
+ $itemtypes->{$one_facet}->{'description'};
+ }
+ }
# but we're down with the whole label being in the link's title.
push @this_facets_array, {
sub _build_stemmed_operand {
my ($operand,$lang) = @_;
require Lingua::Stem::Snowball ;
- my $stemmed_operand;
+ my $stemmed_operand=q{};
# If operand contains a digit, it is almost certainly an identifier, and should
# not be stemmed. This is particularly relevant for ISBNs and ISSNs, which
# FIXME: the locale should be set based on the user's language and/or search choice
#warn "$lang";
+ # Make sure we only use the first two letters from the language code
+ $lang = lc(substr($lang, 0, 2));
+ # The language codes for the two variants of Norwegian will now be "nb" and "nn",
+ # none of which Lingua::Stem::Snowball can use, so we need to "translate" them
+ if ($lang eq 'nb' || $lang eq 'nn') {
+ $lang = 'no';
+ }
my $stemmer = Lingua::Stem::Snowball->new( lang => $lang,
encoding => "UTF-8" );
$weighted_query .=
"Title-cover,ext,r1=\"$operand\""; # exact title-cover
$weighted_query .= " or ti,ext,r2=\"$operand\""; # exact title
- $weighted_query .= " or ti,phr,r3=\"$operand\""; # phrase title
+ $weighted_query .= " or Title-cover,phr,r3=\"$operand\""; # phrase title
#$weighted_query .= " or any,ext,r4=$operand"; # exact any
#$weighted_query .=" or kw,wrdl,r5=\"$operand\""; # word list any
$weighted_query .= " or wrdl,fuzzy,r8=\"$operand\""
'Authority-Number',
'authtype',
'bc',
+ 'Bib-level',
'biblionumber',
'bio',
'biography',
'Date-of-acquisition',
'Date-of-publication',
'Dewey-classification',
+ 'EAN',
'extent',
'fic',
'fiction',
'mc-rtype',
'mus',
'name',
+ 'Music-number',
'Name-geographic',
'Name-geographic-heading',
'Name-geographic-see',
'su-to',
'su-ut',
'ut',
+ 'UPC',
'Term-genre-form',
'Term-genre-form-heading',
'Term-genre-form-see',
'Title',
'Title-cover',
'Title-series',
+ 'Title-host',
'Title-uniform',
'Title-uniform-heading',
'Title-uniform-see',
'reserves',
'restricted',
'stack',
+ 'stocknumber',
+ 'inv',
'uri',
'withdrawn',
my $stopwords_removed; # flag to determine if stopwords have been removed
- my $cclq;
+ my $cclq = 0;
my $cclindexes = getIndexes();
- if( $query !~ /\s*ccl=/ ){
- for my $index (@$cclindexes){
- if($query =~ /($index)(,?\w)*[:=]/){
- $cclq = 1;
- }
+ if ( $query !~ /\s*ccl=/ ) {
+ while ( !$cclq && $query =~ /(?:^|\W)([\w-]+)(,[\w-]+)*[:=]/g ) {
+ my $dx = lc($1);
+ $cclq = grep { lc($_) eq $dx } @$cclindexes;
}
- $query = "ccl=$query" if($cclq);
+ $query = "ccl=$query" if $cclq;
}
# for handling ccl, cql, pqf queries in diagnostic mode, skip the rest of the steps
my $indexes_set;
# If the user is sophisticated enough to specify an index, turn off field weighting, stemming, and stopword handling
- if ( $operands[$i] =~ /(:|=)/ || $scan ) {
+ if ( $operands[$i] =~ /\w(:|=)/ || $scan ) {
$weight_fields = 0;
$stemming = 0;
$remove_stopwords = 0;
+ } else {
+ $operands[$i] =~ s/\?/{?}/g; # need to escape question marks
}
my $operand = $operands[$i];
my $index = $indexes[$i];
}
# ISBN,ISSN,Standard Number, don't need special treatment
elsif ( $index eq 'nb' || $index eq 'ns' ) {
- $indexes_set++;
(
$stemming, $auto_truncation,
$weight_fields, $fuzzy_enabled,
# Set default structure attribute (word list)
my $struct_attr = q{};
- unless ( $indexes_set || !$index || $index =~ /(st-|phr|ext|wrdl)/ ) {
+ unless ( $indexes_set || !$index || $index =~ /(st-|phr|ext|wrdl|nb|ns)/ ) {
$struct_attr = ",wrdl";
}
warn "QUERY BEFORE LIMITS: >$query<" if $DEBUG;
# add limits
- my $group_OR_limits;
+ my %group_OR_limits;
my $availability_limit;
foreach my $this_limit (@limits) {
if ( $this_limit =~ /available/ ) {
# group_OR_limits, prefixed by mc-
# OR every member of the group
elsif ( $this_limit =~ /mc/ ) {
-
- if ( $this_limit =~ /mc-ccode:/ ) {
+ my ($k,$v) = split(/:/, $this_limit,2);
+ if ( $k !~ /mc-i(tem)?type/ ) {
# in case the mc-ccode value has complicating chars like ()'s inside it we wrap in quotes
$this_limit =~ tr/"//d;
- my ($k,$v) = split(/:/, $this_limit,2);
$this_limit = $k.":\"".$v."\"";
}
- $group_OR_limits .= " or " if $group_OR_limits;
- $limit_desc .= " or " if $group_OR_limits;
- $group_OR_limits .= "$this_limit";
+ $group_OR_limits{$k} .= " or " if $group_OR_limits{$k};
+ $limit_desc .= " or " if $group_OR_limits{$k};
+ $group_OR_limits{$k} .= "$this_limit";
$limit_cgi .= "&limit=$this_limit";
$limit_desc .= " $this_limit";
}
}
}
}
- if ($group_OR_limits) {
+ foreach my $k (keys (%group_OR_limits)) {
$limit .= " and " if ( $query || $limit );
- $limit .= "($group_OR_limits)";
+ $limit .= "($group_OR_limits{$k})";
}
if ($availability_limit) {
$limit .= " and " if ( $query || $limit );
# This is flawed , means we can't search anything with : in it
# if user wants to do ccl or cql, start the query with that
# $query =~ s/:/=/g;
- $query =~ s/(?<=(ti|au|pb|su|an|kw|mc)):/=/g;
+ $query =~ s/(?<=(ti|au|pb|su|an|kw|mc|nb|ns)):/=/g;
$query =~ s/(?<=(wrdl)):/=/g;
$query =~ s/(?<=(trn|phr)):/=/g;
$limit =~ s/:/=/g;
# IMO this subroutine is pretty messy still -- it's responsible for
# building the HTML output for the template
sub searchResults {
- my ( $search_context, $searchdesc, $hits, $results_per_page, $offset, $scan, @marcresults, $hidelostitems ) = @_;
+ my ( $search_context, $searchdesc, $hits, $results_per_page, $offset, $scan, $marcresults ) = @_;
my $dbh = C4::Context->dbh;
my @newresults;
- $search_context = 'opac' unless $search_context eq 'opac' or $search_context eq 'intranet';
+ require C4::Items;
+
+ $search_context = 'opac' if !$search_context || $search_context ne 'intranet';
+ my ($is_opac, $hidelostitems);
+ if ($search_context eq 'opac') {
+ $hidelostitems = C4::Context->preference('hidelostitems');
+ $is_opac = 1;
+ }
#Build branchnames hash
#find branchname
}
#search item field code
- my $sth =
- $dbh->prepare(
-"SELECT tagfield FROM marc_subfield_structure WHERE kohafield LIKE 'items.itemnumber'"
- );
- $sth->execute;
- my ($itemtag) = $sth->fetchrow;
+ my ($itemtag, undef) = &GetMarcFromKohaField( "items.itemnumber", "" );
## find column names of items related to MARC
my $sth2 = $dbh->prepare("SHOW COLUMNS FROM items");
my $marcflavour = C4::Context->preference("marcflavour");
# We get the biblionumber position in MARC
my ($bibliotag,$bibliosubf)=GetMarcFromKohaField('biblio.biblionumber','');
- my $fw;
# loop through all of the records we've retrieved
for ( my $i = $offset ; $i <= $times - 1 ; $i++ ) {
- my $marcrecord = MARC::File::USMARC::decode( $marcresults[$i] );
- $fw = $scan
+ my $marcrecord = MARC::File::USMARC::decode( $marcresults->[$i] );
+ my $fw = $scan
? undef
: $bibliotag < 10
? GetFrameworkCode($marcrecord->field($bibliotag)->data)
$oldbiblio->{result_number} = $i + 1;
# add imageurl to itemtype if there is one
- $oldbiblio->{imageurl} = getitemtypeimagelocation( 'opac', $itemtypes{ $oldbiblio->{itemtype} }->{imageurl} );
+ $oldbiblio->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $oldbiblio->{itemtype} }->{imageurl} );
- $oldbiblio->{'authorised_value_images'} = C4::Items::get_authorised_value_images( C4::Biblio::get_biblio_authorised_values( $oldbiblio->{'biblionumber'}, $marcrecord ) );
+ $oldbiblio->{'authorised_value_images'} = ($search_context eq 'opac' && C4::Context->preference('AuthorisedValueImages')) || ($search_context eq 'intranet' && C4::Context->preference('StaffAuthorisedValueImages')) ? C4::Items::get_authorised_value_images( C4::Biblio::get_biblio_authorised_values( $oldbiblio->{'biblionumber'}, $marcrecord ) ) : [];
$oldbiblio->{normalized_upc} = GetNormalizedUPC( $marcrecord,$marcflavour);
$oldbiblio->{normalized_ean} = GetNormalizedEAN( $marcrecord,$marcflavour);
$oldbiblio->{normalized_oclc} = GetNormalizedOCLCNumber($marcrecord,$marcflavour);
# Pull out the items fields
my @fields = $marcrecord->field($itemtag);
+ my $marcflavor = C4::Context->preference("marcflavour");
+ # adding linked items that belong to host records
+ my $analyticsfield = '773';
+ if ($marcflavor eq 'MARC21' || $marcflavor eq 'NORMARC') {
+ $analyticsfield = '773';
+ } elsif ($marcflavor eq 'UNIMARC') {
+ $analyticsfield = '461';
+ }
+ foreach my $hostfield ( $marcrecord->field($analyticsfield)) {
+ my $hostbiblionumber = $hostfield->subfield("0");
+ my $linkeditemnumber = $hostfield->subfield("9");
+ if(!$hostbiblionumber eq undef){
+ my $hostbiblio = GetMarcBiblio($hostbiblionumber, 1);
+ my ($itemfield, undef) = GetMarcFromKohaField( 'items.itemnumber', GetFrameworkCode($hostbiblionumber) );
+ if(!$hostbiblio eq undef){
+ my @hostitems = $hostbiblio->field($itemfield);
+ foreach my $hostitem (@hostitems){
+ if ($hostitem->subfield("9") eq $linkeditemnumber){
+ my $linkeditem =$hostitem;
+ # append linked items if they exist
+ if (!$linkeditem eq undef){
+ push (@fields, $linkeditem);}
+ }
+ }
+ }
+ }
+ }
# Setting item statuses for display
my @available_items_loop;
my $other_count = 0;
my $wthdrawn_count = 0;
my $itemlost_count = 0;
+ my $hideatopac_count = 0;
my $itembinding_count = 0;
my $itemdamaged_count = 0;
my $item_in_transit_count = 0;
my $can_place_holds = 0;
- my $item_onhold_count = 0;
+ my $item_onhold_count = 0;
my $items_count = scalar(@fields);
- my $maxitems =
- ( C4::Context->preference('maxItemsinSearchResults') )
- ? C4::Context->preference('maxItemsinSearchResults') - 1
- : 1;
+ my $maxitems_pref = C4::Context->preference('maxItemsinSearchResults');
+ my $maxitems = $maxitems_pref ? $maxitems_pref - 1 : 1;
# loop through every item
+ my @hiddenitems;
foreach my $field (@fields) {
my $item;
foreach my $code ( keys %subfieldstosearch ) {
$item->{$code} = $field->subfield( $subfieldstosearch{$code} );
}
+ $item->{description} = $itemtypes{ $item->{itype} }{description};
+
+ # Hidden items
+ if ($is_opac) {
+ my @hi = C4::Items::GetHiddenItemnumbers($item);
+ $item->{'hideatopac'} = @hi;
+ push @hiddenitems, @hi;
+ }
+
+ my $hbranch = C4::Context->preference('HomeOrHoldingBranch') eq 'homebranch' ? 'homebranch' : 'holdingbranch';
+ my $otherbranch = C4::Context->preference('HomeOrHoldingBranch') eq 'homebranch' ? 'holdingbranch' : 'homebranch';
- my $hbranch = C4::Context->preference('HomeOrHoldingBranch') eq 'homebranch' ? 'homebranch' : 'holdingbranch';
- my $otherbranch = C4::Context->preference('HomeOrHoldingBranch') eq 'homebranch' ? 'holdingbranch' : 'homebranch';
# set item's branch name, use HomeOrHoldingBranch syspref first, fall back to the other one
if ($item->{$hbranch}) {
$item->{'branchname'} = $branches{$item->{$hbranch}};
my $prefix = $item->{$hbranch} . '--' . $item->{location} . $item->{itype} . $item->{itemcallnumber};
# For each grouping of items (onloan, available, unavailable), we build a key to store relevant info about that item
- if ( $item->{onloan} ) {
+ my $userenv = C4::Context->userenv;
+ if ( $item->{onloan} && !(C4::Members::GetHideLostItemsPreference($userenv->{'number'}) && $item->{itemlost}) ) {
$onloan_count++;
my $key = $prefix . $item->{onloan} . $item->{barcode};
$onloan_items->{$key}->{due_date} = format_date($item->{onloan});
$onloan_items->{$key}->{branchname} = $item->{branchname};
$onloan_items->{$key}->{location} = $shelflocations->{ $item->{location} };
$onloan_items->{$key}->{itemcallnumber} = $item->{itemcallnumber};
- $onloan_items->{$key}->{imageurl} = getitemtypeimagelocation( 'opac', $itemtypes{ $item->{itype} }->{imageurl} );
+ $onloan_items->{$key}->{description} = $item->{description};
+ $onloan_items->{$key}->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $item->{itype} }->{imageurl} );
# if something's checked out and lost, mark it as 'long overdue'
if ( $item->{itemlost} ) {
$onloan_items->{$prefix}->{longoverdue}++;
my ($transfertfrom, $transfertto);
# is item on the reserve shelf?
- my $reservestatus = 0;
+ my $reservestatus = '';
my $reserveitem;
unless ($item->{wthdrawn}
# should map transit status to record indexed in Zebra.
#
($transfertwhen, $transfertfrom, $transfertto) = C4::Circulation::GetTransfers($item->{itemnumber});
- ($reservestatus, $reserveitem) = C4::Reserves::CheckReserves($item->{itemnumber});
+ ($reservestatus, $reserveitem, undef) = C4::Reserves::CheckReserves($item->{itemnumber});
}
- # item is withdrawn, lost or damaged
+ # item is withdrawn, lost, damaged, not for loan, reserved or in transit
if ( $item->{wthdrawn}
|| $item->{itemlost}
|| $item->{damaged}
|| $item->{notforloan} > 0
+ || $item->{hideatopac}
|| $reservestatus eq 'Waiting'
|| ($transfertwhen ne ''))
{
$wthdrawn_count++ if $item->{wthdrawn};
$itemlost_count++ if $item->{itemlost};
$itemdamaged_count++ if $item->{damaged};
+ $hideatopac_count++ if $item->{hideatopac};
$item_in_transit_count++ if $transfertwhen ne '';
$item_onhold_count++ if $reservestatus eq 'Waiting';
$item->{status} = $item->{wthdrawn} . "-" . $item->{itemlost} . "-" . $item->{damaged} . "-" . $item->{notforloan};
+
+ # can place hold on item ?
+ if ((!$item->{damaged} || C4::Context->preference('AllowHoldsOnDamagedItems'))
+ && !$item->{itemlost}
+ && !$item->{withdrawn}
+ ) {
+ $can_place_holds = 1;
+ }
+
$other_count++;
- my $key = $prefix . $item->{status};
- foreach (qw(wthdrawn itemlost damaged branchname itemcallnumber)) {
- $other_items->{$key}->{$_} = $item->{$_};
- }
- $other_items->{$key}->{intransit} = ($transfertwhen ne '') ? 1 : 0;
+ my $key = $prefix . $item->{status};
+ foreach (qw(wthdrawn itemlost damaged branchname itemcallnumber hideatopac)) {
+ $other_items->{$key}->{$_} = $item->{$_};
+ }
+ $other_items->{$key}->{intransit} = ( $transfertwhen ne '' ) ? 1 : 0;
$other_items->{$key}->{onhold} = ($reservestatus) ? 1 : 0;
- $other_items->{$key}->{notforloan} = GetAuthorisedValueDesc('','',$item->{notforloan},'','',$notforloan_authorised_value) if $notforloan_authorised_value;
+ $other_items->{$key}->{notforloan} = GetAuthorisedValueDesc('','',$item->{notforloan},'','',$notforloan_authorised_value) if $notforloan_authorised_value and $item->{notforloan};
$other_items->{$key}->{count}++ if $item->{$hbranch};
$other_items->{$key}->{location} = $shelflocations->{ $item->{location} };
- $other_items->{$key}->{imageurl} = getitemtypeimagelocation( 'opac', $itemtypes{ $item->{itype} }->{imageurl} );
+ $other_items->{$key}->{description} = $item->{description};
+ $other_items->{$key}->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $item->{itype} }->{imageurl} );
}
# item is available
else {
$can_place_holds = 1;
$available_count++;
$available_items->{$prefix}->{count}++ if $item->{$hbranch};
- foreach (qw(branchname itemcallnumber)) {
+ foreach (qw(branchname itemcallnumber hideatopac description)) {
$available_items->{$prefix}->{$_} = $item->{$_};
}
$available_items->{$prefix}->{location} = $shelflocations->{ $item->{location} };
- $available_items->{$prefix}->{imageurl} = getitemtypeimagelocation( 'opac', $itemtypes{ $item->{itype} }->{imageurl} );
+ $available_items->{$prefix}->{imageurl} = getitemtypeimagelocation( $search_context, $itemtypes{ $item->{itype} }->{imageurl} );
}
}
} # notforloan, item level and biblioitem level
+ if ($items_count > 0) {
+ next if $is_opac && $hideatopac_count >= $items_count;
+ next if $hidelostitems && $itemlost_count >= $items_count;
+ }
my ( $availableitemscount, $onloanitemscount, $otheritemscount );
- $maxitems =
- ( C4::Context->preference('maxItemsinSearchResults') )
- ? C4::Context->preference('maxItemsinSearchResults') - 1
- : 1;
for my $key ( sort keys %$onloan_items ) {
(++$onloanitemscount > $maxitems) and last;
push @onloan_items_loop, $onloan_items->{$key};
# XSLT processing of some stuff
use C4::Charset;
SetUTF8Flag($marcrecord);
- $debug && warn $marcrecord->as_formatted;
- if (!$scan && $search_context eq 'opac' && C4::Context->preference("OPACXSLTResultsDisplay")) {
- # FIXME note that XSLTResultsDisplay (use of XSLT to format staff interface bib search results)
- # is not implemented yet
- $oldbiblio->{XSLTResultsRecord} = XSLTParse4Display($oldbiblio->{biblionumber}, $marcrecord, 'Results',
- $search_context, 1);
- # the last parameter tells Koha to clean up the problematic ampersand entities that Zebra outputs
-
+ warn $marcrecord->as_formatted if $DEBUG;
+ my $interface = $search_context eq 'opac' ? 'OPAC' : '';
+ if (!$scan && C4::Context->preference($interface . "XSLTResultsDisplay")) {
+ $oldbiblio->{XSLTResultsRecord} = XSLTParse4Display($oldbiblio->{biblionumber}, $marcrecord, $interface."XSLTResultsDisplay", 1, \@hiddenitems);
+ # the last parameter tells Koha to clean up the problematic ampersand entities that Zebra outputs
}
# if biblio level itypes are used and itemtype is notforloan, it can't be reserved either
$oldbiblio->{intransitcount} = $item_in_transit_count;
$oldbiblio->{onholdcount} = $item_onhold_count;
$oldbiblio->{orderedcount} = $ordered_count;
- $oldbiblio->{isbn} =~
- s/-//g; # deleting - in isbn to enable amazon content
- push( @newresults, $oldbiblio )
- if(not $hidelostitems
- or (($items_count > $itemlost_count )
- && $hidelostitems));
+
+ if (C4::Context->preference("AlternateHoldingsField") && $items_count == 0) {
+ my $fieldspec = C4::Context->preference("AlternateHoldingsField");
+ my $subfields = substr $fieldspec, 3;
+ my $holdingsep = C4::Context->preference("AlternateHoldingsSeparator") || ' ';
+ my @alternateholdingsinfo = ();
+ my @holdingsfields = $marcrecord->field(substr $fieldspec, 0, 3);
+ my $alternateholdingscount = 0;
+
+ for my $field (@holdingsfields) {
+ my %holding = ( holding => '' );
+ my $havesubfield = 0;
+ for my $subfield ($field->subfields()) {
+ if ((index $subfields, $$subfield[0]) >= 0) {
+ $holding{'holding'} .= $holdingsep if (length $holding{'holding'} > 0);
+ $holding{'holding'} .= $$subfield[1];
+ $havesubfield++;
+ }
+ }
+ if ($havesubfield) {
+ push(@alternateholdingsinfo, \%holding);
+ $alternateholdingscount++;
+ }
+ }
+
+ $oldbiblio->{'ALTERNATEHOLDINGS'} = \@alternateholdingsinfo;
+ $oldbiblio->{'alternateholdings_count'} = $alternateholdingscount;
+ }
+
+ push( @newresults, $oldbiblio );
}
return @newresults;
# sort the hash and return the same structure as GetRecords (Zebra querying)
my $result_hash;
my $numbers = 0;
- if ( $ordering eq 'author_za' ) { # sort by author desc
+ if ( $ordering eq 'author_za' || $ordering eq 'author_dsc' ) { # sort by author desc
foreach my $key ( sort { $b cmp $a } ( keys %result ) ) {
$result_hash->{'RECORDS'}[ $numbers++ ] =
$result{$key}->as_usmarc();
sub z3950_search_args {
my $bibrec = shift;
- $bibrec = { title => $bibrec } if !ref $bibrec;
+ my $isbn = Business::ISBN->new($bibrec);
+
+ if (defined $isbn && $isbn->is_valid)
+ {
+ $bibrec = { isbn => $bibrec } if !ref $bibrec;
+ }
+ else {
+ $bibrec = { title => $bibrec } if !ref $bibrec;
+ }
my $array = [];
for my $field (qw/ lccn isbn issn title author dewey subject /)
{
return $array;
}
-=head2 BiblioAddAuthorities
-
-( $countlinked, $countcreated ) = BiblioAddAuthorities($record, $frameworkcode);
-
-this function finds the authorities linked to the biblio
- * search in the authority DB for the same authid (in $9 of the biblio)
- * search in the authority DB for the same 001 (in $3 of the biblio in UNIMARC)
- * search in the authority DB for the same values (exactly) (in all subfields of the biblio)
-OR adds a new authority record
-
-=over 2
-
-=item C<input arg:>
-
- * $record is the MARC record in question (marc blob)
- * $frameworkcode is the bibliographic framework to use (if it is "" it uses the default framework)
-
-=item C<Output arg:>
-
- * $countlinked is the number of authorities records that are linked to this authority
- * $countcreated
-
-=item C<BUGS>
- * I had to add this to Search.pm (instead of the logical Biblio.pm) because of a circular dependency (this sub uses SimpleSearch, and Search.pm uses Biblio.pm)
-
-=back
-
-=cut
-
-
-sub BiblioAddAuthorities{
- my ( $record, $frameworkcode ) = @_;
- my $dbh=C4::Context->dbh;
- my $query=$dbh->prepare(qq|
-SELECT authtypecode,tagfield
-FROM marc_subfield_structure
-WHERE frameworkcode=?
-AND (authtypecode IS NOT NULL AND authtypecode<>\"\")|);
-# SELECT authtypecode,tagfield
-# FROM marc_subfield_structure
-# WHERE frameworkcode=?
-# AND (authtypecode IS NOT NULL OR authtypecode<>\"\")|);
- $query->execute($frameworkcode);
- my ($countcreated,$countlinked);
- while (my $data=$query->fetchrow_hashref){
- foreach my $field ($record->field($data->{tagfield})){
- next if ($field->subfield('3')||$field->subfield('9'));
- # No authorities id in the tag.
- # Search if there is any authorities to link to.
- my $query='at='.$data->{authtypecode}.' ';
- map {$query.= ' and he,ext="'.$_->[1].'"' if ($_->[0]=~/[A-z]/)} $field->subfields();
- my ($error, $results, $total_hits)=SimpleSearch( $query, undef, undef, [ "authorityserver" ] );
- # there is only 1 result
- if ( $error ) {
- warn "BIBLIOADDSAUTHORITIES: $error";
- return (0,0) ;
- }
- if ($results && scalar(@$results)==1) {
- my $marcrecord = MARC::File::USMARC::decode($results->[0]);
- $field->add_subfields('9'=>$marcrecord->field('001')->data);
- $countlinked++;
- } elsif (scalar(@$results)>1) {
- #More than One result
- #This can comes out of a lack of a subfield.
-# my $marcrecord = MARC::File::USMARC::decode($results->[0]);
-# $record->field($data->{tagfield})->add_subfields('9'=>$marcrecord->field('001')->data);
- $countlinked++;
- } else {
- #There are no results, build authority record, add it to Authorities, get authid and add it to 9
- ###NOTICE : This is only valid if a subfield is linked to one and only one authtypecode
- ###NOTICE : This can be a problem. We should also look into other types and rejected forms.
- my $authtypedata=C4::AuthoritiesMarc::GetAuthType($data->{authtypecode});
- next unless $authtypedata;
- my $marcrecordauth=MARC::Record->new();
- my $authfield=MARC::Field->new($authtypedata->{auth_tag_to_report},'','',"a"=>"".$field->subfield('a'));
- map { $authfield->add_subfields($_->[0]=>$_->[1]) if ($_->[0]=~/[A-z]/ && $_->[0] ne "a" )} $field->subfields();
- $marcrecordauth->insert_fields_ordered($authfield);
-
- # bug 2317: ensure new authority knows it's using UTF-8; currently
- # only need to do this for MARC21, as MARC::Record->as_xml_record() handles
- # automatically for UNIMARC (by not transcoding)
- # FIXME: AddAuthority() instead should simply explicitly require that the MARC::Record
- # use UTF-8, but as of 2008-08-05, did not want to introduce that kind
- # of change to a core API just before the 3.0 release.
- if (C4::Context->preference('marcflavour') eq 'MARC21') {
- SetMarcUnicodeFlag($marcrecordauth, 'MARC21');
- }
-
-# warn "AUTH RECORD ADDED : ".$marcrecordauth->as_formatted;
-
- my $authid=AddAuthority($marcrecordauth,'',$data->{authtypecode});
- $countcreated++;
- $field->add_subfields('9'=>$authid);
- }
- }
- }
- return ($countlinked,$countcreated);
-}
-
=head2 GetDistinctValues($field);
C<$field> is a reference to the fields array