View | Details | Raw Unified | Return to bug 30327
Collapse All | Expand All

(-)a/Koha/Biblio.pm (-8 / +14 lines)
Lines 516-523 sub suggestions { Link Here
516
516
517
  my $components = $self->get_marc_components();
517
  my $components = $self->get_marc_components();
518
518
519
Returns an array of MARCXML data, which are component parts of
519
Returns an array of search results data, which are component parts of
520
this object (MARC21 773$w points to this)
520
this object (MARC21 773 points to this)
521
521
522
=cut
522
=cut
523
523
Lines 526-544 sub get_marc_components { Link Here
526
526
527
    return [] if (C4::Context->preference('marcflavour') ne 'MARC21');
527
    return [] if (C4::Context->preference('marcflavour') ne 'MARC21');
528
528
529
    my $searchstr = $self->get_components_query;
529
    my ( $searchstr, $sort ) = $self->get_components_query;
530
530
531
    my $components;
531
    my $components;
532
    if (defined($searchstr)) {
532
    if (defined($searchstr)) {
533
        my $searcher = Koha::SearchEngine::Search->new({index => $Koha::SearchEngine::BIBLIOS_INDEX});
533
        my $searcher = Koha::SearchEngine::Search->new({index => $Koha::SearchEngine::BIBLIOS_INDEX});
534
        my ( $error, $results, $total_hits );
534
        my ( $error, $results, $facets );
535
        eval {
535
        eval {
536
            ( $error, $results, $total_hits ) = $searcher->simple_search_compat( $searchstr, 0, $max_results );
536
            ( $error, $results, $facets ) = $searcher->search_compat( $searchstr, undef, [$sort], ['biblioserver'], $max_results, 0, undef, undef, 'ccl', 0 );
537
        };
537
        };
538
        if( $error || $@ ) {
538
        if( $error || $@ ) {
539
            $error //= q{};
539
            $error //= q{};
540
            $error .= $@ if $@;
540
            $error .= $@ if $@;
541
            warn "Warning from simple_search_compat: '$error'";
541
            warn "Warning from search_compat: '$error'";
542
            $self->add_message(
542
            $self->add_message(
543
                {
543
                {
544
                    type    => 'error',
544
                    type    => 'error',
Lines 547-553 sub get_marc_components { Link Here
547
                }
547
                }
548
            );
548
            );
549
        }
549
        }
550
        $components = $results if defined($results) && @$results;
550
        $components = $results->{biblioserver}->{RECORDS} if defined($results) && $results->{biblioserver}->{hits};
551
    }
551
    }
552
552
553
    return $components // [];
553
    return $components // [];
Lines 565-570 sub get_components_query { Link Here
565
    my $builder = Koha::SearchEngine::QueryBuilder->new(
565
    my $builder = Koha::SearchEngine::QueryBuilder->new(
566
        { index => $Koha::SearchEngine::BIBLIOS_INDEX } );
566
        { index => $Koha::SearchEngine::BIBLIOS_INDEX } );
567
    my $marc = $self->metadata->record;
567
    my $marc = $self->metadata->record;
568
    my $sort = C4::Context->preference('ComponentSortField') . "_" . C4::Context->preference('ComponentSortOrder');
568
569
569
    my $searchstr;
570
    my $searchstr;
570
    if ( C4::Context->preference('UseControlNumber') ) {
571
    if ( C4::Context->preference('UseControlNumber') ) {
Lines 597-604 sub get_components_query { Link Here
597
        $cleaned_title = $builder->clean_search_term($cleaned_title);
598
        $cleaned_title = $builder->clean_search_term($cleaned_title);
598
        $searchstr = "Host-item:($cleaned_title)";
599
        $searchstr = "Host-item:($cleaned_title)";
599
    }
600
    }
601
    my ($error, $query_str) = $builder->build_query_compat( undef, [$searchstr], undef, undef, [$sort], 0 );
602
    if( $error ){
603
        warn $error;
604
        return;
605
    }
600
606
601
    return $searchstr;
607
    return ($query_str, $sort);
602
}
608
}
603
609
604
=head3 subscriptions
610
=head3 subscriptions
(-)a/catalogue/detail.pl (-1 / +3 lines)
Lines 222-228 if ( $showcomp eq 'both' || $showcomp eq 'staff' ) { Link Here
222
              );
222
              );
223
        }
223
        }
