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

(-)a/C4/Biblio.pm (-5 / +3 lines)
Lines 100-106 use C4::Charset qw( Link Here
100
);
100
);
101
use C4::Linker;
101
use C4::Linker;
102
use C4::OAI::Sets;
102
use C4::OAI::Sets;
103
use C4::Items qw( GetHiddenItemnumbers GetMarcItem );
103
use C4::Items qw( GetMarcItem );
104
104
105
use Koha::Logger;
105
use Koha::Logger;
106
use Koha::Caches;
106
use Koha::Caches;
Lines 2516-2530 sub EmbedItemsInMarcBiblio { Link Here
2516
        }
2516
        }
2517
        push @items, { itemnumber => $itemnumber, item => $item };
2517
        push @items, { itemnumber => $itemnumber, item => $item };
2518
    }
2518
    }
2519
    my @items2pass = map { $_->{item} } @items;
2520
    my @hiddenitems =
2521
      $opachiddenitems
2522
      ? C4::Items::GetHiddenItemnumbers({
2523
            items  => \@items2pass,
2519
            items  => \@items2pass,
2524
            borcat => $borcat })
2520
            borcat => $borcat })
2525
      : ();
2521
      : ();
2526
    # Convert to a hash for quick searching
2522
    # Convert to a hash for quick searching
2527
    my %hiddenitems = map { $_ => 1 } @hiddenitems;
2523
    my %hiddenitems = map { $_ => 1 } @hiddenitems;
2524
    my @itemnumbers = Koha::Items->search( { itemnumber => $itemnumbers } )
2525
      ->filter_by_visible_in_opac({ patron => })->get_column('itemnumber');
