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

(-)a/C4/Biblio.pm (-55 / +42 lines)
Lines 291-297 sub ModBiblio { Link Here
291
291
292
    $frameworkcode = "" if !$frameworkcode || $frameworkcode eq "Default"; # XXX
292
    $frameworkcode = "" if !$frameworkcode || $frameworkcode eq "Default"; # XXX
293
293
294
    _strip_item_fields($record, $frameworkcode);
294
    _strip_item_fields($record);
295
295
296
    # update biblionumber and biblioitemnumber in MARC
296
    # update biblionumber and biblioitemnumber in MARC
297
    # FIXME - this is assuming a 1 to 1 relationship between
297
    # FIXME - this is assuming a 1 to 1 relationship between
Lines 325-331 sub ModBiblio { Link Here
325
325
326
=head2 _strip_item_fields
326
=head2 _strip_item_fields
327
327
328
  _strip_item_fields($record, $frameworkcode)
328
  _strip_item_fields($record)
329
329
330
Utility routine to remove item tags from a
330
Utility routine to remove item tags from a
331
MARC bib.
331
MARC bib.
Lines 334-342 MARC bib. Link Here
334
334
335
sub _strip_item_fields {
335
sub _strip_item_fields {
336
    my $record = shift;
336
    my $record = shift;
337
    my $frameworkcode = shift;
338
    # get the items before and append them to the biblio before updating the record, atm we just have the biblio
337
    # get the items before and append them to the biblio before updating the record, atm we just have the biblio
339
    my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
338
    my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber" );
340
339
341
    # delete any item fields from incoming record to avoid
340
    # delete any item fields from incoming record to avoid
342
    # duplication or incorrect data - use AddItem() or ModItem()
341
    # duplication or incorrect data - use AddItem() or ModItem()
Lines 1076-1089 sub GetMarcSubfieldStructure { Link Here
1076
sub GetMarcFromKohaField {
1075
sub GetMarcFromKohaField {
1077
    my ( $kohafield ) = @_;
1076
    my ( $kohafield ) = @_;
1078
    return unless $kohafield;
1077
    return unless $kohafield;
1079
    # The next call uses the Default framework since it is AUTHORITATIVE
1078
1080
    # for all Koha to MARC mappings.
1079
    my $cache     = Koha::Caches->get_instance();
1081
    my $mss = GetMarcSubfieldStructure( '', { unsafe => 1 } ); # Do not change framework
1080
    my $cache_key = "MarcFromKohaField-$kohafield";
1082
    my @retval;
1081
    my $cached    = $cache->get_from_cache($cache_key);
1083
    foreach( @{ $mss->{$kohafield} } ) {
1082
    if ( !defined $cached ) {
1084
        push @retval, $_->{tagfield}, $_->{tagsubfield};
1083
        # The next call uses the Default framework since it is AUTHORITATIVE
1085
    }
1084
        # for all Koha to MARC mappings.
1086
    return wantarray ? @retval : ( @retval ? $retval[0] : undef );
1085
        my $mss = GetMarcSubfieldStructure( '', { unsafe => 1 } ); # Do not change framework
1086
        my @retval;
1087
        foreach( @{ $mss->{$kohafield} } ) {
1088
            push @retval, $_->{tagfield}, $_->{tagsubfield};
1089
        }
1090
        $cached = \@retval;
1091
        $cache->set_in_cache( $cache_key, $cached );
1092
    }
1093
    return wantarray ? @$cached : ( @$cached ? $cached->[0] : undef );
1087
}
1094
}
1088
1095
1089
=head2 GetMarcSubfieldStructureFromKohaField
1096
=head2 GetMarcSubfieldStructureFromKohaField
Lines 2791-2797 override if necessary. Link Here
2791
2798
2792
sub EmbedItemsInMarcBiblio {
2799
sub EmbedItemsInMarcBiblio {
2793
    my ($params) = @_;
2800
    my ($params) = @_;
2794
    my ($marc, $biblionumber, $itemnumbers, $opac, $borcat);
2801
    my ($marc, $biblionumber, $itemnumbers, $use_hidingrules, $borcat);
2795
    $marc = $params->{marc_record};
2802
    $marc = $params->{marc_record};
2796
    if ( !$marc ) {
2803
    if ( !$marc ) {
2797
        carp 'EmbedItemsInMarcBiblio: No MARC record passed';
2804
        carp 'EmbedItemsInMarcBiblio: No MARC record passed';
Lines 2799-2851 sub EmbedItemsInMarcBiblio { Link Here
2799
    }
2806
    }
2800
    $biblionumber = $params->{biblionumber};
2807
    $biblionumber = $params->{biblionumber};
2801
    $itemnumbers = $params->{item_numbers};
2808
    $itemnumbers = $params->{item_numbers};
2802
    $opac = $params->{opac};
2809
    $use_hidingrules = $params->{opac};
2803
    $borcat = $params->{borcat} // q{};
2810
    $borcat = $params->{borcat} // q{};
2804
2811
2805
    $itemnumbers = [] unless defined $itemnumbers;
2812
    $itemnumbers = [] unless defined $itemnumbers;
2806
2813
2807
    my $frameworkcode = GetFrameworkCode($biblionumber);
2814
    _strip_item_fields($marc);
2808
    _strip_item_fields($marc, $frameworkcode);
2809
2815
2810
    # ... and embed the current items
2816
    my $hidingrules = {};
2811
    my $dbh = C4::Context->dbh;
2817
    if ($use_hidingrules && $borcat && !UseHidingRulesWithBorrowerCategory($borcat)) {
2812
    my $sth = $dbh->prepare("SELECT itemnumber FROM items WHERE biblionumber = ?");
2818
        # don't hide anything from this borrower category
2813
    $sth->execute($biblionumber);
2819
        $use_hidingrules = 0;
2814
    my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
2820
    }
2815
2821
2816
    my @item_fields; # Array holding the actual MARC data for items to be included.
2822
    my $yaml = $use_hidingrules ? C4::Context->preference('OpacHiddenItems') : '';
2817
    my @items;       # Array holding items which are both in the list (sitenumbers)
2823
    if ( $yaml =~ /\S/ ) {
2818
                     # and on this biblionumber
2824
        $yaml = "$yaml\n\n"; # YAML is anal on ending \n. Surplus does not hurt
2819
2825
        eval {
2820
    # Flag indicating if there is potential hiding.
2826
            $hidingrules = YAML::Load($yaml);
2821
    my $opachiddenitems = $opac
2827
        };
2822
      && ( C4::Context->preference('OpacHiddenItems') !~ /^\s*$/ );
2828
        if ($@) {
2823
2829
            carp "Unable to parse OpacHiddenItems syspref : $@";
2824
    require C4::Items;
2830
        }
2825
    while ( my ($itemnumber) = $sth->fetchrow_array ) {
2831
    }
2826
        next if @$itemnumbers and not grep { $_ == $itemnumber } @$itemnumbers;
2832
2827
        my $item;
2833
    my $item_fields = C4::Items::GetMarcItemFields( $biblionumber, $itemnumbers, $hidingrules );
2828
        if ( $opachiddenitems ) {
2834
2829
            $item = Koha::Items->find($itemnumber);
2835
    $marc->append_fields(@$item_fields) if ( @$item_fields );
2830
            $item = $item ? $item->unblessed : undef;
2831
        }
2832
        push @items, { itemnumber => $itemnumber, item => $item };
2833
    }
2834
    my @items2pass = map { $_->{item} } @items;
2835
    my @hiddenitems =
2836
      $opachiddenitems
2837
      ? C4::Items::GetHiddenItemnumbers({
2838
            items  => \@items2pass,
2839
            borcat => $borcat })
2840
      : ();
2841
    # Convert to a hash for quick searching
2842
    my %hiddenitems = map { $_ => 1 } @hiddenitems;
2843
    foreach my $itemnumber ( map { $_->{itemnumber} } @items ) {
2844
        next if $hiddenitems{$itemnumber};
2845
        my $item_marc = C4::Items::GetMarcItem( $biblionumber, $itemnumber );
2846
        push @item_fields, $item_marc->field($itemtag);
2847
    }
2848
    $marc->append_fields(@item_fields);
2849
}
2836
}
2850
2837
2851
=head1 INTERNAL FUNCTIONS
2838
=head1 INTERNAL FUNCTIONS
(-)a/C4/Items.pm (-12 / +100 lines)
Lines 43-48 BEGIN { Link Here
43
        GetHostItemsInfo
43
        GetHostItemsInfo
44
        get_hostitemnumbers_of
44
        get_hostitemnumbers_of
45
        GetHiddenItemnumbers
45
        GetHiddenItemnumbers
46
        UseHidingRulesWithBorrowerCategory
46
        ItemSafeToDelete
47
        ItemSafeToDelete
47
        DelItemCheck
48
        DelItemCheck
48
        MoveItemFromBiblio
49
        MoveItemFromBiblio
Lines 1206-1220 to be excluded Link Here
1206
sub GetHiddenItemnumbers {
1207
sub GetHiddenItemnumbers {
1207
    my $params = shift;
1208
    my $params = shift;
1208
    my $items = $params->{items};
1209
    my $items = $params->{items};
1209
    if (my $exceptions = C4::Context->preference('OpacHiddenItemsExceptions') and $params->{'borcat'}){
1210
1210
        foreach my $except (split(/\|/, $exceptions)){
1211
    if ($params->{'borcat'} && !UseHidingRulesWithBorrowerCategory($params->{'borcat'})) {
1211
            if ($params->{'borcat'} eq $except){
1212
        # Don't hide anything from this borrower category
1212
                return; # we don't hide anything for this borrower category
1213
        return;
1213
            }
1214
        }
1215
    }
1214
    }
1216
    my @resultitems;
1217
1215
1216
    my @resultitems;
1218
    my $yaml = C4::Context->preference('OpacHiddenItems');
1217
    my $yaml = C4::Context->preference('OpacHiddenItems');
1219
    return () if (! $yaml =~ /\S/ );
1218
    return () if (! $yaml =~ /\S/ );
1220
    $yaml = "$yaml\n\n"; # YAML is anal on ending \n. Surplus does not hurt
1219
    $yaml = "$yaml\n\n"; # YAML is anal on ending \n. Surplus does not hurt
Lines 1257-1262 sub GetHiddenItemnumbers { Link Here
1257
    return @resultitems;
1256
    return @resultitems;
1258
}
1257
}
1259
1258
1259
=head2 UseHidingRulesWithBorrowerCategory
1260
1261
    if (UseHidingRulesWithBorrowerCategory($category}) { ... }
1262
1263
Checks if item hiding rules should be used with the given borrower category.
1264
1265
=cut
1266
1267
sub UseHidingRulesWithBorrowerCategory {
1268
    my ($borcat) = @_;
1269
1270
    if ($borcat && (my $exceptions = C4::Context->preference('OpacHiddenItemsExceptions'))) {
1271
        foreach my $except (split(/\|/, $exceptions)) {
1272
            if ($borcat eq $except) {
1273
                return 0;
1274
            }
1275
        }
1276
    }
1277
    return 1;
1278
}
1279
1260
=head1 LIMITED USE FUNCTIONS
1280
=head1 LIMITED USE FUNCTIONS
1261
1281
1262
The following functions, while part of the public API,
1282
The following functions, while part of the public API,
Lines 1323-1328 sub Item2Marc { Link Here
1323
	return $itemmarc;
1343
	return $itemmarc;
1324
}
1344
}
1325
1345
1346
=head2 GetMarcItemFields
1347
1348
  my @marc_fields = GetMarcItemFields($biblionumber);
1349
1350
Returns an array of MARC::Record objects of the items for the biblio.
1351
1352
=cut
1353
1354
sub GetMarcItemFields {
1355
	my ( $biblionumber, $itemnumbers, $hidingrules ) = @_;
1356
1357
    my $item_level_itype = C4::Context->preference('item-level_itypes');
1358
    # This is so much faster than using Koha::Items->search that it makes sense even if it's ugly.
1359
    my $query = 'SELECT * FROM items WHERE biblionumber = ?';
1360
    if (@$itemnumbers) {
1361
        $query .= ' AND itemnumber IN (' . join(',', @$itemnumbers) . ')';
1362
    }
1363
    my $sth = C4::Context->dbh->prepare($query);
1364
    $sth->execute($biblionumber);
1365
    my $items = $sth->fetchall_arrayref({});
1366
    $sth->finish();
1367
    my @item_fields;
1368
    my ($itemtag, $itemsubfield) = GetMarcFromKohaField('items.itemnumber');
1369
1370
    ITEMLOOP: foreach my $item (@$items) {
1371
1372
        # Check hiding rules
1373
        if (defined $hidingrules) {
1374
            foreach my $field (keys %$hidingrules) {
1375
                my $val = $item->{$field};
1376
                $val = '' unless defined $val;
1377
1378
                # If the results matches the values in the hiding rules, skip the item
1379
                if (any { $val eq $_ } @{$hidingrules->{$field}}) {
1380
                    next ITEMLOOP;
1381
                }
1382
            }
1383
        }
1384
1385
        # Set correct item type
1386
        if (!$item_level_itype || !$item->{itype}) {
1387
            warn 'item-level_itypes set but no itemtype set for item (' . $item->{itemnumber} . ')' if (!$item->{itype});
1388
            my $biblioitem = Koha::Biblioitems->find($item->{biblioitemnumber});
1389
            $item->{itype} = $biblioitem->itemtype();
1390
        }
1391
1392
        my $mungeditem = {
1393
            map {
1394
                defined($item->{$_}) && $item->{$_} ne '' ? ("items.$_" => $item->{$_}) : ()
1395
            } keys %{ $item }
1396
        };
1397
        my $itemmarc = TransformKohaToMarc($mungeditem);
1398
1399
        my $unlinked_item_subfields = _parse_unlinked_item_subfields_from_xml($mungeditem->{'items.more_subfields_xml'});
1400
        if (defined $unlinked_item_subfields and $#$unlinked_item_subfields > -1) {
1401
            foreach my $field ($itemmarc->field($itemtag)){
1402
                $field->add_subfields(@$unlinked_item_subfields);
1403
            }
1404
        }
1405
1406
        push @item_fields, $itemmarc->field($itemtag);
1407
    }
1408
1409
    return \@item_fields;
1410
}
1411
1412
1326
=head1 PRIVATE FUNCTIONS AND VARIABLES
1413
=head1 PRIVATE FUNCTIONS AND VARIABLES
1327
1414
1328
The following functions are not meant to be called
1415
The following functions are not meant to be called
Lines 1459-1468 sub _do_column_fixes_for_mod { Link Here
1459
        (not defined $item->{'withdrawn'} or $item->{'withdrawn'} eq '')) {
1546
        (not defined $item->{'withdrawn'} or $item->{'withdrawn'} eq '')) {
1460
        $item->{'withdrawn'} = 0;
1547
        $item->{'withdrawn'} = 0;
1461
    }
1548
    }
1462
    if (exists $item->{location}
1549
    if (exists $item->{'location'}
1463
        and $item->{location} ne 'CART'
1550
        and defined $item->{'location'}
1464
        and $item->{location} ne 'PROC'
1551
        and $item->{'location'} ne 'CART'
1465
        and not $item->{permanent_location}
1552
        and $item->{'location'} ne 'PROC'
1553
        and (not defined $item->{'permanent_location'} or not $item->{'permanent_location'})
1466
    ) {
1554
    ) {
1467
        $item->{'permanent_location'} = $item->{'location'};
1555
        $item->{'permanent_location'} = $item->{'location'};
1468
    }
1556
    }
Lines 2117-2123 sub _SearchItems_build_where_fragment { Link Here
2117
        push @columns, Koha::Database->new()->schema()->resultset('Biblioitem')->result_source->columns;
2205
        push @columns, Koha::Database->new()->schema()->resultset('Biblioitem')->result_source->columns;
2118
        my @operators = qw(= != > < >= <= like);
2206
        my @operators = qw(= != > < >= <= like);
2119
        my $field = $filter->{field};
2207
        my $field = $filter->{field};
2120
        if ( (0 < grep /^$field$/, @columns) or (substr($field, 0, 5) eq 'marc:') ) {
2208
        if ( defined $field and ((0 < grep /^$field$/, @columns) or (substr($field, 0, 5) eq 'marc:')) ) {
2121
            my $op = $filter->{operator};
2209
            my $op = $filter->{operator};
2122
            my $query = $filter->{query};
2210
            my $query = $filter->{query};
2123
2211
(-)a/misc/migration_tools/bulkmarcimport.pl (-1 / +1 lines)
Lines 489-495 RECORD: while ( ) { Link Here
489
            # Work on a clone so that if there are real errors, we can maybe
489
            # Work on a clone so that if there are real errors, we can maybe
490
            # fix them up later.
490
            # fix them up later.
491
			my $clone_record = $record->clone();
491
			my $clone_record = $record->clone();
492
            C4::Biblio::_strip_item_fields($clone_record, '');
492
            C4::Biblio::_strip_item_fields($clone_record);
493
            # This sets the marc fields if there was an error, and also calls
493
            # This sets the marc fields if there was an error, and also calls
494
            # defer_marc_save.
494
            # defer_marc_save.
495
            ModBiblioMarc( $clone_record, $biblionumber, $framework );
495
            ModBiblioMarc( $clone_record, $biblionumber, $framework );
(-)a/t/db_dependent/Items.t (-7 / +3 lines)
Lines 717-723 subtest 'C4::Items::_build_default_values_for_mod_marc' => sub { Link Here
717
    Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => '9', kohafield => 'items.itemnumber' })->store;
717
    Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => '9', kohafield => 'items.itemnumber' })->store;
718
    Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => 'p', kohafield => 'items.barcode' })->store;
718
    Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => 'p', kohafield => 'items.barcode' })->store;
719
    Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => 'y', kohafield => 'items.itype' })->store;
719
    Koha::MarcSubfieldStructure->new({ frameworkcode => '', tagfield => '952', tagsubfield => 'y', kohafield => 'items.itype' })->store;
720
    Koha::Caches->get_instance->clear_from_cache( "MarcSubfieldStructure-" );
720
    Koha::Caches->get_instance()->flush_all();
721
721
722
    my $itemtype = $builder->build({ source => 'Itemtype' })->{itemtype};
722
    my $itemtype = $builder->build({ source => 'Itemtype' })->{itemtype};
723
723
Lines 758-766 subtest 'C4::Items::_build_default_values_for_mod_marc' => sub { Link Here
758
    Koha::MarcSubfieldStructures->search({ frameworkcode => '', tagfield => '952', tagsubfield => 'p' })->delete;
758
    Koha::MarcSubfieldStructures->search({ frameworkcode => '', tagfield => '952', tagsubfield => 'p' })->delete;
759
759
760
    # And make sure the caches are cleared
760
    # And make sure the caches are cleared
761
    my $cache = Koha::Caches->get_instance();
761
    Koha::Caches->get_instance()->flush_all();
762
    $cache->clear_from_cache("default_value_for_mod_marc-");
763
    $cache->clear_from_cache("MarcSubfieldStructure-");
764
762
765
    # Update the MARC field with another value
763
    # Update the MARC field with another value
766
    $item_record->delete_fields( $barcode_field );
764
    $item_record->delete_fields( $barcode_field );
Lines 775-782 subtest 'C4::Items::_build_default_values_for_mod_marc' => sub { Link Here
775
    $item = Koha::Items->find($item_itemnumber);
773
    $item = Koha::Items->find($item_itemnumber);
776
    is ( $item->barcode, $a_barcode, 'items.barcode is not mapped anymore, so the DB column has not been updated' );
774
    is ( $item->barcode, $a_barcode, 'items.barcode is not mapped anymore, so the DB column has not been updated' );
777
775
778
    $cache->clear_from_cache("default_value_for_mod_marc-");
776
    Koha::Caches->get_instance()->flush_all();
779
    $cache->clear_from_cache( "MarcSubfieldStructure-" );
780
    $schema->storage->txn_rollback;
777
    $schema->storage->txn_rollback;
781
};
778
};
782
779
783
- 

Return to bug 20664