224
        $template->param( ComponentParts => $parts );
224
        $template->param( ComponentParts => $parts );
225
        $template->param( ComponentPartsQuery => $biblio->get_components_query );
225
        my ( $comp_query, $comp_sort ) = $biblio->get_components_query;
226
        my $cpq = $comp_query . "&sort_by=" . $comp_sort;
227
        $template->param( ComponentPartsQuery => $cpq );
226
    }
228
    }
227
} else { # check if we should show analytics anyway
229
} else { # check if we should show analytics anyway
228
    $show_analytics = 1 if $marc_record && @{$biblio->get_marc_components(1)}; # count matters here, results does not
230
    $show_analytics = 1 if $marc_record && @{$biblio->get_marc_components(1)}; # count matters here, results does not
(-)a/installer/data/mysql/atomicupdate/bug_30327_add_sortComponents_syspref.pl (+16 lines)
Line 0 Link Here
1
use Modern::Perl;
2
3
return {
4
    bug_number => "30327",
5
    description => "Add ComponentsSortField and ComponentsSortOrder sysprefs",
6
    up => sub {
7
        my ($args) = @_;
8
        my ($dbh, $out) = @$args{qw(dbh out)};
9
        $dbh->do(q{
10
            INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, `type` ) VALUES
11
            ('ComponentsSortField','title','call_number|pubdate|acqdate|title|author','Specify the default field used for sorting','Choice'),
12
            ('ComponentsSortOrder','asc','asc|dsc|az|za','Specify the default sort order','Choice')
13
        });
14
        say $out "Added ComponentsSortField and ComponentsSortOrder sysprefs";
15
    },
16
};
(-)a/installer/data/mysql/mandatory/sysprefs.sql (+2 lines)
Lines 144-149 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
144
('CoceProviders', '', 'aws,gb,ol', 'Coce providers', 'multiple'),
144
('CoceProviders', '', 'aws,gb,ol', 'Coce providers', 'multiple'),
145
('COinSinOPACResults','1','','If ON, use COinS in OPAC search results page.  NOTE: this can slow down search response time significantly','YesNo'),
145
('COinSinOPACResults','1','','If ON, use COinS in OPAC search results page.  NOTE: this can slow down search response time significantly','YesNo'),
146
('CollapseFieldsPatronAddForm','',NULL,'Collapse these fields by default when adding a new patron. These fields can still be expanded.','Multiple'),
146
('CollapseFieldsPatronAddForm','',NULL,'Collapse these fields by default when adding a new patron. These fields can still be expanded.','Multiple'),
147
('ComponentsSortField','title','call_number|pubdate|acqdate|title|author','Specify the default field used for sorting','Choice'),
148
('ComponentsSortOrder','asc','asc|dsc|az|za','Specify the default sort order','Choice'),
147
('ConfirmFutureHolds','0','','Number of days for confirming future holds','Integer'),
149
('ConfirmFutureHolds','0','','Number of days for confirming future holds','Integer'),
148
('ConsiderOnSiteCheckoutsAsNormalCheckouts','1',NULL,'Consider on-site checkouts as normal checkouts','YesNo'),
150
('ConsiderOnSiteCheckoutsAsNormalCheckouts','1',NULL,'Consider on-site checkouts as normal checkouts','YesNo'),
149
('CreateAVFromCataloguing', '1', '', 'Ability to create authorized values from the cataloguing module', 'YesNo'),
151
('CreateAVFromCataloguing', '1', '', 'Ability to create authorized values from the cataloguing module', 'YesNo'),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/cataloguing.pref (+16 lines)
Lines 280-285 Cataloging: Link Here
280
            - pref: MaxComponentRecords