2528
    foreach my $itemnumber ( map { $_->{itemnumber} } @items ) {
2526
    foreach my $itemnumber ( map { $_->{itemnumber} } @items ) {
2529
        next if $hiddenitems{$itemnumber};
2527
        next if $hiddenitems{$itemnumber};
2530
        my $item_marc = C4::Items::GetMarcItem( $biblionumber, $itemnumber );
2528
        my $item_marc = C4::Items::GetMarcItem( $biblionumber, $itemnumber );
(-)a/C4/Items.pm (-60 lines)
Lines 38-44 BEGIN { Link Here
38
        GetItemsLocationInfo
38
        GetItemsLocationInfo
39
        GetHostItemsInfo
39
        GetHostItemsInfo
40
        get_hostitemnumbers_of
40
        get_hostitemnumbers_of
41
        GetHiddenItemnumbers
42
        GetMarcItem
41
        GetMarcItem
43
        CartToShelf
42
        CartToShelf
44
        GetAnalyticsCount
43
        GetAnalyticsCount
Lines 975-1039 sub get_hostitemnumbers_of { Link Here
975
    return @returnhostitemnumbers;
974
    return @returnhostitemnumbers;
976
}
975
}
977
976
978
=head2 GetHiddenItemnumbers
979
980
    my @itemnumbers_to_hide = GetHiddenItemnumbers({ items => \@items, borcat => $category });
981
982
Given a list of items it checks which should be hidden from the OPAC given
983
the current configuration. Returns a list of itemnumbers corresponding to
984
those that should be hidden. Optionally takes a borcat parameter for certain borrower types
985
to be excluded
986
987
=cut
988
989
sub GetHiddenItemnumbers {
990
    my $params = shift;
991
    my $items = $params->{items};
992
    if (my $exceptions = C4::Context->preference('OpacHiddenItemsExceptions') and $params->{'borcat'}){
993
        foreach my $except (split(/\|/, $exceptions)){
994
            if ($params->{'borcat'} eq $except){
995
                return; # we don't hide anything for this borrower category
996
            }
997
        }
998
    }
999
    my @resultitems;
1000
1001
    my $hidingrules = C4::Context->yaml_preference('OpacHiddenItems');
1002
1003
    return
1004
        unless $hidingrules;
1005
1006
    my $dbh = C4::Context->dbh;
1007
1008
    # For each item
1009
    foreach my $item (@$items) {
1010
1011
        # We check each rule
1012
        foreach my $field (keys %$hidingrules) {
1013
            my $val;
1014
            if (exists $item->{$field}) {
1015
                $val = $item->{$field};
1016
            }
1017
            else {
1018
                my $query = "SELECT $field from items where itemnumber = ?";
1019
                $val = $dbh->selectrow_array($query, undef, $item->{'itemnumber'});
1020
            }
1021
            $val = '' unless defined $val;
1022
1023
            # If the results matches the values in the yaml file
1024
            if (any { $val eq $_ } @{$hidingrules->{$field}}) {
1025
1026
                # We add the itemnumber to the list
1027
                push @resultitems, $item->{'itemnumber'};
1028
1029
                # If at least one rule matched for an item, no need to test the others
1030
                last;
1031
            }
1032
        }
1033
    }
1034
    return @resultitems;
1035
}
1036
1037
=head1 LIMITED USE FUNCTIONS
977
=head1 LIMITED USE FUNCTIONS
1038
978
1039
The following functions, while part of the public API,
979
The following functions, while part of the public API,
(-)a/C4/Search.pm (-10 / +5 lines)
Lines 1802-1822 sub searchResults { Link Here
1802
            }
1802
            }
1803
            $item->{description} = $itemtypes{ $item->{itype} }{translated_description} if $item->{itype};
1803
            $item->{description} = $itemtypes{ $item->{itype} }{translated_description} if $item->{itype};
1804
1804
1805
	        # OPAC hidden items
1805
            # OPAC hidden items
1806
            if ($is_opac) {
1806
            if ($is_opac) {
1807
                # hidden because lost
1807
                # hidden based on OpacHiddenItems syspref or because lost
1808
                if ($hidelostitems && $item->{itemlost}) {
1808
                my $hi = Koha::Items->search( { itemnumber => $item->{itemnumber} } )
1809
                                    ->filter_by_visible_in_opac({ patron => $search_context->{patron} });
1810
                unless ( $hi->count ) {
1809
                    push @hiddenitems, $item->{itemnumber};
1811
                    push @hiddenitems, $item->{itemnumber};
1810
                    $hideatopac_count++;
1812
                    $hideatopac_count++;
1811
                    next;
1813
                    next;
1812
                }
1814
                }
1813
                # hidden based on OpacHiddenItems syspref
1814
                my @hi = C4::Items::GetHiddenItemnumbers({ items=> [ $item ], borcat => $search_context->{category} });
1815
                if (scalar @hi) {
1816
                    push @hiddenitems, @hi;
1817
                    $hideatopac_count++;
1818
                    next;
1819
                }
1820
            }
1815
            }
1821
1816
1822
            my $hbranch     = C4::Context->preference('StaffSearchResultsDisplayBranch');
1817
            my $hbranch     = C4::Context->preference('StaffSearchResultsDisplayBranch');
(-)a/opac/opac-basket.pl (-24 / +8 lines)
Lines 26-32 use C4::Biblio qw( Link Here
26
    GetMarcSubjects
26
    GetMarcSubjects
27
    GetMarcUrls
27
    GetMarcUrls
28
);
28
);
29
use C4::Items qw( GetHiddenItemnumbers GetItemsInfo );
29
use C4::Items qw( GetItemsInfo );
30
use C4::Circulation qw( GetTransfers );
30
use C4::Circulation qw( GetTransfers );
31
use C4::Auth qw( get_template_and_user );
31
use C4::Auth qw( get_template_and_user );
32
use C4::Output qw( output_html_with_http_headers );
32
use C4::Output qw( output_html_with_http_headers );
Lines 63-74 if (C4::Context->preference('TagsEnabled')) { Link Here
63
	}
63
	}
