X-Git-Url: http://koha-dev.rot13.org:8081/gitweb/?a=blobdiff_plain;f=C4%2FSearch.pm;h=c4276a3078e77e3945eeb1a915eae03bef8133ee;hb=386284d2d5a773e274d30e7ecf1deb137593734e;hp=c69e7873410843bccbcbe008b4f1ffcfd255ef17;hpb=88b3711ca918877796d8577c54efe3f0aba96673;p=koha_gimpoz diff --git a/C4/Search.pm b/C4/Search.pm index c69e787341..c4276a3078 100644 --- a/C4/Search.pm +++ b/C4/Search.pm @@ -30,7 +30,11 @@ use C4::XSLT; 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); @@ -67,6 +71,7 @@ This module provides searching functions for Koha's bibliographic databases &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) @@ -121,18 +126,19 @@ sub FindDuplicate { } } - # 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; @@ -154,12 +160,16 @@ This function provides a simple search API on the bibliographic catalog * $max_results - if present, determines the maximum number of records to fetch. undef is All. defaults to undef. -=item C +=item C - * $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 =back @@ -173,23 +183,23 @@ if (defined $error) { 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); @@ -207,14 +217,14 @@ sub SimpleSearch { 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++ ) { @@ -258,7 +268,7 @@ sub SimpleSearch { for my $j ( $first_record..$last_record ) { my $record = $tmpresults[ $i - 1 ]->record( $j-1 )->raw(); # 0 indexed - push @results, $record; + push @{$results}, $record; } } } @@ -270,7 +280,7 @@ sub SimpleSearch { $zoom_query->destroy(); } - return ( undef, \@results, $total_hits ); + return ( undef, $results, $total_hits ); } } @@ -352,10 +362,10 @@ sub getRecords { # 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 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 @@ -1468,12 +1488,11 @@ sub searchResults { 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) @@ -1547,6 +1566,33 @@ sub searchResults { # Pull out the items fields my @fields = $marcrecord->field($itemtag); + my $marcflavor = C4::Context->preference("marcflavour"); + # adding linked items that belong to host records + my $analyticsfield = '773'; + if ($marcflavor eq 'MARC21' || $marcflavor eq 'NORMARC') { + $analyticsfield = '773'; + } elsif ($marcflavor eq 'UNIMARC') { + $analyticsfield = '461'; + } + foreach my $hostfield ( $marcrecord->field($analyticsfield)) { + my $hostbiblionumber = $hostfield->subfield("0"); + my $linkeditemnumber = $hostfield->subfield("9"); + if(!$hostbiblionumber eq undef){ + my $hostbiblio = GetMarcBiblio($hostbiblionumber, 1); + my ($itemfield, undef) = GetMarcFromKohaField( 'items.itemnumber', GetFrameworkCode($hostbiblionumber) ); + if(!$hostbiblio eq undef){ + my @hostitems = $hostbiblio->field($itemfield); + foreach my $hostitem (@hostitems){ + if ($hostitem->subfield("9") eq $linkeditemnumber){ + my $linkeditem =$hostitem; + # append linked items if they exist + if (!$linkeditem eq undef){ + push (@fields, $linkeditem);} + } + } + } + } + } # Setting item statuses for display my @available_items_loop; @@ -1564,18 +1610,18 @@ sub searchResults { 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; @@ -1584,8 +1630,16 @@ sub searchResults { $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}}; @@ -1628,7 +1682,7 @@ sub searchResults { my ($transfertfrom, $transfertto); # is item on the reserve shelf? - my $reservestatus = 0; + my $reservestatus = ''; my $reserveitem; unless ($item->{wthdrawn} @@ -1650,30 +1704,41 @@ sub searchResults { # 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}; @@ -1685,7 +1750,7 @@ sub searchResults { $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} }; @@ -1693,11 +1758,11 @@ sub searchResults { } } } # 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}; @@ -1711,20 +1776,7 @@ sub searchResults { 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; @@ -1748,8 +1800,8 @@ sub searchResults { $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"); @@ -1779,10 +1831,24 @@ sub searchResults { $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; @@ -2267,7 +2333,7 @@ sub NZorder { # 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(); @@ -2573,7 +2639,15 @@ $template->param ( MYLOOP => C4::Search::z3950_search_args($searchscalar) ) 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 /) { @@ -2640,11 +2714,11 @@ AND (authtypecode IS NOT NULL AND authtypecode<>\"\")|); 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]);