280
            - pref: MaxComponentRecords
281
            - "records will be displayed."
281
            - "records will be displayed."
282
            - "<br/> UNIMARC is not supported."
282
            - "<br/> UNIMARC is not supported."
283
            - By default, sort component results in the staff interface by
284
            - pref: ComponentSortField
285
              default: title
286
              choices:
287
                  call_number: call number
288
                  pubdate: date of publication
289
                  acqdate: date added
290
                  title: title
291
                  author: author
292
            - ','
293
            - pref: ComponentSortOrder
294
              choices:
295
                  asc: ascending.
296
                  dsc: descending.
297
                  az: from A to Z.
298
                  za: from Z to A.
283
    Importing:
299
    Importing:
284
        -
300
        -
285
            - When matching on ISBN with the record import tool,
301
            - When matching on ISBN with the record import tool,
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt (-1 / +1 lines)
Lines 707-713 Note that permanent location is a code, and location may be an authval. Link Here
707
            [% END %]
707
            [% END %]
708
        </table>
708
        </table>
709
        [% IF ComponentParts.size == Koha.Preference('MaxComponentRecords')%]
709
        [% IF ComponentParts.size == Koha.Preference('MaxComponentRecords')%]
710
        <p>Only [% ComponentParts.size | html %] results are shown: <a href="/cgi-bin/koha/catalogue/search.pl?q=[% ComponentPartsQuery | uri %]"/>show all component parts</a></p>
710
        <p>Only [% ComponentParts.size | html %] results are shown: <a href="/cgi-bin/koha/catalogue/search.pl?q=[% ComponentPartsQuery | url %]"/>show all component parts</a></p>
711
        [% END %]
711
        [% END %]
712
    </div> <!-- /.content_set -->
712
    </div> <!-- /.content_set -->
713
</div> <!-- /#components -->
713
</div> <!-- /#components -->
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-detail.tt (-1 / +1 lines)
Lines 600-606 Link Here
600
                                [% END %]
600
                                [% END %]
601
                            </table>
601
                            </table>
602
                            [% IF ComponentParts.size == Koha.Preference('MaxComponentRecords')%]
602
                            [% IF ComponentParts.size == Koha.Preference('MaxComponentRecords')%]
603
                            <p>Only [% ComponentParts.size | html %] results are shown: <a href="/cgi-bin/koha/opac-search.pl?q=[% ComponentPartsQuery | uri %]"/>show all component parts</a></p>
603
                            <p>Only [% ComponentParts.size | html %] results are shown: <a href="/cgi-bin/koha/opac-search.pl?q=[% ComponentPartsQuery | url %]"/>show all component parts</a></p>
604
                            [% END %]
604
                            [% END %]
605
                        </div>
605
                        </div>
606
                    </div>
606
                    </div>
(-)a/opac/opac-detail.pl (-1 / +3 lines)
Lines 650-656 if ( $showcomp eq 'both' || $showcomp eq 'opac' ) { Link Here
650
              );
650
              );
651
        }
651
        }
652
        $template->param( ComponentParts => $parts );
652
        $template->param( ComponentParts => $parts );
653
        $template->param( ComponentPartsQuery => $biblio->get_components_query );
653
        my ( $comp_query, $comp_sort ) = $biblio->get_components_query;
654
        my $cpq = $comp_query . "&sort_by=" . $comp_sort;
655
        $template->param( ComponentPartsQuery => $cpq );
654
    }
656
    }