64
}
64
}
65
65
66
my $borcat = q{};
66
my $logged_in_user = Koha::Patrons->find($borrowernumber);
67
if ( C4::Context->preference('OpacHiddenItemsExceptions') ) {
68
    # we need to fetch the borrower info here, so we can pass the category
69
    my $patron = Koha::Patrons->find($borrowernumber);
70
    $borcat = $patron ? $patron->categorycode : $borcat;
71
}
72
67
73
my $record_processor = Koha::RecordProcessor->new({ filters => 'ViewPolicy' });
68
my $record_processor = Koha::RecordProcessor->new({ filters => 'ViewPolicy' });
74
my $rules = C4::Context->yaml_preference('OpacHiddenItems');
69
my $rules = C4::Context->yaml_preference('OpacHiddenItems');
Lines 95-121 foreach my $biblionumber ( @bibs ) { Link Here
95
    my $marcseriesarray  = GetMarcSeries  ($record,$marcflavour);
90
    my $marcseriesarray  = GetMarcSeries  ($record,$marcflavour);
96
    my $marcurlsarray    = GetMarcUrls    ($record,$marcflavour);
91
    my $marcurlsarray    = GetMarcUrls    ($record,$marcflavour);
97
92
98
    # grab all the items...
99
    my @all_items        = &GetItemsInfo( $biblionumber );
100
101
    # determine which ones should be hidden / visible
102
    my @hidden_items     = GetHiddenItemnumbers({ items => \@all_items, borcat => $borcat });
103
104
    # If every item is hidden, then the biblio should be hidden too.
93
    # If every item is hidden, then the biblio should be hidden too.
105
    next
94
    next
106
      if $biblio->hidden_in_opac({ rules => $rules });
95
      if $biblio->hidden_in_opac({ rules => $rules });
107
96
108
    # copy the visible ones into the items array.
97
    # grab all the items...
109
    my @items;
98
    my @items        = $biblio->items->filter_by_visible_in_opac({ patron => $logged_in_user })->unblessed;
110
    foreach my $item (@all_items) {
99
    foreach my $item (@items) {
111
100
        my $reserve_status = C4::Reserves::GetReserveStatus($item->{itemnumber});
112
            # next if item is hidden
101
        if( $reserve_status eq "Waiting"){ $item->{'waiting'} = 1; }
113
            next  if  grep  { $item->{itemnumber} eq $_  } @hidden_items ;
102
        if( $reserve_status eq "Reserved"){ $item->{'onhold'} = 1; }
114
115
            my $reserve_status = C4::Reserves::GetReserveStatus($item->{itemnumber});
116
            if( $reserve_status eq "Waiting"){ $item->{'waiting'} = 1; }
117
            if( $reserve_status eq "Reserved"){ $item->{'onhold'} = 1; }
118
            push @items, $item;
119
    }
103
    }
120
104
121
    my $hasauthors = 0;
105
    my $hasauthors = 0;
(-)a/opac/opac-detail.pl (-15 / +14 lines)
Lines 45-51 use C4::Biblio qw( Link Here
45
    GetMarcSubjects
45
    GetMarcSubjects
46
    GetMarcUrls
46
    GetMarcUrls
47
);
47
);
48
use C4::Items qw( GetHiddenItemnumbers GetItemsInfo );
48
use C4::Items qw( GetItemsInfo );
49
use C4::Circulation qw( GetTransfers );
49
use C4::Circulation qw( GetTransfers );
50
use C4::Tags qw( get_tags );
50
use C4::Tags qw( get_tags );
51
use C4::XISBN qw( get_xisbns );
51
use C4::XISBN qw( get_xisbns );
Lines 108-114 if( $specific_item ) { Link Here
108
    @all_items = grep { $_->{itemnumber} == $query->param('itemnumber') } @all_items;
108
    @all_items = grep { $_->{itemnumber} == $query->param('itemnumber') } @all_items;
109
    $template->param( specific_item => 1 );
109
    $template->param( specific_item => 1 );
110
}
110
}
111
my @hiddenitems;
111
my @items_to_show;
112
my $patron = Koha::Patrons->find( $borrowernumber );
112
my $patron = Koha::Patrons->find( $borrowernumber );
113
113
114
my $biblio = Koha::Biblios->find( $biblionumber );
114
my $biblio = Koha::Biblios->find( $biblionumber );
Lines 126-133 unless ( $patron and $patron->category->override_hidden_items ) { Link Here
126
        exit;
126
        exit;
127
    }
127
    }
