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
27 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
30 # set the version for version checking
43 BatchFindBibDuplicates
48 GetImportBatchRangeDesc
49 GetNumberOfNonZ3950ImportBatches
51 GetItemNumbersFromImportBatch
55 GetImportBatchOverlayAction
56 SetImportBatchOverlayAction
57 GetImportBatchNoMatchAction
58 SetImportBatchNoMatchAction
59 GetImportBatchItemAction
60 SetImportBatchItemAction
63 GetImportRecordOverlayStatus
64 SetImportRecordOverlayStatus
67 GetImportRecordMatches
68 SetImportRecordMatches
74 C4::ImportBatch - manage batches of imported MARC records
86 =head2 GetZ3950BatchId
90 my $batchid = GetZ3950BatchId($z3950server);
94 Retrieves the ID of the import batch for the Z39.50
95 reservoir for the given target. If necessary,
96 creates the import batch.
100 sub GetZ3950BatchId {
101 my ($z3950server) = @_;
103 my $dbh = C4::Context->dbh;
104 my $sth = $dbh->prepare("SELECT import_batch_id FROM import_batches
105 WHERE batch_type = 'z3950'
107 $sth->execute($z3950server);
108 my $rowref = $sth->fetchrow_arrayref();
110 if (defined $rowref) {
113 my $batch_id = AddImportBatch('create_new', 'staged', 'z3950', $z3950server, '');
119 =head2 GetImportRecordMarc
123 my ($marcblob, $encoding) = GetImportRecordMarc($import_record_id);
129 sub GetImportRecordMarc {
130 my ($import_record_id) = @_;
132 my $dbh = C4::Context->dbh;
133 my $sth = $dbh->prepare("SELECT marc, encoding FROM import_records WHERE import_record_id = ?");
134 $sth->execute($import_record_id);
135 my ($marc, $encoding) = $sth->fetchrow();
141 =head2 AddImportBatch
145 my $batch_id = AddImportBatch($overlay_action, $import_status, $type, $file_name, $comments);
152 my ($overlay_action, $import_status, $type, $file_name, $comments) = @_;
154 my $dbh = C4::Context->dbh;
155 my $sth = $dbh->prepare("INSERT INTO import_batches (overlay_action, import_status, batch_type,
157 VALUES (?, ?, ?, ?, ?)");
158 $sth->execute($overlay_action, $import_status, $type, $file_name, $comments);
159 my $batch_id = $dbh->{'mysql_insertid'};
166 =head2 GetImportBatch
170 my $row = GetImportBatch($batch_id);
174 Retrieve a hashref of an import_batches row.
181 my $dbh = C4::Context->dbh;
182 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches WHERE import_batch_id = ?");
183 $sth->bind_param(1, $batch_id);
185 my $result = $sth->fetchrow_hashref;
191 =head2 AddBiblioToBatch
195 my $import_record_id = AddBiblioToBatch($batch_id, $record_sequence, $marc_record, $encoding, $z3950random, $update_counts);
201 sub AddBiblioToBatch {
202 my $batch_id = shift;
203 my $record_sequence = shift;
204 my $marc_record = shift;
205 my $encoding = shift;
206 my $z3950random = shift;
207 my $update_counts = @_ ? shift : 1;
209 my $import_record_id = _create_import_record($batch_id, $record_sequence, $marc_record, 'biblio', $encoding, $z3950random);
210 _add_biblio_fields($import_record_id, $marc_record);
211 _update_batch_record_counts($batch_id) if $update_counts;
212 return $import_record_id;
215 =head2 ModBiblioInBatch
219 ModBiblioInBatch($import_record_id, $marc_record);
225 sub ModBiblioInBatch {
226 my ($import_record_id, $marc_record) = @_;
228 _update_import_record_marc($import_record_id, $marc_record);
229 _update_biblio_fields($import_record_id, $marc_record);
233 =head2 BatchStageMarcRecords
237 ($batch_id, $num_records, $num_items, @invalid_records) =
238 BatchStageMarcRecords($marc_flavor, $marc_records, $file_name,
239 $comments, $branch_code, $parse_items,
241 $progress_interval, $progress_callback);
247 sub BatchStageMarcRecords {
248 my $marc_flavor = shift;
249 my $marc_records = shift;
250 my $file_name = shift;
251 my $comments = shift;
252 my $branch_code = shift;
253 my $parse_items = shift;
254 my $leave_as_staging = shift;
256 # optional callback to monitor status
258 my $progress_interval = 0;
259 my $progress_callback = undef;
261 $progress_interval = shift;
262 $progress_callback = shift;
263 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
264 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
267 my $batch_id = AddImportBatch('create_new', 'staging', 'batch', $file_name, $comments);
269 SetImportBatchItemAction($batch_id, 'always_add');
271 SetImportBatchItemAction($batch_id, 'ignore');
274 my @invalid_records = ();
277 # FIXME - for now, we're dealing only with bibs
279 foreach my $marc_blob (split(/\x1D/, $marc_records)) {
280 $marc_blob =~ s/^\s+//g;
281 $marc_blob =~ s/\s+$//g;
282 next unless $marc_blob;
284 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
285 &$progress_callback($rec_num);
287 my ($marc_record, $charset_guessed, $char_errors) =
288 MarcToUTF8Record($marc_blob, C4::Context->preference("marcflavour"));
289 my $import_record_id;
290 if (scalar($marc_record->fields()) == 0) {
291 push @invalid_records, $marc_blob;
294 $import_record_id = AddBiblioToBatch($batch_id, $rec_num, $marc_record, $marc_flavor, int(rand(99999)), 0);
296 my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, 0);
297 $num_items += scalar(@import_items_ids);
301 unless ($leave_as_staging) {
302 SetImportBatchStatus($batch_id, 'staged');
304 # FIXME branch_code, number of bibs, number of items
305 _update_batch_record_counts($batch_id);
306 return ($batch_id, $num_valid, $num_items, @invalid_records);
309 =head2 AddItemsToImportBiblio
313 my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, $update_counts);
319 sub AddItemsToImportBiblio {
320 my $batch_id = shift;
321 my $import_record_id = shift;
322 my $marc_record = shift;
323 my $update_counts = @_ ? shift : 0;
325 my @import_items_ids = ();
327 my $dbh = C4::Context->dbh;
328 my ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",'');
329 foreach my $item_field ($marc_record->field($item_tag)) {
330 my $item_marc = MARC::Record->new();
331 $item_marc->leader("00000 a "); # must set Leader/09 to 'a'
332 $item_marc->append_fields($item_field);
333 $marc_record->delete_field($item_field);
334 my $sth = $dbh->prepare_cached("INSERT INTO import_items (import_record_id, status, marcxml)
336 $sth->bind_param(1, $import_record_id);
337 $sth->bind_param(2, 'staged');
338 $sth->bind_param(3, $item_marc->as_xml());
340 push @import_items_ids, $dbh->{'mysql_insertid'};
344 if ($#import_items_ids > -1) {
345 _update_batch_record_counts($batch_id) if $update_counts;
346 _update_import_record_marc($import_record_id, $marc_record);
348 return @import_items_ids;
351 =head2 BatchFindBibDuplicates
355 my $num_with_matches = BatchFindBibDuplicates($batch_id, $matcher, $max_matches, $progress_interval, $progress_callback);
359 Goes through the records loaded in the batch and attempts to
360 find duplicates for each one. Sets the matching status
361 of each record to "no_match" or "auto_match" as appropriate.
363 The $max_matches parameter is optional; if it is not supplied,
366 The $progress_interval and $progress_callback parameters are
367 optional; if both are supplied, the sub referred to by
368 $progress_callback will be invoked every $progress_interval
369 records using the number of records processed as the
374 sub BatchFindBibDuplicates {
375 my $batch_id = shift;
377 my $max_matches = @_ ? shift : 10;
379 # optional callback to monitor status
381 my $progress_interval = 0;
382 my $progress_callback = undef;
384 $progress_interval = shift;
385 $progress_callback = shift;
386 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
387 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
390 my $dbh = C4::Context->dbh;
392 my $sth = $dbh->prepare("SELECT import_record_id, marc
394 JOIN import_biblios USING (import_record_id)
395 WHERE import_batch_id = ?");
396 $sth->execute($batch_id);
397 my $num_with_matches = 0;
399 while (my $rowref = $sth->fetchrow_hashref) {
401 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
402 &$progress_callback($rec_num);
404 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
406 if (defined $matcher) {
407 @matches = $matcher->get_matches($marc_record, $max_matches);
409 if (scalar(@matches) > 0) {
411 SetImportRecordMatches($rowref->{'import_record_id'}, @matches);
412 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'auto_match');
414 SetImportRecordMatches($rowref->{'import_record_id'}, ());
415 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'no_match');
419 return $num_with_matches;
422 =head2 BatchCommitBibRecords
426 my ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored) =
427 BatchCommitBibRecords($batch_id, $progress_interval, $progress_callback);
433 sub BatchCommitBibRecords {
434 my $batch_id = shift;
436 # optional callback to monitor status
438 my $progress_interval = 0;
439 my $progress_callback = undef;
441 $progress_interval = shift;
442 $progress_callback = shift;
443 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
444 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
449 my $num_items_added = 0;
450 my $num_items_errored = 0;
452 # commit (i.e., save, all records in the batch)
453 # FIXME biblio only at the moment
454 SetImportBatchStatus('importing');
455 my $overlay_action = GetImportBatchOverlayAction($batch_id);
456 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
457 my $item_action = GetImportBatchItemAction($batch_id);
458 my $dbh = C4::Context->dbh;
459 my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marc, encoding
461 JOIN import_biblios USING (import_record_id)
462 WHERE import_batch_id = ?");
463 $sth->execute($batch_id);
465 while (my $rowref = $sth->fetchrow_hashref) {
467 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
468 &$progress_callback($rec_num);
470 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'imported') {
474 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
476 # remove any item tags - rely on BatchCommitItems
477 my ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",'');
478 foreach my $item_field ($marc_record->field($item_tag)) {
479 $marc_record->delete_field($item_field);
482 # decide what what to do with the bib and item records
483 my ($bib_result, $item_result, $bib_match) =
484 _get_commit_action($overlay_action, $nomatch_action, $item_action,
485 $rowref->{'overlay_status'}, $rowref->{'import_record_id'});
487 if ($bib_result eq 'create_new') {
489 my ($biblionumber, $biblioitemnumber) = AddBiblio($marc_record, '');
490 my $sth = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
491 $sth->execute($biblionumber, $rowref->{'import_record_id'});
493 if ($item_result eq 'create_new') {
494 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
495 $num_items_added += $bib_items_added;
496 $num_items_errored += $bib_items_errored;
498 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
499 } elsif ($bib_result eq 'replace') {
501 my $biblionumber = $bib_match;
502 my ($count, $oldbiblio) = GetBiblio($biblionumber);
503 my $oldxml = GetXmlBiblio($biblionumber);
505 # remove item fields so that they don't get
506 # added again if record is reverted
507 my $old_marc = MARC::Record->new_from_xml(StripNonXmlChars($oldxml), 'UTF-8', $rowref->{'encoding'});
508 foreach my $item_field ($old_marc->field($item_tag)) {
509 $old_marc->delete_field($item_field);
512 ModBiblio($marc_record, $biblionumber, $oldbiblio->{'frameworkcode'});
513 my $sth = $dbh->prepare_cached("UPDATE import_records SET marcxml_old = ? WHERE import_record_id = ?");
514 $sth->execute($old_marc->as_xml(), $rowref->{'import_record_id'});
516 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
517 $sth2->execute($biblionumber, $rowref->{'import_record_id'});
519 if ($item_result eq 'create_new') {
520 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
521 $num_items_added += $bib_items_added;
522 $num_items_errored += $bib_items_errored;
524 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
525 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
526 } elsif ($bib_result eq 'ignore') {
528 my $biblionumber = $bib_match;
529 if (defined $biblionumber and $item_result eq 'create_new') {
530 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
531 $num_items_added += $bib_items_added;
532 $num_items_errored += $bib_items_errored;
533 # still need to record the matched biblionumber so that the
534 # items can be reverted
535 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
536 $sth2->execute($biblionumber, $rowref->{'import_record_id'});
537 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
539 SetImportRecordStatus($rowref->{'import_record_id'}, 'ignored');
543 SetImportBatchStatus($batch_id, 'imported');
544 return ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored);
547 =head2 BatchCommitItems
551 ($num_items_added, $num_items_errored) = BatchCommitItems($import_record_id, $biblionumber);
557 sub BatchCommitItems {
558 my ($import_record_id, $biblionumber) = @_;
560 my $dbh = C4::Context->dbh;
562 my $num_items_added = 0;
563 my $num_items_errored = 0;
564 my $sth = $dbh->prepare("SELECT import_items_id, import_items.marcxml, encoding
566 JOIN import_records USING (import_record_id)
567 WHERE import_record_id = ?
568 ORDER BY import_items_id");
569 $sth->bind_param(1, $import_record_id);
571 while (my $row = $sth->fetchrow_hashref()) {
572 my $item_marc = MARC::Record->new_from_xml(StripNonXmlChars($row->{'marcxml'}), 'UTF-8', $row->{'encoding'});
573 # FIXME - duplicate barcode check needs to become part of AddItemFromMarc()
574 my $item = TransformMarcToKoha($dbh, $item_marc);
575 my $duplicate_barcode = exists($item->{'barcode'}) && GetItemnumberFromBarcode($item->{'barcode'});
576 if ($duplicate_barcode) {
577 my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, import_error = ? WHERE import_items_id = ?");
578 $updsth->bind_param(1, 'error');
579 $updsth->bind_param(2, 'duplicate item barcode');
580 $updsth->bind_param(3, $row->{'import_items_id'});
582 $num_items_errored++;
584 my ($item_biblionumber, $biblioitemnumber, $itemnumber) = AddItemFromMarc($item_marc, $biblionumber);
585 my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, itemnumber = ? WHERE import_items_id = ?");
586 $updsth->bind_param(1, 'imported');
587 $updsth->bind_param(2, $itemnumber);
588 $updsth->bind_param(3, $row->{'import_items_id'});
595 return ($num_items_added, $num_items_errored);
598 =head2 BatchRevertBibRecords
602 my ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored) = BatchRevertBibRecords($batch_id);
608 sub BatchRevertBibRecords {
609 my $batch_id = shift;
613 my $num_reverted = 0;
614 my $num_items_deleted = 0;
616 # commit (i.e., save, all records in the batch)
617 # FIXME biblio only at the moment
618 SetImportBatchStatus('reverting');
619 my $overlay_action = GetImportBatchOverlayAction($batch_id);
620 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
621 my $dbh = C4::Context->dbh;
622 my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marcxml_old, encoding, matched_biblionumber
624 JOIN import_biblios USING (import_record_id)
625 WHERE import_batch_id = ?");
626 $sth->execute($batch_id);
627 while (my $rowref = $sth->fetchrow_hashref) {
628 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'reverted') {
632 my $bib_result = _get_revert_action($overlay_action, $rowref->{'overlay_status'}, $rowref->{'status'});
634 if ($bib_result eq 'delete') {
635 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
636 my $error = DelBiblio($rowref->{'matched_biblionumber'});
637 if (defined $error) {
641 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
643 } elsif ($bib_result eq 'restore') {
645 my $old_record = MARC::Record->new_from_xml(StripNonXmlChars($rowref->{'marcxml_old'}), 'UTF-8', $rowref->{'encoding'});
646 my $biblionumber = $rowref->{'matched_biblionumber'};
647 my ($count, $oldbiblio) = GetBiblio($biblionumber);
648 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
649 ModBiblio($old_record, $biblionumber, $oldbiblio->{'frameworkcode'});
650 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
651 } elsif ($bib_result eq 'ignore') {
652 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
653 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
658 SetImportBatchStatus($batch_id, 'reverted');
659 return ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored);
662 =head2 BatchRevertItems
666 my $num_items_deleted = BatchRevertItems($import_record_id, $biblionumber);
672 sub BatchRevertItems {
673 my ($import_record_id, $biblionumber) = @_;
675 my $dbh = C4::Context->dbh;
676 my $num_items_deleted = 0;
678 my $sth = $dbh->prepare_cached("SELECT import_items_id, itemnumber
680 JOIN items USING (itemnumber)
681 WHERE import_record_id = ?");
682 $sth->bind_param(1, $import_record_id);
684 while (my $row = $sth->fetchrow_hashref()) {
685 DelItem($dbh, $biblionumber, $row->{'itemnumber'});
686 my $updsth = $dbh->prepare("UPDATE import_items SET status = ? WHERE import_items_id = ?");
687 $updsth->bind_param(1, 'reverted');
688 $updsth->bind_param(2, $row->{'import_items_id'});
691 $num_items_deleted++;
694 return $num_items_deleted;
697 =head2 GetAllImportBatches
701 my $results = GetAllImportBatches();
705 Returns a references to an array of hash references corresponding
706 to all import_batches rows (of batch_type 'batch'), sorted in
707 ascending order by import_batch_id.
711 sub GetAllImportBatches {
712 my $dbh = C4::Context->dbh;
713 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches
714 WHERE batch_type = 'batch'
715 ORDER BY import_batch_id ASC");
719 while (my $row = $sth->fetchrow_hashref) {
720 push @$results, $row;
726 =head2 GetImportBatchRangeDesc
730 my $results = GetImportBatchRangeDesc($offset, $results_per_group);
734 Returns a reference to an array of hash references corresponding to
735 import_batches rows (sorted in descending order by import_batch_id)
736 start at the given offset.
740 sub GetImportBatchRangeDesc {
741 my ($offset, $results_per_group) = @_;
743 my $dbh = C4::Context->dbh;
744 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches
745 WHERE batch_type = 'batch'
746 ORDER BY import_batch_id DESC
748 $sth->bind_param(1, $results_per_group);
749 $sth->bind_param(2, $offset);
753 while (my $row = $sth->fetchrow_hashref) {
754 push @$results, $row;
760 =head2 GetItemNumbersFromImportBatch
766 sub GetItemNumbersFromImportBatch {
768 my $dbh = C4::Context->dbh;
769 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=?");
770 $sth->execute($batch_id);
772 while ( my ($itm) = $sth->fetchrow_array ) {
778 =head2 GetNumberOfImportBatches
782 my $count = GetNumberOfImportBatches();
788 sub GetNumberOfNonZ3950ImportBatches {
789 my $dbh = C4::Context->dbh;
790 my $sth = $dbh->prepare("SELECT COUNT(*) FROM import_batches WHERE batch_type='batch'");
792 my ($count) = $sth->fetchrow_array();
797 =head2 GetImportBibliosRange
801 my $results = GetImportBibliosRange($batch_id, $offset, $results_per_group);
805 Returns a reference to an array of hash references corresponding to
806 import_biblios/import_records rows for a given batch
807 starting at the given offset.
811 sub GetImportBibliosRange {
812 my ($batch_id, $offset, $results_per_group) = @_;
814 my $dbh = C4::Context->dbh;
815 my $sth = $dbh->prepare_cached("SELECT title, author, isbn, issn, import_record_id, record_sequence,
816 status, overlay_status
818 JOIN import_biblios USING (import_record_id)
819 WHERE import_batch_id = ?
820 ORDER BY import_record_id LIMIT ? OFFSET ?");
821 $sth->bind_param(1, $batch_id);
822 $sth->bind_param(2, $results_per_group);
823 $sth->bind_param(3, $offset);
826 while (my $row = $sth->fetchrow_hashref) {
827 push @$results, $row;
834 =head2 GetBestRecordMatch
838 my $record_id = GetBestRecordMatch($import_record_id);
844 sub GetBestRecordMatch {
845 my ($import_record_id) = @_;
847 my $dbh = C4::Context->dbh;
848 my $sth = $dbh->prepare("SELECT candidate_match_id
849 FROM import_record_matches
850 WHERE import_record_id = ?
851 ORDER BY score DESC, candidate_match_id DESC");
852 $sth->execute($import_record_id);
853 my ($record_id) = $sth->fetchrow_array();
858 =head2 GetImportBatchStatus
862 my $status = GetImportBatchStatus($batch_id);
868 sub GetImportBatchStatus {
871 my $dbh = C4::Context->dbh;
872 my $sth = $dbh->prepare("SELECT import_status FROM import_batches WHERE batch_id = ?");
873 $sth->execute($batch_id);
874 my ($status) = $sth->fetchrow_array();
881 =head2 SetImportBatchStatus
885 SetImportBatchStatus($batch_id, $new_status);
891 sub SetImportBatchStatus {
892 my ($batch_id, $new_status) = @_;
894 my $dbh = C4::Context->dbh;
895 my $sth = $dbh->prepare("UPDATE import_batches SET import_status = ? WHERE import_batch_id = ?");
896 $sth->execute($new_status, $batch_id);
901 =head2 GetImportBatchOverlayAction
905 my $overlay_action = GetImportBatchOverlayAction($batch_id);
911 sub GetImportBatchOverlayAction {
914 my $dbh = C4::Context->dbh;
915 my $sth = $dbh->prepare("SELECT overlay_action FROM import_batches WHERE import_batch_id = ?");
916 $sth->execute($batch_id);
917 my ($overlay_action) = $sth->fetchrow_array();
919 return $overlay_action;
924 =head2 SetImportBatchOverlayAction
928 SetImportBatchOverlayAction($batch_id, $new_overlay_action);
934 sub SetImportBatchOverlayAction {
935 my ($batch_id, $new_overlay_action) = @_;
937 my $dbh = C4::Context->dbh;
938 my $sth = $dbh->prepare("UPDATE import_batches SET overlay_action = ? WHERE import_batch_id = ?");
939 $sth->execute($new_overlay_action, $batch_id);
944 =head2 GetImportBatchNoMatchAction
948 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
954 sub GetImportBatchNoMatchAction {
957 my $dbh = C4::Context->dbh;
958 my $sth = $dbh->prepare("SELECT nomatch_action FROM import_batches WHERE import_batch_id = ?");
959 $sth->execute($batch_id);
960 my ($nomatch_action) = $sth->fetchrow_array();
962 return $nomatch_action;
967 =head2 SetImportBatchNoMatchAction
971 SetImportBatchNoMatchAction($batch_id, $new_nomatch_action);
977 sub SetImportBatchNoMatchAction {
978 my ($batch_id, $new_nomatch_action) = @_;
980 my $dbh = C4::Context->dbh;
981 my $sth = $dbh->prepare("UPDATE import_batches SET nomatch_action = ? WHERE import_batch_id = ?");
982 $sth->execute($new_nomatch_action, $batch_id);
987 =head2 GetImportBatchItemAction
991 my $item_action = GetImportBatchItemAction($batch_id);
997 sub GetImportBatchItemAction {
1000 my $dbh = C4::Context->dbh;
1001 my $sth = $dbh->prepare("SELECT item_action FROM import_batches WHERE import_batch_id = ?");
1002 $sth->execute($batch_id);
1003 my ($item_action) = $sth->fetchrow_array();
1005 return $item_action;
1010 =head2 SetImportBatchItemAction
1014 SetImportBatchItemAction($batch_id, $new_item_action);
1020 sub SetImportBatchItemAction {
1021 my ($batch_id, $new_item_action) = @_;
1023 my $dbh = C4::Context->dbh;
1024 my $sth = $dbh->prepare("UPDATE import_batches SET item_action = ? WHERE import_batch_id = ?");
1025 $sth->execute($new_item_action, $batch_id);
1030 =head2 GetImportBatchMatcher
1034 my $matcher_id = GetImportBatchMatcher($batch_id);
1040 sub GetImportBatchMatcher {
1041 my ($batch_id) = @_;
1043 my $dbh = C4::Context->dbh;
1044 my $sth = $dbh->prepare("SELECT matcher_id FROM import_batches WHERE import_batch_id = ?");
1045 $sth->execute($batch_id);
1046 my ($matcher_id) = $sth->fetchrow_array();
1053 =head2 SetImportBatchMatcher
1057 SetImportBatchMatcher($batch_id, $new_matcher_id);
1063 sub SetImportBatchMatcher {
1064 my ($batch_id, $new_matcher_id) = @_;
1066 my $dbh = C4::Context->dbh;
1067 my $sth = $dbh->prepare("UPDATE import_batches SET matcher_id = ? WHERE import_batch_id = ?");
1068 $sth->execute($new_matcher_id, $batch_id);
1073 =head2 GetImportRecordOverlayStatus
1077 my $overlay_status = GetImportRecordOverlayStatus($import_record_id);
1083 sub GetImportRecordOverlayStatus {
1084 my ($import_record_id) = @_;
1086 my $dbh = C4::Context->dbh;
1087 my $sth = $dbh->prepare("SELECT overlay_status FROM import_records WHERE import_record_id = ?");
1088 $sth->execute($import_record_id);
1089 my ($overlay_status) = $sth->fetchrow_array();
1091 return $overlay_status;
1096 =head2 SetImportRecordOverlayStatus
1100 SetImportRecordOverlayStatus($import_record_id, $new_overlay_status);
1106 sub SetImportRecordOverlayStatus {
1107 my ($import_record_id, $new_overlay_status) = @_;
1109 my $dbh = C4::Context->dbh;
1110 my $sth = $dbh->prepare("UPDATE import_records SET overlay_status = ? WHERE import_record_id = ?");
1111 $sth->execute($new_overlay_status, $import_record_id);
1116 =head2 GetImportRecordStatus
1120 my $overlay_status = GetImportRecordStatus($import_record_id);
1126 sub GetImportRecordStatus {
1127 my ($import_record_id) = @_;
1129 my $dbh = C4::Context->dbh;
1130 my $sth = $dbh->prepare("SELECT status FROM import_records WHERE import_record_id = ?");
1131 $sth->execute($import_record_id);
1132 my ($overlay_status) = $sth->fetchrow_array();
1134 return $overlay_status;
1139 =head2 SetImportRecordStatus
1143 SetImportRecordStatus($import_record_id, $new_overlay_status);
1149 sub SetImportRecordStatus {
1150 my ($import_record_id, $new_overlay_status) = @_;
1152 my $dbh = C4::Context->dbh;
1153 my $sth = $dbh->prepare("UPDATE import_records SET status = ? WHERE import_record_id = ?");
1154 $sth->execute($new_overlay_status, $import_record_id);
1159 =head2 GetImportRecordMatches
1163 my $results = GetImportRecordMatches($import_record_id, $best_only);
1169 sub GetImportRecordMatches {
1170 my $import_record_id = shift;
1171 my $best_only = @_ ? shift : 0;
1173 my $dbh = C4::Context->dbh;
1174 # FIXME currently biblio only
1175 my $sth = $dbh->prepare_cached("SELECT title, author, biblionumber, score
1177 JOIN import_record_matches USING (import_record_id)
1178 JOIN biblio ON (biblionumber = candidate_match_id)
1179 WHERE import_record_id = ?
1180 ORDER BY score DESC, biblionumber DESC");
1181 $sth->bind_param(1, $import_record_id);
1184 while (my $row = $sth->fetchrow_hashref) {
1185 push @$results, $row;
1195 =head2 SetImportRecordMatches
1199 SetImportRecordMatches($import_record_id, @matches);
1205 sub SetImportRecordMatches {
1206 my $import_record_id = shift;
1209 my $dbh = C4::Context->dbh;
1210 my $delsth = $dbh->prepare("DELETE FROM import_record_matches WHERE import_record_id = ?");
1211 $delsth->execute($import_record_id);
1214 my $sth = $dbh->prepare("INSERT INTO import_record_matches (import_record_id, candidate_match_id, score)
1216 foreach my $match (@matches) {
1217 $sth->execute($import_record_id, $match->{'record_id'}, $match->{'score'});
1222 # internal functions
1224 sub _create_import_record {
1225 my ($batch_id, $record_sequence, $marc_record, $record_type, $encoding, $z3950random) = @_;
1227 my $dbh = C4::Context->dbh;
1228 my $sth = $dbh->prepare("INSERT INTO import_records (import_batch_id, record_sequence, marc, marcxml,
1229 record_type, encoding, z3950random)
1230 VALUES (?, ?, ?, ?, ?, ?, ?)");
1231 $sth->execute($batch_id, $record_sequence, $marc_record->as_usmarc(), $marc_record->as_xml(),
1232 $record_type, $encoding, $z3950random);
1233 my $import_record_id = $dbh->{'mysql_insertid'};
1235 return $import_record_id;
1238 sub _update_import_record_marc {
1239 my ($import_record_id, $marc_record) = @_;
1241 my $dbh = C4::Context->dbh;
1242 my $sth = $dbh->prepare("UPDATE import_records SET marc = ?, marcxml = ?
1243 WHERE import_record_id = ?");
1244 $sth->execute($marc_record->as_usmarc(), $marc_record->as_xml(), $import_record_id);
1248 sub _add_biblio_fields {
1249 my ($import_record_id, $marc_record) = @_;
1251 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1252 my $dbh = C4::Context->dbh;
1253 # FIXME no controlnumber, originalsource
1254 # FIXME 2 - should regularize normalization of ISBN wherever it is done
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>