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
51 GetImportBatchRangeDesc
52 GetNumberOfNonZ3950ImportBatches
54 GetItemNumbersFromImportBatch
58 GetImportBatchOverlayAction
59 SetImportBatchOverlayAction
60 GetImportBatchNoMatchAction
61 SetImportBatchNoMatchAction
62 GetImportBatchItemAction
63 SetImportBatchItemAction
66 GetImportRecordOverlayStatus
67 SetImportRecordOverlayStatus
70 GetImportRecordMatches
71 SetImportRecordMatches
77 C4::ImportBatch - manage batches of imported MARC records
89 =head2 GetZ3950BatchId
93 my $batchid = GetZ3950BatchId($z3950server);
97 Retrieves the ID of the import batch for the Z39.50
98 reservoir for the given target. If necessary,
99 creates the import batch.
103 sub GetZ3950BatchId {
104 my ($z3950server) = @_;
106 my $dbh = C4::Context->dbh;
107 my $sth = $dbh->prepare("SELECT import_batch_id FROM import_batches
108 WHERE batch_type = 'z3950'
110 $sth->execute($z3950server);
111 my $rowref = $sth->fetchrow_arrayref();
113 if (defined $rowref) {
116 my $batch_id = AddImportBatch('create_new', 'staged', 'z3950', $z3950server, '');
122 =head2 GetImportRecordMarc
126 my ($marcblob, $encoding) = GetImportRecordMarc($import_record_id);
132 sub GetImportRecordMarc {
133 my ($import_record_id) = @_;
135 my $dbh = C4::Context->dbh;
136 my $sth = $dbh->prepare("SELECT marc, encoding FROM import_records WHERE import_record_id = ?");
137 $sth->execute($import_record_id);
138 my ($marc, $encoding) = $sth->fetchrow();
140 return $marc, $encoding;
144 =head2 AddImportBatch
148 my $batch_id = AddImportBatch($overlay_action, $import_status, $type, $file_name, $comments);
155 my ($overlay_action, $import_status, $type, $file_name, $comments) = @_;
157 my $dbh = C4::Context->dbh;
158 my $sth = $dbh->prepare("INSERT INTO import_batches (overlay_action, import_status, batch_type,
160 VALUES (?, ?, ?, ?, ?)");
161 $sth->execute($overlay_action, $import_status, $type, $file_name, $comments);
162 my $batch_id = $dbh->{'mysql_insertid'};
169 =head2 GetImportBatch
173 my $row = GetImportBatch($batch_id);
177 Retrieve a hashref of an import_batches row.
184 my $dbh = C4::Context->dbh;
185 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches WHERE import_batch_id = ?");
186 $sth->bind_param(1, $batch_id);
188 my $result = $sth->fetchrow_hashref;
194 =head2 AddBiblioToBatch
198 my $import_record_id = AddBiblioToBatch($batch_id, $record_sequence, $marc_record, $encoding, $z3950random, $update_counts);
204 sub AddBiblioToBatch {
205 my $batch_id = shift;
206 my $record_sequence = shift;
207 my $marc_record = shift;
208 my $encoding = shift;
209 my $z3950random = shift;
210 my $update_counts = @_ ? shift : 1;
212 my $import_record_id = _create_import_record($batch_id, $record_sequence, $marc_record, 'biblio', $encoding, $z3950random);
213 _add_biblio_fields($import_record_id, $marc_record);
214 _update_batch_record_counts($batch_id) if $update_counts;
215 return $import_record_id;
218 =head2 ModBiblioInBatch
222 ModBiblioInBatch($import_record_id, $marc_record);
228 sub ModBiblioInBatch {
229 my ($import_record_id, $marc_record) = @_;
231 _update_import_record_marc($import_record_id, $marc_record);
232 _update_biblio_fields($import_record_id, $marc_record);
236 =head2 BatchStageMarcRecords
240 ($batch_id, $num_records, $num_items, @invalid_records) =
241 BatchStageMarcRecords($marc_flavor, $marc_records, $file_name,
242 $comments, $branch_code, $parse_items,
244 $progress_interval, $progress_callback);
250 sub BatchStageMarcRecords {
251 my $marc_flavor = shift;
252 my $marc_records = shift;
253 my $file_name = shift;
254 my $comments = shift;
255 my $branch_code = shift;
256 my $parse_items = shift;
257 my $leave_as_staging = shift;
259 # optional callback to monitor status
261 my $progress_interval = 0;
262 my $progress_callback = undef;
264 $progress_interval = shift;
265 $progress_callback = shift;
266 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
267 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
270 my $batch_id = AddImportBatch('create_new', 'staging', 'batch', $file_name, $comments);
272 SetImportBatchItemAction($batch_id, 'always_add');
274 SetImportBatchItemAction($batch_id, 'ignore');
277 my @invalid_records = ();
280 # FIXME - for now, we're dealing only with bibs
282 foreach my $marc_blob (split(/\x1D/, $marc_records)) {
283 $marc_blob =~ s/^\s+//g;
284 $marc_blob =~ s/\s+$//g;
285 next unless $marc_blob;
287 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
288 &$progress_callback($rec_num);
290 my ($marc_record, $charset_guessed, $char_errors) =
291 MarcToUTF8Record($marc_blob, C4::Context->preference("marcflavour"));
292 my $import_record_id;
293 if (scalar($marc_record->fields()) == 0) {
294 push @invalid_records, $marc_blob;
297 $import_record_id = AddBiblioToBatch($batch_id, $rec_num, $marc_record, $marc_flavor, int(rand(99999)), 0);
299 my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, 0);
300 $num_items += scalar(@import_items_ids);
304 unless ($leave_as_staging) {
305 SetImportBatchStatus($batch_id, 'staged');
307 # FIXME branch_code, number of bibs, number of items
308 _update_batch_record_counts($batch_id);
309 return ($batch_id, $num_valid, $num_items, @invalid_records);
312 =head2 AddItemsToImportBiblio
316 my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, $update_counts);
322 sub AddItemsToImportBiblio {
323 my $batch_id = shift;
324 my $import_record_id = shift;
325 my $marc_record = shift;
326 my $update_counts = @_ ? shift : 0;
328 my @import_items_ids = ();
330 my $dbh = C4::Context->dbh;
331 my ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",'');
332 foreach my $item_field ($marc_record->field($item_tag)) {
333 my $item_marc = MARC::Record->new();
334 $item_marc->leader("00000 a "); # must set Leader/09 to 'a'
335 $item_marc->append_fields($item_field);
336 $marc_record->delete_field($item_field);
337 my $sth = $dbh->prepare_cached("INSERT INTO import_items (import_record_id, status, marcxml)
339 $sth->bind_param(1, $import_record_id);
340 $sth->bind_param(2, 'staged');
341 $sth->bind_param(3, $item_marc->as_xml());
343 push @import_items_ids, $dbh->{'mysql_insertid'};
347 if ($#import_items_ids > -1) {
348 _update_batch_record_counts($batch_id) if $update_counts;
349 _update_import_record_marc($import_record_id, $marc_record);
351 return @import_items_ids;
354 =head2 BatchFindBibDuplicates
358 my $num_with_matches = BatchFindBibDuplicates($batch_id, $matcher, $max_matches, $progress_interval, $progress_callback);
362 Goes through the records loaded in the batch and attempts to
363 find duplicates for each one. Sets the matching status
364 of each record to "no_match" or "auto_match" as appropriate.
366 The $max_matches parameter is optional; if it is not supplied,
369 The $progress_interval and $progress_callback parameters are
370 optional; if both are supplied, the sub referred to by
371 $progress_callback will be invoked every $progress_interval
372 records using the number of records processed as the
377 sub BatchFindBibDuplicates {
378 my $batch_id = shift;
380 my $max_matches = @_ ? shift : 10;
382 # optional callback to monitor status
384 my $progress_interval = 0;
385 my $progress_callback = undef;
387 $progress_interval = shift;
388 $progress_callback = shift;
389 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
390 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
393 my $dbh = C4::Context->dbh;
395 my $sth = $dbh->prepare("SELECT import_record_id, marc
397 JOIN import_biblios USING (import_record_id)
398 WHERE import_batch_id = ?");
399 $sth->execute($batch_id);
400 my $num_with_matches = 0;
402 while (my $rowref = $sth->fetchrow_hashref) {
404 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
405 &$progress_callback($rec_num);
407 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
409 if (defined $matcher) {
410 @matches = $matcher->get_matches($marc_record, $max_matches);
412 if (scalar(@matches) > 0) {
414 SetImportRecordMatches($rowref->{'import_record_id'}, @matches);
415 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'auto_match');
417 SetImportRecordMatches($rowref->{'import_record_id'}, ());
418 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'no_match');
422 return $num_with_matches;
425 =head2 BatchCommitBibRecords
429 my ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored) =
430 BatchCommitBibRecords($batch_id, $progress_interval, $progress_callback);
436 sub BatchCommitBibRecords {
437 my $batch_id = shift;
439 # optional callback to monitor status
441 my $progress_interval = 0;
442 my $progress_callback = undef;
444 $progress_interval = shift;
445 $progress_callback = shift;
446 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
447 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
452 my $num_items_added = 0;
453 my $num_items_errored = 0;
455 # commit (i.e., save, all records in the batch)
456 # FIXME biblio only at the moment
457 SetImportBatchStatus('importing');
458 my $overlay_action = GetImportBatchOverlayAction($batch_id);
459 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
460 my $item_action = GetImportBatchItemAction($batch_id);
461 my $dbh = C4::Context->dbh;
462 my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marc, encoding
464 JOIN import_biblios USING (import_record_id)
465 WHERE import_batch_id = ?");
466 $sth->execute($batch_id);
468 while (my $rowref = $sth->fetchrow_hashref) {
470 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
471 &$progress_callback($rec_num);
473 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'imported') {
478 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
480 # remove any item tags - rely on BatchCommitItems
481 my ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",'');
482 foreach my $item_field ($marc_record->field($item_tag)) {
483 $marc_record->delete_field($item_field);
486 # decide what what to do with the bib and item records
487 my ($bib_result, $item_result, $bib_match) =
488 _get_commit_action($overlay_action, $nomatch_action, $item_action,
489 $rowref->{'overlay_status'}, $rowref->{'import_record_id'});
491 if ($bib_result eq 'create_new') {
493 my ($biblionumber, $biblioitemnumber) = AddBiblio($marc_record, '');
494 my $sth = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
495 $sth->execute($biblionumber, $rowref->{'import_record_id'});
497 if ($item_result eq 'create_new') {
498 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
499 $num_items_added += $bib_items_added;
500 $num_items_errored += $bib_items_errored;
502 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
503 } elsif ($bib_result eq 'replace') {
505 my $biblionumber = $bib_match;
506 my ($count, $oldbiblio) = GetBiblio($biblionumber);
507 my $oldxml = GetXmlBiblio($biblionumber);
509 # remove item fields so that they don't get
510 # added again if record is reverted
511 my $old_marc = MARC::Record->new_from_xml(StripNonXmlChars($oldxml), 'UTF-8', $rowref->{'encoding'});
512 foreach my $item_field ($old_marc->field($item_tag)) {
513 $old_marc->delete_field($item_field);
516 ModBiblio($marc_record, $biblionumber, $oldbiblio->{'frameworkcode'});
517 my $sth = $dbh->prepare_cached("UPDATE import_records SET marcxml_old = ? WHERE import_record_id = ?");
518 $sth->execute($old_marc->as_xml(), $rowref->{'import_record_id'});
520 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
521 $sth2->execute($biblionumber, $rowref->{'import_record_id'});
523 if ($item_result eq 'create_new') {
524 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
525 $num_items_added += $bib_items_added;
526 $num_items_errored += $bib_items_errored;
528 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
529 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
530 } elsif ($bib_result eq 'ignore') {
532 my $biblionumber = $bib_match;
533 if (defined $biblionumber and $item_result eq 'create_new') {
534 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
535 $num_items_added += $bib_items_added;
536 $num_items_errored += $bib_items_errored;
537 # still need to record the matched biblionumber so that the
538 # items can be reverted
539 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
540 $sth2->execute($biblionumber, $rowref->{'import_record_id'});
541 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
543 SetImportRecordStatus($rowref->{'import_record_id'}, 'ignored');
547 SetImportBatchStatus($batch_id, 'imported');
548 return ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored);
551 =head2 BatchCommitItems
555 ($num_items_added, $num_items_errored) = BatchCommitItems($import_record_id, $biblionumber);
561 sub BatchCommitItems {
562 my ($import_record_id, $biblionumber) = @_;
564 my $dbh = C4::Context->dbh;
566 my $num_items_added = 0;
567 my $num_items_errored = 0;
568 my $sth = $dbh->prepare("SELECT import_items_id, import_items.marcxml, encoding
570 JOIN import_records USING (import_record_id)
571 WHERE import_record_id = ?
572 ORDER BY import_items_id");
573 $sth->bind_param(1, $import_record_id);
575 while (my $row = $sth->fetchrow_hashref()) {
576 my $item_marc = MARC::Record->new_from_xml(StripNonXmlChars($row->{'marcxml'}), 'UTF-8', $row->{'encoding'});
577 # FIXME - duplicate barcode check needs to become part of AddItemFromMarc()
578 my $item = TransformMarcToKoha($dbh, $item_marc);
579 my $duplicate_barcode = exists($item->{'barcode'}) && GetItemnumberFromBarcode($item->{'barcode'});
580 if ($duplicate_barcode) {
581 my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, import_error = ? WHERE import_items_id = ?");
582 $updsth->bind_param(1, 'error');
583 $updsth->bind_param(2, 'duplicate item barcode');
584 $updsth->bind_param(3, $row->{'import_items_id'});
586 $num_items_errored++;
588 my ($item_biblionumber, $biblioitemnumber, $itemnumber) = AddItemFromMarc($item_marc, $biblionumber);
589 my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, itemnumber = ? WHERE import_items_id = ?");
590 $updsth->bind_param(1, 'imported');
591 $updsth->bind_param(2, $itemnumber);
592 $updsth->bind_param(3, $row->{'import_items_id'});
599 return ($num_items_added, $num_items_errored);
602 =head2 BatchRevertBibRecords
606 my ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored) = BatchRevertBibRecords($batch_id);
612 sub BatchRevertBibRecords {
613 my $batch_id = shift;
617 my $num_reverted = 0;
618 my $num_items_deleted = 0;
620 # commit (i.e., save, all records in the batch)
621 # FIXME biblio only at the moment
622 SetImportBatchStatus('reverting');
623 my $overlay_action = GetImportBatchOverlayAction($batch_id);
624 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
625 my $dbh = C4::Context->dbh;
626 my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marcxml_old, encoding, matched_biblionumber
628 JOIN import_biblios USING (import_record_id)
629 WHERE import_batch_id = ?");
630 $sth->execute($batch_id);
631 while (my $rowref = $sth->fetchrow_hashref) {
632 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'reverted') {
637 my $bib_result = _get_revert_action($overlay_action, $rowref->{'overlay_status'}, $rowref->{'status'});
639 if ($bib_result eq 'delete') {
640 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
641 my $error = DelBiblio($rowref->{'matched_biblionumber'});
642 if (defined $error) {
646 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
648 } elsif ($bib_result eq 'restore') {
650 my $old_record = MARC::Record->new_from_xml(StripNonXmlChars($rowref->{'marcxml_old'}), 'UTF-8', $rowref->{'encoding'});
651 my $biblionumber = $rowref->{'matched_biblionumber'};
652 my ($count, $oldbiblio) = GetBiblio($biblionumber);
653 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
654 ModBiblio($old_record, $biblionumber, $oldbiblio->{'frameworkcode'});
655 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
656 } elsif ($bib_result eq 'ignore') {
657 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
658 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
660 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = NULL WHERE import_record_id = ?");
661 $sth2->execute($rowref->{'import_record_id'});
665 SetImportBatchStatus($batch_id, 'reverted');
666 return ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored);
669 =head2 BatchRevertItems
673 my $num_items_deleted = BatchRevertItems($import_record_id, $biblionumber);
679 sub BatchRevertItems {
680 my ($import_record_id, $biblionumber) = @_;
682 my $dbh = C4::Context->dbh;
683 my $num_items_deleted = 0;
685 my $sth = $dbh->prepare_cached("SELECT import_items_id, itemnumber
687 JOIN items USING (itemnumber)
688 WHERE import_record_id = ?");
689 $sth->bind_param(1, $import_record_id);
691 while (my $row = $sth->fetchrow_hashref()) {
692 DelItem($dbh, $biblionumber, $row->{'itemnumber'});
693 my $updsth = $dbh->prepare("UPDATE import_items SET status = ? WHERE import_items_id = ?");
694 $updsth->bind_param(1, 'reverted');
695 $updsth->bind_param(2, $row->{'import_items_id'});
698 $num_items_deleted++;
701 return $num_items_deleted;
708 CleanBatch($batch_id)
712 Deletes all staged records from the import batch
713 and sets the status of the batch to 'cleaned'. Note
714 that deleting a stage record does *not* affect
715 any record that has been committed to the database.
720 my $batch_id = shift;
721 return unless defined $batch_id;
723 C4::Context->dbh->do('DELETE FROM import_records WHERE import_batch_id = ?', {}, $batch_id);
724 SetImportBatchStatus($batch_id, 'cleaned');
727 =head2 GetAllImportBatches
731 my $results = GetAllImportBatches();
735 Returns a references to an array of hash references corresponding
736 to all import_batches rows (of batch_type 'batch'), sorted in
737 ascending order by import_batch_id.
741 sub GetAllImportBatches {
742 my $dbh = C4::Context->dbh;
743 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches
744 WHERE batch_type = 'batch'
745 ORDER BY import_batch_id ASC");
749 while (my $row = $sth->fetchrow_hashref) {
750 push @$results, $row;
756 =head2 GetImportBatchRangeDesc
760 my $results = GetImportBatchRangeDesc($offset, $results_per_group);
764 Returns a reference to an array of hash references corresponding to
765 import_batches rows (sorted in descending order by import_batch_id)
766 start at the given offset.
770 sub GetImportBatchRangeDesc {
771 my ($offset, $results_per_group) = @_;
773 my $dbh = C4::Context->dbh;
774 my $query = "SELECT * FROM import_batches
775 WHERE batch_type = 'batch'
776 ORDER BY import_batch_id DESC";
779 if ($results_per_group){
780 $query .= " LIMIT ?";
781 push(@params, $results_per_group);
783 $query .= " OFFSET ?";
784 push(@params, $offset);
786 my $sth = $dbh->prepare_cached($query);
787 $sth->execute(@params);
788 my $results = $sth->fetchall_arrayref({});
793 =head2 GetItemNumbersFromImportBatch
797 sub GetItemNumbersFromImportBatch {
799 my $dbh = C4::Context->dbh;
800 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=?");
801 $sth->execute($batch_id);
803 while ( my ($itm) = $sth->fetchrow_array ) {
809 =head2 GetNumberOfImportBatches
813 my $count = GetNumberOfImportBatches();
819 sub GetNumberOfNonZ3950ImportBatches {
820 my $dbh = C4::Context->dbh;
821 my $sth = $dbh->prepare("SELECT COUNT(*) FROM import_batches WHERE batch_type='batch'");
823 my ($count) = $sth->fetchrow_array();
828 =head2 GetImportBibliosRange
832 my $results = GetImportBibliosRange($batch_id, $offset, $results_per_group);
836 Returns a reference to an array of hash references corresponding to
837 import_biblios/import_records rows for a given batch
838 starting at the given offset.
842 sub GetImportBibliosRange {
843 my ($batch_id, $offset, $results_per_group) = @_;
845 my $dbh = C4::Context->dbh;
846 my $query = "SELECT title, author, isbn, issn, import_record_id, record_sequence,
847 status, overlay_status
849 JOIN import_biblios USING (import_record_id)
850 WHERE import_batch_id = ?
851 ORDER BY import_record_id";
853 push(@params, $batch_id);
855 if($results_per_group){
856 $query .= " LIMIT ?";
857 push(@params, $results_per_group);
859 $query .= " OFFSET ?";
860 push(@params, $offset);
862 my $sth = $dbh->prepare_cached($query);
863 $sth->execute(@params);
864 my $results = $sth->fetchall_arrayref({});
870 =head2 GetBestRecordMatch
874 my $record_id = GetBestRecordMatch($import_record_id);
880 sub GetBestRecordMatch {
881 my ($import_record_id) = @_;
883 my $dbh = C4::Context->dbh;
884 my $sth = $dbh->prepare("SELECT candidate_match_id
885 FROM import_record_matches
886 WHERE import_record_id = ?
887 ORDER BY score DESC, candidate_match_id DESC");
888 $sth->execute($import_record_id);
889 my ($record_id) = $sth->fetchrow_array();
894 =head2 GetImportBatchStatus
898 my $status = GetImportBatchStatus($batch_id);
904 sub GetImportBatchStatus {
907 my $dbh = C4::Context->dbh;
908 my $sth = $dbh->prepare("SELECT import_status FROM import_batches WHERE import_batch_id = ?");
909 $sth->execute($batch_id);
910 my ($status) = $sth->fetchrow_array();
916 =head2 SetImportBatchStatus
920 SetImportBatchStatus($batch_id, $new_status);
926 sub SetImportBatchStatus {
927 my ($batch_id, $new_status) = @_;
929 my $dbh = C4::Context->dbh;
930 my $sth = $dbh->prepare("UPDATE import_batches SET import_status = ? WHERE import_batch_id = ?");
931 $sth->execute($new_status, $batch_id);
936 =head2 GetImportBatchOverlayAction
940 my $overlay_action = GetImportBatchOverlayAction($batch_id);
946 sub GetImportBatchOverlayAction {
949 my $dbh = C4::Context->dbh;
950 my $sth = $dbh->prepare("SELECT overlay_action FROM import_batches WHERE import_batch_id = ?");
951 $sth->execute($batch_id);
952 my ($overlay_action) = $sth->fetchrow_array();
954 return $overlay_action;
959 =head2 SetImportBatchOverlayAction
963 SetImportBatchOverlayAction($batch_id, $new_overlay_action);
969 sub SetImportBatchOverlayAction {
970 my ($batch_id, $new_overlay_action) = @_;
972 my $dbh = C4::Context->dbh;
973 my $sth = $dbh->prepare("UPDATE import_batches SET overlay_action = ? WHERE import_batch_id = ?");
974 $sth->execute($new_overlay_action, $batch_id);
979 =head2 GetImportBatchNoMatchAction
983 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
989 sub GetImportBatchNoMatchAction {
992 my $dbh = C4::Context->dbh;
993 my $sth = $dbh->prepare("SELECT nomatch_action FROM import_batches WHERE import_batch_id = ?");
994 $sth->execute($batch_id);
995 my ($nomatch_action) = $sth->fetchrow_array();
997 return $nomatch_action;
1002 =head2 SetImportBatchNoMatchAction
1006 SetImportBatchNoMatchAction($batch_id, $new_nomatch_action);
1012 sub SetImportBatchNoMatchAction {
1013 my ($batch_id, $new_nomatch_action) = @_;
1015 my $dbh = C4::Context->dbh;
1016 my $sth = $dbh->prepare("UPDATE import_batches SET nomatch_action = ? WHERE import_batch_id = ?");
1017 $sth->execute($new_nomatch_action, $batch_id);
1022 =head2 GetImportBatchItemAction
1026 my $item_action = GetImportBatchItemAction($batch_id);
1032 sub GetImportBatchItemAction {
1033 my ($batch_id) = @_;
1035 my $dbh = C4::Context->dbh;
1036 my $sth = $dbh->prepare("SELECT item_action FROM import_batches WHERE import_batch_id = ?");
1037 $sth->execute($batch_id);
1038 my ($item_action) = $sth->fetchrow_array();
1040 return $item_action;
1045 =head2 SetImportBatchItemAction
1049 SetImportBatchItemAction($batch_id, $new_item_action);
1055 sub SetImportBatchItemAction {
1056 my ($batch_id, $new_item_action) = @_;
1058 my $dbh = C4::Context->dbh;
1059 my $sth = $dbh->prepare("UPDATE import_batches SET item_action = ? WHERE import_batch_id = ?");
1060 $sth->execute($new_item_action, $batch_id);
1065 =head2 GetImportBatchMatcher
1069 my $matcher_id = GetImportBatchMatcher($batch_id);
1075 sub GetImportBatchMatcher {
1076 my ($batch_id) = @_;
1078 my $dbh = C4::Context->dbh;
1079 my $sth = $dbh->prepare("SELECT matcher_id FROM import_batches WHERE import_batch_id = ?");
1080 $sth->execute($batch_id);
1081 my ($matcher_id) = $sth->fetchrow_array();
1088 =head2 SetImportBatchMatcher
1092 SetImportBatchMatcher($batch_id, $new_matcher_id);
1098 sub SetImportBatchMatcher {
1099 my ($batch_id, $new_matcher_id) = @_;
1101 my $dbh = C4::Context->dbh;
1102 my $sth = $dbh->prepare("UPDATE import_batches SET matcher_id = ? WHERE import_batch_id = ?");
1103 $sth->execute($new_matcher_id, $batch_id);
1108 =head2 GetImportRecordOverlayStatus
1112 my $overlay_status = GetImportRecordOverlayStatus($import_record_id);
1118 sub GetImportRecordOverlayStatus {
1119 my ($import_record_id) = @_;
1121 my $dbh = C4::Context->dbh;
1122 my $sth = $dbh->prepare("SELECT overlay_status FROM import_records WHERE import_record_id = ?");
1123 $sth->execute($import_record_id);
1124 my ($overlay_status) = $sth->fetchrow_array();
1126 return $overlay_status;
1131 =head2 SetImportRecordOverlayStatus
1135 SetImportRecordOverlayStatus($import_record_id, $new_overlay_status);
1141 sub SetImportRecordOverlayStatus {
1142 my ($import_record_id, $new_overlay_status) = @_;
1144 my $dbh = C4::Context->dbh;
1145 my $sth = $dbh->prepare("UPDATE import_records SET overlay_status = ? WHERE import_record_id = ?");
1146 $sth->execute($new_overlay_status, $import_record_id);
1151 =head2 GetImportRecordStatus
1155 my $overlay_status = GetImportRecordStatus($import_record_id);
1161 sub GetImportRecordStatus {
1162 my ($import_record_id) = @_;
1164 my $dbh = C4::Context->dbh;
1165 my $sth = $dbh->prepare("SELECT status FROM import_records WHERE import_record_id = ?");
1166 $sth->execute($import_record_id);
1167 my ($overlay_status) = $sth->fetchrow_array();
1169 return $overlay_status;
1174 =head2 SetImportRecordStatus
1178 SetImportRecordStatus($import_record_id, $new_overlay_status);
1184 sub SetImportRecordStatus {
1185 my ($import_record_id, $new_overlay_status) = @_;
1187 my $dbh = C4::Context->dbh;
1188 my $sth = $dbh->prepare("UPDATE import_records SET status = ? WHERE import_record_id = ?");
1189 $sth->execute($new_overlay_status, $import_record_id);
1194 =head2 GetImportRecordMatches
1198 my $results = GetImportRecordMatches($import_record_id, $best_only);
1204 sub GetImportRecordMatches {
1205 my $import_record_id = shift;
1206 my $best_only = @_ ? shift : 0;
1208 my $dbh = C4::Context->dbh;
1209 # FIXME currently biblio only
1210 my $sth = $dbh->prepare_cached("SELECT title, author, biblionumber, score
1212 JOIN import_record_matches USING (import_record_id)
1213 JOIN biblio ON (biblionumber = candidate_match_id)
1214 WHERE import_record_id = ?
1215 ORDER BY score DESC, biblionumber DESC");
1216 $sth->bind_param(1, $import_record_id);
1219 while (my $row = $sth->fetchrow_hashref) {
1220 push @$results, $row;
1230 =head2 SetImportRecordMatches
1234 SetImportRecordMatches($import_record_id, @matches);
1240 sub SetImportRecordMatches {
1241 my $import_record_id = shift;
1244 my $dbh = C4::Context->dbh;
1245 my $delsth = $dbh->prepare("DELETE FROM import_record_matches WHERE import_record_id = ?");
1246 $delsth->execute($import_record_id);
1249 my $sth = $dbh->prepare("INSERT INTO import_record_matches (import_record_id, candidate_match_id, score)
1251 foreach my $match (@matches) {
1252 $sth->execute($import_record_id, $match->{'record_id'}, $match->{'score'});
1257 # internal functions
1259 sub _create_import_record {
1260 my ($batch_id, $record_sequence, $marc_record, $record_type, $encoding, $z3950random) = @_;
1262 my $dbh = C4::Context->dbh;
1263 my $sth = $dbh->prepare("INSERT INTO import_records (import_batch_id, record_sequence, marc, marcxml,
1264 record_type, encoding, z3950random)
1265 VALUES (?, ?, ?, ?, ?, ?, ?)");
1266 $sth->execute($batch_id, $record_sequence, $marc_record->as_usmarc(), $marc_record->as_xml(),
1267 $record_type, $encoding, $z3950random);
1268 my $import_record_id = $dbh->{'mysql_insertid'};
1270 return $import_record_id;
1273 sub _update_import_record_marc {
1274 my ($import_record_id, $marc_record) = @_;
1276 my $dbh = C4::Context->dbh;
1277 my $sth = $dbh->prepare("UPDATE import_records SET marc = ?, marcxml = ?
1278 WHERE import_record_id = ?");
1279 $sth->execute($marc_record->as_usmarc(), $marc_record->as_xml(), $import_record_id);
1283 sub _add_biblio_fields {
1284 my ($import_record_id, $marc_record) = @_;
1286 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1287 my $dbh = C4::Context->dbh;
1288 # FIXME no controlnumber, originalsource
1289 $isbn = C4::Koha::_isbn_cleanup($isbn); # FIXME C4::Koha::_isbn_cleanup should be made public
1290 my $sth = $dbh->prepare("INSERT INTO import_biblios (import_record_id, title, author, isbn, issn) VALUES (?, ?, ?, ?, ?)");
1291 $sth->execute($import_record_id, $title, $author, $isbn, $issn);
1296 sub _update_biblio_fields {
1297 my ($import_record_id, $marc_record) = @_;
1299 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1300 my $dbh = C4::Context->dbh;
1301 # FIXME no controlnumber, originalsource
1302 # FIXME 2 - should regularize normalization of ISBN wherever it is done
1306 my $sth = $dbh->prepare("UPDATE import_biblios SET title = ?, author = ?, isbn = ?, issn = ?
1307 WHERE import_record_id = ?");
1308 $sth->execute($title, $author, $isbn, $issn, $import_record_id);
1312 sub _parse_biblio_fields {
1313 my ($marc_record) = @_;
1315 my $dbh = C4::Context->dbh;
1316 my $bibliofields = TransformMarcToKoha($dbh, $marc_record, '');
1317 return ($bibliofields->{'title'}, $bibliofields->{'author'}, $bibliofields->{'isbn'}, $bibliofields->{'issn'});
1321 sub _update_batch_record_counts {
1322 my ($batch_id) = @_;
1324 my $dbh = C4::Context->dbh;
1325 my $sth = $dbh->prepare_cached("UPDATE import_batches SET num_biblios = (
1328 WHERE import_batch_id = import_batches.import_batch_id
1329 AND record_type = 'biblio')
1330 WHERE import_batch_id = ?");
1331 $sth->bind_param(1, $batch_id);
1334 $sth = $dbh->prepare_cached("UPDATE import_batches SET num_items = (
1337 JOIN import_items USING (import_record_id)
1338 WHERE import_batch_id = import_batches.import_batch_id
1339 AND record_type = 'biblio')
1340 WHERE import_batch_id = ?");
1341 $sth->bind_param(1, $batch_id);
1347 sub _get_commit_action {
1348 my ($overlay_action, $nomatch_action, $item_action, $overlay_status, $import_record_id) = @_;
1350 my ($bib_result, $bib_match, $item_result);
1352 if ($overlay_status ne 'no_match') {
1353 $bib_match = GetBestRecordMatch($import_record_id);
1354 if ($overlay_action eq 'replace') {
1355 $bib_result = defined($bib_match) ? 'replace' : 'create_new';
1356 } elsif ($overlay_action eq 'create_new') {
1357 $bib_result = 'create_new';
1358 } elsif ($overlay_action eq 'ignore') {
1359 $bib_result = 'ignore';
1361 $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_matches') ? 'create_new' : 'ignore';
1363 $bib_result = $nomatch_action;
1364 $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_new') ? 'create_new' : 'ignore';
1367 return ($bib_result, $item_result, $bib_match);
1370 sub _get_revert_action {
1371 my ($overlay_action, $overlay_status, $status) = @_;
1375 if ($status eq 'ignored') {
1376 $bib_result = 'ignore';
1378 if ($overlay_action eq 'create_new') {
1379 $bib_result = 'delete';
1381 $bib_result = ($overlay_status eq 'match_applied') ? 'restore' : 'delete';
1392 Koha Development Team <info@koha.org>
1394 Galen Charlton <galen.charlton@liblime.com>