Bug 7131: teach MARC import how to overlay items
authorElliott Davis <elliott@bywatersolutions.com>
Wed, 10 Oct 2012 19:21:22 +0000 (14:21 -0500)
committerGalen Charlton <gmc@esilibrary.com>
Wed, 30 Oct 2013 04:31:07 +0000 (04:31 +0000)
When staging biblios with items attached you previously had only two
options, add or don't add.

This patch adds a third option to replace an item record if a match is
found on itemnumber or barcode, else it adds the item.

Test Plan:
1) Stage a file of biblios with items attached.
2) Import the batch into the catalog.
3) Run the indexer so the matcher will match
4) Modify the item data for at least one bib in the file
5) Re-stage the file with the item matching option set to "Replace
   items if matching bib was found"
6) Let the indexer run again
7) You should see updated item information after the overlay

Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com>
Signed-off-by: Henry Bankhead <hbankhead@losgatosca.gov>
Signed-off-by: Galen Charlton <gmc@esilibrary.com>
C4/ImportBatch.pm
installer/data/mysql/kohastructure.sql
koha-tmpl/intranet-tmpl/prog/en/includes/tools-item-action.inc
koha-tmpl/intranet-tmpl/prog/en/modules/tools/manage-marc-import.tt
tools/manage-marc-import.pl

index 3ce5c67..52d4c05 100644 (file)
@@ -514,7 +514,7 @@ sub BatchFindDuplicates {
 
 =head2 BatchCommitRecords
 
-  my ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored) =
+  my ($num_added, $num_updated, $num_items_added, $num_items_replaced, $num_items_errored, $num_ignored) =
         BatchCommitRecords($batch_id, $framework,
         $progress_interval, $progress_callback);
 
