1 package C4::ImportBatch;
3 # Copyright (C) 2007 LibLime
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License along with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA 02111-1307 USA
29 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
32 # set the version for version checking
45 BatchFindBibDuplicates
50 GetImportBatchRangeDesc
51 GetNumberOfNonZ3950ImportBatches
53 GetItemNumbersFromImportBatch
57 GetImportBatchOverlayAction
58 SetImportBatchOverlayAction
59 GetImportBatchNoMatchAction
60 SetImportBatchNoMatchAction
61 GetImportBatchItemAction
62 SetImportBatchItemAction
65 GetImportRecordOverlayStatus
66 SetImportRecordOverlayStatus
69 GetImportRecordMatches
70 SetImportRecordMatches
76 C4::ImportBatch - manage batches of imported MARC records
88 =head2 GetZ3950BatchId
92 my $batchid = GetZ3950BatchId($z3950server);
96 Retrieves the ID of the import batch for the Z39.50
97 reservoir for the given target. If necessary,
98 creates the import batch.
102 sub GetZ3950BatchId {
103 my ($z3950server) = @_;
105 my $dbh = C4::Context->dbh;
106 my $sth = $dbh->prepare("SELECT import_batch_id FROM import_batches
107 WHERE batch_type = 'z3950'
109 $sth->execute($z3950server);
110 my $rowref = $sth->fetchrow_arrayref();
112 if (defined $rowref) {
115 my $batch_id = AddImportBatch('create_new', 'staged', 'z3950', $z3950server, '');
121 =head2 GetImportRecordMarc
125 my ($marcblob, $encoding) = GetImportRecordMarc($import_record_id);
131 sub GetImportRecordMarc {
132 my ($import_record_id) = @_;
134 my $dbh = C4::Context->dbh;
135 my $sth = $dbh->prepare("SELECT marc, encoding FROM import_records WHERE import_record_id = ?");
136 $sth->execute($import_record_id);
137 my ($marc, $encoding) = $sth->fetchrow();
143 =head2 AddImportBatch
147 my $batch_id = AddImportBatch($overlay_action, $import_status, $type, $file_name, $comments);
154 my ($overlay_action, $import_status, $type, $file_name, $comments) = @_;
156 my $dbh = C4::Context->dbh;
157 my $sth = $dbh->prepare("INSERT INTO import_batches (overlay_action, import_status, batch_type,
159 VALUES (?, ?, ?, ?, ?)");
160 $sth->execute($overlay_action, $import_status, $type, $file_name, $comments);
161 my $batch_id = $dbh->{'mysql_insertid'};
168 =head2 GetImportBatch
172 my $row = GetImportBatch($batch_id);
176 Retrieve a hashref of an import_batches row.
183 my $dbh = C4::Context->dbh;
184 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches WHERE import_batch_id = ?");
185 $sth->bind_param(1, $batch_id);
187 my $result = $sth->fetchrow_hashref;
193 =head2 AddBiblioToBatch
197 my $import_record_id = AddBiblioToBatch($batch_id, $record_sequence, $marc_record, $encoding, $z3950random, $update_counts);
203 sub AddBiblioToBatch {
204 my $batch_id = shift;
205 my $record_sequence = shift;
206 my $marc_record = shift;
207 my $encoding = shift;
208 my $z3950random = shift;
209 my $update_counts = @_ ? shift : 1;
211 my $import_record_id = _create_import_record($batch_id, $record_sequence, $marc_record, 'biblio', $encoding, $z3950random);
212 _add_biblio_fields($import_record_id, $marc_record);
213 _update_batch_record_counts($batch_id) if $update_counts;
214 return $import_record_id;
217 =head2 ModBiblioInBatch
221 ModBiblioInBatch($import_record_id, $marc_record);
227 sub ModBiblioInBatch {
228 my ($import_record_id, $marc_record) = @_;
230 _update_import_record_marc($import_record_id, $marc_record);
231 _update_biblio_fields($import_record_id, $marc_record);
235 =head2 BatchStageMarcRecords
239 ($batch_id, $num_records, $num_items, @invalid_records) =
240 BatchStageMarcRecords($marc_flavor, $marc_records, $file_name,
241 $comments, $branch_code, $parse_items,
243 $progress_interval, $progress_callback);
249 sub BatchStageMarcRecords {
250 my $marc_flavor = shift;
251 my $marc_records = shift;
252 my $file_name = shift;
253 my $comments = shift;
254 my $branch_code = shift;
255 my $parse_items = shift;
256 my $leave_as_staging = shift;
258 # optional callback to monitor status
260 my $progress_interval = 0;
261 my $progress_callback = undef;
263 $progress_interval = shift;
264 $progress_callback = shift;
265 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
266 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
269 my $batch_id = AddImportBatch('create_new', 'staging', 'batch', $file_name, $comments);
271 SetImportBatchItemAction($batch_id, 'always_add');
273 SetImportBatchItemAction($batch_id, 'ignore');
276 my @invalid_records = ();
279 # FIXME - for now, we're dealing only with bibs
281 foreach my $marc_blob (split(/\x1D/, $marc_records)) {
282 $marc_blob =~ s/^\s+//g;
283 $marc_blob =~ s/\s+$//g;
284 next unless $marc_blob;
286 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
287 &$progress_callback($rec_num);
289 my ($marc_record, $charset_guessed, $char_errors) =
290 MarcToUTF8Record($marc_blob, C4::Context->preference("marcflavour"));
291 my $import_record_id;
292 if (scalar($marc_record->fields()) == 0) {
293 push @invalid_records, $marc_blob;
296 $import_record_id = AddBiblioToBatch($batch_id, $rec_num, $marc_record, $marc_flavor, int(rand(99999)), 0);
298 my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, 0);
299 $num_items += scalar(@import_items_ids);
303 unless ($leave_as_staging) {
304 SetImportBatchStatus($batch_id, 'staged');
306 # FIXME branch_code, number of bibs, number of items
307 _update_batch_record_counts($batch_id);
308 return ($batch_id, $num_valid, $num_items, @invalid_records);
311 =head2 AddItemsToImportBiblio
315 my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, $update_counts);
321 sub AddItemsToImportBiblio {
322 my $batch_id = shift;
323 my $import_record_id = shift;
324 my $marc_record = shift;
325 my $update_counts = @_ ? shift : 0;
327 my @import_items_ids = ();
329 my $dbh = C4::Context->dbh;
330 my ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",'');
331 foreach my $item_field ($marc_record->field($item_tag)) {
332 my $item_marc = MARC::Record->new();
333 $item_marc->leader("00000 a "); # must set Leader/09 to 'a'
334 $item_marc->append_fields($item_field);
335 $marc_record->delete_field($item_field);
336 my $sth = $dbh->prepare_cached("INSERT INTO import_items (import_record_id, status, marcxml)
338 $sth->bind_param(1, $import_record_id);
339 $sth->bind_param(2, 'staged');
340 $sth->bind_param(3, $item_marc->as_xml());
342 push @import_items_ids, $dbh->{'mysql_insertid'};
346 if ($#import_items_ids > -1) {
347 _update_batch_record_counts($batch_id) if $update_counts;
348 _update_import_record_marc($import_record_id, $marc_record);
350 return @import_items_ids;
353 =head2 BatchFindBibDuplicates
357 my $num_with_matches = BatchFindBibDuplicates($batch_id, $matcher, $max_matches, $progress_interval, $progress_callback);
361 Goes through the records loaded in the batch and attempts to
362 find duplicates for each one. Sets the matching status
363 of each record to "no_match" or "auto_match" as appropriate.
365 The $max_matches parameter is optional; if it is not supplied,
368 The $progress_interval and $progress_callback parameters are
369 optional; if both are supplied, the sub referred to by
370 $progress_callback will be invoked every $progress_interval
371 records using the number of records processed as the
376 sub BatchFindBibDuplicates {
377 my $batch_id = shift;
379 my $max_matches = @_ ? shift : 10;
381 # optional callback to monitor status
383 my $progress_interval = 0;
384 my $progress_callback = undef;
386 $progress_interval = shift;
387 $progress_callback = shift;
388 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
389 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
392 my $dbh = C4::Context->dbh;
394 my $sth = $dbh->prepare("SELECT import_record_id, marc
396 JOIN import_biblios USING (import_record_id)
397 WHERE import_batch_id = ?");
398 $sth->execute($batch_id);
399 my $num_with_matches = 0;
401 while (my $rowref = $sth->fetchrow_hashref) {
403 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
404 &$progress_callback($rec_num);
406 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
408 if (defined $matcher) {
409 @matches = $matcher->get_matches($marc_record, $max_matches);
411 if (scalar(@matches) > 0) {
413 SetImportRecordMatches($rowref->{'import_record_id'}, @matches);
414 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'auto_match');
416 SetImportRecordMatches($rowref->{'import_record_id'}, ());
417 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'no_match');
421 return $num_with_matches;
424 =head2 BatchCommitBibRecords
428 my ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored) =
429 BatchCommitBibRecords($batch_id, $progress_interval, $progress_callback);
435 sub BatchCommitBibRecords {
436 my $batch_id = shift;
438 # optional callback to monitor status
440 my $progress_interval = 0;
441 my $progress_callback = undef;
443 $progress_interval = shift;
444 $progress_callback = shift;
445 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
446 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
451 my $num_items_added = 0;
452 my $num_items_errored = 0;
454 # commit (i.e., save, all records in the batch)
455 # FIXME biblio only at the moment
456 SetImportBatchStatus('importing');
457 my $overlay_action = GetImportBatchOverlayAction($batch_id);
458 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
459 my $item_action = GetImportBatchItemAction($batch_id);
460 my $dbh = C4::Context->dbh;
461 my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marc, encoding
463 JOIN import_biblios USING (import_record_id)
464 WHERE import_batch_id = ?");
465 $sth->execute($batch_id);
467 while (my $rowref = $sth->fetchrow_hashref) {
469 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
470 &$progress_callback($rec_num);
472 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'imported') {
477 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
479 # remove any item tags - rely on BatchCommitItems
480 my ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",'');
481 foreach my $item_field ($marc_record->field($item_tag)) {
482 $marc_record->delete_field($item_field);
485 # decide what what to do with the bib and item records
486 my ($bib_result, $item_result, $bib_match) =
487 _get_commit_action($overlay_action, $nomatch_action, $item_action,
488 $rowref->{'overlay_status'}, $rowref->{'import_record_id'});
490 if ($bib_result eq 'create_new') {
492 my ($biblionumber, $biblioitemnumber) = AddBiblio($marc_record, '');
493 my $sth = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
494 $sth->execute($biblionumber, $rowref->{'import_record_id'});
496 if ($item_result eq 'create_new') {
497 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
498 $num_items_added += $bib_items_added;
499 $num_items_errored += $bib_items_errored;
501 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
502 } elsif ($bib_result eq 'replace') {
504 my $biblionumber = $bib_match;
505 my ($count, $oldbiblio) = GetBiblio($biblionumber);
506 my $oldxml = GetXmlBiblio($biblionumber);
508 # remove item fields so that they don't get
509 # added again if record is reverted
510 my $old_marc = MARC::Record->new_from_xml(StripNonXmlChars($oldxml), 'UTF-8', $rowref->{'encoding'});
511 foreach my $item_field ($old_marc->field($item_tag)) {
512 $old_marc->delete_field($item_field);
515 ModBiblio($marc_record, $biblionumber, $oldbiblio->{'frameworkcode'});
516 my $sth = $dbh->prepare_cached("UPDATE import_records SET marcxml_old = ? WHERE import_record_id = ?");
517 $sth->execute($old_marc->as_xml(), $rowref->{'import_record_id'});
519 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
520 $sth2->execute($biblionumber, $rowref->{'import_record_id'});
522 if ($item_result eq 'create_new') {
523 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
524 $num_items_added += $bib_items_added;
525 $num_items_errored += $bib_items_errored;
527 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
528 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
529 } elsif ($bib_result eq 'ignore') {
531 my $biblionumber = $bib_match;
532 if (defined $biblionumber and $item_result eq 'create_new') {
533 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
534 $num_items_added += $bib_items_added;
535 $num_items_errored += $bib_items_errored;
536 # still need to record the matched biblionumber so that the
537 # items can be reverted
538 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
539 $sth2->execute($biblionumber, $rowref->{'import_record_id'});
540 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
542 SetImportRecordStatus($rowref->{'import_record_id'}, 'ignored');
546 SetImportBatchStatus($batch_id, 'imported');
547 return ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored);
550 =head2 BatchCommitItems
554 ($num_items_added, $num_items_errored) = BatchCommitItems($import_record_id, $biblionumber);
560 sub BatchCommitItems {
561 my ($import_record_id, $biblionumber) = @_;
563 my $dbh = C4::Context->dbh;
565 my $num_items_added = 0;
566 my $num_items_errored = 0;
567 my $sth = $dbh->prepare("SELECT import_items_id, import_items.marcxml, encoding
569 JOIN import_records USING (import_record_id)
570 WHERE import_record_id = ?
571 ORDER BY import_items_id");
572 $sth->bind_param(1, $import_record_id);
574 while (my $row = $sth->fetchrow_hashref()) {
575 my $item_marc = MARC::Record->new_from_xml(StripNonXmlChars($row->{'marcxml'}), 'UTF-8', $row->{'encoding'});
576 # FIXME - duplicate barcode check needs to become part of AddItemFromMarc()
577 my $item = TransformMarcToKoha($dbh, $item_marc);
578 my $duplicate_barcode = exists($item->{'barcode'}) && GetItemnumberFromBarcode($item->{'barcode'});
579 if ($duplicate_barcode) {
580 my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, import_error = ? WHERE import_items_id = ?");
581 $updsth->bind_param(1, 'error');
582 $updsth->bind_param(2, 'duplicate item barcode');
583 $updsth->bind_param(3, $row->{'import_items_id'});
585 $num_items_errored++;
587 my ($item_biblionumber, $biblioitemnumber, $itemnumber) = AddItemFromMarc($item_marc, $biblionumber);
588 my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, itemnumber = ? WHERE import_items_id = ?");
589 $updsth->bind_param(1, 'imported');
590 $updsth->bind_param(2, $itemnumber);
591 $updsth->bind_param(3, $row->{'import_items_id'});
598 return ($num_items_added, $num_items_errored);
601 =head2 BatchRevertBibRecords
605 my ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored) = BatchRevertBibRecords($batch_id);
611 sub BatchRevertBibRecords {
612 my $batch_id = shift;
616 my $num_reverted = 0;
617 my $num_items_deleted = 0;
619 # commit (i.e., save, all records in the batch)
620 # FIXME biblio only at the moment
621 SetImportBatchStatus('reverting');
622 my $overlay_action = GetImportBatchOverlayAction($batch_id);
623 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
624 my $dbh = C4::Context->dbh;
625 my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marcxml_old, encoding, matched_biblionumber
627 JOIN import_biblios USING (import_record_id)
628 WHERE import_batch_id = ?");
629 $sth->execute($batch_id);
630 while (my $rowref = $sth->fetchrow_hashref) {
631 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'reverted') {
636 my $bib_result = _get_revert_action($overlay_action, $rowref->{'overlay_status'}, $rowref->{'status'});
638 if ($bib_result eq 'delete') {
639 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
640 my $error = DelBiblio($rowref->{'matched_biblionumber'});
641 if (defined $error) {
645 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
647 } elsif ($bib_result eq 'restore') {
649 my $old_record = MARC::Record->new_from_xml(StripNonXmlChars($rowref->{'marcxml_old'}), 'UTF-8', $rowref->{'encoding'});
650 my $biblionumber = $rowref->{'matched_biblionumber'};
651 my ($count, $oldbiblio) = GetBiblio($biblionumber);
652 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
653 ModBiblio($old_record, $biblionumber, $oldbiblio->{'frameworkcode'});
654 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
655 } elsif ($bib_result eq 'ignore') {
656 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
657 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
659 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = NULL WHERE import_record_id = ?");
660 $sth2->execute($rowref->{'import_record_id'});
664 SetImportBatchStatus($batch_id, 'reverted');
665 return ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored);
668 =head2 BatchRevertItems
672 my $num_items_deleted = BatchRevertItems($import_record_id, $biblionumber);
678 sub BatchRevertItems {
679 my ($import_record_id, $biblionumber) = @_;
681 my $dbh = C4::Context->dbh;
682 my $num_items_deleted = 0;
684 my $sth = $dbh->prepare_cached("SELECT import_items_id, itemnumber
686 JOIN items USING (itemnumber)
687 WHERE import_record_id = ?");
688 $sth->bind_param(1, $import_record_id);
690 while (my $row = $sth->fetchrow_hashref()) {
691 DelItem($dbh, $biblionumber, $row->{'itemnumber'});
692 my $updsth = $dbh->prepare("UPDATE import_items SET status = ? WHERE import_items_id = ?");
693 $updsth->bind_param(1, 'reverted');
694 $updsth->bind_param(2, $row->{'import_items_id'});
697 $num_items_deleted++;
700 return $num_items_deleted;
703 =head2 GetAllImportBatches
707 my $results = GetAllImportBatches();
711 Returns a references to an array of hash references corresponding
712 to all import_batches rows (of batch_type 'batch'), sorted in
713 ascending order by import_batch_id.
717 sub GetAllImportBatches {
718 my $dbh = C4::Context->dbh;
719 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches
720 WHERE batch_type = 'batch'
721 ORDER BY import_batch_id ASC");
725 while (my $row = $sth->fetchrow_hashref) {
726 push @$results, $row;
732 =head2 GetImportBatchRangeDesc
736 my $results = GetImportBatchRangeDesc($offset, $results_per_group);
740 Returns a reference to an array of hash references corresponding to
741 import_batches rows (sorted in descending order by import_batch_id)
742 start at the given offset.
746 sub GetImportBatchRangeDesc {
747 my ($offset, $results_per_group) = @_;
749 my $dbh = C4::Context->dbh;
750 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches
751 WHERE batch_type = 'batch'
752 ORDER BY import_batch_id DESC
754 $sth->bind_param(1, $results_per_group);
755 $sth->bind_param(2, $offset);
759 while (my $row = $sth->fetchrow_hashref) {
760 push @$results, $row;
766 =head2 GetItemNumbersFromImportBatch
770 sub GetItemNumbersFromImportBatch {
772 my $dbh = C4::Context->dbh;
773 my $sth = $dbh->prepare("select itemnumber from import_batches,import_records,import_items where import_batches.import_batch_id=import_records.import_batch_id and import_records.import_record_id=import_items.import_record_id and import_batches.import_batch_id=?");
774 $sth->execute($batch_id);
776 while ( my ($itm) = $sth->fetchrow_array ) {
782 =head2 GetNumberOfImportBatches
786 my $count = GetNumberOfImportBatches();
792 sub GetNumberOfNonZ3950ImportBatches {
793 my $dbh = C4::Context->dbh;
794 my $sth = $dbh->prepare("SELECT COUNT(*) FROM import_batches WHERE batch_type='batch'");
796 my ($count) = $sth->fetchrow_array();
801 =head2 GetImportBibliosRange
805 my $results = GetImportBibliosRange($batch_id, $offset, $results_per_group);
809 Returns a reference to an array of hash references corresponding to
810 import_biblios/import_records rows for a given batch
811 starting at the given offset.
815 sub GetImportBibliosRange {
816 my ($batch_id, $offset, $results_per_group) = @_;
818 my $dbh = C4::Context->dbh;
819 my $sth = $dbh->prepare_cached("SELECT title, author, isbn, issn, import_record_id, record_sequence,
820 matched_biblionumber, status, overlay_status
822 JOIN import_biblios USING (import_record_id)
823 WHERE import_batch_id = ?
824 ORDER BY import_record_id LIMIT ? OFFSET ?");
825 $sth->bind_param(1, $batch_id);
826 $sth->bind_param(2, $results_per_group);
827 $sth->bind_param(3, $offset);
830 while (my $row = $sth->fetchrow_hashref) {
831 push @$results, $row;
838 =head2 GetBestRecordMatch
842 my $record_id = GetBestRecordMatch($import_record_id);
848 sub GetBestRecordMatch {
849 my ($import_record_id) = @_;
851 my $dbh = C4::Context->dbh;
852 my $sth = $dbh->prepare("SELECT candidate_match_id
853 FROM import_record_matches
854 WHERE import_record_id = ?
855 ORDER BY score DESC, candidate_match_id DESC");
856 $sth->execute($import_record_id);
857 my ($record_id) = $sth->fetchrow_array();
862 =head2 GetImportBatchStatus
866 my $status = GetImportBatchStatus($batch_id);
872 sub GetImportBatchStatus {
875 my $dbh = C4::Context->dbh;
876 my $sth = $dbh->prepare("SELECT import_status FROM import_batches WHERE import_batch_id = ?");
877 $sth->execute($batch_id);
878 my ($status) = $sth->fetchrow_array();
884 =head2 SetImportBatchStatus
888 SetImportBatchStatus($batch_id, $new_status);
894 sub SetImportBatchStatus {
895 my ($batch_id, $new_status) = @_;
897 my $dbh = C4::Context->dbh;
898 my $sth = $dbh->prepare("UPDATE import_batches SET import_status = ? WHERE import_batch_id = ?");
899 $sth->execute($new_status, $batch_id);
904 =head2 GetImportBatchOverlayAction
908 my $overlay_action = GetImportBatchOverlayAction($batch_id);
914 sub GetImportBatchOverlayAction {
917 my $dbh = C4::Context->dbh;
918 my $sth = $dbh->prepare("SELECT overlay_action FROM import_batches WHERE import_batch_id = ?");
919 $sth->execute($batch_id);
920 my ($overlay_action) = $sth->fetchrow_array();
922 return $overlay_action;
927 =head2 SetImportBatchOverlayAction
931 SetImportBatchOverlayAction($batch_id, $new_overlay_action);
937 sub SetImportBatchOverlayAction {
938 my ($batch_id, $new_overlay_action) = @_;
940 my $dbh = C4::Context->dbh;
941 my $sth = $dbh->prepare("UPDATE import_batches SET overlay_action = ? WHERE import_batch_id = ?");
942 $sth->execute($new_overlay_action, $batch_id);
947 =head2 GetImportBatchNoMatchAction
951 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
957 sub GetImportBatchNoMatchAction {
960 my $dbh = C4::Context->dbh;
961 my $sth = $dbh->prepare("SELECT nomatch_action FROM import_batches WHERE import_batch_id = ?");
962 $sth->execute($batch_id);
963 my ($nomatch_action) = $sth->fetchrow_array();
965 return $nomatch_action;
970 =head2 SetImportBatchNoMatchAction
974 SetImportBatchNoMatchAction($batch_id, $new_nomatch_action);
980 sub SetImportBatchNoMatchAction {
981 my ($batch_id, $new_nomatch_action) = @_;
983 my $dbh = C4::Context->dbh;
984 my $sth = $dbh->prepare("UPDATE import_batches SET nomatch_action = ? WHERE import_batch_id = ?");
985 $sth->execute($new_nomatch_action, $batch_id);
990 =head2 GetImportBatchItemAction
994 my $item_action = GetImportBatchItemAction($batch_id);
1000 sub GetImportBatchItemAction {
1001 my ($batch_id) = @_;
1003 my $dbh = C4::Context->dbh;
1004 my $sth = $dbh->prepare("SELECT item_action FROM import_batches WHERE import_batch_id = ?");
1005 $sth->execute($batch_id);
1006 my ($item_action) = $sth->fetchrow_array();
1008 return $item_action;
1013 =head2 SetImportBatchItemAction
1017 SetImportBatchItemAction($batch_id, $new_item_action);
1023 sub SetImportBatchItemAction {
1024 my ($batch_id, $new_item_action) = @_;
1026 my $dbh = C4::Context->dbh;
1027 my $sth = $dbh->prepare("UPDATE import_batches SET item_action = ? WHERE import_batch_id = ?");
1028 $sth->execute($new_item_action, $batch_id);
1033 =head2 GetImportBatchMatcher
1037 my $matcher_id = GetImportBatchMatcher($batch_id);
1043 sub GetImportBatchMatcher {
1044 my ($batch_id) = @_;
1046 my $dbh = C4::Context->dbh;
1047 my $sth = $dbh->prepare("SELECT matcher_id FROM import_batches WHERE import_batch_id = ?");
1048 $sth->execute($batch_id);
1049 my ($matcher_id) = $sth->fetchrow_array();
1056 =head2 SetImportBatchMatcher
1060 SetImportBatchMatcher($batch_id, $new_matcher_id);
1066 sub SetImportBatchMatcher {
1067 my ($batch_id, $new_matcher_id) = @_;
1069 my $dbh = C4::Context->dbh;
1070 my $sth = $dbh->prepare("UPDATE import_batches SET matcher_id = ? WHERE import_batch_id = ?");
1071 $sth->execute($new_matcher_id, $batch_id);
1076 =head2 GetImportRecordOverlayStatus
1080 my $overlay_status = GetImportRecordOverlayStatus($import_record_id);
1086 sub GetImportRecordOverlayStatus {
1087 my ($import_record_id) = @_;
1089 my $dbh = C4::Context->dbh;
1090 my $sth = $dbh->prepare("SELECT overlay_status FROM import_records WHERE import_record_id = ?");
1091 $sth->execute($import_record_id);
1092 my ($overlay_status) = $sth->fetchrow_array();
1094 return $overlay_status;
1099 =head2 SetImportRecordOverlayStatus
1103 SetImportRecordOverlayStatus($import_record_id, $new_overlay_status);
1109 sub SetImportRecordOverlayStatus {
1110 my ($import_record_id, $new_overlay_status) = @_;
1112 my $dbh = C4::Context->dbh;
1113 my $sth = $dbh->prepare("UPDATE import_records SET overlay_status = ? WHERE import_record_id = ?");
1114 $sth->execute($new_overlay_status, $import_record_id);
1119 =head2 GetImportRecordStatus
1123 my $overlay_status = GetImportRecordStatus($import_record_id);
1129 sub GetImportRecordStatus {
1130 my ($import_record_id) = @_;
1132 my $dbh = C4::Context->dbh;
1133 my $sth = $dbh->prepare("SELECT status FROM import_records WHERE import_record_id = ?");
1134 $sth->execute($import_record_id);
1135 my ($overlay_status) = $sth->fetchrow_array();
1137 return $overlay_status;
1142 =head2 SetImportRecordStatus
1146 SetImportRecordStatus($import_record_id, $new_overlay_status);
1152 sub SetImportRecordStatus {
1153 my ($import_record_id, $new_overlay_status) = @_;
1155 my $dbh = C4::Context->dbh;
1156 my $sth = $dbh->prepare("UPDATE import_records SET status = ? WHERE import_record_id = ?");
1157 $sth->execute($new_overlay_status, $import_record_id);
1162 =head2 GetImportRecordMatches
1166 my $results = GetImportRecordMatches($import_record_id, $best_only);
1172 sub GetImportRecordMatches {
1173 my $import_record_id = shift;
1174 my $best_only = @_ ? shift : 0;
1176 my $dbh = C4::Context->dbh;
1177 # FIXME currently biblio only
1178 my $sth = $dbh->prepare_cached("SELECT title, author, biblionumber, score
1180 JOIN import_record_matches USING (import_record_id)
1181 JOIN biblio ON (biblionumber = candidate_match_id)
1182 WHERE import_record_id = ?
1183 ORDER BY score DESC, biblionumber DESC");
1184 $sth->bind_param(1, $import_record_id);
1187 while (my $row = $sth->fetchrow_hashref) {
1188 push @$results, $row;
1198 =head2 SetImportRecordMatches
1202 SetImportRecordMatches($import_record_id, @matches);
1208 sub SetImportRecordMatches {
1209 my $import_record_id = shift;
1212 my $dbh = C4::Context->dbh;
1213 my $delsth = $dbh->prepare("DELETE FROM import_record_matches WHERE import_record_id = ?");
1214 $delsth->execute($import_record_id);
1217 my $sth = $dbh->prepare("INSERT INTO import_record_matches (import_record_id, candidate_match_id, score)
1219 foreach my $match (@matches) {
1220 $sth->execute($import_record_id, $match->{'record_id'}, $match->{'score'});
1225 # internal functions
1227 sub _create_import_record {
1228 my ($batch_id, $record_sequence, $marc_record, $record_type, $encoding, $z3950random) = @_;
1230 my $dbh = C4::Context->dbh;
1231 my $sth = $dbh->prepare("INSERT INTO import_records (import_batch_id, record_sequence, marc, marcxml,
1232 record_type, encoding, z3950random)
1233 VALUES (?, ?, ?, ?, ?, ?, ?)");
1234 $sth->execute($batch_id, $record_sequence, $marc_record->as_usmarc(), $marc_record->as_xml(),
1235 $record_type, $encoding, $z3950random);
1236 my $import_record_id = $dbh->{'mysql_insertid'};
1238 return $import_record_id;
1241 sub _update_import_record_marc {
1242 my ($import_record_id, $marc_record) = @_;
1244 my $dbh = C4::Context->dbh;
1245 my $sth = $dbh->prepare("UPDATE import_records SET marc = ?, marcxml = ?
1246 WHERE import_record_id = ?");
1247 $sth->execute($marc_record->as_usmarc(), $marc_record->as_xml(), $import_record_id);
1251 sub _add_biblio_fields {
1252 my ($import_record_id, $marc_record) = @_;
1254 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1255 my $dbh = C4::Context->dbh;
1256 # FIXME no controlnumber, originalsource
1257 $isbn = C4::Koha::_isbn_cleanup($isbn); # FIXME C4::Koha::_isbn_cleanup should be made public
1258 my $sth = $dbh->prepare("INSERT INTO import_biblios (import_record_id, title, author, isbn, issn) VALUES (?, ?, ?, ?, ?)");
1259 $sth->execute($import_record_id, $title, $author, $isbn, $issn);
1264 sub _update_biblio_fields {
1265 my ($import_record_id, $marc_record) = @_;
1267 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1268 my $dbh = C4::Context->dbh;
1269 # FIXME no controlnumber, originalsource
1270 # FIXME 2 - should regularize normalization of ISBN wherever it is done
1274 my $sth = $dbh->prepare("UPDATE import_biblios SET title = ?, author = ?, isbn = ?, issn = ?
1275 WHERE import_record_id = ?");
1276 $sth->execute($title, $author, $isbn, $issn, $import_record_id);
1280 sub _parse_biblio_fields {
1281 my ($marc_record) = @_;
1283 my $dbh = C4::Context->dbh;
1284 my $bibliofields = TransformMarcToKoha($dbh, $marc_record, '');
1285 return ($bibliofields->{'title'}, $bibliofields->{'author'}, $bibliofields->{'isbn'}, $bibliofields->{'issn'});
1289 sub _update_batch_record_counts {
1290 my ($batch_id) = @_;
1292 my $dbh = C4::Context->dbh;
1293 my $sth = $dbh->prepare_cached("UPDATE import_batches SET num_biblios = (
1296 WHERE import_batch_id = import_batches.import_batch_id
1297 AND record_type = 'biblio')
1298 WHERE import_batch_id = ?");
1299 $sth->bind_param(1, $batch_id);
1302 $sth = $dbh->prepare_cached("UPDATE import_batches SET num_items = (
1305 JOIN import_items USING (import_record_id)
1306 WHERE import_batch_id = import_batches.import_batch_id
1307 AND record_type = 'biblio')
1308 WHERE import_batch_id = ?");
1309 $sth->bind_param(1, $batch_id);
1315 sub _get_commit_action {
1316 my ($overlay_action, $nomatch_action, $item_action, $overlay_status, $import_record_id) = @_;
1318 my ($bib_result, $bib_match, $item_result);
1320 if ($overlay_status ne 'no_match') {
1321 $bib_match = GetBestRecordMatch($import_record_id);
1322 if ($overlay_action eq 'replace') {
1323 $bib_result = defined($bib_match) ? 'replace' : 'create_new';
1324 } elsif ($overlay_action eq 'create_new') {
1325 $bib_result = 'create_new';
1326 } elsif ($overlay_action eq 'ignore') {
1327 $bib_result = 'ignore';
1329 $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_matches') ? 'create_new' : 'ignore';
1331 $bib_result = $nomatch_action;
1332 $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_new') ? 'create_new' : 'ignore';
1335 return ($bib_result, $item_result, $bib_match);
1338 sub _get_revert_action {
1339 my ($overlay_action, $overlay_status, $status) = @_;
1343 if ($status eq 'ignored') {
1344 $bib_result = 'ignore';
1346 if ($overlay_action eq 'create_new') {
1347 $bib_result = 'delete';
1349 $bib_result = ($overlay_status eq 'match_applied') ? 'restore' : 'delete';
1360 Koha Development Team <info@koha.org>
1362 Galen Charlton <galen.charlton@liblime.com>