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

(-)a/C4/Biblio.pm (-48 / +39 lines)
Lines 292-298 sub ModBiblio { Link Here
292
292
293
    $frameworkcode = "" if !$frameworkcode || $frameworkcode eq "Default"; # XXX
293
    $frameworkcode = "" if !$frameworkcode || $frameworkcode eq "Default"; # XXX
294
294
295
    _strip_item_fields($record, $frameworkcode);
295
    _strip_item_fields($record);
296
296
297
    # update biblionumber and biblioitemnumber in MARC
297
    # update biblionumber and biblioitemnumber in MARC
298
    # FIXME - this is assuming a 1 to 1 relationship between
298
    # FIXME - this is assuming a 1 to 1 relationship between
Lines 326-332 sub ModBiblio { Link Here
326
326
327
=head2 _strip_item_fields
327
=head2 _strip_item_fields
328
328
329
  _strip_item_fields($record, $frameworkcode)
329
  _strip_item_fields($record)
330
330
331
Utility routine to remove item tags from a
331
Utility routine to remove item tags from a
332
MARC bib.
332
MARC bib.
Lines 335-343 MARC bib. Link Here
335
335
336
sub _strip_item_fields {
336
sub _strip_item_fields {
337
    my $record = shift;
337
    my $record = shift;
338
    my $frameworkcode = shift;
339
    # get the items before and append them to the biblio before updating the record, atm we just have the biblio
338
    # get the items before and append them to the biblio before updating the record, atm we just have the biblio
340
    my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
339
    my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber" );
341
340
342
    # delete any item fields from incoming record to avoid
341
    # delete any item fields from incoming record to avoid
343
    # duplication or incorrect data - use AddItem() or ModItem()
342
    # duplication or incorrect data - use AddItem() or ModItem()
Lines 1077-1090 sub GetMarcSubfieldStructure { Link Here
1077
sub GetMarcFromKohaField {
1076
sub GetMarcFromKohaField {
1078
    my ( $kohafield ) = @_;
1077
    my ( $kohafield ) = @_;
1079
    return unless $kohafield;
1078
    return unless $kohafield;
1080
    # The next call uses the Default framework since it is AUTHORITATIVE
1079
1081
    # for all Koha to MARC mappings.
1080
    my $cache     = Koha::Caches->get_instance();
1082
    my $mss = GetMarcSubfieldStructure( '', { unsafe => 1 } ); # Do not change framework
1081
    my $cache_key = "MarcFromKohaField-$kohafield";
1083
    my @retval;
1082
    my $cached    = $cache->get_from_cache($cache_key);
1084
    foreach( @{ $mss->{$kohafield} } ) {
1083
    if ( !defined $cached ) {
1085
        push @retval, $_->{tagfield}, $_->{tagsubfield};
1084
        # The next call uses the Default framework since it is AUTHORITATIVE
1086
    }
1085
        # for all Koha to MARC mappings.
1087
    return wantarray ? @retval : ( @retval ? $retval[0] : undef );
1086
        my $mss = GetMarcSubfieldStructure( '', { unsafe => 1 } ); # Do not change framework
1087
        my @retval;
1088
        foreach( @{ $mss->{$kohafield} } ) {
1089
            push @retval, $_->{tagfield}, $_->{tagsubfield};
1090
        }
1091
        $cached = \@retval;
1092
        $cache->set_in_cache( $cache_key, $cached );
1093
    }
1094
    return wantarray ? @$cached : ( @$cached ? $cached->[0] : undef );
1088
}
1095
}
1089
1096
1090
=head2 GetMarcSubfieldStructureFromKohaField
1097
=head2 GetMarcSubfieldStructureFromKohaField
Lines 2793-2799 override if necessary. Link Here
2793
2800
2794
sub EmbedItemsInMarcBiblio {
2801
sub EmbedItemsInMarcBiblio {
2795
    my ($params) = @_;
2802
    my ($params) = @_;
2796
    my ($marc, $biblionumber, $itemnumbers, $opac, $borcat);
2803
    my ($marc, $biblionumber, $itemnumbers, $use_hidingrules, $borcat);
2797
    $marc = $params->{marc_record};
2804
    $marc = $params->{marc_record};
2798
    if ( !$marc ) {
2805
    if ( !$marc ) {
2799
        carp 'EmbedItemsInMarcBiblio: No MARC record passed';
2806
        carp 'EmbedItemsInMarcBiblio: No MARC record passed';
Lines 2801-2849 sub EmbedItemsInMarcBiblio { Link Here
2801
    }
2808
    }
2802
    $biblionumber = $params->{biblionumber};
2809
    $biblionumber = $params->{biblionumber};
2803
    $itemnumbers = $params->{item_numbers};
2810
    $itemnumbers = $params->{item_numbers};
2804
    $opac = $params->{opac};
2811
    $use_hidingrules = $params->{opac};
2805
    $borcat = $params->{borcat} // q{};
2812
    $borcat = $params->{borcat} // q{};
2806
2813
2807
    $itemnumbers = [] unless defined $itemnumbers;
2814
    $itemnumbers = [] unless defined $itemnumbers;
2808
2815
2809
    my $frameworkcode = GetFrameworkCode($biblionumber);
2816
    _strip_item_fields($marc);
2810
    _strip_item_fields($marc, $frameworkcode);
2811
2817
2812
    # ... and embed the current items
2818
    my $hidingrules = {};
2813
    my $dbh = C4::Context->dbh;
2819
    if ($use_hidingrules && $borcat && !UseHidingRulesWithBorrowerCategory($borcat)) {
2814
    my $sth = $dbh->prepare("SELECT itemnumber FROM items WHERE biblionumber = ?");
2820
        # don't hide anything from this borrower category
2815
    $sth->execute($biblionumber);
2821
        $use_hidingrules = 0;
2816
    my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
2822
    }
2817
2823
2818
    my @item_fields; # Array holding the actual MARC data for items to be included.
2824
    my $yaml = $use_hidingrules ? C4::Context->preference('OpacHiddenItems') : '';
2819
    my @items;       # Array holding items which are both in the list (sitenumbers)
2825
    if ( $yaml =~ /\S/ ) {
2820
                     # and on this biblionumber
2826
        $yaml = "$yaml\n\n"; # YAML is anal on ending \n. Surplus does not hurt
2827
        eval {
2828
            $hidingrules = YAML::Load($yaml);
2829
        };
2830
        if ($@) {
2831
            carp "Unable to parse OpacHiddenItems syspref : $@";
2832
        }
2833
    }
2821
2834
2822
    # Flag indicating if there is potential hiding.
2835
    my $item_fields = C4::Items::GetMarcItemFields( $biblionumber, $itemnumbers, $hidingrules );
2823
    my $opachiddenitems = $opac
2824
      && ( C4::Context->preference('OpacHiddenItems') !~ /^\s*$/ );
2825
2836
2826
    require C4::Items;
2837
    $marc->append_fields(@$item_fields) if ( @$item_fields );
2827
    while ( my ($itemnumber) = $sth->fetchrow_array ) {
2828
        next if @$itemnumbers and not grep { $_ == $itemnumber } @$itemnumbers;
2829
        my $i = $opachiddenitems ? C4::Items::GetItem($itemnumber) : undef;
2830
        push @items, { itemnumber => $itemnumber, item => $i };
2831
    }
2832
    my @items2pass = map { $_->{item} } @items;
2833
    my @hiddenitems =
2834
      $opachiddenitems
2835
      ? C4::Items::GetHiddenItemnumbers({
2836
            items  => \@items2pass,
2837
            borcat => $borcat })
2838
      : ();
2839
    # Convert to a hash for quick searching
2840
    my %hiddenitems = map { $_ => 1 } @hiddenitems;
2841
    foreach my $itemnumber ( map { $_->{itemnumber} } @items ) {
2842
        next if $hiddenitems{$itemnumber};
2843
        my $item_marc = C4::Items::GetMarcItem( $biblionumber, $itemnumber );
2844
        push @item_fields, $item_marc->field($itemtag);
2845
    }
2846
    $marc->append_fields(@item_fields);
2847
}
2838
}
2848
2839
2849
=head1 INTERNAL FUNCTIONS
2840
=head1 INTERNAL FUNCTIONS
(-)a/C4/Items.pm (-12 / +100 lines)
Lines 44-49 BEGIN { Link Here
44
        GetHostItemsInfo
44
        GetHostItemsInfo
45
        get_hostitemnumbers_of
45
        get_hostitemnumbers_of
46
        GetHiddenItemnumbers
46
        GetHiddenItemnumbers
47
        UseHidingRulesWithBorrowerCategory
47
        ItemSafeToDelete
48
        ItemSafeToDelete
48
        DelItemCheck
49
        DelItemCheck
49
        MoveItemFromBiblio
50
        MoveItemFromBiblio
Lines 1243-1257 to be excluded Link Here
1243
sub GetHiddenItemnumbers {
1244
sub GetHiddenItemnumbers {
1244
    my $params = shift;
1245
    my $params = shift;
1245
    my $items = $params->{items};
1246
    my $items = $params->{items};
1246
    if (my $exceptions = C4::Context->preference('OpacHiddenItemsExceptions') and $params->{'borcat'}){
1247
1247
        foreach my $except (split(/\|/, $exceptions)){
1248
    if ($params->{'borcat'} && !UseHidingRulesWithBorrowerCategory($params->{'borcat'})) {
1248
            if ($params->{'borcat'} eq $except){
1249
        # Don't hide anything from this borrower category
1249
                return; # we don't hide anything for this borrower category
1250
        return;
1250
            }
1251
        }
1252
    }
1251
    }
1252
    
1253
    my @resultitems;
1253
    my @resultitems;
1254
1255
    my $yaml = C4::Context->preference('OpacHiddenItems');
1254
    my $yaml = C4::Context->preference('OpacHiddenItems');
1256
    return () if (! $yaml =~ /\S/ );
1255
    return () if (! $yaml =~ /\S/ );
1257
    $yaml = "$yaml\n\n"; # YAML is anal on ending \n. Surplus does not hurt
1256
    $yaml = "$yaml\n\n"; # YAML is anal on ending \n. Surplus does not hurt
Lines 1294-1299 sub GetHiddenItemnumbers { Link Here
1294
    return @resultitems;
1293
    return @resultitems;
1295
}
1294
}
1296
1295
1296
=head2 UseHidingRulesWithBorrowerCategory
1297
1298
    if (UseHidingRulesWithBorrowerCategory($category}) { ... }
1299
1300
Checks if item hiding rules should be used with the given borrower category.
1301
1302
=cut
1303
1304
sub UseHidingRulesWithBorrowerCategory {
1305
    my ($borcat) = @_;
1306
1307
    if ($borcat && (my $exceptions = C4::Context->preference('OpacHiddenItemsExceptions'))) {
1308
        foreach my $except (split(/\|/, $exceptions)) {
1309
            if ($borcat eq $except) {
1310
                return 0;
1311
            }
1312
        }
1313
    }
1314
    return 1;
1315
}
1316
1297
=head1 LIMITED USE FUNCTIONS
1317
=head1 LIMITED USE FUNCTIONS
1298
1318
1299
The following functions, while part of the public API,
1319
The following functions, while part of the public API,
Lines 1361-1366 sub Item2Marc { Link Here
1361
	return $itemmarc;
1381
	return $itemmarc;
1362
}
1382
}
1363
1383
1384
=head2 GetMarcItemFields
1385
1386
  my @marc_fields = GetMarcItemFields($biblionumber);
1387
1388
Returns an array of MARC::Record objects of the items for the biblio.
1389
1390
=cut
1391
1392
sub GetMarcItemFields {
1393
	my ( $biblionumber, $itemnumbers, $hidingrules ) = @_;
1394
1395
    my $item_level_itype = C4::Context->preference('item-level_itypes');
1396
    # This is so much faster than using Koha::Items->search that it makes sense even if it's ugly.
1397
    my $query = 'SELECT * FROM items WHERE biblionumber = ?';
1398
    if (@$itemnumbers) {
1399
        $query .= ' AND itemnumber IN (' . join(',', @$itemnumbers) . ')';
1400
    }
1401
    my $sth = C4::Context->dbh->prepare($query);
1402
    $sth->execute($biblionumber);
1403
    my $items = $sth->fetchall_arrayref({});
1404
    $sth->finish();
1405
    my @item_fields;
1406
    my ($itemtag, $itemsubfield) = GetMarcFromKohaField('items.itemnumber');
1407
1408
    ITEMLOOP: foreach my $item (@$items) {
1409
1410
        # Check hiding rules
1411
        if (defined $hidingrules) {
1412
            foreach my $field (keys %$hidingrules) {
1413
                my $val = $item->{$field};
1414
                $val = '' unless defined $val;
1415
1416
                # If the results matches the values in the hiding rules, skip the item
1417
                if (any { $val eq $_ } @{$hidingrules->{$field}}) {
1418
                    next ITEMLOOP;
1419
                }
1420
            }
1421
        }
1422
1423
        # Set correct item type
1424
        if (!$item_level_itype || !$item->{itype}) {
1425
            warn 'item-level_itypes set but no itemtype set for item (' . $item->{itemnumber} . ')' if (!$item->{itype});
1426
            my $biblioitem = Koha::Biblioitems->find($item->{biblioitemnumber});
1427
            $item->{itype} = $biblioitem->itemtype();
1428
        }
1429
1430
        my $mungeditem = {
1431
            map {
1432
                defined($item->{$_}) && $item->{$_} ne '' ? ("items.$_" => $item->{$_}) : ()
1433
            } keys %{ $item }
1434
        };
1435
        my $itemmarc = TransformKohaToMarc($mungeditem);
1436
1437
        my $unlinked_item_subfields = _parse_unlinked_item_subfields_from_xml($mungeditem->{'items.more_subfields_xml'});
1438
        if (defined $unlinked_item_subfields and $#$unlinked_item_subfields > -1) {
1439
            foreach my $field ($itemmarc->field($itemtag)){
1440
                $field->add_subfields(@$unlinked_item_subfields);
1441
            }
1442
        }
1443
1444
        push @item_fields, $itemmarc->field($itemtag);
1445
    }
1446
1447
    return \@item_fields;
1448
}
1449
1450
1364
=head1 PRIVATE FUNCTIONS AND VARIABLES
1451
=head1 PRIVATE FUNCTIONS AND VARIABLES
1365
1452
1366
The following functions are not meant to be called
1453
The following functions are not meant to be called
Lines 1497-1506 sub _do_column_fixes_for_mod { Link Here
1497
        (not defined $item->{'withdrawn'} or $item->{'withdrawn'} eq '')) {
1584
        (not defined $item->{'withdrawn'} or $item->{'withdrawn'} eq '')) {
1498
        $item->{'withdrawn'} = 0;
1585
        $item->{'withdrawn'} = 0;
1499
    }
1586
    }
1500
    if (exists $item->{location}
1587
    if (exists $item->{'location'}
1501
        and $item->{location} ne 'CART'
1588
        and defined $item->{'location'}
1502
        and $item->{location} ne 'PROC'
1589
        and $item->{'location'} ne 'CART'
1503
        and not $item->{permanent_location}
1590
        and $item->{'location'} ne 'PROC'
1591
        and (not defined $item->{'permanent_location'} or not $item->{'permanent_location'})
1504
    ) {
1592
    ) {
1505
        $item->{'permanent_location'} = $item->{'location'};
1593
        $item->{'permanent_location'} = $item->{'location'};
1506
    }
1594
    }
Lines 2165-2171 sub _SearchItems_build_where_fragment { Link Here
2165
        push @columns, Koha::Database->new()->schema()->resultset('Biblioitem')->result_source->columns;
2253
        push @columns, Koha::Database->new()->schema()->resultset('Biblioitem')->result_source->columns;
2166
        my @operators = qw(= != > < >= <= like);
2254
        my @operators = qw(= != > < >= <= like);
2167
        my $field = $filter->{field};
2255
        my $field = $filter->{field};
2168
        if ( (0 < grep /^$field$/, @columns) or (substr($field, 0, 5) eq 'marc:') ) {
2256
        if ( defined $field and ((0 < grep /^$field$/, @columns) or (substr($field, 0, 5) eq 'marc:')) ) {
2169
            my $op = $filter->{operator};
2257
            my $op = $filter->{operator};
2170
            my $query = $filter->{query};
2258
            my $query = $filter->{query};
2171
2259
(-)a/misc/migration_tools/bulkmarcimport.pl (-1 / +1 lines)
Lines 486-492 RECORD: while ( ) { Link Here
486
            # Work on a clone so that if there are real errors, we can maybe
486
            # Work on a clone so that if there are real errors, we can maybe
487
            # fix them up later.
487
            # fix them up later.
488
			my $clone_record = $record->clone();
488
			my $clone_record = $record->clone();
489
            C4::Biblio::_strip_item_fields($clone_record, '');
489
            C4::Biblio::_strip_item_fields($clone_record);
490
            # This sets the marc fields if there was an error, and also calls
490
            # This sets the marc fields if there was an error, and also calls
491
            # defer_marc_save.
491
            # defer_marc_save.
492
            ModBiblioMarc( $clone_record, $biblionumber, $framework );
492
            ModBiblioMarc( $clone_record, $biblionumber, $framework );
(-)a/t/db_dependent/Items.t (-7 / +3 lines)
Lines 698-704 subtest 'C4::Items::_build_default_values_for_mod_marc' => sub { Link Here
698
    Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => '9', kohafield => 'items.itemnumber' })->store;
698
    Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => '9', kohafield => 'items.itemnumber' })->store;
699
    Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => 'p', kohafield => 'items.barcode' })->store;
699
    Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => 'p', kohafield => 'items.barcode' })->store;
700
    Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => 'y', kohafield => 'items.itype' })->store;
700
    Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => 'y', kohafield => 'items.itype' })->store;
