Bugzilla – Attachment 10423 Details for
Bug 7475
Option to overlay authorities
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 7475: Enable authority overlay
Bug-7475-Enable-authority-overlay.patch (text/plain), 48.33 KB, created by
Jared Camins-Esakov
on 2012-06-22 03:53:47 UTC
(
hide
)
Description:
Bug 7475: Enable authority overlay
Filename:
MIME Type:
Creator:
Jared Camins-Esakov
Created:
2012-06-22 03:53:47 UTC
Size:
48.33 KB
patch
obsolete
>From 478ae788e7c1da7d8378a4504b1d61108a23f700 Mon Sep 17 00:00:00 2001 >From: Jared Camins-Esakov <jcamins@cpbibliography.com> >Date: Mon, 21 May 2012 13:12:12 -0400 >Subject: [PATCH] Bug 7475: Enable authority overlay >Content-Type: text/plain; charset="UTF-8" > >This patch does the following: >* Completes authority support within Koha's import batch code >* Completes authority support in Koha's matching rule code >* Exposes the ability to stage and commit batches of authorities using > the renamed scripts misc/stage_file.pl and misc/commit_file.pl > >To test (note that these instructions assume you have a MARC21 >installation and are using the provided sample file): >1. Find a file of authorities (a sample file with MARC21 authorities > is attached to bug 7475) and download it to your server >2. Stage the file using the following command (replace <filename> with > the name of the file you saved in step 1): > > misc/stage_file.pl --file <filename> --authorities >3. Note the batch number the script assigns to your batch >4. Commit the records using the following command (replace <batchnumber> > with the batch number you made note of in step 3): > > misc/commit_file.pl --batch-number <batchnumber> >5. Index the authorities Zebraqueue (or wait) >6. Confirm that the new authorities appear. >7. Create a matching rule with the following settings: > Code: AUTHTEST > Description: Personal name main entry > Match threshold: 999 > Record type: Authority record > Search index: Heading-main > Score: 1000 > Tag: 100 > Subfields: a > Offset: 0 > Length: 0 > (note the ID of this matching rule) >8. Stage the authority file again, this time using the following > command: > > misc/stage_file.pl --file <filename> --authorities \ > --match <matchingrule> >7. Revert the import with the following command: > > misc/commit_file.pl --batch-number <batchnumber> --revert >8. Index the authorities Zebraqueue (or wait) >9. Confirm that the records have been removed >--- > C4/ImportBatch.pm | 320 +++++++++++++------ > C4/Matcher.pm | 73 ++++- > admin/matching-rules.pl | 12 +- > .../data/mysql/atomicupdate/importauthorities.pl | 19 ++ > installer/data/mysql/kohastructure.sql | 15 + > .../prog/en/modules/admin/matching-rules.tt | 11 + > misc/{commit_biblios_file.pl => commit_file.pl} | 54 +++- > misc/cronjobs/import_webservice_batch.pl | 2 +- > misc/{stage_biblios_file.pl => stage_file.pl} | 84 +++--- > svc/import_bib | 2 +- > tools/manage-marc-import.pl | 4 +- > 11 files changed, 425 insertions(+), 171 deletions(-) > create mode 100755 installer/data/mysql/atomicupdate/importauthorities.pl > rename misc/{commit_biblios_file.pl => commit_file.pl} (63%) > rename misc/{stage_biblios_file.pl => stage_file.pl} (67%) > >diff --git a/C4/ImportBatch.pm b/C4/ImportBatch.pm >index a64a0d2..007f339 100644 >--- a/C4/ImportBatch.pm >+++ b/C4/ImportBatch.pm >@@ -1,6 +1,6 @@ > package C4::ImportBatch; > >-# Copyright (C) 2007 LibLime >+# Copyright (C) 2007 LibLime, 2012 C & P Bibliography Services > # > # This file is part of Koha. > # >@@ -40,14 +40,16 @@ BEGIN { > GetImportRecordMarcXML > AddImportBatch > GetImportBatch >+ AddAuthorityToBatch > AddBiblioToBatch > AddItemsToImportBiblio >+ ModAuthorityInBatch > ModBiblioInBatch > > BatchStageMarcRecords >- BatchFindBibDuplicates >- BatchCommitBibRecords >- BatchRevertBibRecords >+ BatchFindDuplicates >+ BatchCommitRecords >+ BatchRevertRecords > CleanBatch > > GetAllImportBatches >@@ -272,10 +274,44 @@ sub ModBiblioInBatch { > > } > >+=head2 AddAuthToBatch >+ >+ my $import_record_id = AddAuthToBatch($batch_id, $record_sequence, >+ $marc_record, $encoding, $z3950random, $update_counts); >+ >+=cut >+ >+sub AddAuthToBatch { >+ my $batch_id = shift; >+ my $record_sequence = shift; >+ my $marc_record = shift; >+ my $encoding = shift; >+ my $z3950random = shift; >+ my $update_counts = @_ ? shift : 1; >+ >+ my $import_record_id = _create_import_record($batch_id, $record_sequence, $marc_record, 'auth', $encoding, $z3950random); >+ _add_auth_fields($import_record_id, $marc_record); >+ _update_batch_record_counts($batch_id) if $update_counts; >+ return $import_record_id; >+} >+ >+=head2 ModAuthInBatch >+ >+ ModAuthInBatch($import_record_id, $marc_record); >+ >+=cut >+ >+sub ModAuthInBatch { >+ my ($import_record_id, $marc_record) = @_; >+ >+ _update_import_record_marc($import_record_id, $marc_record); >+ >+} >+ > =head2 BatchStageMarcRecords > > ($batch_id, $num_records, $num_items, @invalid_records) = >- BatchStageMarcRecords($encoding, $marc_records, $file_name, >+ BatchStageMarcRecords($record_type, $encoding, $marc_records, $file_name, > $comments, $branch_code, $parse_items, > $leave_as_staging, > $progress_interval, $progress_callback); >@@ -283,6 +319,7 @@ sub ModBiblioInBatch { > =cut > > sub BatchStageMarcRecords { >+ my $record_type = shift; > my $encoding = shift; > my $marc_records = shift; > my $file_name = shift; >@@ -338,10 +375,14 @@ sub BatchStageMarcRecords { > push @invalid_records, $marc_blob; > } else { > $num_valid++; >- $import_record_id = AddBiblioToBatch($batch_id, $rec_num, $marc_record, $encoding, int(rand(99999)), 0); >- if ($parse_items) { >- my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, 0); >- $num_items += scalar(@import_items_ids); >+ if ($record_type eq 'biblio') { >+ $import_record_id = AddBiblioToBatch($batch_id, $rec_num, $marc_record, $encoding, int(rand(99999)), 0); >+ if ($parse_items) { >+ my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, 0); >+ $num_items += scalar(@import_items_ids); >+ } >+ } elsif ($record_type eq 'auth') { >+ $import_record_id = AddAuthToBatch($batch_id, $rec_num, $marc_record, $encoding, int(rand(99999)), 0); > } > } > } >@@ -392,9 +433,9 @@ sub AddItemsToImportBiblio { > return @import_items_ids; > } > >-=head2 BatchFindBibDuplicates >+=head2 BatchFindDuplicates > >- my $num_with_matches = BatchFindBibDuplicates($batch_id, $matcher, >+ my $num_with_matches = BatchFindDuplicates($batch_id, $matcher, > $max_matches, $progress_interval, $progress_callback); > > Goes through the records loaded in the batch and attempts to >@@ -412,7 +453,7 @@ singular argument. > > =cut > >-sub BatchFindBibDuplicates { >+sub BatchFindDuplicates { > my $batch_id = shift; > my $matcher = shift; > my $max_matches = @_ ? shift : 10; >@@ -430,9 +471,10 @@ sub BatchFindBibDuplicates { > > my $dbh = C4::Context->dbh; > >- my $sth = $dbh->prepare("SELECT import_record_id, marc >+ my $sth = $dbh->prepare("SELECT import_records.import_record_id, record_type, marc > FROM import_records >- JOIN import_biblios USING (import_record_id) >+ LEFT JOIN import_auths ON (import_records.import_record_id=import_auths.import_record_id) >+ LEFT JOIN import_biblios ON (import_records.import_record_id=import_biblios.import_record_id) > WHERE import_batch_id = ?"); > $sth->execute($batch_id); > my $num_with_matches = 0; >@@ -460,15 +502,15 @@ sub BatchFindBibDuplicates { > return $num_with_matches; > } > >-=head2 BatchCommitBibRecords >+=head2 BatchCommitRecords > >- my ($num_added, $num_updated, $num_items_added, $num_items_errored, >- $num_ignored) = BatchCommitBibRecords($batch_id, $framework, >- $progress_interval, $progress_callback); >+ my ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored) = >+ BatchCommitRecords($batch_id, $framework, >+ $progress_interval, $progress_callback); > > =cut > >-sub BatchCommitBibRecords { >+sub BatchCommitRecords { > my $batch_id = shift; > my $framework = shift; > >@@ -483,25 +525,29 @@ sub BatchCommitBibRecords { > $progress_interval = 0 unless 'CODE' eq ref $progress_callback; > } > >+ my $record_type; > my $num_added = 0; > my $num_updated = 0; > my $num_items_added = 0; > my $num_items_errored = 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 $nomatch_action = GetImportBatchNoMatchAction($batch_id); > my $item_action = GetImportBatchItemAction($batch_id); >+ my $item_tag; >+ my $item_subfield; > my $dbh = C4::Context->dbh; >- my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marc, encoding >+ my $sth = $dbh->prepare("SELECT import_records.import_record_id, record_type, status, overlay_status, marc, encoding > FROM import_records >- JOIN import_biblios USING (import_record_id) >+ LEFT JOIN import_auths ON (import_records.import_record_id=import_auths.import_record_id) >+ LEFT JOIN import_biblios ON (import_records.import_record_id=import_biblios.import_record_id) > WHERE import_batch_id = ?"); > $sth->execute($batch_id); > my $rec_num = 0; > while (my $rowref = $sth->fetchrow_hashref) { >+ $record_type = $rowref->{'record_type'}; > $rec_num++; > if ($progress_interval and (0 == ($rec_num % $progress_interval))) { > &$progress_callback($rec_num); >@@ -513,67 +559,87 @@ sub BatchCommitBibRecords { > > my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'}); > >- # remove any item tags - rely on BatchCommitItems >- my ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",''); >- foreach my $item_field ($marc_record->field($item_tag)) { >- $marc_record->delete_field($item_field); >+ if ($record_type eq 'biblio') { >+ # remove any item tags - rely on BatchCommitItems >+ ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",''); >+ foreach my $item_field ($marc_record->field($item_tag)) { >+ $marc_record->delete_field($item_field); >+ } > } > >- # decide what what to do with the bib and item records >- my ($bib_result, $item_result, $bib_match) = >+ my ($record_result, $item_result, $record_match) = > _get_commit_action($overlay_action, $nomatch_action, $item_action, >- $rowref->{'overlay_status'}, $rowref->{'import_record_id'}); >+ $rowref->{'overlay_status'}, $rowref->{'import_record_id'}, $record_type); > >- if ($bib_result eq 'create_new') { >+ my $recordid; >+ my $query; >+ if ($record_result eq 'create_new') { > $num_added++; >- my ($biblionumber, $biblioitemnumber) = AddBiblio($marc_record, $framework); >- my $sth = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?"); >- $sth->execute($biblionumber, $rowref->{'import_record_id'}); >- $sth->finish(); >- if ($item_result eq 'create_new') { >- my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber); >- $num_items_added += $bib_items_added; >- $num_items_errored += $bib_items_errored; >+ if ($record_type eq 'biblio') { >+ 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); >+ $num_items_added += $bib_items_added; >+ $num_items_errored += $bib_items_errored; >+ } >+ } else { >+ my $authid = AddAuthority($marc_record, undef, GuessAuthTypeCode($marc_record)); >+ $query = "UPDATE import_auths SET matched_authid = ? WHERE import_record_id = ?"; > } >+ my $sth = $dbh->prepare_cached($query); >+ $sth->execute($recordid, $rowref->{'import_record_id'}); >+ $sth->finish(); > SetImportRecordStatus($rowref->{'import_record_id'}, 'imported'); >- } elsif ($bib_result eq 'replace') { >+ } elsif ($record_result eq 'replace') { > $num_updated++; >- my $biblionumber = $bib_match; >- my ($count, $oldbiblio) = GetBiblio($biblionumber); >- my $oldxml = GetXmlBiblio($biblionumber); >- >- # remove item fields so that they don't get >- # added again if record is reverted >- my $old_marc = MARC::Record->new_from_xml(StripNonXmlChars($oldxml), 'UTF-8', $rowref->{'encoding'}); >- foreach my $item_field ($old_marc->field($item_tag)) { >- $old_marc->delete_field($item_field); >- } >+ $recordid = $record_match; >+ my $oldxml; >+ if ($record_type eq 'biblio') { >+ my ($count, $oldbiblio) = GetBiblio($recordid); >+ $oldxml = GetXmlBiblio($recordid); >+ >+ # remove item fields so that they don't get >+ # added again if record is reverted >+ my $old_marc = MARC::Record->new_from_xml(StripNonXmlChars($oldxml), 'UTF-8', $rowref->{'encoding'}); >+ foreach my $item_field ($old_marc->field($item_tag)) { >+ $old_marc->delete_field($item_field); >+ } >+ $oldxml = $old_marc->as_xml(); >+ >+ 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); >+ $num_items_added += $bib_items_added; >+ $num_items_errored += $bib_items_errored; >+ } >+ } else { >+ my $oldxml = GetAuthorityXML($recordid); > >- ModBiblio($marc_record, $biblionumber, $oldbiblio->{'frameworkcode'}); >+ ModAuthority($recordid, $marc_record, GuessAuthTypeCode($marc_record)); >+ $query = "UPDATE import_auths SET matched_authid = ? WHERE import_record_id = ?"; >+ } > my $sth = $dbh->prepare_cached("UPDATE import_records SET marcxml_old = ? WHERE import_record_id = ?"); >- $sth->execute($old_marc->as_xml(), $rowref->{'import_record_id'}); >+ $sth->execute($oldxml, $rowref->{'import_record_id'}); > $sth->finish(); >- my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?"); >- $sth2->execute($biblionumber, $rowref->{'import_record_id'}); >+ my $sth2 = $dbh->prepare_cached($query); >+ $sth2->execute($recordid, $rowref->{'import_record_id'}); > $sth2->finish(); >- if ($item_result eq 'create_new') { >- my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber); >- $num_items_added += $bib_items_added; >- $num_items_errored += $bib_items_errored; >- } > SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied'); > SetImportRecordStatus($rowref->{'import_record_id'}, 'imported'); >- } elsif ($bib_result eq 'ignore') { >+ } elsif ($record_result eq 'ignore') { > $num_ignored++; >- my $biblionumber = $bib_match; >- if (defined $biblionumber and $item_result eq 'create_new') { >- my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber); >+ 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); > $num_items_added += $bib_items_added; > $num_items_errored += $bib_items_errored; > # still need to record the matched biblionumber so that the > # items can be reverted > my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?"); >- $sth2->execute($biblionumber, $rowref->{'import_record_id'}); >+ $sth2->execute($recordid, $rowref->{'import_record_id'}); > SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied'); > } > SetImportRecordStatus($rowref->{'import_record_id'}, 'ignored'); >@@ -632,63 +698,84 @@ sub BatchCommitItems { > return ($num_items_added, $num_items_errored); > } > >-=head2 BatchRevertBibRecords >+=head2 BatchRevertRecords > > my ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, >- $num_ignored) = BatchRevertBibRecords($batch_id); >+ $num_ignored) = BatchRevertRecords($batch_id); > > =cut > >-sub BatchRevertBibRecords { >+sub BatchRevertRecords { > my $batch_id = shift; > >+ my $record_type; > my $num_deleted = 0; > my $num_errors = 0; > my $num_reverted = 0; >- my $num_items_deleted = 0; > my $num_ignored = 0; >+ my $num_items_deleted = 0; > # commit (i.e., save, all records in the batch) >- # FIXME biblio only at the moment > SetImportBatchStatus('reverting'); > my $overlay_action = GetImportBatchOverlayAction($batch_id); > my $nomatch_action = GetImportBatchNoMatchAction($batch_id); > my $dbh = C4::Context->dbh; >- my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marcxml_old, encoding, matched_biblionumber >+ my $sth = $dbh->prepare("SELECT import_records.import_record_id, record_type, status, overlay_status, marcxml_old, encoding, matched_biblionumber, matched_authid > FROM import_records >- JOIN import_biblios USING (import_record_id) >+ LEFT JOIN import_auths ON (import_records.import_record_id=import_auths.import_record_id) >+ LEFT JOIN import_biblios ON (import_records.import_record_id=import_biblios.import_record_id) > WHERE import_batch_id = ?"); > $sth->execute($batch_id); > while (my $rowref = $sth->fetchrow_hashref) { >+ $record_type = $rowref->{'record_type'}; > if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'reverted') { > $num_ignored++; > next; > } > >- my $bib_result = _get_revert_action($overlay_action, $rowref->{'overlay_status'}, $rowref->{'status'}); >+ my $record_result = _get_revert_action($overlay_action, $rowref->{'overlay_status'}, $rowref->{'status'}); > >- if ($bib_result eq 'delete') { >- $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'}); >- my $error = DelBiblio($rowref->{'matched_biblionumber'}); >+ if ($record_result eq 'delete') { >+ my $error = undef; >+ if ($record_type eq 'biblio') { >+ $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'}); >+ $error = DelBiblio($rowref->{'matched_biblionumber'}); >+ } else { >+ my $deletedauthid = DelAuthority($rowref->{'matched_authid'}); >+ } > if (defined $error) { > $num_errors++; > } else { > $num_deleted++; > SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted'); > } >- } elsif ($bib_result eq 'restore') { >+ } elsif ($record_result eq 'restore') { > $num_reverted++; > my $old_record = MARC::Record->new_from_xml(StripNonXmlChars($rowref->{'marcxml_old'}), 'UTF-8', $rowref->{'encoding'}); >- my $biblionumber = $rowref->{'matched_biblionumber'}; >- my ($count, $oldbiblio) = GetBiblio($biblionumber); >- $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'}); >- ModBiblio($old_record, $biblionumber, $oldbiblio->{'frameworkcode'}); >+ if ($record_type eq 'biblio') { >+ my $biblionumber = $rowref->{'matched_biblionumber'}; >+ my ($count, $oldbiblio) = GetBiblio($biblionumber); >+ $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'}); >+ ModBiblio($old_record, $biblionumber, $oldbiblio->{'frameworkcode'}); >+ } else { >+ my $authid = $rowref->{'matched_authid'}; >+ ModAuthority($authid, $old_record, GuessAuthTypeCode($old_record)); >+ } > SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted'); >- } elsif ($bib_result eq 'ignore') { >- $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'}); >+ } elsif ($record_result eq 'ignore') { >+ if ($record_type eq 'biblio') { >+ $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'}); >+ } > SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted'); > } >- # remove matched_biblionumber only if there is no 'imported' item left >- my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = NULL WHERE import_record_id = ? AND NOT EXISTS (SELECT * FROM import_items WHERE import_items.import_record_id=import_biblios.import_record_id and status='imported')" ); >+ my $query; >+ if ($record_type eq 'biblio') { >+ # remove matched_biblionumber only if there is no 'imported' item left >+ $query = "UPDATE import_biblios SET matched_biblionumber = NULL WHERE import_record_id = ?"; >+ $query = "UPDATE import_biblios SET matched_biblionumber = NULL WHERE import_record_id = ? AND NOT EXISTS (SELECT * FROM import_items WHERE import_items.import_record_id=import_biblios.import_record_id and status='imported')"; >+ } else { >+ $query = "UPDATE import_auths SET matched_authid = NULL WHERE import_record_id = ?"; >+ } >+ my $sth2 = $dbh->prepare_cached($query); > $sth2->execute($rowref->{'import_record_id'}); > } > >@@ -1263,6 +1350,18 @@ sub _add_biblio_fields { > > } > >+sub _add_auth_fields { >+ my ($import_record_id, $marc_record) = @_; >+ >+ my $dbh = C4::Context->dbh; >+ # FIXME no controlnumber >+ my $sth = $dbh->prepare("INSERT INTO import_auths (import_record_id) VALUES (?)"); >+ $sth->execute($import_record_id); >+ $sth->finish(); >+ >+} >+ >+ > sub _update_biblio_fields { > my ($import_record_id, $marc_record) = @_; > >@@ -1311,26 +1410,45 @@ sub _update_batch_record_counts { > } > > sub _get_commit_action { >- my ($overlay_action, $nomatch_action, $item_action, $overlay_status, $import_record_id) = @_; >+ my ($overlay_action, $nomatch_action, $item_action, $overlay_status, $import_record_id, $record_type) = @_; > >- my ($bib_result, $bib_match, $item_result); >- >- if ($overlay_status ne 'no_match') { >- $bib_match = GetBestRecordMatch($import_record_id); >- if ($overlay_action eq 'replace') { >- $bib_result = defined($bib_match) ? 'replace' : 'create_new'; >- } elsif ($overlay_action eq 'create_new') { >- $bib_result = 'create_new'; >- } 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'; >- } else { >- $bib_result = $nomatch_action; >- $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_new') ? 'create_new' : 'ignore'; >- } >+ if ($record_type eq 'biblio') { >+ my ($bib_result, $bib_match, $item_result); >+ >+ if ($overlay_status ne 'no_match') { >+ $bib_match = GetBestRecordMatch($import_record_id); >+ if ($overlay_action eq 'replace') { >+ $bib_result = defined($bib_match) ? 'replace' : 'create_new'; >+ } elsif ($overlay_action eq 'create_new') { >+ $bib_result = 'create_new'; >+ } 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'; >+ } else { >+ $bib_result = $nomatch_action; >+ $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_new') ? 'create_new' : 'ignore'; >+ } >+ return ($bib_result, $item_result, $bib_match); >+ } else { # must be auths >+ my ($auth_result, $auth_match); >+ >+ if ($overlay_status ne 'no_match') { >+ $auth_match = GetBestRecordMatch($import_record_id); >+ if ($overlay_action eq 'replace') { >+ $auth_result = defined($auth_match) ? 'replace' : 'create_new'; >+ } elsif ($overlay_action eq 'create_new') { >+ $auth_result = 'create_new'; >+ } elsif ($overlay_action eq 'ignore') { >+ $auth_result = 'ignore'; >+ } >+ } else { >+ $auth_result = $nomatch_action; >+ } > >- return ($bib_result, $item_result, $bib_match); >+ return ($auth_result, undef, $auth_match); >+ >+ } > } > > sub _get_revert_action { >diff --git a/C4/Matcher.pm b/C4/Matcher.pm >index 59b5876..c9f418d 100644 >--- a/C4/Matcher.pm >+++ b/C4/Matcher.pm >@@ -1,6 +1,6 @@ > package C4::Matcher; > >-# Copyright (C) 2007 LibLime >+# Copyright (C) 2007 LibLime, 2012 C & P Bibliography Services > # > # This file is part of Koha. > # >@@ -22,8 +22,6 @@ use warnings; > > use C4::Context; > use MARC::Record; >-use C4::Search; >-use C4::Biblio; > > use vars qw($VERSION); > >@@ -384,6 +382,20 @@ sub delete { > $sth->execute($matcher_id); # relying on cascading deletes to clean up everything > } > >+=head2 record_type >+ >+ $matcher->record_type('biblio'); >+ my $record_type = $matcher->record_type(); >+ >+Accessor method. >+ >+=cut >+ >+sub record_type { >+ my $self = shift; >+ @_ ? $self->{'record_type'} = shift : $self->{'record_type'}; >+} >+ > =head2 threshold > > $matcher->threshold(1000); >@@ -582,7 +594,7 @@ sub add_simple_required_check { > ); > } > >-=head2 find_matches >+=head2 get_matches > > my @matches = $matcher->get_matches($marc_record, $max_matches); > foreach $match (@matches) { >@@ -618,9 +630,34 @@ sub get_matches { > my @source_keys = _get_match_keys($source_record, $matchpoint); > next if scalar(@source_keys) == 0; > # build query >- my $query = join(" or ", map { "$matchpoint->{'index'}=$_" } @source_keys); >- # FIXME only searching biblio index at the moment >- my ($error, $searchresults, $total_hits) = SimpleSearch($query, 0, $max_matches); >+ my $query; >+ my $error; >+ my $searchresults; >+ my $total_hits; >+ if ($self->{'record_type'} eq 'biblio') { >+ $query = join(" or ", map { "$matchpoint->{'index'}=$_" } @source_keys); >+# FIXME only searching biblio index at the moment >+ require C4::Search; >+ ($error, $searchresults, $total_hits) = C4::Search::SimpleSearch($query, 0, $max_matches); >+ } elsif ($self->{'record_type'} eq 'authority') { >+ my $authresults; >+ my @marclist; >+ my @and_or; >+ my @excluding = []; >+ my @operator; >+ my @value; >+ foreach my $key (@source_keys) { >+ push @marclist, $matchpoint->{'index'}; >+ push @and_or, 'or'; >+ push @operator, 'exact'; >+ push @value, $key; >+ } >+ require C4::AuthoritiesMarc; >+ ($searchresults, $total_hits) = C4::AuthoritiesMarc::SearchAuthorities( >+ \@marclist, \@and_or, \@excluding, \@operator, >+ \@value, 0, 20, undef, 'AuthidAsc', 1 >+ ); >+ } > > if (defined $error ) { > warn "search failed ($query) $error"; >@@ -639,13 +676,20 @@ sub get_matches { > keys %matches; > > my @results = (); >- foreach my $marcblob (keys %matches) { >- my $target_record = MARC::Record->new_from_usmarc($marcblob); >- my $result = TransformMarcToKoha(C4::Context->dbh, $target_record, ''); >- # FIXME - again, bibliospecific >- # also, can search engine be induced to give just the number in the first place? >- my $record_number = $result->{'biblionumber'}; >- push @results, { 'record_id' => $record_number, 'score' => $matches{$marcblob} }; >+ if ($self->{'record_type'} eq 'biblio') { >+ require C4::Biblio; >+ foreach my $marcblob (keys %matches) { >+ my $target_record = MARC::Record->new_from_usmarc($marcblob); >+ my $record_number; >+ my $result = C4::Biblio::TransformMarcToKoha(C4::Context->dbh, $target_record, ''); >+ $record_number = $result->{'biblionumber'}; >+ push @results, { 'record_id' => $record_number, 'score' => $matches{$marcblob} }; >+ } >+ } elsif ($self->{'record_type'} eq 'authority') { >+ require C4::AuthoritiesMarc; >+ foreach my $authid (keys %matches) { >+ push @results, { 'record_id' => $authid, 'score' => $matches{$authid} }; >+ } > } > @results = sort { $b->{'score'} cmp $a->{'score'} } @results; > if (scalar(@results) > $max_matches) { >@@ -673,6 +717,7 @@ sub dump { > $result->{'matcher_id'} = $self->{'id'}; > $result->{'code'} = $self->{'code'}; > $result->{'description'} = $self->{'description'}; >+ $result->{'record_type'} = $self->{'record_type'}; > > $result->{'matchpoints'} = []; > foreach my $matchpoint (@{ $self->{'matchpoints'} }) { >diff --git a/admin/matching-rules.pl b/admin/matching-rules.pl >index b167026..e682fb5 100755 >--- a/admin/matching-rules.pl >+++ b/admin/matching-rules.pl >@@ -92,9 +92,10 @@ sub add_matching_rule_form { > sub add_update_matching_rule { > my $template = shift; > my $matcher_id = shift; >+ my $record_type = $input->param('record_type') || 'biblio'; > > # do parsing >- my $matcher = C4::Matcher->new('biblio', 1000); # FIXME biblio only for now >+ my $matcher = C4::Matcher->new($record_type, 1000); > $matcher->code($input->param('code')); > $matcher->description($input->param('description')); > $matcher->threshold($input->param('threshold')); >@@ -203,10 +204,11 @@ sub edit_matching_rule_form { > > my $matcher = C4::Matcher->fetch($matcher_id); > >- $template->param(matcher_id => $matcher_id); >- $template->param(code => $matcher->code()); >- $template->param(description => $matcher->description()); >- $template->param(threshold => $matcher->threshold()); >+ $template->{VARS}->{'matcher_id'} = $matcher_id; >+ $template->{VARS}->{'code'} = $matcher->code(); >+ $template->{VARS}->{'description'} = $matcher->description(); >+ $template->{VARS}->{'threshold'} = $matcher->threshold(); >+ $template->{VARS}->{'record_type'} = $matcher->record_type(); > > my $matcher_info = $matcher->dump(); > my @matchpoints = (); >diff --git a/installer/data/mysql/atomicupdate/importauthorities.pl b/installer/data/mysql/atomicupdate/importauthorities.pl >new file mode 100755 >index 0000000..f242f61 >--- /dev/null >+++ b/installer/data/mysql/atomicupdate/importauthorities.pl >@@ -0,0 +1,19 @@ >+#!/usr/bin/perl >+ >+use strict; >+use warnings; >+use C4::Context; >+my $dbh = C4::Context->dbh; >+ >+$dbh->do( >+q|CREATE TABLE `import_auths` ( >+ `import_record_id` int(11) NOT NULL, >+ `matched_authid` int(11) default NULL, >+ `control_number` varchar(25) default NULL, >+ `original_source` varchar(25) default NULL, >+ CONSTRAINT `import_auths_ibfk_1` FOREIGN KEY (`import_record_id`) >+ REFERENCES `import_records` (`import_record_id`) ON DELETE CASCADE ON UPDATE CASCADE, >+ KEY `matched_authid` (`matched_authid`) >+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;| >+); >+print "Upgrade done (Added support for staging authorities)\n"; >diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql >index 54498c3..13864ce 100644 >--- a/installer/data/mysql/kohastructure.sql >+++ b/installer/data/mysql/kohastructure.sql >@@ -909,6 +909,21 @@ CREATE TABLE `import_record_matches` ( > ) ENGINE=InnoDB DEFAULT CHARSET=utf8; > > -- >+-- Table structure for table `import_auths` >+-- >+ >+DROP TABLE IF EXISTS `import_auths`; >+CREATE TABLE `import_auths` ( >+ `import_record_id` int(11) NOT NULL, >+ `matched_authid` int(11) default NULL, >+ `control_number` varchar(25) default NULL, >+ `original_source` varchar(25) default NULL, >+ CONSTRAINT `import_auths_ibfk_1` FOREIGN KEY (`import_record_id`) >+ REFERENCES `import_records` (`import_record_id`) ON DELETE CASCADE ON UPDATE CASCADE, >+ KEY `matched_authid` (`matched_authid`), >+) ENGINE=InnoDB DEFAULT CHARSET=utf8; >+ >+-- > -- Table structure for table `import_biblios` > -- > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/matching-rules.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/matching-rules.tt >index 5835244..2bd8aaf 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/matching-rules.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/matching-rules.tt >@@ -220,6 +220,17 @@ function CheckRuleForm(f) { > <input type="text" id="threshold" name="threshold" size="5" maxlength="5" > value="[% threshold |html %]" /> <span class="required">Required</span> > </li> >+ <li><label for="record_type" class="required">Record type: </label> >+ <select id="record_type" name="record_type"> >+ [% IF ( record_type == "authority" ) %] >+ <option value="biblio">Bibliographic record</option> >+ <option value="authority" selected="selected">Authority record</option> >+ [% ELSE %] >+ <option value="biblio" selected="selected">Bibliographic record</option> >+ <option value="authority">Authority record</option> >+ [% END %] >+ </select><span class="required">Required</span> >+ </li> > </ol> > </fieldset> > >diff --git a/misc/commit_biblios_file.pl b/misc/commit_file.pl >similarity index 63% >rename from misc/commit_biblios_file.pl >rename to misc/commit_file.pl >index b4be670..1f54faf 100755 >--- a/misc/commit_biblios_file.pl >+++ b/misc/commit_file.pl >@@ -18,11 +18,13 @@ $| = 1; > # command-line parameters > my $batch_number = ""; > my $list_batches = 0; >+my $revert = 0; > my $want_help = 0; > > my $result = GetOptions( > 'batch-number:s' => \$batch_number, > 'list-batches' => \$list_batches, >+ 'revert' => \$revert, > 'h|help' => \$want_help > ); > >@@ -45,9 +47,15 @@ $dbh->{AutoCommit} = 0; > if ($batch_number =~ /^\d+$/ and $batch_number > 0) { > my $batch = GetImportBatch($batch_number); > die "$0: import batch $batch_number does not exist in database\n" unless defined $batch; >- die "$0: import batch $batch_number status is '" . $batch->{'import_status'} . "', and therefore cannot be imported\n" >- unless $batch->{'import_status'} eq "staged" or $batch->{'import_status'} eq "reverted"; >- process_batch($batch_number); >+ if ($revert) { >+ die "$0: import batch $batch_number status is '" . $batch->{'import_status'} . "', and therefore cannot be imported\n" >+ unless $batch->{'import_status'} eq "imported"; >+ revert_batch($batch_number); >+ } else { >+ die "$0: import batch $batch_number status is '" . $batch->{'import_status'} . "', and therefore cannot be imported\n" >+ unless $batch->{'import_status'} eq "staged" or $batch->{'import_status'} eq "reverted"; >+ process_batch($batch_number); >+ } > $dbh->commit(); > } else { > die "$0: please specify a numeric batch ID\n"; >@@ -74,8 +82,8 @@ sub process_batch { > my ($import_batch_id) = @_; > > print "... importing MARC records -- please wait\n"; >- my ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored) = >- BatchCommitBibRecords($import_batch_id, '', 100, \&print_progress_and_commit); >+ my ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored) = >+ BatchCommitRecords($import_batch_id, '', 100, \&print_progress_and_commit); > print "... finished importing MARC records\n"; > > print <<_SUMMARY_; >@@ -83,17 +91,40 @@ sub process_batch { > MARC record import report > ---------------------------------------- > Batch number: $import_batch_id >-Number of new bibs added: $num_added >-Number of bibs replaced: $num_updated >-Number of bibs ignored: $num_ignored >+Number of new records added: $num_added >+Number of records replaced: $num_updated >+Number of records ignored: $num_ignored > Number of items added: $num_items_added > Number of items ignored: $num_items_errored > >-Note: an item is ignored if its barcode is a >+Note: an item is ignored if its barcode is a > duplicate of one already in the database. > _SUMMARY_ > } > >+sub revert_batch { >+ my ($import_batch_id) = @_; >+ >+ print "... reverting batch -- please wait\n"; >+ my ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored) = >+ BatchRevertRecords($import_batch_id, 100, \&print_progress_and_commit); >+ print "... finished reverting batch\n"; >+ >+ print <<_SUMMARY_; >+ >+MARC record import report >+---------------------------------------- >+Batch number: $import_batch_id >+Number of records deleted: $num_deleted >+Number of errors: $num_errors >+Number of records reverted: $num_reverted >+Number of records ignored: $num_ignored >+Number of items added: $num_items_deleted >+ >+_SUMMARY_ >+} >+ >+ > sub print_progress_and_commit { > my $recs = shift; > print "... processed $recs records\n"; >@@ -106,7 +137,7 @@ $0: import a batch of staged MARC records into database. > > Use this batch job to complete the import of a batch of > MARC records that was staged either by the batch job >-stage_biblios_file.pl or by the Koha Tools option >+stage_file.pl or by the Koha Tools option > "Stage MARC Records for Import". > > Parameters: >@@ -114,6 +145,7 @@ Parameters: > to import > --list-batches print a list of record batches > available to commit >- --help or -h show this message. >+ --revert revert a batch instead of importing it >+ --help or -h show this message. > _USAGE_ > } >diff --git a/misc/cronjobs/import_webservice_batch.pl b/misc/cronjobs/import_webservice_batch.pl >index d1b30ef..3f57779 100755 >--- a/misc/cronjobs/import_webservice_batch.pl >+++ b/misc/cronjobs/import_webservice_batch.pl >@@ -54,4 +54,4 @@ EOF > my $batch_ids = GetStagedWebserviceBatches() or exit; > > $framework ||= ''; >-BatchCommitBibRecords($_, $framework) foreach @$batch_ids; >+BatchCommitRecords($_, $framework) foreach @$batch_ids; >diff --git a/misc/stage_biblios_file.pl b/misc/stage_file.pl >similarity index 67% >rename from misc/stage_biblios_file.pl >rename to misc/stage_file.pl >index 6e2b30c..4ce16b5 100755 >--- a/misc/stage_biblios_file.pl >+++ b/misc/stage_file.pl >@@ -4,6 +4,7 @@ > # > # Copyright (C) 2007 LibLime > # Parts Copyright BSZ 2011 >+# Parts Copyright C & P Bibliography Services 2012 > # > # Koha is free software; you can redistribute it and/or modify it under the > # terms of the GNU General Public License as published by the Free Software >@@ -35,8 +36,10 @@ use Getopt::Long; > $| = 1; > > # command-line parameters >+my $record_type = "biblio"; > my $encoding = ""; >-my $match_bibs = 0; >+my $authorities = 0; >+my $match = 0; > my $add_items = 0; > my $input_file = ""; > my $batch_comment = ""; >@@ -46,13 +49,16 @@ my $no_replace ; > my $result = GetOptions( > 'encoding:s' => \$encoding, > 'file:s' => \$input_file, >- 'match-bibs:s' => \$match_bibs, >+ 'match|match-bibs:s' => \$match, > 'add-items' => \$add_items, > 'no-replace' => \$no_replace, > 'comment:s' => \$batch_comment, >+ 'authorities' => \$authorities, > 'h|help' => \$want_help > ); > >+$record_type = 'auth' if ($authorities); >+ > if ($encoding eq "") { > $encoding = "utf8"; > } >@@ -68,13 +74,13 @@ unless (-r $input_file) { > > my $dbh = C4::Context->dbh; > $dbh->{AutoCommit} = 0; >-process_batch($input_file, $match_bibs, $add_items, $batch_comment); >+process_batch($input_file, $record_type, $match, $add_items, $batch_comment); > $dbh->commit(); > > exit 0; > > sub process_batch { >- my ($input_file, $match_bibs, $add_items, $batch_comment) = @_; >+ my ($input_file, $record_type, $match, $add_items, $batch_comment) = @_; > > open IN, "<$input_file" or die "$0: cannot open input file $input_file: $!\n"; > my $marc_records = ""; >@@ -92,50 +98,53 @@ sub process_batch { > close IN; > > print "... staging MARC records -- please wait\n"; >- my ($batch_id, $num_valid, $num_items, @import_errors) = >- BatchStageMarcRecords($encoding, $marc_records, $input_file, $batch_comment, '', $add_items, 0, >+ my ($batch_id, $num_valid_records, $num_items, @import_errors) = >+ BatchStageMarcRecords($record_type, $encoding, $marc_records, $input_file, $batch_comment, '', $add_items, 0, > 100, \&print_progress_and_commit); > print "... finished staging MARC records\n"; > > my $num_with_matches = 0; >- if ($match_bibs) { >- my $matcher = C4::Matcher->fetch($match_bibs) ; >- if (! defined $matcher) { >- $matcher = C4::Matcher->new('biblio'); >+ if ($match) { >+ my $matcher = C4::Matcher->fetch($match) ; >+ if (defined $matcher) { >+ SetImportBatchMatcher($batch_id, $match); >+ } elsif ($record_type eq 'biblio') { >+ $matcher = C4::Matcher->new($record_type); > $matcher->add_simple_matchpoint('isbn', 1000, '020', 'a', -1, 0, ''); >- $matcher->add_simple_required_check('245', 'a', -1, 0, '', >+ $matcher->add_simple_required_check('245', 'a', -1, 0, '', > '245', 'a', -1, 0, ''); >- } else { >- SetImportBatchMatcher($batch_id, $match_bibs); > } > # set default record overlay behavior > SetImportBatchOverlayAction($batch_id, ($no_replace) ? 'ignore' : 'replace'); > SetImportBatchNoMatchAction($batch_id, 'create_new'); > SetImportBatchItemAction($batch_id, 'always_add'); > print "... looking for matches with records already in database\n"; >- $num_with_matches = BatchFindBibDuplicates($batch_id, $matcher, 10, 100, \&print_progress_and_commit); >+ $num_with_matches = BatchFindDuplicates($batch_id, $matcher, 10, 100, \&print_progress_and_commit); > print "... finished looking for matches\n"; > } > >- my $num_invalid_bibs = scalar(@import_errors); >+ my $num_invalid_records = scalar(@import_errors); > print <<_SUMMARY_; > > MARC record staging report > ------------------------------------ >-Input file: $input_file >-Number of input bibs: $num_input_records >-Number of valid bibs: $num_valid >-Number of invalid bibs: $num_invalid_bibs >+Input file: $input_file >+Record type: $record_type >+Number of input records: $num_input_records >+Number of valid records: $num_valid_records >+Number of invalid records: $num_invalid_records > _SUMMARY_ >- if ($match_bibs) { >- print "Number of bibs matched: $num_with_matches\n"; >+ if ($match) { >+ print "Number of records matched: $num_with_matches\n"; > } else { >- print "Incoming bibs not matched against existing bibs (--match-bibs option not supplied)\n"; >+ print "Incoming records not matched against existing records (--match option not supplied)\n"; > } >- if ($add_items) { >- print "Number of items parsed: $num_items\n"; >- } else { >- print "No items parsed (--add-items option not supplied)\n"; >+ if ($record_type eq 'biblio') { >+ if ($add_items) { >+ print "Number of items parsed: $num_items\n"; >+ } else { >+ print "No items parsed (--add-items option not supplied)\n"; >+ } > } > > print "\n"; >@@ -151,31 +160,34 @@ sub print_progress_and_commit { > > sub print_usage { > print <<_USAGE_; >-$0: stage MARC bib file into reservoir. >+$0: stage MARC file into reservoir. > >-Use this batch job to load a file of MARC bibliographic records >-(with optional item information) into the Koha reservoir. >+Use this batch job to load a file of MARC bibliographic >+(with optional item information) or authority records into >+the Koha reservoir. > > After running this program to stage your file, you can use >-either the batch job commit_biblios_file.pl or the Koha >+either the batch job commit_file.pl or the Koha > Tools option "Manage Staged MARC Records" to load the > records into the main Koha database. > > Parameters: > --file <file_name> name of input MARC bib file >+ --authorities stage authority records instead of bibs > --encoding <encoding> encoding of MARC records, default is utf8. > Other possible options are: MARC-8, > ISO_5426, ISO_6937, ISO_8859-1, EUC-KR >- --match-bibs <match_id> use this option to match bibs >- in the file with bibs already in >+ --match <match_id> use this option to match records >+ in the file with records already in > the database for future overlay. >- If <match_id> isn't defined, a default >- MARC21 ISBN & title match rule will be applied. >+ If <match_id> isn't defined, a default >+ MARC21 ISBN & title match rule will be applied >+ for bib imports. > --add-items use this option to specify that > item data is embedded in the MARC > bibs and should be parsed. >- --no-replace overlay action for bib record: default is to >- replace extant bib with the imported record. >+ --no-replace overlay action for record: default is to >+ replace extant with the imported record. > --comment <comment> optional comment to describe > the record batch; if the comment > has spaces in it, surround the >diff --git a/svc/import_bib b/svc/import_bib >index 5e7e493..c130204 100755 >--- a/svc/import_bib >+++ b/svc/import_bib >@@ -92,7 +92,7 @@ sub import_bib { > $marcxml =~ s/<\?xml.*?\?>//i; > > # XXX we are ignoring the result of this; >- BatchCommitBibRecords($batch_id, $framework) if lc($import_mode) eq 'direct'; >+ BatchCommitRecords($batch_id, $framework) if lc($import_mode) eq 'direct'; > > $result->{'status'} = "ok"; > $result->{'import_batch_id'} = $batch_id; >diff --git a/tools/manage-marc-import.pl b/tools/manage-marc-import.pl >index 8a8d9e8..7346c59 100755 >--- a/tools/manage-marc-import.pl >+++ b/tools/manage-marc-import.pl >@@ -244,7 +244,7 @@ sub commit_batch { > $callback = progress_callback($job, $dbh); > } > my ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored) = >- BatchCommitBibRecords($import_batch_id, $framework, 50, $callback); >+ BatchCommitRecords($import_batch_id, $framework, 50, $callback); > $dbh->commit(); > > my $results = { >@@ -273,7 +273,7 @@ sub revert_batch { > $callback = progress_callback($job, $dbh); > } > my ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored) = >- BatchRevertBibRecords($import_batch_id, 50, $callback); >+ BatchRevertRecords($import_batch_id, 50, $callback); > $dbh->commit(); > > my $results = { >-- >1.7.2.5
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 7475
:
10262
|
10263
|
10264
|
10423