655
} else { # check if we should show analytics anyway
657
} else { # check if we should show analytics anyway
656
    $show_analytics = 1 if @{$biblio->get_marc_components(1)}; # count matters here, results does not
658
    $show_analytics = 1 if @{$biblio->get_marc_components(1)}; # count matters here, results does not
(-)a/t/db_dependent/Koha/Biblio.t (-14 / +24 lines)
Lines 518-524 subtest 'get_marc_components() tests' => sub { Link Here
518
    my $host_biblio = Koha::Biblios->find($host_bibnum);
518
    my $host_biblio = Koha::Biblios->find($host_bibnum);
519
    t::lib::Mocks::mock_preference( 'SearchEngine', 'Zebra' );
519
    t::lib::Mocks::mock_preference( 'SearchEngine', 'Zebra' );
520
    my $search_mod = Test::MockModule->new( 'Koha::SearchEngine::Zebra::Search' );
520
    my $search_mod = Test::MockModule->new( 'Koha::SearchEngine::Zebra::Search' );
521
    $search_mod->mock( 'simple_search_compat', \&search_component_record2 );
521
    $search_mod->mock( 'search_compat', \&search_component_record2 );
522
522
523
    my $components = $host_biblio->get_marc_components;
523
    my $components = $host_biblio->get_marc_components;
524
    is( ref($components), 'ARRAY', 'Return type is correct' );
524
    is( ref($components), 'ARRAY', 'Return type is correct' );
Lines 529-536 subtest 'get_marc_components() tests' => sub { Link Here
529
        '->get_marc_components returns an empty ARRAY'
529
        '->get_marc_components returns an empty ARRAY'
530
    );
530
    );
531
531
532
    $search_mod->unmock( 'simple_search_compat');
532
    $search_mod->unmock( 'search_compat');
533
    $search_mod->mock( 'simple_search_compat', \&search_component_record1 );
533
    $search_mod->mock( 'search_compat', \&search_component_record1 );
534
    my $component_record = component_record1()->as_xml();
534
    my $component_record = component_record1()->as_xml();
535
535
536
    is_deeply(
536
    is_deeply(
Lines 538-550 subtest 'get_marc_components() tests' => sub { Link Here
538
        [$component_record],
538
        [$component_record],
539
        '->get_marc_components returns the related component part record'
539
        '->get_marc_components returns the related component part record'
540
    );
540
    );
541
    $search_mod->unmock( 'simple_search_compat');
541
    $search_mod->unmock( 'search_compat');
542
542
543
    $search_mod->mock( 'simple_search_compat',
543
    $search_mod->mock( 'search_compat',
544
        sub { Koha::Exception->throw("error searching analytics") }
544
        sub { Koha::Exception->throw("error searching analytics") }
545
    );
545
    );
546
    warning_like { $components = $host_biblio->get_marc_components }
546
    warning_like { $components = $host_biblio->get_marc_components }
547
        qr{Warning from simple_search_compat: .* 'error searching analytics'};
547
        qr{Warning from search_compat: .* 'error searching analytics'};
548
548
549
    is_deeply(
549
    is_deeply(
550
        $host_biblio->object_messages,
550
        $host_biblio->object_messages,
Lines 556-590 subtest 'get_marc_components() tests' => sub { Link Here
556
            }
556
            }
557
        ]
557
        ]
558
    );
558
    );
559
    $search_mod->unmock( 'simple_search_compat');
559
    $search_mod->unmock( 'search_compat');
560
560
561
    $schema->storage->txn_rollback;
561
    $schema->storage->txn_rollback;
