use C4::Branch;
use C4::Reserves; # CheckReserves
use C4::Debug;
+use C4::Items;
+use C4::Charset;
+use YAML;
use URI::Escape;
+use Business::ISBN;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG);
&AddSearchHistory
&GetDistinctValues
&BiblioAddAuthorities
+ &enabled_staff_search_views
);
#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)
}
}
- # 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 );
}
}
# 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" ) {
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 {
'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',
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
# 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';
+ $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
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)
# 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;
$item->{$code} = $field->subfield( $subfieldstosearch{$code} );
}
- my $hbranch = C4::Context->preference('HomeOrHoldingBranch') eq 'homebranch' ? 'homebranch' : 'holdingbranch';
- my $otherbranch = C4::Context->preference('HomeOrHoldingBranch') eq 'homebranch' ? 'holdingbranch' : 'homebranch';
+ # Hidden items
+ if ($is_opac) {
+ my @hi = 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';
+
# set item's branch name, use HomeOrHoldingBranch syspref first, fall back to the other one
if ($item->{$hbranch}) {
$item->{'branchname'} = $branches{$item->{$hbranch}};
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}->{count}++ if $item->{$hbranch};
$can_place_holds = 1;
$available_count++;
$available_items->{$prefix}->{count}++ if $item->{$hbranch};
- foreach (qw(branchname itemcallnumber)) {
+ foreach (qw(branchname itemcallnumber hideatopac)) {
$available_items->{$prefix}->{$_} = $item->{$_};
}
$available_items->{$prefix}->{location} = $shelflocations->{ $item->{location} };
}
}
} # notforloan, item level and biblioitem level
+
+ 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};
push @available_items_loop, $available_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
-
- }
-
- # if biblio level itypes are used and itemtype is notforloan, it can't be reserved either
+ # if biblio level itypes are used and itemtype is notforloan, it can't be reserved either
if (!C4::Context->preference("item-level_itypes")) {
if ($itemtypes{ $oldbiblio->{itemtype} }->{notforloan}) {
$can_place_holds = 0;
$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
+ # deleting - in isbn to enable amazon content
+ $oldbiblio->{isbn} =~ s/-//g;
if (C4::Context->preference("AlternateHoldingsField") && $items_count == 0) {
my $fieldspec = C4::Context->preference("AlternateHoldingsField");
$oldbiblio->{'alternateholdings_count'} = $alternateholdingscount;
}
- push( @newresults, $oldbiblio )
- if(not $hidelostitems
- or (($items_count > $itemlost_count )
- && $hidelostitems));
+ # XSLT processing of some stuff
+ if (!$scan && $search_context eq 'opac' && C4::Context->preference("OPACXSLTResultsDisplay")) {
+ SetUTF8Flag($marcrecord);
+ $debug && warn $marcrecord->as_formatted;
+ # 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, # clean up the problematic ampersand entities that Zebra outputs
+ \@hiddenitems
+ );
+
+ }
+
+ 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 /)
{
warn "BIBLIOADDSAUTHORITIES: $error";
return (0,0) ;
}
- if ($results && scalar(@$results)==1) {
+ if ( @{$results} == 1 ) {
my $marcrecord = MARC::File::USMARC::decode($results->[0]);
$field->add_subfields('9'=>$marcrecord->field('001')->data);
$countlinked++;
- } elsif (scalar(@$results)>1) {
+ } elsif ( @{$results} > 1 ) {
#More than One result
#This can comes out of a lack of a subfield.
# my $marcrecord = MARC::File::USMARC::decode($results->[0]);