@@ -539,6 +539,7 @@ sub BatchCommitRecords {
     my $num_added = 0;
     my $num_updated = 0;
     my $num_items_added = 0;
+    my $num_items_replaced = 0;
     my $num_items_errored = 0;
     my $num_ignored = 0;
     # commit (i.e., save, all records in the batch)
@@ -598,9 +599,10 @@ sub BatchCommitRecords {
                 my $biblioitemnumber;
                 ($recordid, $biblioitemnumber) = AddBiblio($marc_record, $framework);
                 $query = "UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?";
-                if ($item_result eq 'create_new') {
-                    my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid);
+                if ($item_result eq 'create_new' || $item_result eq 'replace') {
+                    my ($bib_items_added, $bib_items_replaced, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid, $item_result);
                     $num_items_added += $bib_items_added;
+                    $num_items_replaced += $bib_items_replaced;
                     $num_items_errored += $bib_items_errored;
                 }
             } else {
@@ -631,9 +633,10 @@ sub BatchCommitRecords {
                 ModBiblio($marc_record, $recordid, $oldbiblio->{'frameworkcode'});
                 $query = "UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?";
 
-                if ($item_result eq 'create_new') {
-                    my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid);
+                if ($item_result eq 'create_new' || $item_result eq 'replace') {
+                    my ($bib_items_added, $bib_items_replaced, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid, $item_result);
                     $num_items_added += $bib_items_added;
+                    $num_items_replaced += $bib_items_replaced;
                     $num_items_errored += $bib_items_errored;
                 }
             } else {
@@ -654,8 +657,9 @@ sub BatchCommitRecords {
             $num_ignored++;
             $recordid = $record_match;
             if ($record_type eq 'biblio' and defined $recordid and $item_result eq 'create_new') {
-                my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid);
+                my ($bib_items_added, $bib_items_replaced, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid, $item_result);
                 $num_items_added += $bib_items_added;
+         $num_items_replaced += $bib_items_replaced;
                 $num_items_errored += $bib_items_errored;
                 # still need to record the matched biblionumber so that the
                 # items can be reverted
@@ -668,7 +672,7 @@ sub BatchCommitRecords {
     }
     $sth->finish();
     SetImportBatchStatus($batch_id, 'imported');
-    return ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored);
+    return ($num_added, $num_updated, $num_items_added, $num_items_replaced, $num_items_errored, $num_ignored);
 }
 
 =head2 BatchCommitItems
@@ -679,12 +683,11 @@ sub BatchCommitRecords {
 =cut
 
 sub BatchCommitItems {
-    my ($import_record_id, $biblionumber) = @_;
+    my ($import_record_id, $biblionumber, $action) = @_;
 
     my $dbh = C4::Context->dbh;
 
-    my $num_items_added = 0;
-    my $num_items_errored = 0;
+    my ($num_items_added, $num_items_errored, $num_items_replaced) = 0;
     my $sth = $dbh->prepare("SELECT import_items_id, import_items.marcxml, encoding
                              FROM import_items
                              JOIN import_records USING (import_record_id)
@@ -694,11 +697,24 @@ sub BatchCommitItems {
     $sth->execute();
     while (my $row = $sth->fetchrow_hashref()) {
         my $item_marc = MARC::Record->new_from_xml(StripNonXmlChars($row->{'marcxml'}), 'UTF-8', $row->{'encoding'});
+    #delete date_due subfield as to not accidentally delete item checkout due dates
+        my ($MARCfield,$MARCsubfield) = GetMarcFromKohaField('items.onloan', GetFrameworkCode($biblionumber));
+ $item_marc->field($MARCfield)->delete_subfield(code => $MARCsubfield);
         # FIXME - duplicate barcode check needs to become part of AddItemFromMarc()
         my $item = TransformMarcToKoha($dbh, $item_marc);
         my $duplicate_barcode = exists($item->{'barcode'}) && GetItemnumberFromBarcode($item->{'barcode'});
-        if ($duplicate_barcode) {
-            my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, import_error = ? WHERE import_items_id = ?");
+        my $duplicate_itemnumber = exists($item->{'itemnumber'});
+     my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, itemnumber = ? WHERE import_items_id = ?");
+    if($action eq "replace" && $duplicate_itemnumber){
+         ModItemFromMarc($item_marc, $biblionumber, $item->{itemnumber});
+            $updsth->bind_param(1, 'imported');
+            $updsth->bind_param(2, $item->{itemnumber});
+            $updsth->bind_param(3, $row->{'import_items_id'});
+            $updsth->execute();
+            $updsth->finish();
+        $num_items_replaced++;
+     }
+        elsif ($duplicate_barcode) {
             $updsth->bind_param(1, 'error');
             $updsth->bind_param(2, 'duplicate item barcode');
             $updsth->bind_param(3, $row->{'import_items_id'});
@@ -706,7 +722,6 @@ sub BatchCommitItems {
             $num_items_errored++;
         } else {
             my ($item_biblionumber, $biblioitemnumber, $itemnumber) = AddItemFromMarc($item_marc, $biblionumber);
-            my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, itemnumber = ? WHERE import_items_id = ?");
             $updsth->bind_param(1, 'imported');
             $updsth->bind_param(2, $itemnumber);
             $updsth->bind_param(3, $row->{'import_items_id'});
@@ -716,7 +731,7 @@ sub BatchCommitItems {
         }
     }
     $sth->finish();
-    return ($num_items_added, $num_items_errored);
+    return ($num_items_added, $num_items_replaced, $num_items_errored);
 }
 
 =head2 BatchRevertRecords
@@ -1467,7 +1482,15 @@ sub _get_commit_action {
             } elsif ($overlay_action eq 'ignore') {
                 $bib_result  = 'ignore';
             }
-            $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_matches') ? 'create_new' : 'ignore';
+         if($item_action eq 'always_add' or $item_action eq 'add_only_for_matches'){
+                $item_result = 'create_new';
+       }
+      elsif($item_action eq 'replace'){
+          $item_result = 'replace';
+          }
+      else {
+             $item_result = 'ignore';
+           }
         } else {
             $bib_result = $nomatch_action;
             $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_new')     ? 'create_new' : 'ignore';
index 17615c5..a6a779e 100644 (file)
@@ -970,7 +970,7 @@ CREATE TABLE `import_batches` ( -- information about batches of marc records tha
   `upload_timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP, -- date and time the file was uploaded
   `overlay_action` enum('replace', 'create_new', 'use_template', 'ignore') NOT NULL default 'create_new', -- how to handle duplicate records
   `nomatch_action` enum('create_new', 'ignore') NOT NULL default 'create_new', -- how to handle records where no match is found
-  `item_action` enum('always_add', 'add_only_for_matches', 'add_only_for_new', 'ignore') NOT NULL default 'always_add', -- what to do with item records
+  `item_action` enum('always_add', 'add_only_for_matches', 'add_only_for_new', 'ignore', 'replace') NOT NULL default 'always_add', -- what to do with item records
   `import_status` enum('staging', 'staged', 'importing', 'imported', 'reverting', 'reverted', 'cleaned') NOT NULL default 'staging', -- the status of the imported file
   `batch_type` enum('batch', 'z3950', 'webservice') NOT NULL default 'batch', -- where this batch has come from
   `record_type` enum('biblio', 'auth', 'holdings') NOT NULL default 'biblio', -- type of record in the batch
index 0c8d37b..9b54869 100644 (file)
                 <option value="add_only_for_new">
             [% END %]
                 Add items only if no matching bib was found</option>
+            [% IF ( item_action_replace ) %]
+                <option value="replace" selected="selected">
+            [% ELSE %]
+                <option value="replace">
+            [% END %]
+                Replace items if matching bib was found (only for existing items)</option>
             [% IF ( item_action_ignore ) %]
                 <option value="ignore" selected="selected">
             [% ELSE %]
index 3d159c4..e8384c1 100644 (file)
@@ -282,6 +282,7 @@ $(document).ready(function(){
   <tr><td>Number of records updated</td><td>[% num_updated %]</td></tr>
   <tr><td>Number of records ignored</td><td>[% num_ignored %]</td></tr>
   <tr><td>Number of items added</td><td>[% num_items_added %]</td></tr>
+  <tr><td>Number of items replaced</td><td>[% num_items_replaced %]</td></tr>
   <tr><td>Number of items ignored because of duplicate barcode</td><td>[% num_items_errored %]</td></tr>
   </table>
   [% END %]
index c0584c9..f1a6c83 100755 (executable)
@@ -240,7 +240,7 @@ sub commit_batch {
         $job = put_in_background($import_batch_id);
         $callback = progress_callback($job, $dbh);
     }
-    my ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored) = 
+    my ($num_added, $num_updated, $num_items_added, $num_items_replaced, $num_items_errored, $num_ignored) =
         BatchCommitRecords($import_batch_id, $framework, 50, $callback);
     $dbh->commit();
 
@@ -249,6 +249,7 @@ sub commit_batch {
         num_added => $num_added,
         num_updated => $num_updated,
         num_items_added => $num_items_added,
+        num_items_replaced => $num_items_replaced,
         num_items_errored => $num_items_errored,
         num_ignored => $num_ignored
     };