more work on batch import
[srvgit] / C4 / ImportBatch.pm
index 056e06b..b2b77b0 100644 (file)
@@ -21,6 +21,7 @@ use strict;
 use C4::Context;
 use C4::Koha;
 use C4::Biblio;
+use C4::Matcher;
 require Exporter;
 
 
@@ -52,6 +53,18 @@ use C4::ImportBatch;
     AddImportBatch
     AddBiblioToBatch
     ModBiblioInBatch
+
+    BatchStageMarcRecords
+    BatchFindBibDuplicates
+    BatchCommitBibRecords
+    
+    GetImportBatchStatus
+    SetImportBatchStatus
+    GetImportBatchOverlayAction
+    SetImportBatchOverlayAction
+    GetImportRecordOverlayStatus
+    SetImportRecordOverlayStatus
+    SetImportRecordMatches
 );
 
 =head2 GetZ3950BatchId
@@ -140,12 +153,14 @@ sub AddImportBatch {
 
 my $import_record_id = AddBiblioToBatch($batch_id, $record_sequence, $marc_record, $encoding, $z3950random);
 
+=back
+
 =cut
 
 sub AddBiblioToBatch {
     my ($batch_id, $record_sequence, $marc_record, $encoding, $z3950random) = @_;
 
-    my $import_record_id = _create_import_record($batch_id, $record_sequence, $marc_record, 'bib', $encoding, $z3950random);
+    my $import_record_id = _create_import_record($batch_id, $record_sequence, $marc_record, 'biblio', $encoding, $z3950random);
     _add_biblio_fields($import_record_id, $marc_record);
     return $import_record_id;
 }
@@ -156,6 +171,8 @@ sub AddBiblioToBatch {
 
 ModBiblioInBatch($import_record_id, $marc_record);
 
+=back
+
 =cut
 
 sub ModBiblioInBatch {
@@ -166,6 +183,326 @@ sub ModBiblioInBatch {
 
 }
 
+=head2 BatchStageMarcRecords
+
+=over 4
+
+($batch_id, $num_records, @invalid_records) = BatchStageMarcRecords($marc_flavor, $marc_records, $file_name, 
+                                                                    $comments, $branch_code, $leave_as_staging);
+
+=back
+
+=cut
+
+sub  BatchStageMarcRecords {
+    my ($marc_flavor, $marc_records, $file_name, $comments, $branch_code, $leave_as_staging) = @_;
+
+    my $batch_id = AddImportBatch('create_new', 'staging', 'batch', $file_name, $comments);
+    my @invalid_records = ();
+    my $num_valid = 0;
+    # FIXME - for now, we're dealing only with bibs
+    my $rec_num = 0;
+    foreach my $marc_blob (split(/\x1D/, $marc_records)) {
+        $rec_num++;
+        my $marc_record = FixEncoding($marc_blob, "\x1D");
+        my $import_record_id;
+        if (scalar($marc_record->fields()) == 0) {
+            push @invalid_records, $marc_blob;
+        } else {
+            $num_valid++;
+            $import_record_id = AddBiblioToBatch($batch_id, $rec_num, $marc_record, $marc_flavor, int(rand(99999)));
+        }
+    }
+    unless ($leave_as_staging) {
+        SetImportBatchStatus($batch_id, 'staged');
+    }
+    # FIXME batch_code, number of bibs, number of items
+    return ($batch_id, $num_valid, @invalid_records);
+}
+
+=head2 BatchFindBibDuplicates
+
+=over4
+
+my $num_with_matches = BatchFindBibDuplicates($batch_id, $matcher, $max_matches);
+
+=back
+
+Goes through the records loaded in the batch and attempts to 
+find duplicates for each one.  Sets the overlay action to
+'replace' if it was 'create_new', and sets the overlay status
+of each record to 'no_match' or 'auto_match' as appropriate.
+
+The $max_matches parameter is optional; if it is not supplied,
+it defaults to 10.
+
+=cut
+
+sub BatchFindBibDuplicates {
+    my $batch_id = shift;
+    my $matcher = shift;
+    my $max_matches = @_ ? shift : 10;
+
+    my $dbh = C4::Context->dbh;
+    my $old_overlay_action = GetImportBatchOverlayAction($batch_id);
+    if ($old_overlay_action eq "create_new") {
+        SetImportBatchOverlayAction($batch_id, 'replace');
+    }
+
+    my $sth = $dbh->prepare("SELECT import_record_id, marc
+                             FROM import_records
+                             JOIN import_biblios USING (import_record_id)
+                             WHERE import_batch_id = ?");
+    $sth->execute($batch_id);
+    my $num_with_matches = 0;
+    while (my $rowref = $sth->fetchrow_hashref) {
+        my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
+        my @matches = $matcher->get_matches($marc_record, $max_matches);
+        if (scalar(@matches) > 0) {
+            $num_with_matches++;
+            SetImportRecordMatches($rowref->{'import_record_id'}, @matches);
+            SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'auto_match');
+        } else {
+            SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'no_match');
+        }
+    }
+    $sth->finish();
+    return $num_with_matches;
+}
+
+=head2 BatchCommitBibRecords
+
+=over 4
+
+my ($num_added, $num_updated, $num_ignored) = BatchCommitBibRecords($batch_id);
+
+=back
+
+=cut
+
+sub BatchCommitBibRecords {
+    my $batch_id = shift;
+
+    my $num_added = 0;
+    my $num_updated = 0;
+    my $num_ignored = 0;
+    # commit (i.e., save, all records in the batch)
+    # FIXME biblio only at the moment
+    SetImportBatchStatus('importing');
+    my $overlay_action = GetImportBatchOverlayAction($batch_id);
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marc
+                             FROM import_records
+                             JOIN import_biblios USING (import_record_id)
+                             WHERE import_batch_id = ?");
+    $sth->execute($batch_id);
+    while (my $rowref = $sth->fetchrow_hashref) {
+        if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'imported') {
+            $num_ignored++;
+        }
+        my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
+        if ($overlay_action eq 'create_new' or
+            ($overlay_action eq 'replace' and $rowref->{'overlay_status'} eq 'no_match')) {
+            $num_added++;
+            my ($biblionumber, $biblioitemnumber) = AddBiblio($marc_record, '');
+        } else {
+            $num_updated++;
+            my $biblionumber = GetBestRecordMatch($rowref->{'import_record_id'});
+            my ($count, $oldbiblio) = GetBiblio($biblionumber);
+            my $oldxml = GetXmlBiblio($biblionumber);
+            ModBiblio($marc_record, $biblionumber, $oldbiblio->{'frameworkcode'});
+            my $dbh = C4::Context->dbh;
+            my $sth = $dbh->prepare("UPDATE import_records SET marcxml_old = ? WHERE import_record_id = ?");
+            $sth->execute($oldxml, $rowref->{'import_record_id'});
+            $sth->finish();
+            SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
+        }
+    }
+    $sth->finish();
+    SetImportBatchStatus('imported');
+    return ($num_added, $num_updated, $num_ignored);
+}
+
+=head2 GetBestRecordMatch
+
+=over 4
+
+my $record_id = GetBestRecordMatch($import_record_id);
+
+=back
+
+=cut
+
+sub GetBestRecordMatch {
+    my ($import_record_id) = @_;
+
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare("SELECT candidate_match_id
+                             FROM   import_record_matches
+                             WHERE  import_record_id = ?
+                             ORDER BY score DESC, candidate_match_id DESC");
+    $sth->execute($import_record_id);
+    my ($record_id) = $sth->fetchrow_array();
+    $sth->finish();
+    return $record_id;
+}
+
+=head2 GetImportBatchStatus
+
+=over 4
+
+my $status = GetImportBatchStatus($batch_id);
+
+=back
+
+=cut
+
+sub GetImportBatchStatus {
+    my ($batch_id) = @_;
+
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare("SELECT import_status FROM import_batches WHERE batch_id = ?");
+    $sth->execute($batch_id);
+    my ($status) = $sth->fetchrow_array();
+    $sth->finish();
+    return;
+
+}
+
+
+=head2 SetImportBatchStatus
+
+=over 4
+
+SetImportBatchStatus($batch_id, $new_status);
+
+=back
+
+=cut
+
+sub SetImportBatchStatus {
+    my ($batch_id, $new_status) = @_;
+
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare("UPDATE import_batches SET import_status = ? WHERE import_batch_id = ?");
+    $sth->execute($new_status, $batch_id);
+    $sth->finish();
+
+}
+
+=head2 GetImportBatchOverlayAction
+
+=over 4
+
+my $overlay_action = GetImportBatchOverlayAction($batch_id);
+
+=back
+
+=cut
+
+sub GetImportBatchOverlayAction {
+    my ($batch_id) = @_;
+
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare("SELECT overlay_action FROM import_batches WHERE import_batch_id = ?");
+    $sth->execute($batch_id);
+    my ($overlay_action) = $sth->fetchrow_array();
+    $sth->finish();
+    return $overlay_action;
+
+}
+
+
+=head2 SetImportBatchOverlayAction
+
+=over 4
+
+SetImportBatchOverlayAction($batch_id, $new_overlay_action);
+
+=back
+
+=cut
+
+sub SetImportBatchOverlayAction {
+    my ($batch_id, $new_overlay_action) = @_;
+
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare("UPDATE import_batches SET overlay_action = ? WHERE import_batch_id = ?");
+    $sth->execute($new_overlay_action, $batch_id);
+    $sth->finish();
+
+}
+
+=head2 GetImportRecordOverlayStatus
+
+=over 4
+
+my $overlay_status = GetImportRecordOverlayStatus($import_record_id);
+
+=back
+
+=cut
+
+sub GetImportRecordOverlayStatus {
+    my ($import_record_id) = @_;
+
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare("SELECT overlay_status FROM import_records WHERE import_record_id = ?");
+    $sth->execute($import_record_id);
+    my ($overlay_status) = $sth->fetchrow_array();
+    $sth->finish();
+    return $overlay_status;
+
+}
+
+
+=head2 SetImportRecordOverlayStatus
+
+=over 4
+
+SetImportRecordOverlayStatus($import_record_id, $new_overlay_status);
+
+=back
+
+=cut
+
+sub SetImportRecordOverlayStatus {
+    my ($import_record_id, $new_overlay_status) = @_;
+
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare("UPDATE import_records SET overlay_status = ? WHERE import_record_id = ?");
+    $sth->execute($new_overlay_status, $import_record_id);
+    $sth->finish();
+
+}
+
+=head2 SetImportRecordMatches
+
+=over 4
+
+SetImportRecordMatches($import_record_id, @matches);
+
+=back
+
+=cut
+
+sub SetImportRecordMatches {
+    my $import_record_id = shift;
+    my @matches = @_;
+
+    my $dbh = C4::Context->dbh;
+    my $delsth = $dbh->prepare("DELETE FROM import_record_matches WHERE import_record_id = ?");
+    $delsth->execute($import_record_id);
+    $delsth->finish();
+
+    my $sth = $dbh->prepare("INSERT INTO import_record_matches (import_record_id, candidate_match_id, score)
+                                    VALUES (?, ?, ?)");
+    foreach my $match (@matches) {
+        $sth->execute($import_record_id, $match->{'record_id'}, $match->{'score'});
+    }
+}
+
+
 # internal functions
 
 sub _create_import_record {