From 265f269e0d756db286789165255941286caf1240 Mon Sep 17 00:00:00 2001 From: Kyle Hall Date: Tue, 7 Feb 2023 14:07:57 -0500 Subject: [PATCH] Bug 32902: Add option to only overlay if matched item is on matched record Bug 32084 resolves an bug where an overlaid item could have its' biblionumber changed. Fixing this has the effect of enabling items to be updated even if the item is on a different record. This can be wanted or unwanted behavior depending on the situation. It would be good if the cataloger could choose which behavior is preferred on a per-batch bases. Test Plan: 1) Grab the sample marc record file from bug 32804 2) Upload this file, chose to match on biblionumber and replace matching item if any matching record was found 3) Import the batch 4) Note the item was replaced 5) Revert the import 6) Change the rule to replace matching items if matching item is on matching record 7) Apply different matching rules 8) Import the batch into the catalog 9) Note the item was not replaced --- C4/ImportBatch.pm | 74 +++++++++++++------ .../data/mysql/atomicupdate/bug_32902.pl | 14 ++++ installer/data/mysql/kohastructure.sql | 2 +- .../prog/en/includes/tools-item-action.inc | 8 +- .../en/modules/tools/manage-marc-import.tt | 4 + 5 files changed, 76 insertions(+), 26 deletions(-) create mode 100755 installer/data/mysql/atomicupdate/bug_32902.pl diff --git a/C4/ImportBatch.pm b/C4/ImportBatch.pm index 110e81af3b..4477fb97c5 100644 --- a/C4/ImportBatch.pm +++ b/C4/ImportBatch.pm @@ -764,40 +764,59 @@ sub _batchCommitItems { my $item = TransformMarcToKoha({ record => $item_marc, kohafields => ['items.barcode','items.itemnumber'] }); - my $item_match; my $duplicate_barcode = exists( $item->{'barcode'} ); my $duplicate_itemnumber = exists( $item->{'itemnumber'} ); # We assume that when replaicing tiems we do not want to move them - the onus is on the importer to # ensure the correct items/records are being updated my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, itemnumber = ?, import_error = ? WHERE import_items_id = ?"); + my $matched_itemnumber_item = Koha::Items->find( $item->{itemnumber} ); + my $matched_barcode_item = Koha::Items->find({ barcode => $item->{barcode} }); if ( - $action eq "replace" && + rindex( $action, 'replace', 0 ) && $duplicate_itemnumber && - ( $item_match = Koha::Items->find( $item->{itemnumber} )) + $matched_itemnumber_item ) { - # Duplicate itemnumbers have precedence, that way we can update barcodes by overlaying - ModItemFromMarc( $item_marc, $item_match->biblionumber, $item->{itemnumber}, { skip_record_index => 1 } ); - $updsth->bind_param( 1, 'imported' ); - $updsth->bind_param( 2, $item->{itemnumber} ); - $updsth->bind_param( 3, undef ); - $updsth->bind_param( 4, $row->{'import_items_id'} ); - $updsth->execute(); - $updsth->finish(); - $num_items_replaced++; + if ( $action eq 'replace_if_bib_match' && $matched_itemnumber_item->biblionumber != $biblionumber ) { + $updsth->bind_param( 1, 'error' ); + $updsth->bind_param( 2, undef ); + $updsth->bind_param( 3, 'matched itemnumber on different record' ); + $updsth->bind_param( 4, $row->{'import_items_id'} ); + $updsth->execute(); + $num_items_errored++; + } else { + # Duplicate itemnumbers have precedence, that way we can update barcodes by overlaying + ModItemFromMarc( $item_marc, $matched_itemnumber_item->biblionumber, $item->{itemnumber}, { skip_record_index => 1 } ); + $updsth->bind_param( 1, 'imported' ); + $updsth->bind_param( 2, $item->{itemnumber} ); + $updsth->bind_param( 3, undef ); + $updsth->bind_param( 4, $row->{'import_items_id'} ); + $updsth->execute(); + $updsth->finish(); + $num_items_replaced++; + } } elsif ( $action eq "replace" && $duplicate_barcode && - ( $item_match = Koha::Items->find({ barcode => $item->{'barcode'} }) ) + $matched_barcode_item ) { - ModItemFromMarc( $item_marc, $item_match->biblionumber, $item_match->itemnumber, { skip_record_index => 1 } ); - $updsth->bind_param( 1, 'imported' ); - $updsth->bind_param( 2, $item->{itemnumber} ); - $updsth->bind_param( 3, undef ); - $updsth->bind_param( 4, $row->{'import_items_id'} ); - $updsth->execute(); - $updsth->finish(); - $num_items_replaced++; + if ( $action eq 'replace_if_bib_match' && $matched_barcode_item->biblionumber != $biblionumber ) { + $updsth->bind_param( 1, 'error' ); + $updsth->bind_param( 2, undef ); + $updsth->bind_param( 3, 'matched barcode on different record' ); + $updsth->bind_param( 4, $row->{'import_items_id'} ); + $updsth->execute(); + $num_items_errored++; + } else { + ModItemFromMarc( $item_marc, $matched_barcode_item->biblionumber, $matched_barcode_item->itemnumber, { skip_record_index => 1 } ); + $updsth->bind_param( 1, 'imported' ); + $updsth->bind_param( 2, $item->{itemnumber} ); + $updsth->bind_param( 3, undef ); + $updsth->bind_param( 4, $row->{'import_items_id'} ); + $updsth->execute(); + $updsth->finish(); + $num_items_replaced++; + } } elsif ($duplicate_barcode) { $updsth->bind_param( 1, 'error' ); $updsth->bind_param( 2, undef ); @@ -1748,11 +1767,18 @@ sub _get_commit_action { $bib_result = $overlay_action; - if($item_action eq 'always_add' or $item_action eq 'add_only_for_matches'){ + if ( $item_action eq 'always_add' + or $item_action eq 'add_only_for_matches' ) + { $item_result = 'create_new'; - } elsif($item_action eq 'replace'){ + } + elsif ( $item_action eq 'replace' ) { $item_result = 'replace'; - } else { + } + elsif ( $item_action eq 'replace_if_bib_match' ) { + $item_result = 'replace_if_bib_match'; + } + else { $item_result = 'ignore'; } diff --git a/installer/data/mysql/atomicupdate/bug_32902.pl b/installer/data/mysql/atomicupdate/bug_32902.pl new file mode 100755 index 0000000000..d2b6e3bc5f --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_32902.pl @@ -0,0 +1,14 @@ +use Modern::Perl; + +return { + bug_number => "32902", + description => "Add new item overlay action 'replace_if_bib_match'", + up => sub { + my ($args) = @_; + my ($dbh, $out) = @$args{qw(dbh out)}; + $dbh->do(q{ + ALTER TABLE import_batches MODIFY item_action + enum('always_add','add_only_for_matches','add_only_for_new','ignore','replace','replace_if_bib_match') NOT NULL DEFAULT 'always_add' + COMMENT 'what to do with item records'}); + }, +}; diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index df66cee175..e8b08b47ff 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/installer/data/mysql/kohastructure.sql @@ -3328,7 +3328,7 @@ CREATE TABLE `import_batches` ( `upload_timestamp` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'date and time the file was uploaded', `overlay_action` enum('replace','create_new','use_template','ignore') NOT NULL DEFAULT 'create_new' COMMENT 'how to handle duplicate records', `nomatch_action` enum('create_new','ignore') NOT NULL DEFAULT 'create_new' COMMENT 'how to handle records where no match is found', - `item_action` enum('always_add','add_only_for_matches','add_only_for_new','ignore','replace') NOT NULL DEFAULT 'always_add' COMMENT 'what to do with item records', + `item_action` enum('always_add','add_only_for_matches','add_only_for_new','ignore','replace','replace_if_bib_match') NOT NULL DEFAULT 'always_add' COMMENT 'what to do with item records', `import_status` enum('staging','staged','importing','imported','reverting','reverted','cleaned') NOT NULL DEFAULT 'staging' COMMENT 'the status of the imported file', `batch_type` enum('batch','z3950','webservice') NOT NULL DEFAULT 'batch' COMMENT 'where this batch has come from', `record_type` enum('biblio','auth','holdings') NOT NULL DEFAULT 'biblio' COMMENT 'type of record in the batch', diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-item-action.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/tools-item-action.inc index 88ba6adf07..29362aa6e9 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/includes/tools-item-action.inc +++ b/koha-tmpl/intranet-tmpl/prog/en/includes/tools-item-action.inc @@ -26,7 +26,13 @@ [% ELSE %] + Replace matching items if any matching record was found (only for existing items) + [% IF ( item_action_replace_if_bib_match ) %] + [% IF ( item_action_ignore ) %]