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
49 GetImportBatchRangeDesc
50 GetNumberOfNonZ3950ImportBatches
52 GetItemNumbersFromImportBatch
56 GetImportBatchOverlayAction
57 SetImportBatchOverlayAction
58 GetImportBatchNoMatchAction
59 SetImportBatchNoMatchAction
60 GetImportBatchItemAction
61 SetImportBatchItemAction
64 GetImportRecordOverlayStatus
65 SetImportRecordOverlayStatus
68 GetImportRecordMatches
69 SetImportRecordMatches
75 C4::ImportBatch - manage batches of imported MARC records
87 =head2 GetZ3950BatchId
91 my $batchid = GetZ3950BatchId($z3950server);
95 Retrieves the ID of the import batch for the Z39.50
96 reservoir for the given target. If necessary,
97 creates the import batch.
101 sub GetZ3950BatchId {
102 my ($z3950server) = @_;
104 my $dbh = C4::Context->dbh;
105 my $sth = $dbh->prepare("SELECT import_batch_id FROM import_batches
106 WHERE batch_type = 'z3950'
108 $sth->execute($z3950server);
109 my $rowref = $sth->fetchrow_arrayref();
111 if (defined $rowref) {
114 my $batch_id = AddImportBatch('create_new', 'staged', 'z3950', $z3950server, '');
120 =head2 GetImportRecordMarc
124 my ($marcblob, $encoding) = GetImportRecordMarc($import_record_id);
130 sub GetImportRecordMarc {
131 my ($import_record_id) = @_;
133 my $dbh = C4::Context->dbh;
134 my $sth = $dbh->prepare("SELECT marc, encoding FROM import_records WHERE import_record_id = ?");
135 $sth->execute($import_record_id);
136 my ($marc, $encoding) = $sth->fetchrow();
142 =head2 AddImportBatch
146 my $batch_id = AddImportBatch($overlay_action, $import_status, $type, $file_name, $comments);
153 my ($overlay_action, $import_status, $type, $file_name, $comments) = @_;
155 my $dbh = C4::Context->dbh;
156 my $sth = $dbh->prepare("INSERT INTO import_batches (overlay_action, import_status, batch_type,
158 VALUES (?, ?, ?, ?, ?)");
159 $sth->execute($overlay_action, $import_status, $type, $file_name, $comments);
160 my $batch_id = $dbh->{'mysql_insertid'};
167 =head2 GetImportBatch
171 my $row = GetImportBatch($batch_id);
175 Retrieve a hashref of an import_batches row.
182 my $dbh = C4::Context->dbh;
183 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches WHERE import_batch_id = ?");
184 $sth->bind_param(1, $batch_id);
186 my $result = $sth->fetchrow_hashref;
192 =head2 AddBiblioToBatch
196 my $import_record_id = AddBiblioToBatch($batch_id, $record_sequence, $marc_record, $encoding, $z3950random, $update_counts);
202 sub AddBiblioToBatch {
203 my $batch_id = shift;
204 my $record_sequence = shift;
205 my $marc_record = shift;
206 my $encoding = shift;
207 my $z3950random = shift;
208 my $update_counts = @_ ? shift : 1;
210 my $import_record_id = _create_import_record($batch_id, $record_sequence, $marc_record, 'biblio', $encoding, $z3950random);
211 _add_biblio_fields($import_record_id, $marc_record);
212 _update_batch_record_counts($batch_id) if $update_counts;
213 return $import_record_id;
216 =head2 ModBiblioInBatch
220 ModBiblioInBatch($import_record_id, $marc_record);
226 sub ModBiblioInBatch {
227 my ($import_record_id, $marc_record) = @_;
229 _update_import_record_marc($import_record_id, $marc_record);
230 _update_biblio_fields($import_record_id, $marc_record);
234 =head2 BatchStageMarcRecords
238 ($batch_id, $num_records, $num_items, @invalid_records) =
239 BatchStageMarcRecords($marc_flavor, $marc_records, $file_name,
240 $comments, $branch_code, $parse_items,
242 $progress_interval, $progress_callback);
248 sub BatchStageMarcRecords {
249 my $marc_flavor = shift;
250 my $marc_records = shift;
251 my $file_name = shift;
252 my $comments = shift;
253 my $branch_code = shift;
254 my $parse_items = shift;
255 my $leave_as_staging = shift;
257 # optional callback to monitor status
259 my $progress_interval = 0;
260 my $progress_callback = undef;
262 $progress_interval = shift;
263 $progress_callback = shift;
264 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
265 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
268 my $batch_id = AddImportBatch('create_new', 'staging', 'batch', $file_name, $comments);
270 SetImportBatchItemAction($batch_id, 'always_add');
272 SetImportBatchItemAction($batch_id, 'ignore');
275 my @invalid_records = ();
278 # FIXME - for now, we're dealing only with bibs
280 foreach my $marc_blob (split(/\x1D/, $marc_records)) {
281 $marc_blob =~ s/^\s+//g;
282 $marc_blob =~ s/\s+$//g;
283 next unless $marc_blob;
285 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
286 &$progress_callback($rec_num);
288 my ($marc_record, $charset_guessed, $char_errors) =
289 MarcToUTF8Record($marc_blob, C4::Context->preference("marcflavour"));
290 my $import_record_id;
291 if (scalar($marc_record->fields()) == 0) {
292 push @invalid_records, $marc_blob;
295 $import_record_id = AddBiblioToBatch($batch_id, $rec_num, $marc_record, $marc_flavor, int(rand(99999)), 0);
297 my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, 0);
298 $num_items += scalar(@import_items_ids);
302 unless ($leave_as_staging) {
303 SetImportBatchStatus($batch_id, 'staged');
305 # FIXME branch_code, number of bibs, number of items
306 _update_batch_record_counts($batch_id);
307 return ($batch_id, $num_valid, $num_items, @invalid_records);
310 =head2 AddItemsToImportBiblio
314 my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, $update_counts);
320 sub AddItemsToImportBiblio {
321 my $batch_id = shift;
322 my $import_record_id = shift;
323 my $marc_record = shift;
324 my $update_counts = @_ ? shift : 0;
326 my @import_items_ids = ();
328 my $dbh = C4::Context->dbh;
329 my ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",'');
330 foreach my $item_field ($marc_record->field($item_tag)) {
331 my $item_marc = MARC::Record->new();
332 $item_marc->leader("00000 a "); # must set Leader/09 to 'a'
333 $item_marc->append_fields($item_field);
334 $marc_record->delete_field($item_field);
335 my $sth = $dbh->prepare_cached("INSERT INTO import_items (import_record_id, status, marcxml)
337 $sth->bind_param(1, $import_record_id);
338 $sth->bind_param(2, 'staged');
339 $sth->bind_param(3, $item_marc->as_xml());
341 push @import_items_ids, $dbh->{'mysql_insertid'};
345 if ($#import_items_ids > -1) {
346 _update_batch_record_counts($batch_id) if $update_counts;
347 _update_import_record_marc($import_record_id, $marc_record);
349 return @import_items_ids;
352 =head2 BatchFindBibDuplicates
356 my $num_with_matches = BatchFindBibDuplicates($batch_id, $matcher, $max_matches, $progress_interval, $progress_callback);
360 Goes through the records loaded in the batch and attempts to
361 find duplicates for each one. Sets the matching status
362 of each record to "no_match" or "auto_match" as appropriate.
364 The $max_matches parameter is optional; if it is not supplied,
367 The $progress_interval and $progress_callback parameters are
368 optional; if both are supplied, the sub referred to by
369 $progress_callback will be invoked every $progress_interval
370 records using the number of records processed as the
375 sub BatchFindBibDuplicates {
376 my $batch_id = shift;
378 my $max_matches = @_ ? shift : 10;
380 # optional callback to monitor status
382 my $progress_interval = 0;
383 my $progress_callback = undef;
385 $progress_interval = shift;
386 $progress_callback = shift;
387 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
388 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
391 my $dbh = C4::Context->dbh;
393 my $sth = $dbh->prepare("SELECT import_record_id, marc
395 JOIN import_biblios USING (import_record_id)
396 WHERE import_batch_id = ?");
397 $sth->execute($batch_id);
398 my $num_with_matches = 0;
400 while (my $rowref = $sth->fetchrow_hashref) {
402 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
403 &$progress_callback($rec_num);
405 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
407 if (defined $matcher) {
408 @matches = $matcher->get_matches($marc_record, $max_matches);
410 if (scalar(@matches) > 0) {
412 SetImportRecordMatches($rowref->{'import_record_id'}, @matches);
413 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'auto_match');
415 SetImportRecordMatches($rowref->{'import_record_id'}, ());
416 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'no_match');
420 return $num_with_matches;
423 =head2 BatchCommitBibRecords
427 my ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored) =
428 BatchCommitBibRecords($batch_id, $progress_interval, $progress_callback);
434 sub BatchCommitBibRecords {
435 my $batch_id = shift;
437 # optional callback to monitor status
439 my $progress_interval = 0;
440 my $progress_callback = undef;
442 $progress_interval = shift;
443 $progress_callback = shift;
444 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
445 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
450 my $num_items_added = 0;
451 my $num_items_errored = 0;
453 # commit (i.e., save, all records in the batch)
454 # FIXME biblio only at the moment
455 SetImportBatchStatus('importing');
456 my $overlay_action = GetImportBatchOverlayAction($batch_id);
457 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
458 my $item_action = GetImportBatchItemAction($batch_id);
459 my $dbh = C4::Context->dbh;
460 my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marc, encoding
462 JOIN import_biblios USING (import_record_id)
463 WHERE import_batch_id = ?");
464 $sth->execute($batch_id);
466 while (my $rowref = $sth->fetchrow_hashref) {
468 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
469 &$progress_callback($rec_num);
471 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'imported') {
476 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
478 # remove any item tags - rely on BatchCommitItems
479 my ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",'');
480 foreach my $item_field ($marc_record->field($item_tag)) {
481 $marc_record->delete_field($item_field);
484 # decide what what to do with the bib and item records
485 my ($bib_result, $item_result, $bib_match) =
486 _get_commit_action($overlay_action, $nomatch_action, $item_action,
487 $rowref->{'overlay_status'}, $rowref->{'import_record_id'});
489 if ($bib_result eq 'create_new') {
491 my ($biblionumber, $biblioitemnumber) = AddBiblio($marc_record, '');
492 my $sth = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
493 $sth->execute($biblionumber, $rowref->{'import_record_id'});
495 if ($item_result eq 'create_new') {
496 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
497 $num_items_added += $bib_items_added;
498 $num_items_errored += $bib_items_errored;
500 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
501 } elsif ($bib_result eq 'replace') {
503 my $biblionumber = $bib_match;
504 my ($count, $oldbiblio) = GetBiblio($biblionumber);
505 my $oldxml = GetXmlBiblio($biblionumber);
507 # remove item fields so that they don't get
508 # added again if record is reverted
509 my $old_marc = MARC::Record->new_from_xml(StripNonXmlChars($oldxml), 'UTF-8', $rowref->{'encoding'});
510 foreach my $item_field ($old_marc->field($item_tag)) {
511 $old_marc->delete_field($item_field);
514 ModBiblio($marc_record, $biblionumber, $oldbiblio->{'frameworkcode'});
515 my $sth = $dbh->prepare_cached("UPDATE import_records SET marcxml_old = ? WHERE import_record_id = ?");
516 $sth->execute($old_marc->as_xml(), $rowref->{'import_record_id'});
518 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
519 $sth2->execute($biblionumber, $rowref->{'import_record_id'});
521 if ($item_result eq 'create_new') {
522 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
523 $num_items_added += $bib_items_added;
524 $num_items_errored += $bib_items_errored;
526 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
527 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
528 } elsif ($bib_result eq 'ignore') {
530 my $biblionumber = $bib_match;
531 if (defined $biblionumber and $item_result eq 'create_new') {
532 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
533 $num_items_added += $bib_items_added;
534 $num_items_errored += $bib_items_errored;
535 # still need to record the matched biblionumber so that the
536 # items can be reverted
537 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
538 $sth2->execute($biblionumber, $rowref->{'import_record_id'});
539 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
541 SetImportRecordStatus($rowref->{'import_record_id'}, 'ignored');
545 SetImportBatchStatus($batch_id, 'imported');
546 return ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored);
549 =head2 BatchCommitItems
553 ($num_items_added, $num_items_errored) = BatchCommitItems($import_record_id, $biblionumber);
559 sub BatchCommitItems {
560 my ($import_record_id, $biblionumber) = @_;
562 my $dbh = C4::Context->dbh;
564 my $num_items_added = 0;
565 my $num_items_errored = 0;
566 my $sth = $dbh->prepare("SELECT import_items_id, import_items.marcxml, encoding
568 JOIN import_records USING (import_record_id)
569 WHERE import_record_id = ?
570 ORDER BY import_items_id");
571 $sth->bind_param(1, $import_record_id);
573 while (my $row = $sth->fetchrow_hashref()) {
574 my $item_marc = MARC::Record->new_from_xml(StripNonXmlChars($row->{'marcxml'}), 'UTF-8', $row->{'encoding'});
575 # FIXME - duplicate barcode check needs to become part of AddItemFromMarc()
576 my $item = TransformMarcToKoha($dbh, $item_marc);
577 my $duplicate_barcode = exists($item->{'barcode'}) && GetItemnumberFromBarcode($item->{'barcode'});
578 if ($duplicate_barcode) {
579 my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, import_error = ? WHERE import_items_id = ?");
580 $updsth->bind_param(1, 'error');
581 $updsth->bind_param(2, 'duplicate item barcode');
582 $updsth->bind_param(3, $row->{'import_items_id'});
584 $num_items_errored++;
586 my ($item_biblionumber, $biblioitemnumber, $itemnumber) = AddItemFromMarc($item_marc, $biblionumber);
587 my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, itemnumber = ? WHERE import_items_id = ?");
588 $updsth->bind_param(1, 'imported');
589 $updsth->bind_param(2, $itemnumber);
590 $updsth->bind_param(3, $row->{'import_items_id'});
597 return ($num_items_added, $num_items_errored);
600 =head2 BatchRevertBibRecords
604 my ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored) = BatchRevertBibRecords($batch_id);
610 sub BatchRevertBibRecords {
611 my $batch_id = shift;
615 my $num_reverted = 0;
616 my $num_items_deleted = 0;
618 # commit (i.e., save, all records in the batch)
619 # FIXME biblio only at the moment
620 SetImportBatchStatus('reverting');
621 my $overlay_action = GetImportBatchOverlayAction($batch_id);
622 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
623 my $dbh = C4::Context->dbh;
624 my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marcxml_old, encoding, matched_biblionumber
626 JOIN import_biblios USING (import_record_id)
627 WHERE import_batch_id = ?");
628 $sth->execute($batch_id);
629 while (my $rowref = $sth->fetchrow_hashref) {
630 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'reverted') {
635 my $bib_result = _get_revert_action($overlay_action, $rowref->{'overlay_status'}, $rowref->{'status'});
637 if ($bib_result eq 'delete') {
638 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
639 my $error = DelBiblio($rowref->{'matched_biblionumber'});
640 if (defined $error) {
644 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
646 } elsif ($bib_result eq 'restore') {
648 my $old_record = MARC::Record->new_from_xml(StripNonXmlChars($rowref->{'marcxml_old'}), 'UTF-8', $rowref->{'encoding'});
649 my $biblionumber = $rowref->{'matched_biblionumber'};
650 my ($count, $oldbiblio) = GetBiblio($biblionumber);
651 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
652 ModBiblio($old_record, $biblionumber, $oldbiblio->{'frameworkcode'});
653 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
654 } elsif ($bib_result eq 'ignore') {
655 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
656 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
658 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = NULL WHERE import_record_id = ?");
659 $sth2->execute($rowref->{'import_record_id'});
663 SetImportBatchStatus($batch_id, 'reverted');
664 return ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored);
667 =head2 BatchRevertItems
671 my $num_items_deleted = BatchRevertItems($import_record_id, $biblionumber);
677 sub BatchRevertItems {
678 my ($import_record_id, $biblionumber) = @_;
680 my $dbh = C4::Context->dbh;
681 my $num_items_deleted = 0;
683 my $sth = $dbh->prepare_cached("SELECT import_items_id, itemnumber
685 JOIN items USING (itemnumber)
686 WHERE import_record_id = ?");
687 $sth->bind_param(1, $import_record_id);
689 while (my $row = $sth->fetchrow_hashref()) {
690 DelItem($dbh, $biblionumber, $row->{'itemnumber'});
691 my $updsth = $dbh->prepare("UPDATE import_items SET status = ? WHERE import_items_id = ?");
692 $updsth->bind_param(1, 'reverted');
693 $updsth->bind_param(2, $row->{'import_items_id'});
696 $num_items_deleted++;
699 return $num_items_deleted;
706 CleanBatch($batch_id)
710 Deletes all staged records from the import batch
711 and sets the status of the batch to 'cleaned'. Note
712 that deleting a stage record does *not* affect
713 any record that has been committed to the database.
718 my $batch_id = shift;
719 return unless defined $batch_id;
721 C4::Context->dbh->do('DELETE FROM import_records WHERE import_batch_id = ?', {}, $batch_id);
722 SetImportBatchStatus($batch_id, 'cleaned');
725 =head2 GetAllImportBatches
729 my $results = GetAllImportBatches();
733 Returns a references to an array of hash references corresponding
734 to all import_batches rows (of batch_type 'batch'), sorted in
735 ascending order by import_batch_id.
739 sub GetAllImportBatches {
740 my $dbh = C4::Context->dbh;
741 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches
742 WHERE batch_type = 'batch'
743 ORDER BY import_batch_id ASC");
747 while (my $row = $sth->fetchrow_hashref) {
748 push @$results, $row;
754 =head2 GetImportBatchRangeDesc
758 my $results = GetImportBatchRangeDesc($offset, $results_per_group);
762 Returns a reference to an array of hash references corresponding to
763 import_batches rows (sorted in descending order by import_batch_id)
764 start at the given offset.
768 sub GetImportBatchRangeDesc {
769 my ($offset, $results_per_group) = @_;
771 my $dbh = C4::Context->dbh;
772 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches
773 WHERE batch_type = 'batch'
774 ORDER BY import_batch_id DESC
776 $sth->bind_param(1, $results_per_group);
777 $sth->bind_param(2, $offset);
781 while (my $row = $sth->fetchrow_hashref) {
782 push @$results, $row;
788 =head2 GetItemNumbersFromImportBatch
792 sub GetItemNumbersFromImportBatch {
794 my $dbh = C4::Context->dbh;
795 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=?");
796 $sth->execute($batch_id);
798 while ( my ($itm) = $sth->fetchrow_array ) {
804 =head2 GetNumberOfImportBatches
808 my $count = GetNumberOfImportBatches();
814 sub GetNumberOfNonZ3950ImportBatches {
815 my $dbh = C4::Context->dbh;
816 my $sth = $dbh->prepare("SELECT COUNT(*) FROM import_batches WHERE batch_type='batch'");
818 my ($count) = $sth->fetchrow_array();
823 =head2 GetImportBibliosRange
827 my $results = GetImportBibliosRange($batch_id, $offset, $results_per_group);
831 Returns a reference to an array of hash references corresponding to
832 import_biblios/import_records rows for a given batch
833 starting at the given offset.
837 sub GetImportBibliosRange {
838 my ($batch_id, $offset, $results_per_group) = @_;
840 my $dbh = C4::Context->dbh;
841 my $sth = $dbh->prepare_cached("SELECT title, author, isbn, issn, import_record_id, record_sequence,
842 matched_biblionumber, status, overlay_status
844 JOIN import_biblios USING (import_record_id)
845 WHERE import_batch_id = ?
846 ORDER BY import_record_id LIMIT ? OFFSET ?");
847 $sth->bind_param(1, $batch_id);
848 $sth->bind_param(2, $results_per_group);
849 $sth->bind_param(3, $offset);
852 while (my $row = $sth->fetchrow_hashref) {
853 push @$results, $row;
860 =head2 GetBestRecordMatch
864 my $record_id = GetBestRecordMatch($import_record_id);
870 sub GetBestRecordMatch {
871 my ($import_record_id) = @_;
873 my $dbh = C4::Context->dbh;
874 my $sth = $dbh->prepare("SELECT candidate_match_id
875 FROM import_record_matches
876 WHERE import_record_id = ?
877 ORDER BY score DESC, candidate_match_id DESC");
878 $sth->execute($import_record_id);
879 my ($record_id) = $sth->fetchrow_array();
884 =head2 GetImportBatchStatus
888 my $status = GetImportBatchStatus($batch_id);
894 sub GetImportBatchStatus {
897 my $dbh = C4::Context->dbh;
898 my $sth = $dbh->prepare("SELECT import_status FROM import_batches WHERE import_batch_id = ?");
899 $sth->execute($batch_id);
900 my ($status) = $sth->fetchrow_array();
906 =head2 SetImportBatchStatus
910 SetImportBatchStatus($batch_id, $new_status);
916 sub SetImportBatchStatus {
917 my ($batch_id, $new_status) = @_;
919 my $dbh = C4::Context->dbh;
920 my $sth = $dbh->prepare("UPDATE import_batches SET import_status = ? WHERE import_batch_id = ?");
921 $sth->execute($new_status, $batch_id);
926 =head2 GetImportBatchOverlayAction
930 my $overlay_action = GetImportBatchOverlayAction($batch_id);
936 sub GetImportBatchOverlayAction {
939 my $dbh = C4::Context->dbh;
940 my $sth = $dbh->prepare("SELECT overlay_action FROM import_batches WHERE import_batch_id = ?");
941 $sth->execute($batch_id);
942 my ($overlay_action) = $sth->fetchrow_array();
944 return $overlay_action;
949 =head2 SetImportBatchOverlayAction
953 SetImportBatchOverlayAction($batch_id, $new_overlay_action);
959 sub SetImportBatchOverlayAction {
960 my ($batch_id, $new_overlay_action) = @_;
962 my $dbh = C4::Context->dbh;
963 my $sth = $dbh->prepare("UPDATE import_batches SET overlay_action = ? WHERE import_batch_id = ?");
964 $sth->execute($new_overlay_action, $batch_id);
969 =head2 GetImportBatchNoMatchAction
973 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
979 sub GetImportBatchNoMatchAction {
982 my $dbh = C4::Context->dbh;
983 my $sth = $dbh->prepare("SELECT nomatch_action FROM import_batches WHERE import_batch_id = ?");
984 $sth->execute($batch_id);
985 my ($nomatch_action) = $sth->fetchrow_array();
987 return $nomatch_action;
992 =head2 SetImportBatchNoMatchAction
996 SetImportBatchNoMatchAction($batch_id, $new_nomatch_action);
1002 sub SetImportBatchNoMatchAction {
1003 my ($batch_id, $new_nomatch_action) = @_;
1005 my $dbh = C4::Context->dbh;
1006 my $sth = $dbh->prepare("UPDATE import_batches SET nomatch_action = ? WHERE import_batch_id = ?");
1007 $sth->execute($new_nomatch_action, $batch_id);
1012 =head2 GetImportBatchItemAction
1016 my $item_action = GetImportBatchItemAction($batch_id);
1022 sub GetImportBatchItemAction {
1023 my ($batch_id) = @_;
1025 my $dbh = C4::Context->dbh;
1026 my $sth = $dbh->prepare("SELECT item_action FROM import_batches WHERE import_batch_id = ?");
1027 $sth->execute($batch_id);
1028 my ($item_action) = $sth->fetchrow_array();
1030 return $item_action;
1035 =head2 SetImportBatchItemAction
1039 SetImportBatchItemAction($batch_id, $new_item_action);
1045 sub SetImportBatchItemAction {
1046 my ($batch_id, $new_item_action) = @_;
1048 my $dbh = C4::Context->dbh;
1049 my $sth = $dbh->prepare("UPDATE import_batches SET item_action = ? WHERE import_batch_id = ?");
1050 $sth->execute($new_item_action, $batch_id);
1055 =head2 GetImportBatchMatcher
1059 my $matcher_id = GetImportBatchMatcher($batch_id);
1065 sub GetImportBatchMatcher {
1066 my ($batch_id) = @_;
1068 my $dbh = C4::Context->dbh;
1069 my $sth = $dbh->prepare("SELECT matcher_id FROM import_batches WHERE import_batch_id = ?");
1070 $sth->execute($batch_id);
1071 my ($matcher_id) = $sth->fetchrow_array();
1078 =head2 SetImportBatchMatcher
1082 SetImportBatchMatcher($batch_id, $new_matcher_id);
1088 sub SetImportBatchMatcher {
1089 my ($batch_id, $new_matcher_id) = @_;
1091 my $dbh = C4::Context->dbh;
1092 my $sth = $dbh->prepare("UPDATE import_batches SET matcher_id = ? WHERE import_batch_id = ?");
1093 $sth->execute($new_matcher_id, $batch_id);
1098 =head2 GetImportRecordOverlayStatus
1102 my $overlay_status = GetImportRecordOverlayStatus($import_record_id);
1108 sub GetImportRecordOverlayStatus {
1109 my ($import_record_id) = @_;
1111 my $dbh = C4::Context->dbh;
1112 my $sth = $dbh->prepare("SELECT overlay_status FROM import_records WHERE import_record_id = ?");
1113 $sth->execute($import_record_id);
1114 my ($overlay_status) = $sth->fetchrow_array();
1116 return $overlay_status;
1121 =head2 SetImportRecordOverlayStatus
1125 SetImportRecordOverlayStatus($import_record_id, $new_overlay_status);
1131 sub SetImportRecordOverlayStatus {
1132 my ($import_record_id, $new_overlay_status) = @_;
1134 my $dbh = C4::Context->dbh;
1135 my $sth = $dbh->prepare("UPDATE import_records SET overlay_status = ? WHERE import_record_id = ?");
1136 $sth->execute($new_overlay_status, $import_record_id);
1141 =head2 GetImportRecordStatus
1145 my $overlay_status = GetImportRecordStatus($import_record_id);
1151 sub GetImportRecordStatus {
1152 my ($import_record_id) = @_;
1154 my $dbh = C4::Context->dbh;
1155 my $sth = $dbh->prepare("SELECT status FROM import_records WHERE import_record_id = ?");
1156 $sth->execute($import_record_id);
1157 my ($overlay_status) = $sth->fetchrow_array();
1159 return $overlay_status;
1164 =head2 SetImportRecordStatus
1168 SetImportRecordStatus($import_record_id, $new_overlay_status);
1174 sub SetImportRecordStatus {
1175 my ($import_record_id, $new_overlay_status) = @_;
1177 my $dbh = C4::Context->dbh;
1178 my $sth = $dbh->prepare("UPDATE import_records SET status = ? WHERE import_record_id = ?");
1179 $sth->execute($new_overlay_status, $import_record_id);
1184 =head2 GetImportRecordMatches
1188 my $results = GetImportRecordMatches($import_record_id, $best_only);
1194 sub GetImportRecordMatches {
1195 my $import_record_id = shift;
1196 my $best_only = @_ ? shift : 0;
1198 my $dbh = C4::Context->dbh;
1199 # FIXME currently biblio only
1200 my $sth = $dbh->prepare_cached("SELECT title, author, biblionumber, score
1202 JOIN import_record_matches USING (import_record_id)
1203 JOIN biblio ON (biblionumber = candidate_match_id)
1204 WHERE import_record_id = ?
1205 ORDER BY score DESC, biblionumber DESC");
1206 $sth->bind_param(1, $import_record_id);
1209 while (my $row = $sth->fetchrow_hashref) {
1210 push @$results, $row;
1220 =head2 SetImportRecordMatches
1224 SetImportRecordMatches($import_record_id, @matches);
1230 sub SetImportRecordMatches {
1231 my $import_record_id = shift;
1234 my $dbh = C4::Context->dbh;
1235 my $delsth = $dbh->prepare("DELETE FROM import_record_matches WHERE import_record_id = ?");
1236 $delsth->execute($import_record_id);
1239 my $sth = $dbh->prepare("INSERT INTO import_record_matches (import_record_id, candidate_match_id, score)
1241 foreach my $match (@matches) {
1242 $sth->execute($import_record_id, $match->{'record_id'}, $match->{'score'});
1247 # internal functions
1249 sub _create_import_record {
1250 my ($batch_id, $record_sequence, $marc_record, $record_type, $encoding, $z3950random) = @_;
1252 my $dbh = C4::Context->dbh;
1253 my $sth = $dbh->prepare("INSERT INTO import_records (import_batch_id, record_sequence, marc, marcxml,
1254 record_type, encoding, z3950random)
1255 VALUES (?, ?, ?, ?, ?, ?, ?)");
1256 $sth->execute($batch_id, $record_sequence, $marc_record->as_usmarc(), $marc_record->as_xml(),
1257 $record_type, $encoding, $z3950random);
1258 my $import_record_id = $dbh->{'mysql_insertid'};
1260 return $import_record_id;
1263 sub _update_import_record_marc {
1264 my ($import_record_id, $marc_record) = @_;
1266 my $dbh = C4::Context->dbh;
1267 my $sth = $dbh->prepare("UPDATE import_records SET marc = ?, marcxml = ?
1268 WHERE import_record_id = ?");
1269 $sth->execute($marc_record->as_usmarc(), $marc_record->as_xml(), $import_record_id);
1273 sub _add_biblio_fields {
1274 my ($import_record_id, $marc_record) = @_;
1276 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1277 my $dbh = C4::Context->dbh;
1278 # FIXME no controlnumber, originalsource
1279 # FIXME 2 - should regularize normalization of ISBN wherever it is done
1283 my $sth = $dbh->prepare("INSERT INTO import_biblios (import_record_id, title, author, isbn, issn) VALUES (?, ?, ?, ?, ?)");
1284 $sth->execute($import_record_id, $title, $author, $isbn, $issn);
1289 sub _update_biblio_fields {
1290 my ($import_record_id, $marc_record) = @_;
1292 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1293 my $dbh = C4::Context->dbh;
1294 # FIXME no controlnumber, originalsource
1295 # FIXME 2 - should regularize normalization of ISBN wherever it is done
1299 my $sth = $dbh->prepare("UPDATE import_biblios SET title = ?, author = ?, isbn = ?, issn = ?
1300 WHERE import_record_id = ?");
1301 $sth->execute($title, $author, $isbn, $issn, $import_record_id);
1305 sub _parse_biblio_fields {
1306 my ($marc_record) = @_;
1308 my $dbh = C4::Context->dbh;
1309 my $bibliofields = TransformMarcToKoha($dbh, $marc_record, '');
1310 return ($bibliofields->{'title'}, $bibliofields->{'author'}, $bibliofields->{'isbn'}, $bibliofields->{'issn'});
1314 sub _update_batch_record_counts {
1315 my ($batch_id) = @_;
1317 my $dbh = C4::Context->dbh;
1318 my $sth = $dbh->prepare_cached("UPDATE import_batches SET num_biblios = (
1321 WHERE import_batch_id = import_batches.import_batch_id
1322 AND record_type = 'biblio')
1323 WHERE import_batch_id = ?");
1324 $sth->bind_param(1, $batch_id);
1327 $sth = $dbh->prepare_cached("UPDATE import_batches SET num_items = (
1330 JOIN import_items USING (import_record_id)
1331 WHERE import_batch_id = import_batches.import_batch_id
1332 AND record_type = 'biblio')
1333 WHERE import_batch_id = ?");
1334 $sth->bind_param(1, $batch_id);
1340 sub _get_commit_action {
1341 my ($overlay_action, $nomatch_action, $item_action, $overlay_status, $import_record_id) = @_;
1343 my ($bib_result, $bib_match, $item_result);
1345 if ($overlay_status ne 'no_match') {
1346 $bib_match = GetBestRecordMatch($import_record_id);
1347 if ($overlay_action eq 'replace') {
1348 $bib_result = defined($bib_match) ? 'replace' : 'create_new';
1349 } elsif ($overlay_action eq 'create_new') {
1350 $bib_result = 'create_new';
1351 } elsif ($overlay_action eq 'ignore') {
1352 $bib_result = 'ignore';
1354 $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_matches') ? 'create_new' : 'ignore';
1356 $bib_result = $nomatch_action;
1357 $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_new') ? 'create_new' : 'ignore';
1360 return ($bib_result, $item_result, $bib_match);
1363 sub _get_revert_action {
1364 my ($overlay_action, $overlay_status, $status) = @_;
1368 if ($status eq 'ignored') {
1369 $bib_result = 'ignore';
1371 if ($overlay_action eq 'create_new') {
1372 $bib_result = 'delete';
1374 $bib_result = ($overlay_status eq 'match_applied') ? 'restore' : 'delete';
1385 Koha Development Team <info@koha.org>
1387 Galen Charlton <galen.charlton@liblime.com>