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 968-1032 sub get_hostitemnumbers_of { Link Here
968
    return @returnhostitemnumbers;
967
    return @returnhostitemnumbers;
969
}
968
}
970
969
971
=head2 GetHiddenItemnumbers
972
973
    my @itemnumbers_to_hide = GetHiddenItemnumbers({ items => \@items, borcat => $category });
974
975
Given a list of items it checks which should be hidden from the OPAC given
976
the current configuration. Returns a list of itemnumbers corresponding to
977
those that should be hidden. Optionally takes a borcat parameter for certain borrower types
978
to be excluded
979
980
=cut
981
982
sub GetHiddenItemnumbers {
983
    my $params = shift;
984
    my $items = $params->{items};
985
    if (my $exceptions = C4::Context->preference('OpacHiddenItemsExceptions') and $params->{'borcat'}){
986
        foreach my $except (split(/\|/, $exceptions)){
987
            if ($params->{'borcat'} eq $except){
988
                return; # we don't hide anything for this borrower category
989
            }
990
        }
991
    }
992
    my @resultitems;
993
994
    my $hidingrules = C4::Context->yaml_preference('OpacHiddenItems');
995
996
    return
997
        unless $hidingrules;
998
999
    my $dbh = C4::Context->dbh;
1000
1001
    # For each item
1002
    foreach my $item (@$items) {
1003
1004
        # We check each rule
1005
        foreach my $field (keys %$hidingrules) {
1006
            my $val;
1007
            if (exists $item->{$field}) {
1008
                $val = $item->{$field};
1009
            }
1010
            else {
1011
                my $query = "SELECT $field from items where itemnumber = ?";
1012
                $val = $dbh->selectrow_array($query, undef, $item->{'itemnumber'});
1013
            }
1014
            $val = '' unless defined $val;
1015
1016
            # If the results matches the values in the yaml file
1017
            if (any { $val eq $_ } @{$hidingrules->{$field}}) {
1018
1019
                # We add the itemnumber to the list
1020
                push @resultitems, $item->{'itemnumber'};
1021
1022
                # If at least one rule matched for an item, no need to test the others
1023
                last;
1024
            }
1025
        }
1026
    }
1027
    return @resultitems;
1028
}
1029
1030
=head1 LIMITED USE FUNCTIONS
970
=head1 LIMITED USE FUNCTIONS
1031
971
1032
The following functions, while part of the public API,
972
The following functions, while part of the public API,
(-)a/C4/Search.pm (-10 / +6 lines)
Lines 1802-1818 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
                    $hideatopac_count++;
1809
                                    ->filter_by_visible_in_opac({ patron => $search_context->{patron} });
1810
                    next;
1810
                unless ( $hi->count ) {
1811
                }
1811
                    push @hiddenitems, $item->{itemnumber};
1812
                # hidden based on OpacHiddenItems syspref
1813
                my @hi = C4::Items::GetHiddenItemnumbers({ items=> [ $item ], borcat => $search_context->{category} });
1814
                if (scalar @hi) {
1815
                    push @hiddenitems, @hi;
1816
                    $hideatopac_count++;
1812
                    $hideatopac_count++;
1817
                    next;
1813
                    next;
1818
                }
1814
                }