128
    if ( scalar @all_items >= 1 ) {
128
    if ( scalar @all_items >= 1 ) {
129
        push @hiddenitems,
129
        @items_to_show = Koha::Items->search( { itemnumbers => [ map { $_->{itemnumber} } @all_items ] } )
130
          GetHiddenItemnumbers( { items => \@all_items, borcat => $patron ? $patron->categorycode : undef } );
130
                                    ->filter_by_visible_in_opac( { patron => $patron } );
131
    }
131
    }
132
}
132
}
133
133
Lines 249-256 if ($session->param('busc')) { Link Here
249
        my $hits;
249
        my $hits;
250
        my @newresults;
250
        my @newresults;
251
        my $search_context = {
251
        my $search_context = {
252
            'interface' => 'opac',
252
            interface => 'opac',
253
            'category'  => ($patron) ? $patron->categorycode : q{}
253
            patron    => $patron,
254
        };
254
        };
255
        for (my $i=0;$i<@servers;$i++) {
255
        for (my $i=0;$i<@servers;$i++) {
256
            my $server = $servers[$i];
256
            my $server = $servers[$i];
Lines 513-530 if ( C4::Context->preference('EasyAnalyticalRecords') ) { Link Here
513
my @items;
513
my @items;
514
514
515
# Are there items to hide?
515
# Are there items to hide?
516
my $hideitems;
517
$hideitems = 1 if C4::Context->preference('hidelostitems') or scalar(@hiddenitems) > 0;
518
519
# Hide items
516
# Hide items
520
if ($hideitems) {
517
if ( @items_to_show != @all_items ) {
521
    for my $itm (@all_items) {
518
    for my $itm (@all_items) {
522
	if  ( C4::Context->preference('hidelostitems') ) {
519
        next unless any { $itm->{itemnumber} eq $_ } @items_to_show;
523
	    push @items, $itm unless $itm->{itemlost} or any { $itm->{'itemnumber'} eq $_ } @hiddenitems;
520
        if ( C4::Context->preference('hidelostitems') ) {
524
	} else {
521
            push @items, $itm unless $itm->{itemlost};
525
	    push @items, $itm unless any { $itm->{'itemnumber'} eq $_ } @hiddenitems;
522
        }
523
        else {
524
            push @items, $itm;
525
        }
526
    }
526
    }
527
}
528
} else {
527
} else {
529
    # Or not
528
    # Or not
530
    @items = @all_items;
529
    @items = @all_items;
(-)a/opac/opac-search.pl (-1 / +1 lines)
Lines 587-593 my @sup_results_array; Link Here
587
my $search_context = {};
587
my $search_context = {};
588
$search_context->{'interface'} = 'opac';
588
$search_context->{'interface'} = 'opac';
589
if (C4::Context->preference('OpacHiddenItemsExceptions')){
589
if (C4::Context->preference('OpacHiddenItemsExceptions')){
590
    $search_context->{'category'} = $patron ? $patron->categorycode : q{};
590
    $search_context->{patron} = $patron;
591
}
591
}
592
592
593
my $variables = { anonymous_session => ($borrowernumber) ? 0 : 1 };
593
my $variables = { anonymous_session => ($borrowernumber) ? 0 : 1 };
(-)a/opac/opac-tags.pl (-11 / +8 lines)
Lines 34-46 use Modern::Perl; Link Here
34
34
35
use CGI qw ( -utf8 );
35
use CGI qw ( -utf8 );
36
use CGI::Cookie; # need to check cookies before having CGI parse the POST request
36
use CGI::Cookie; # need to check cookies before having CGI parse the POST request
37
use Array::Utils qw( array_minus );
37
38
38
use C4::Auth qw( check_cookie_auth get_template_and_user );
39
use C4::Auth qw( check_cookie_auth get_template_and_user );
39
use C4::Context;
40
use C4::Context;
40
use C4::Output qw( output_with_http_headers is_ajax output_html_with_http_headers );
41
use C4::Output qw( output_with_http_headers is_ajax output_html_with_http_headers );
41
use C4::Scrubber;
42
use C4::Scrubber;
42
use C4::Biblio qw( GetMarcBiblio );
43
use C4::Biblio qw( GetMarcBiblio );
43
use C4::Items qw( GetHiddenItemnumbers GetItemsInfo );
44
use C4::Items qw( GetItemsInfo );
44
use C4::Tags qw(
45
use C4::Tags qw(
45
    add_tag
46
    add_tag
46
    get_approval_rows
47
    get_approval_rows
Lines 226-232 if ($is_ajax) { Link Here
226
227
227
my $results = [];
228
my $results = [];
228
my $my_tags = [];
229
my $my_tags = [];
229
my $borcat  = q{};
230
230
231
if ($loggedinuser) {
231
if ($loggedinuser) {
232
    my $patron = Koha::Patrons->find( { borrowernumber => $loggedinuser } );
232
    my $patron = Koha::Patrons->find( { borrowernumber => $loggedinuser } );
Lines 258-272 if ($loggedinuser) { Link Here
258
            opac         => 1,
258
            opac         => 1,
259
            borcat       => $borcat });
259
            borcat       => $borcat });
260
        next unless $record;
260
        next unless $record;
261
        my $hidden_items = undef;
261
        my @hidden_items;
262
        my @hidden_itemnumbers;
263
        my @all_items;
264
        if ($should_hide) {
262
        if ($should_hide) {
265
            @all_items = GetItemsInfo( $tag->{biblionumber} );
263
            my $items = $biblio->items;
266
            @hidden_itemnumbers = GetHiddenItemnumbers({
264
            my @all_itemnumbers = $items->get_column('itemnumber');
267
                items => \@all_items,
265
            my @items_to_show = $items->filter_by_visible_in_opac({ opac => 1, patron => $patron });
268
                borcat => $borcat });
266
            @hidden_items = array_minus( @all_itemnumbers, @items_to_show );
269
            $hidden_items = \@hidden_itemnumbers;
270
        }
267
        }
271
        next
268
        next
272
          if (
269
          if (
Lines 294-300 if ($loggedinuser) { Link Here
294
                record         => $record,
291
                record         => $record,
295
                xsl_syspref    => 'OPACXSLTResultsDisplay',
292
                xsl_syspref    => 'OPACXSLTResultsDisplay',
296
                fix_amps       => 1,
293
                fix_amps       => 1,
297
                hidden_items   => $hidden_items,
294
                hidden_items   => \@hidden_items,
298
                xslt_variables => $variables
295
                xslt_variables => $variables
299
            }
296
            }
300
        );
297
        );
(-)a/t/db_dependent/Items.t (-101 / +1 lines)
Lines 19-25 use Modern::Perl; Link Here
19
use Data::Dumper;
19
use Data::Dumper;
20
20
21
use MARC::Record;
21
use MARC::Record;
22
use C4::Items qw( ModItemTransfer GetHiddenItemnumbers GetItemsInfo SearchItems AddItemFromMarc ModItemFromMarc get_hostitemnumbers_of Item2Marc );
22
use C4::Items qw( ModItemTransfer GetItemsInfo SearchItems AddItemFromMarc ModItemFromMarc get_hostitemnumbers_of Item2Marc );
23
use C4::Biblio qw( GetMarcFromKohaField EmbedItemsInMarcBiblio GetMarcBiblio AddBiblio );
23
use C4::Biblio qw( GetMarcFromKohaField EmbedItemsInMarcBiblio GetMarcBiblio AddBiblio );
24
use C4::Circulation qw( AddIssue );
24
use C4::Circulation qw( AddIssue );
25
use Koha::Items;
25
use Koha::Items;
Lines 190-294 subtest 'ModItemTransfer tests' => sub { Link Here
190
    $schema->storage->txn_rollback;
190
    $schema->storage->txn_rollback;
191
};
191
};
192
192
193
subtest 'GetHiddenItemnumbers tests' => sub {
194
195
    plan tests => 11;
196
197
    # This sub is controlled by the OpacHiddenItems system preference.
198
199
    $schema->storage->txn_begin;
200
201
    my $builder = t::lib::TestBuilder->new;
202
    my $library1 = $builder->build({
203
        source => 'Branch',
204
    });
205
206
    my $library2 = $builder->build({
207
        source => 'Branch',
208
    });
209
    my $itemtype = $builder->build({
210
        source => 'Itemtype',
211
    });
212
213
    # Create a new biblio
214
    t::lib::Mocks::mock_preference('marcflavour', 'MARC21');
215
    my $biblio = $builder->build_sample_biblio();
216
217
    # Add two items
218
    my $item1_itemnumber = $builder->build_sample_item(
219
        {
220
            biblionumber => $biblio->biblionumber,
221
            library      => $library1->{branchcode},
222
            withdrawn    => 1,
223
            itype        => $itemtype->{itemtype}
224
        }
225
    )->itemnumber;
226
    my $item2_itemnumber = $builder->build_sample_item(
227
        {
228
            biblionumber => $biblio->biblionumber,
229
            library      => $library2->{branchcode},
230
            withdrawn    => 0,
231
            itype        => $itemtype->{itemtype}
232
        }
233
    )->itemnumber;
234
    my $opachiddenitems;
235
    my @itemnumbers = ($item1_itemnumber,$item2_itemnumber);
236
    my @hidden;
237
    my @items;
238
    push @items, Koha::Items->find( $item1_itemnumber )->unblessed;
239
    push @items, Koha::Items->find( $item2_itemnumber )->unblessed;
240
241
    # Empty OpacHiddenItems
242
    t::lib::Mocks::mock_preference('OpacHiddenItems','');
243
    ok( !defined( GetHiddenItemnumbers( { items => \@items } ) ),
244
        "Hidden items list undef if OpacHiddenItems empty");
245
246
    # Blank spaces
247
    t::lib::Mocks::mock_preference('OpacHiddenItems','  ');
248
    ok( scalar GetHiddenItemnumbers( { items => \@items } ) == 0,
249
        "Hidden items list empty if OpacHiddenItems only contains blanks");
250
251
    # One variable / value
252
    $opachiddenitems = "
253
        withdrawn: [1]";
254
    t::lib::Mocks::mock_preference( 'OpacHiddenItems', $opachiddenitems );
255
    @hidden = GetHiddenItemnumbers( { items => \@items } );
256
    ok( scalar @hidden == 1, "Only one hidden item");
257
    is( $hidden[0], $item1_itemnumber, "withdrawn=1 is hidden");
258
259
    # One variable, two values
260
    $opachiddenitems = "
261
        withdrawn: [1,0]";
262
    t::lib::Mocks::mock_preference( 'OpacHiddenItems', $opachiddenitems );
263
    @hidden = GetHiddenItemnumbers( { items => \@items } );
264
    ok( scalar @hidden == 2, "Two items hidden");
265
    is_deeply( \@hidden, \@itemnumbers, "withdrawn=1 and withdrawn=0 hidden");
266
267
    # Two variables, a value each
268
    $opachiddenitems = "
269
        withdrawn: [1]
270
        homebranch: [$library2->{branchcode}]
271
    ";
272
    t::lib::Mocks::mock_preference( 'OpacHiddenItems', $opachiddenitems );
273
    @hidden = GetHiddenItemnumbers( { items => \@items } );
274
    ok( scalar @hidden == 2, "Two items hidden");
275
    is_deeply( \@hidden, \@itemnumbers, "withdrawn=1 and homebranch library2 hidden");
276
277
    # Override hidden with patron category
278
    t::lib::Mocks::mock_preference( 'OpacHiddenItemsExceptions', 'S' );
279
    @hidden = GetHiddenItemnumbers( { items => \@items, borcat => 'PT' } );
280
    ok( scalar @hidden == 2, "Two items still hidden");
281
    @hidden = GetHiddenItemnumbers( { items => \@items, borcat => 'S' } );
282
    ok( scalar @hidden == 0, "Two items not hidden");
283
284
    # Valid OpacHiddenItems, empty list
285
    @items = ();
286
    @hidden = GetHiddenItemnumbers( { items => \@items } );
287
    ok( scalar @hidden == 0, "Empty items list, no item hidden");
288
289
    $schema->storage->txn_rollback;
290
};
291
292
subtest 'GetItemsInfo tests' => sub {
193
subtest 'GetItemsInfo tests' => sub {
293
194
294
    plan tests => 9;
195
    plan tests => 9;
295
- 

Return to bug 29697