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();
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 $sth = $dbh->prepare_cached("SELECT * FROM import_batches
775 WHERE batch_type = 'batch'
776 ORDER BY import_batch_id DESC
778 $sth->bind_param(1, $results_per_group);
779 $sth->bind_param(2, $offset);
783 while (my $row = $sth->fetchrow_hashref) {
784 push @$results, $row;
790 =head2 GetItemNumbersFromImportBatch
794 sub GetItemNumbersFromImportBatch {
796 my $dbh = C4::Context->dbh;
797 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=?");
798 $sth->execute($batch_id);
800 while ( my ($itm) = $sth->fetchrow_array ) {
806 =head2 GetNumberOfImportBatches
810 my $count = GetNumberOfImportBatches();
816 sub GetNumberOfNonZ3950ImportBatches {
817 my $dbh = C4::Context->dbh;
818 my $sth = $dbh->prepare("SELECT COUNT(*) FROM import_batches WHERE batch_type='batch'");
820 my ($count) = $sth->fetchrow_array();
825 =head2 GetImportBibliosRange
829 my $results = GetImportBibliosRange($batch_id, $offset, $results_per_group);
833 Returns a reference to an array of hash references corresponding to
834 import_biblios/import_records rows for a given batch
835 starting at the given offset.
839 sub GetImportBibliosRange {
840 my ($batch_id, $offset, $results_per_group) = @_;
842 my $dbh = C4::Context->dbh;
843 my $sth = $dbh->prepare_cached("SELECT title, author, isbn, issn, import_record_id, record_sequence,
844 matched_biblionumber, status, overlay_status
846 JOIN import_biblios USING (import_record_id)
847 WHERE import_batch_id = ?
848 ORDER BY import_record_id LIMIT ? OFFSET ?");
849 $sth->bind_param(1, $batch_id);
850 $sth->bind_param(2, $results_per_group);
851 $sth->bind_param(3, $offset);
854 while (my $row = $sth->fetchrow_hashref) {
855 push @$results, $row;
862 =head2 GetBestRecordMatch
866 my $record_id = GetBestRecordMatch($import_record_id);
872 sub GetBestRecordMatch {
873 my ($import_record_id) = @_;
875 my $dbh = C4::Context->dbh;
876 my $sth = $dbh->prepare("SELECT candidate_match_id
877 FROM import_record_matches
878 WHERE import_record_id = ?
879 ORDER BY score DESC, candidate_match_id DESC");
880 $sth->execute($import_record_id);
881 my ($record_id) = $sth->fetchrow_array();
886 =head2 GetImportBatchStatus
890 my $status = GetImportBatchStatus($batch_id);
896 sub GetImportBatchStatus {
899 my $dbh = C4::Context->dbh;
900 my $sth = $dbh->prepare("SELECT import_status FROM import_batches WHERE import_batch_id = ?");
901 $sth->execute($batch_id);
902 my ($status) = $sth->fetchrow_array();
908 =head2 SetImportBatchStatus
912 SetImportBatchStatus($batch_id, $new_status);
918 sub SetImportBatchStatus {
919 my ($batch_id, $new_status) = @_;
921 my $dbh = C4::Context->dbh;
922 my $sth = $dbh->prepare("UPDATE import_batches SET import_status = ? WHERE import_batch_id = ?");
923 $sth->execute($new_status, $batch_id);
928 =head2 GetImportBatchOverlayAction
932 my $overlay_action = GetImportBatchOverlayAction($batch_id);
938 sub GetImportBatchOverlayAction {
941 my $dbh = C4::Context->dbh;
942 my $sth = $dbh->prepare("SELECT overlay_action FROM import_batches WHERE import_batch_id = ?");
943 $sth->execute($batch_id);
944 my ($overlay_action) = $sth->fetchrow_array();
946 return $overlay_action;
951 =head2 SetImportBatchOverlayAction
955 SetImportBatchOverlayAction($batch_id, $new_overlay_action);
961 sub SetImportBatchOverlayAction {
962 my ($batch_id, $new_overlay_action) = @_;
964 my $dbh = C4::Context->dbh;
965 my $sth = $dbh->prepare("UPDATE import_batches SET overlay_action = ? WHERE import_batch_id = ?");
966 $sth->execute($new_overlay_action, $batch_id);
971 =head2 GetImportBatchNoMatchAction
975 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
981 sub GetImportBatchNoMatchAction {
984 my $dbh = C4::Context->dbh;
985 my $sth = $dbh->prepare("SELECT nomatch_action FROM import_batches WHERE import_batch_id = ?");
986 $sth->execute($batch_id);
987 my ($nomatch_action) = $sth->fetchrow_array();
989 return $nomatch_action;
994 =head2 SetImportBatchNoMatchAction
998 SetImportBatchNoMatchAction($batch_id, $new_nomatch_action);
1004 sub SetImportBatchNoMatchAction {
1005 my ($batch_id, $new_nomatch_action) = @_;
1007 my $dbh = C4::Context->dbh;
1008 my $sth = $dbh->prepare("UPDATE import_batches SET nomatch_action = ? WHERE import_batch_id = ?");
1009 $sth->execute($new_nomatch_action, $batch_id);
1014 =head2 GetImportBatchItemAction
1018 my $item_action = GetImportBatchItemAction($batch_id);
1024 sub GetImportBatchItemAction {
1025 my ($batch_id) = @_;
1027 my $dbh = C4::Context->dbh;
1028 my $sth = $dbh->prepare("SELECT item_action FROM import_batches WHERE import_batch_id = ?");
1029 $sth->execute($batch_id);
1030 my ($item_action) = $sth->fetchrow_array();
1032 return $item_action;
1037 =head2 SetImportBatchItemAction
1041 SetImportBatchItemAction($batch_id, $new_item_action);
1047 sub SetImportBatchItemAction {
1048 my ($batch_id, $new_item_action) = @_;
1050 my $dbh = C4::Context->dbh;
1051 my $sth = $dbh->prepare("UPDATE import_batches SET item_action = ? WHERE import_batch_id = ?");
1052 $sth->execute($new_item_action, $batch_id);
1057 =head2 GetImportBatchMatcher
1061 my $matcher_id = GetImportBatchMatcher($batch_id);
1067 sub GetImportBatchMatcher {
1068 my ($batch_id) = @_;
1070 my $dbh = C4::Context->dbh;
1071 my $sth = $dbh->prepare("SELECT matcher_id FROM import_batches WHERE import_batch_id = ?");
1072 $sth->execute($batch_id);
1073 my ($matcher_id) = $sth->fetchrow_array();
1080 =head2 SetImportBatchMatcher
1084 SetImportBatchMatcher($batch_id, $new_matcher_id);
1090 sub SetImportBatchMatcher {
1091 my ($batch_id, $new_matcher_id) = @_;
1093 my $dbh = C4::Context->dbh;
1094 my $sth = $dbh->prepare("UPDATE import_batches SET matcher_id = ? WHERE import_batch_id = ?");
1095 $sth->execute($new_matcher_id, $batch_id);
1100 =head2 GetImportRecordOverlayStatus
1104 my $overlay_status = GetImportRecordOverlayStatus($import_record_id);
1110 sub GetImportRecordOverlayStatus {
1111 my ($import_record_id) = @_;
1113 my $dbh = C4::Context->dbh;
1114 my $sth = $dbh->prepare("SELECT overlay_status FROM import_records WHERE import_record_id = ?");
1115 $sth->execute($import_record_id);
1116 my ($overlay_status) = $sth->fetchrow_array();
1118 return $overlay_status;
1123 =head2 SetImportRecordOverlayStatus
1127 SetImportRecordOverlayStatus($import_record_id, $new_overlay_status);
1133 sub SetImportRecordOverlayStatus {
1134 my ($import_record_id, $new_overlay_status) = @_;
1136 my $dbh = C4::Context->dbh;
1137 my $sth = $dbh->prepare("UPDATE import_records SET overlay_status = ? WHERE import_record_id = ?");
1138 $sth->execute($new_overlay_status, $import_record_id);
1143 =head2 GetImportRecordStatus
1147 my $overlay_status = GetImportRecordStatus($import_record_id);
1153 sub GetImportRecordStatus {
1154 my ($import_record_id) = @_;
1156 my $dbh = C4::Context->dbh;
1157 my $sth = $dbh->prepare("SELECT status FROM import_records WHERE import_record_id = ?");
1158 $sth->execute($import_record_id);
1159 my ($overlay_status) = $sth->fetchrow_array();
1161 return $overlay_status;
1166 =head2 SetImportRecordStatus
1170 SetImportRecordStatus($import_record_id, $new_overlay_status);
1176 sub SetImportRecordStatus {
1177 my ($import_record_id, $new_overlay_status) = @_;
1179 my $dbh = C4::Context->dbh;
1180 my $sth = $dbh->prepare("UPDATE import_records SET status = ? WHERE import_record_id = ?");
1181 $sth->execute($new_overlay_status, $import_record_id);
1186 =head2 GetImportRecordMatches
1190 my $results = GetImportRecordMatches($import_record_id, $best_only);
1196 sub GetImportRecordMatches {
1197 my $import_record_id = shift;
1198 my $best_only = @_ ? shift : 0;
1200 my $dbh = C4::Context->dbh;
1201 # FIXME currently biblio only
1202 my $sth = $dbh->prepare_cached("SELECT title, author, biblionumber, score
1204 JOIN import_record_matches USING (import_record_id)
1205 JOIN biblio ON (biblionumber = candidate_match_id)
1206 WHERE import_record_id = ?
1207 ORDER BY score DESC, biblionumber DESC");
1208 $sth->bind_param(1, $import_record_id);
1211 while (my $row = $sth->fetchrow_hashref) {
1212 push @$results, $row;
1222 =head2 SetImportRecordMatches
1226 SetImportRecordMatches($import_record_id, @matches);
1232 sub SetImportRecordMatches {
1233 my $import_record_id = shift;
1236 my $dbh = C4::Context->dbh;
1237 my $delsth = $dbh->prepare("DELETE FROM import_record_matches WHERE import_record_id = ?");
1238 $delsth->execute($import_record_id);
1241 my $sth = $dbh->prepare("INSERT INTO import_record_matches (import_record_id, candidate_match_id, score)
1243 foreach my $match (@matches) {
1244 $sth->execute($import_record_id, $match->{'record_id'}, $match->{'score'});
1249 # internal functions
1251 sub _create_import_record {
1252 my ($batch_id, $record_sequence, $marc_record, $record_type, $encoding, $z3950random) = @_;
1254 my $dbh = C4::Context->dbh;
1255 my $sth = $dbh->prepare("INSERT INTO import_records (import_batch_id, record_sequence, marc, marcxml,
1256 record_type, encoding, z3950random)
1257 VALUES (?, ?, ?, ?, ?, ?, ?)");
1258 $sth->execute($batch_id, $record_sequence, $marc_record->as_usmarc(), $marc_record->as_xml(),
1259 $record_type, $encoding, $z3950random);
1260 my $import_record_id = $dbh->{'mysql_insertid'};
1262 return $import_record_id;
1265 sub _update_import_record_marc {
1266 my ($import_record_id, $marc_record) = @_;
1268 my $dbh = C4::Context->dbh;
1269 my $sth = $dbh->prepare("UPDATE import_records SET marc = ?, marcxml = ?
1270 WHERE import_record_id = ?");
1271 $sth->execute($marc_record->as_usmarc(), $marc_record->as_xml(), $import_record_id);
1275 sub _add_biblio_fields {
1276 my ($import_record_id, $marc_record) = @_;
1278 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1279 my $dbh = C4::Context->dbh;
1280 # FIXME no controlnumber, originalsource
1281 $isbn = C4::Koha::_isbn_cleanup($isbn); # FIXME C4::Koha::_isbn_cleanup should be made public
1282 my $sth = $dbh->prepare("INSERT INTO import_biblios (import_record_id, title, author, isbn, issn) VALUES (?, ?, ?, ?, ?)");
1283 $sth->execute($import_record_id, $title, $author, $isbn, $issn);
1288 sub _update_biblio_fields {
1289 my ($import_record_id, $marc_record) = @_;
1291 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1292 my $dbh = C4::Context->dbh;
1293 # FIXME no controlnumber, originalsource
1294 # FIXME 2 - should regularize normalization of ISBN wherever it is done
1298 my $sth = $dbh->prepare("UPDATE import_biblios SET title = ?, author = ?, isbn = ?, issn = ?
1299 WHERE import_record_id = ?");
1300 $sth->execute($title, $author, $isbn, $issn, $import_record_id);
1304 sub _parse_biblio_fields {
1305 my ($marc_record) = @_;
1307 my $dbh = C4::Context->dbh;
1308 my $bibliofields = TransformMarcToKoha($dbh, $marc_record, '');
1309 return ($bibliofields->{'title'}, $bibliofields->{'author'}, $bibliofields->{'isbn'}, $bibliofields->{'issn'});
1313 sub _update_batch_record_counts {
1314 my ($batch_id) = @_;
1316 my $dbh = C4::Context->dbh;
1317 my $sth = $dbh->prepare_cached("UPDATE import_batches SET num_biblios = (
1320 WHERE import_batch_id = import_batches.import_batch_id
1321 AND record_type = 'biblio')
1322 WHERE import_batch_id = ?");
1323 $sth->bind_param(1, $batch_id);
1326 $sth = $dbh->prepare_cached("UPDATE import_batches SET num_items = (
1329 JOIN import_items USING (import_record_id)
1330 WHERE import_batch_id = import_batches.import_batch_id
1331 AND record_type = 'biblio')
1332 WHERE import_batch_id = ?");
1333 $sth->bind_param(1, $batch_id);
1339 sub _get_commit_action {
1340 my ($overlay_action, $nomatch_action, $item_action, $overlay_status, $import_record_id) = @_;
1342 my ($bib_result, $bib_match, $item_result);
1344 if ($overlay_status ne 'no_match') {
1345 $bib_match = GetBestRecordMatch($import_record_id);
1346 if ($overlay_action eq 'replace') {
1347 $bib_result = defined($bib_match) ? 'replace' : 'create_new';
1348 } elsif ($overlay_action eq 'create_new') {
1349 $bib_result = 'create_new';
1350 } elsif ($overlay_action eq 'ignore') {
1351 $bib_result = 'ignore';
1353 $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_matches') ? 'create_new' : 'ignore';
1355 $bib_result = $nomatch_action;
1356 $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_new') ? 'create_new' : 'ignore';
1359 return ($bib_result, $item_result, $bib_match);
1362 sub _get_revert_action {
1363 my ($overlay_action, $overlay_status, $status) = @_;
1367 if ($status eq 'ignored') {
1368 $bib_result = 'ignore';
1370 if ($overlay_action eq 'create_new') {
1371 $bib_result = 'delete';
1373 $bib_result = ($overlay_status eq 'match_applied') ? 'restore' : 'delete';
1384 Koha Development Team <info@koha.org>
1386 Galen Charlton <galen.charlton@liblime.com>