(-)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 Koha::Items;
24
use Koha::Items;
25
use Koha::Database;
25
use Koha::Database;
Lines 189-293 subtest 'ModItemTransfer tests' => sub { Link Here
189
    $schema->storage->txn_rollback;
189
    $schema->storage->txn_rollback;
190
};
190
};
191
191
192
subtest 'GetHiddenItemnumbers tests' => sub {
193
194
    plan tests => 11;
195
196
    # This sub is controlled by the OpacHiddenItems system preference.
197
198
    $schema->storage->txn_begin;
199
200
    my $builder = t::lib::TestBuilder->new;
201
    my $library1 = $builder->build({
202
        source => 'Branch',
203
    });
204
205
    my $library2 = $builder->build({
206
        source => 'Branch',
207
    });
208
    my $itemtype = $builder->build({
209
        source => 'Itemtype',
210
    });
211
212
    # Create a new biblio
213
    t::lib::Mocks::mock_preference('marcflavour', 'MARC21');
214
    my $biblio = $builder->build_sample_biblio();
215
216
    # Add two items
217
    my $item1_itemnumber = $builder->build_sample_item(
218
        {
219
            biblionumber => $biblio->biblionumber,
220
            library      => $library1->{branchcode},
221
            withdrawn    => 1,
222
            itype        => $itemtype->{itemtype}
223
        }
224
    )->itemnumber;
225
    my $item2_itemnumber = $builder->build_sample_item(
226
        {
227
            biblionumber => $biblio->biblionumber,
228
            library      => $library2->{branchcode},
229
            withdrawn    => 0,
230
            itype        => $itemtype->{itemtype}
231
        }
232
    )->itemnumber;
233
    my $opachiddenitems;
234
    my @itemnumbers = ($item1_itemnumber,$item2_itemnumber);
235
    my @hidden;
236
    my @items;
237
    push @items, Koha::Items->find( $item1_itemnumber )->unblessed;
238
    push @items, Koha::Items->find( $item2_itemnumber )->unblessed;
239
240
    # Empty OpacHiddenItems
241
    t::lib::Mocks::mock_preference('OpacHiddenItems','');
242
    ok( !defined( GetHiddenItemnumbers( { items => \@items } ) ),
243
        "Hidden items list undef if OpacHiddenItems empty");
244
245
    # Blank spaces
246
    t::lib::Mocks::mock_preference('OpacHiddenItems','  ');
247
    ok( scalar GetHiddenItemnumbers( { items => \@items } ) == 0,
248
        "Hidden items list empty if OpacHiddenItems only contains blanks");
249
250
    # One variable / value
251
    $opachiddenitems = "
252
        withdrawn: [1]";
253
    t::lib::Mocks::mock_preference( 'OpacHiddenItems', $opachiddenitems );
254
    @hidden = GetHiddenItemnumbers( { items => \@items } );
255
    ok( scalar @hidden == 1, "Only one hidden item");
256
    is( $hidden[0], $item1_itemnumber, "withdrawn=1 is hidden");
257
258
    # One variable, two values
259
    $opachiddenitems = "
260
        withdrawn: [1,0]";
261
    t::lib::Mocks::mock_preference( 'OpacHiddenItems', $opachiddenitems );
262
    @hidden = GetHiddenItemnumbers( { items => \@items } );
263
    ok( scalar @hidden == 2, "Two items hidden");
264
    is_deeply( \@hidden, \@itemnumbers, "withdrawn=1 and withdrawn=0 hidden");
265
266
    # Two variables, a value each
267
    $opachiddenitems = "
268
        withdrawn: [1]
269
        homebranch: [$library2->{branchcode}]
270
    ";
271
    t::lib::Mocks::mock_preference( 'OpacHiddenItems', $opachiddenitems );
272
    @hidden = GetHiddenItemnumbers( { items => \@items } );
273
    ok( scalar @hidden == 2, "Two items hidden");
274
    is_deeply( \@hidden, \@itemnumbers, "withdrawn=1 and homebranch library2 hidden");
275
276
    # Override hidden with patron category
277
    t::lib::Mocks::mock_preference( 'OpacHiddenItemsExceptions', 'S' );
278
    @hidden = GetHiddenItemnumbers( { items => \@items, borcat => 'PT' } );
279
    ok( scalar @hidden == 2, "Two items still hidden");
280
    @hidden = GetHiddenItemnumbers( { items => \@items, borcat => 'S' } );
281
    ok( scalar @hidden == 0, "Two items not hidden");
282
283
    # Valid OpacHiddenItems, empty list
284
    @items = ();
285
    @hidden = GetHiddenItemnumbers( { items => \@items } );
286
    ok( scalar @hidden == 0, "Empty items list, no item hidden");
287
288
    $schema->storage->txn_rollback;
289
};
290
291
subtest 'GetItemsInfo tests' => sub {
192
subtest 'GetItemsInfo tests' => sub {
292
193
293
    plan tests => 9;
194
    plan tests => 9;
294
- 

Return to bug 29697