562
};
562
};
563
563
564
subtest 'get_components_query' => sub {
564
subtest 'get_components_query' => sub {
565
    plan tests => 3;
565
    plan tests => 6;
566
566
567
    my $biblio = $builder->build_sample_biblio();
567
    my $biblio = $builder->build_sample_biblio();
568
    my $biblionumber = $biblio->biblionumber;
568
    my $biblionumber = $biblio->biblionumber;
569
    my $record = $biblio->metadata->record;
569
    my $record = $biblio->metadata->record;
570
570
571
    t::lib::Mocks::mock_preference( 'UseControlNumber', '0' );
571
    t::lib::Mocks::mock_preference( 'UseControlNumber', '0' );
572
    is($biblio->get_components_query, "Host-item:(Some boring read)", "UseControlNumber disabled");
572
    t::lib::Mocks::mock_preference( 'ComponentSortField', 'author' );
573
    t::lib::Mocks::mock_preference( 'ComponentSortOrder', 'za' );
574
    my ( $comp_q, $comp_s ) = $biblio->get_components_query;
575
    is($comp_q, "Host-item:(Some boring read)",, "UseControlNumber disabled");
576
    is($comp_s, "author_za", "UseControlNumber disabled sort is correct");
573
577
574
    t::lib::Mocks::mock_preference( 'UseControlNumber', '1' );
578
    t::lib::Mocks::mock_preference( 'UseControlNumber', '1' );
579
    t::lib::Mocks::mock_preference( 'ComponentSortOrder', 'az' );
575
    my $marc_001_field = MARC::Field->new('001', $biblionumber);
580
    my $marc_001_field = MARC::Field->new('001', $biblionumber);
576
    $record->append_fields($marc_001_field);
581
    $record->append_fields($marc_001_field);
577
    C4::Biblio::ModBiblio( $record, $biblio->biblionumber );
582
    C4::Biblio::ModBiblio( $record, $biblio->biblionumber );
578
    $biblio = Koha::Biblios->find( $biblio->biblionumber);
583
    $biblio = Koha::Biblios->find( $biblio->biblionumber);
579
584
580
    is($biblio->get_components_query, "(rcn:$biblionumber AND (bib-level:a OR bib-level:b))", "UseControlNumber enabled without MarcOrgCode");
585
    ( $comp_q, $comp_s ) = $biblio->get_components_query;
586
    is($comp_q, "(rcn:$biblionumber AND (bib-level:a OR bib-level:b))", "UseControlNumber enabled without MarcOrgCode");
587
    is($comp_s, "author_az", "UseControlNumber enabled without MarcOrgCode sort is correct");
581
588
582
    my $marc_003_field = MARC::Field->new('003', 'OSt');
589
    my $marc_003_field = MARC::Field->new('003', 'OSt');
583
    $record->append_fields($marc_003_field);
590
    $record->append_fields($marc_003_field);
584
    C4::Biblio::ModBiblio( $record, $biblio->biblionumber );
591
    C4::Biblio::ModBiblio( $record, $biblio->biblionumber );
585
    $biblio = Koha::Biblios->find( $biblio->biblionumber);
592
    $biblio = Koha::Biblios->find( $biblio->biblionumber);
586
593
587
    is($biblio->get_components_query, "(((rcn:$biblionumber AND cni:OSt) OR rcn:\"OSt $biblionumber\") AND (bib-level:a OR bib-level:b))", "UseControlNumber enabled with MarcOrgCode");
594
    t::lib::Mocks::mock_preference( 'ComponentSortField', 'title' );
595
    t::lib::Mocks::mock_preference( 'ComponentSortOrder', 'asc' );
596
    ( $comp_q, $comp_s ) = $biblio->get_components_query;
597
    is($comp_q, "(((rcn:$biblionumber AND cni:OSt) OR rcn:\"OSt $biblionumber\") AND (bib-level:a OR bib-level:b))", "UseControlNumber enabled with MarcOrgCode");
598
    is($comp_s, "title_asc", "UseControlNumber enabled with MarcOrgCode sort if correct");
588
};
599
};
589
600
590
subtest 'orders() and active_orders() tests' => sub {
601
subtest 'orders() and active_orders() tests' => sub {
Lines 1014-1025 sub component_record1 { Link Here
1014
}
1025
}
1015
sub search_component_record1 {
1026
sub search_component_record1 {
1016
    my @results = ( component_record1()->as_xml() );
1027
    my @results = ( component_record1()->as_xml() );
1017
    return ( undef, \@results, 1 );
1028
    return ( undef, { biblioserver => { RECORDS => \@results, hits => 1 } }, 1 );
1018
}
1029
}
1019
1030
1020
sub search_component_record2 {
1031
sub search_component_record2 {
1021
    my @results;
1032
    my @results;
1022
    return ( undef, \@results, 0 );
1033
    return ( undef, { biblioserver => { RECORDS => \@results, hits => 0 } }, 0 );
1023
}
1034
}
1024
1035
1025
sub host_record {
1036
sub host_record {
1026
- 

Return to bug 30327