701
    Koha::Caches->get_instance->clear_from_cache( "MarcSubfieldStructure-" );
701
    Koha::Caches->get_instance()->flush_all();
702
702
703
    my $itemtype = $builder->build({ source => 'Itemtype' })->{itemtype};
703
    my $itemtype = $builder->build({ source => 'Itemtype' })->{itemtype};
704
704
Lines 739-747 subtest 'C4::Items::_build_default_values_for_mod_marc' => sub { Link Here
739
    Koha::MarcSubfieldStructures->search({ frameworkcode => '', tagfield => '952', tagsubfield => 'p' })->delete;
739
    Koha::MarcSubfieldStructures->search({ frameworkcode => '', tagfield => '952', tagsubfield => 'p' })->delete;
740
740
741
    # And make sure the caches are cleared
741
    # And make sure the caches are cleared
742
    my $cache = Koha::Caches->get_instance();
742
    Koha::Caches->get_instance()->flush_all();
743
    $cache->clear_from_cache("default_value_for_mod_marc-");
744
    $cache->clear_from_cache("MarcSubfieldStructure-");
745
743
746
    # Update the MARC field with another value
744
    # Update the MARC field with another value
747
    $item_record->delete_fields( $barcode_field );
745
    $item_record->delete_fields( $barcode_field );
Lines 756-763 subtest 'C4::Items::_build_default_values_for_mod_marc' => sub { Link Here
756
    $item = GetItem($item_itemnumber);
754
    $item = GetItem($item_itemnumber);
757
    is ( $item->{barcode}, $a_barcode, 'items.barcode is not mapped anymore, so the DB column has not been updated' );
755
    is ( $item->{barcode}, $a_barcode, 'items.barcode is not mapped anymore, so the DB column has not been updated' );
758
756
759
    $cache->clear_from_cache("default_value_for_mod_marc-");
757
    Koha::Caches->get_instance()->flush_all();
760
    $cache->clear_from_cache( "MarcSubfieldStructure-" );
761
    $schema->storage->txn_rollback;
758
    $schema->storage->txn_rollback;
762
};
759
};
763
760
764
- 

Return to bug 20664