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
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
85 =head2 GetZ3950BatchId
87 my $batchid = GetZ3950BatchId($z3950server);
89 Retrieves the ID of the import batch for the Z39.50
90 reservoir for the given target. If necessary,
91 creates the import batch.
96 my ($z3950server) = @_;
98 my $dbh = C4::Context->dbh;
99 my $sth = $dbh->prepare("SELECT import_batch_id FROM import_batches
100 WHERE batch_type = 'z3950'
102 $sth->execute($z3950server);
103 my $rowref = $sth->fetchrow_arrayref();
105 if (defined $rowref) {
108 my $batch_id = AddImportBatch('create_new', 'staged', 'z3950', $z3950server, '');
114 =head2 GetImportRecordMarc
116 my ($marcblob, $encoding) = GetImportRecordMarc($import_record_id);
120 sub GetImportRecordMarc {
121 my ($import_record_id) = @_;
123 my $dbh = C4::Context->dbh;
124 my $sth = $dbh->prepare("SELECT marc, encoding FROM import_records WHERE import_record_id = ?");
125 $sth->execute($import_record_id);
126 my ($marc, $encoding) = $sth->fetchrow();
128 return $marc, $encoding;
132 =head2 AddImportBatch
134 my $batch_id = AddImportBatch($overlay_action, $import_status, $type,
135 $file_name, $comments);
140 my ($overlay_action, $import_status, $type, $file_name, $comments) = @_;
142 my $dbh = C4::Context->dbh;
143 my $sth = $dbh->prepare("INSERT INTO import_batches (overlay_action, import_status, batch_type,
145 VALUES (?, ?, ?, ?, ?)");
146 $sth->execute($overlay_action, $import_status, $type, $file_name, $comments);
147 my $batch_id = $dbh->{'mysql_insertid'};
154 =head2 GetImportBatch
156 my $row = GetImportBatch($batch_id);
158 Retrieve a hashref of an import_batches row.
165 my $dbh = C4::Context->dbh;
166 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches WHERE import_batch_id = ?");
167 $sth->bind_param(1, $batch_id);
169 my $result = $sth->fetchrow_hashref;
175 =head2 AddBiblioToBatch
177 my $import_record_id = AddBiblioToBatch($batch_id, $record_sequence,
178 $marc_record, $encoding, $z3950random, $update_counts);
182 sub AddBiblioToBatch {
183 my $batch_id = shift;
184 my $record_sequence = shift;
185 my $marc_record = shift;
186 my $encoding = shift;
187 my $z3950random = shift;
188 my $update_counts = @_ ? shift : 1;
190 my $import_record_id = _create_import_record($batch_id, $record_sequence, $marc_record, 'biblio', $encoding, $z3950random);
191 _add_biblio_fields($import_record_id, $marc_record);
192 _update_batch_record_counts($batch_id) if $update_counts;
193 return $import_record_id;
196 =head2 ModBiblioInBatch
198 ModBiblioInBatch($import_record_id, $marc_record);
202 sub ModBiblioInBatch {
203 my ($import_record_id, $marc_record) = @_;
205 _update_import_record_marc($import_record_id, $marc_record);
206 _update_biblio_fields($import_record_id, $marc_record);
210 =head2 BatchStageMarcRecords
212 ($batch_id, $num_records, $num_items, @invalid_records) =
213 BatchStageMarcRecords($encoding, $marc_records, $file_name,
214 $comments, $branch_code, $parse_items,
216 $progress_interval, $progress_callback);
220 sub BatchStageMarcRecords {
221 my $encoding = shift;
222 my $marc_records = shift;
223 my $file_name = shift;
224 my $comments = shift;
225 my $branch_code = shift;
226 my $parse_items = shift;
227 my $leave_as_staging = shift;
229 # optional callback to monitor status
231 my $progress_interval = 0;
232 my $progress_callback = undef;
234 $progress_interval = shift;
235 $progress_callback = shift;
236 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
237 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
240 my $batch_id = AddImportBatch('create_new', 'staging', 'batch', $file_name, $comments);
242 SetImportBatchItemAction($batch_id, 'always_add');
244 SetImportBatchItemAction($batch_id, 'ignore');
247 my @invalid_records = ();
250 # FIXME - for now, we're dealing only with bibs
252 foreach my $marc_blob (split(/\x1D/, $marc_records)) {
253 $marc_blob =~ s/^\s+//g;
254 $marc_blob =~ s/\s+$//g;
255 next unless $marc_blob;
257 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
258 &$progress_callback($rec_num);
260 my ($marc_record, $charset_guessed, $char_errors) =
261 MarcToUTF8Record($marc_blob, C4::Context->preference("marcflavour"), $encoding);
263 $encoding = $charset_guessed unless $encoding;
265 my $import_record_id;
266 if (scalar($marc_record->fields()) == 0) {
267 push @invalid_records, $marc_blob;
270 $import_record_id = AddBiblioToBatch($batch_id, $rec_num, $marc_record, $encoding, int(rand(99999)), 0);
272 my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, 0);
273 $num_items += scalar(@import_items_ids);
277 unless ($leave_as_staging) {
278 SetImportBatchStatus($batch_id, 'staged');
280 # FIXME branch_code, number of bibs, number of items
281 _update_batch_record_counts($batch_id);
282 return ($batch_id, $num_valid, $num_items, @invalid_records);
285 =head2 AddItemsToImportBiblio
287 my @import_items_ids = AddItemsToImportBiblio($batch_id,
288 $import_record_id, $marc_record, $update_counts);
292 sub AddItemsToImportBiblio {
293 my $batch_id = shift;
294 my $import_record_id = shift;
295 my $marc_record = shift;
296 my $update_counts = @_ ? shift : 0;
298 my @import_items_ids = ();
300 my $dbh = C4::Context->dbh;
301 my ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",'');
302 foreach my $item_field ($marc_record->field($item_tag)) {
303 my $item_marc = MARC::Record->new();
304 $item_marc->leader("00000 a "); # must set Leader/09 to 'a'
305 $item_marc->append_fields($item_field);
306 $marc_record->delete_field($item_field);
307 my $sth = $dbh->prepare_cached("INSERT INTO import_items (import_record_id, status, marcxml)
309 $sth->bind_param(1, $import_record_id);
310 $sth->bind_param(2, 'staged');
311 $sth->bind_param(3, $item_marc->as_xml());
313 push @import_items_ids, $dbh->{'mysql_insertid'};
317 if ($#import_items_ids > -1) {
318 _update_batch_record_counts($batch_id) if $update_counts;
319 _update_import_record_marc($import_record_id, $marc_record);
321 return @import_items_ids;
324 =head2 BatchFindBibDuplicates
326 my $num_with_matches = BatchFindBibDuplicates($batch_id, $matcher,
327 $max_matches, $progress_interval, $progress_callback);
329 Goes through the records loaded in the batch and attempts to
330 find duplicates for each one. Sets the matching status
331 of each record to "no_match" or "auto_match" as appropriate.
333 The $max_matches parameter is optional; if it is not supplied,
336 The $progress_interval and $progress_callback parameters are
337 optional; if both are supplied, the sub referred to by
338 $progress_callback will be invoked every $progress_interval
339 records using the number of records processed as the
344 sub BatchFindBibDuplicates {
345 my $batch_id = shift;
347 my $max_matches = @_ ? shift : 10;
349 # optional callback to monitor status
351 my $progress_interval = 0;
352 my $progress_callback = undef;
354 $progress_interval = shift;
355 $progress_callback = shift;
356 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
357 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
360 my $dbh = C4::Context->dbh;
362 my $sth = $dbh->prepare("SELECT import_record_id, marc
364 JOIN import_biblios USING (import_record_id)
365 WHERE import_batch_id = ?");
366 $sth->execute($batch_id);
367 my $num_with_matches = 0;
369 while (my $rowref = $sth->fetchrow_hashref) {
371 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
372 &$progress_callback($rec_num);
374 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
376 if (defined $matcher) {
377 @matches = $matcher->get_matches($marc_record, $max_matches);
379 if (scalar(@matches) > 0) {
381 SetImportRecordMatches($rowref->{'import_record_id'}, @matches);
382 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'auto_match');
384 SetImportRecordMatches($rowref->{'import_record_id'}, ());
385 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'no_match');
389 return $num_with_matches;
392 =head2 BatchCommitBibRecords
394 my ($num_added, $num_updated, $num_items_added, $num_items_errored,
395 $num_ignored) = BatchCommitBibRecords($batch_id, $framework,
396 $progress_interval, $progress_callback);
400 sub BatchCommitBibRecords {
401 my $batch_id = shift;
402 my $framework = shift;
404 # optional callback to monitor status
406 my $progress_interval = 0;
407 my $progress_callback = undef;
409 $progress_interval = shift;
410 $progress_callback = shift;
411 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
412 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
417 my $num_items_added = 0;
418 my $num_items_errored = 0;
420 # commit (i.e., save, all records in the batch)
421 # FIXME biblio only at the moment
422 SetImportBatchStatus('importing');
423 my $overlay_action = GetImportBatchOverlayAction($batch_id);
424 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
425 my $item_action = GetImportBatchItemAction($batch_id);
426 my $dbh = C4::Context->dbh;
427 my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marc, encoding
429 JOIN import_biblios USING (import_record_id)
430 WHERE import_batch_id = ?");
431 $sth->execute($batch_id);
433 while (my $rowref = $sth->fetchrow_hashref) {
435 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
436 &$progress_callback($rec_num);
438 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'imported') {
443 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
445 # remove any item tags - rely on BatchCommitItems
446 my ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",'');
447 foreach my $item_field ($marc_record->field($item_tag)) {
448 $marc_record->delete_field($item_field);
451 # decide what what to do with the bib and item records
452 my ($bib_result, $item_result, $bib_match) =
453 _get_commit_action($overlay_action, $nomatch_action, $item_action,
454 $rowref->{'overlay_status'}, $rowref->{'import_record_id'});
456 if ($bib_result eq 'create_new') {
458 my ($biblionumber, $biblioitemnumber) = AddBiblio($marc_record, $framework);
459 my $sth = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
460 $sth->execute($biblionumber, $rowref->{'import_record_id'});
462 if ($item_result eq 'create_new') {
463 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
464 $num_items_added += $bib_items_added;
465 $num_items_errored += $bib_items_errored;
467 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
468 } elsif ($bib_result eq 'replace') {
470 my $biblionumber = $bib_match;
471 my ($count, $oldbiblio) = GetBiblio($biblionumber);
472 my $oldxml = GetXmlBiblio($biblionumber);
474 # remove item fields so that they don't get
475 # added again if record is reverted
476 my $old_marc = MARC::Record->new_from_xml(StripNonXmlChars($oldxml), 'UTF-8', $rowref->{'encoding'});
477 foreach my $item_field ($old_marc->field($item_tag)) {
478 $old_marc->delete_field($item_field);
481 ModBiblio($marc_record, $biblionumber, $oldbiblio->{'frameworkcode'});
482 my $sth = $dbh->prepare_cached("UPDATE import_records SET marcxml_old = ? WHERE import_record_id = ?");
483 $sth->execute($old_marc->as_xml(), $rowref->{'import_record_id'});
485 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
486 $sth2->execute($biblionumber, $rowref->{'import_record_id'});
488 if ($item_result eq 'create_new') {
489 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
490 $num_items_added += $bib_items_added;
491 $num_items_errored += $bib_items_errored;
493 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
494 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
495 } elsif ($bib_result eq 'ignore') {
497 my $biblionumber = $bib_match;
498 if (defined $biblionumber and $item_result eq 'create_new') {
499 my ($bib_items_added, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
500 $num_items_added += $bib_items_added;
501 $num_items_errored += $bib_items_errored;
502 # still need to record the matched biblionumber so that the
503 # items can be reverted
504 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
505 $sth2->execute($biblionumber, $rowref->{'import_record_id'});
506 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
508 SetImportRecordStatus($rowref->{'import_record_id'}, 'ignored');
512 SetImportBatchStatus($batch_id, 'imported');
513 return ($num_added, $num_updated, $num_items_added, $num_items_errored, $num_ignored);
516 =head2 BatchCommitItems
518 ($num_items_added, $num_items_errored) =
519 BatchCommitItems($import_record_id, $biblionumber);
523 sub BatchCommitItems {
524 my ($import_record_id, $biblionumber) = @_;
526 my $dbh = C4::Context->dbh;
528 my $num_items_added = 0;
529 my $num_items_errored = 0;
530 my $sth = $dbh->prepare("SELECT import_items_id, import_items.marcxml, encoding
532 JOIN import_records USING (import_record_id)
533 WHERE import_record_id = ?
534 ORDER BY import_items_id");
535 $sth->bind_param(1, $import_record_id);
537 while (my $row = $sth->fetchrow_hashref()) {
538 my $item_marc = MARC::Record->new_from_xml(StripNonXmlChars($row->{'marcxml'}), 'UTF-8', $row->{'encoding'});
539 # FIXME - duplicate barcode check needs to become part of AddItemFromMarc()
540 my $item = TransformMarcToKoha($dbh, $item_marc);
541 my $duplicate_barcode = exists($item->{'barcode'}) && GetItemnumberFromBarcode($item->{'barcode'});
542 if ($duplicate_barcode) {
543 my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, import_error = ? WHERE import_items_id = ?");
544 $updsth->bind_param(1, 'error');
545 $updsth->bind_param(2, 'duplicate item barcode');
546 $updsth->bind_param(3, $row->{'import_items_id'});
548 $num_items_errored++;
550 my ($item_biblionumber, $biblioitemnumber, $itemnumber) = AddItemFromMarc($item_marc, $biblionumber);
551 my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, itemnumber = ? WHERE import_items_id = ?");
552 $updsth->bind_param(1, 'imported');
553 $updsth->bind_param(2, $itemnumber);
554 $updsth->bind_param(3, $row->{'import_items_id'});
561 return ($num_items_added, $num_items_errored);
564 =head2 BatchRevertBibRecords
566 my ($num_deleted, $num_errors, $num_reverted, $num_items_deleted,
567 $num_ignored) = BatchRevertBibRecords($batch_id);
571 sub BatchRevertBibRecords {
572 my $batch_id = shift;
576 my $num_reverted = 0;
577 my $num_items_deleted = 0;
579 # commit (i.e., save, all records in the batch)
580 # FIXME biblio only at the moment
581 SetImportBatchStatus('reverting');
582 my $overlay_action = GetImportBatchOverlayAction($batch_id);
583 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
584 my $dbh = C4::Context->dbh;
585 my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marcxml_old, encoding, matched_biblionumber
587 JOIN import_biblios USING (import_record_id)
588 WHERE import_batch_id = ?");
589 $sth->execute($batch_id);
590 while (my $rowref = $sth->fetchrow_hashref) {
591 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'reverted') {
596 my $bib_result = _get_revert_action($overlay_action, $rowref->{'overlay_status'}, $rowref->{'status'});
598 if ($bib_result eq 'delete') {
599 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
600 my $error = DelBiblio($rowref->{'matched_biblionumber'});
601 if (defined $error) {
605 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
607 } elsif ($bib_result eq 'restore') {
609 my $old_record = MARC::Record->new_from_xml(StripNonXmlChars($rowref->{'marcxml_old'}), 'UTF-8', $rowref->{'encoding'});
610 my $biblionumber = $rowref->{'matched_biblionumber'};
611 my ($count, $oldbiblio) = GetBiblio($biblionumber);
612 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
613 ModBiblio($old_record, $biblionumber, $oldbiblio->{'frameworkcode'});
614 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
615 } elsif ($bib_result eq 'ignore') {
616 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
617 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
619 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = NULL WHERE import_record_id = ?");
620 $sth2->execute($rowref->{'import_record_id'});
624 SetImportBatchStatus($batch_id, 'reverted');
625 return ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored);
628 =head2 BatchRevertItems
630 my $num_items_deleted = BatchRevertItems($import_record_id, $biblionumber);
634 sub BatchRevertItems {
635 my ($import_record_id, $biblionumber) = @_;
637 my $dbh = C4::Context->dbh;
638 my $num_items_deleted = 0;
640 my $sth = $dbh->prepare_cached("SELECT import_items_id, itemnumber
642 JOIN items USING (itemnumber)
643 WHERE import_record_id = ?");
644 $sth->bind_param(1, $import_record_id);
646 while (my $row = $sth->fetchrow_hashref()) {
647 DelItem($dbh, $biblionumber, $row->{'itemnumber'});
648 my $updsth = $dbh->prepare("UPDATE import_items SET status = ? WHERE import_items_id = ?");
649 $updsth->bind_param(1, 'reverted');
650 $updsth->bind_param(2, $row->{'import_items_id'});
653 $num_items_deleted++;
656 return $num_items_deleted;
661 CleanBatch($batch_id)
663 Deletes all staged records from the import batch
664 and sets the status of the batch to 'cleaned'. Note
665 that deleting a stage record does *not* affect
666 any record that has been committed to the database.
671 my $batch_id = shift;
672 return unless defined $batch_id;
674 C4::Context->dbh->do('DELETE FROM import_records WHERE import_batch_id = ?', {}, $batch_id);
675 SetImportBatchStatus($batch_id, 'cleaned');
678 =head2 GetAllImportBatches
680 my $results = GetAllImportBatches();
682 Returns a references to an array of hash references corresponding
683 to all import_batches rows (of batch_type 'batch'), sorted in
684 ascending order by import_batch_id.
688 sub GetAllImportBatches {
689 my $dbh = C4::Context->dbh;
690 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches
691 WHERE batch_type = 'batch'
692 ORDER BY import_batch_id ASC");
696 while (my $row = $sth->fetchrow_hashref) {
697 push @$results, $row;
703 =head2 GetImportBatchRangeDesc
705 my $results = GetImportBatchRangeDesc($offset, $results_per_group);
707 Returns a reference to an array of hash references corresponding to
708 import_batches rows (sorted in descending order by import_batch_id)
709 start at the given offset.
713 sub GetImportBatchRangeDesc {
714 my ($offset, $results_per_group) = @_;
716 my $dbh = C4::Context->dbh;
717 my $query = "SELECT * FROM import_batches
718 WHERE batch_type = 'batch'
719 ORDER BY import_batch_id DESC";
721 if ($results_per_group){
722 $query .= " LIMIT ?";
723 push(@params, $results_per_group);
726 $query .= " OFFSET ?";
727 push(@params, $offset);
729 my $sth = $dbh->prepare_cached($query);
730 $sth->execute(@params);
731 my $results = $sth->fetchall_arrayref({});
736 =head2 GetItemNumbersFromImportBatch
738 my @itemsnos = GetItemNumbersFromImportBatch($batch_id);
742 sub GetItemNumbersFromImportBatch {
744 my $dbh = C4::Context->dbh;
745 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=?");
746 $sth->execute($batch_id);
748 while ( my ($itm) = $sth->fetchrow_array ) {
754 =head2 GetNumberOfImportBatches
756 my $count = GetNumberOfImportBatches();
760 sub GetNumberOfNonZ3950ImportBatches {
761 my $dbh = C4::Context->dbh;
762 my $sth = $dbh->prepare("SELECT COUNT(*) FROM import_batches WHERE batch_type='batch'");
764 my ($count) = $sth->fetchrow_array();
769 =head2 GetImportBibliosRange
771 my $results = GetImportBibliosRange($batch_id, $offset, $results_per_group);
773 Returns a reference to an array of hash references corresponding to
774 import_biblios/import_records rows for a given batch
775 starting at the given offset.
779 sub GetImportBibliosRange {
780 my ($batch_id, $offset, $results_per_group, $status) = @_;
782 my $dbh = C4::Context->dbh;
783 my $query = "SELECT title, author, isbn, issn, import_record_id, record_sequence,
784 status, overlay_status, matched_biblionumber
786 JOIN import_biblios USING (import_record_id)
787 WHERE import_batch_id = ?";
789 push(@params, $batch_id);
791 $query .= " AND status=?";
792 push(@params,$status);
794 $query.=" ORDER BY import_record_id";
796 if($results_per_group){
797 $query .= " LIMIT ?";
798 push(@params, $results_per_group);
801 $query .= " OFFSET ?";
802 push(@params, $offset);
804 my $sth = $dbh->prepare_cached($query);
805 $sth->execute(@params);
806 my $results = $sth->fetchall_arrayref({});
812 =head2 GetBestRecordMatch
814 my $record_id = GetBestRecordMatch($import_record_id);
818 sub GetBestRecordMatch {
819 my ($import_record_id) = @_;
821 my $dbh = C4::Context->dbh;
822 my $sth = $dbh->prepare("SELECT candidate_match_id
823 FROM import_record_matches
824 WHERE import_record_id = ?
825 ORDER BY score DESC, candidate_match_id DESC");
826 $sth->execute($import_record_id);
827 my ($record_id) = $sth->fetchrow_array();
832 =head2 GetImportBatchStatus
834 my $status = GetImportBatchStatus($batch_id);
838 sub GetImportBatchStatus {
841 my $dbh = C4::Context->dbh;
842 my $sth = $dbh->prepare("SELECT import_status FROM import_batches WHERE import_batch_id = ?");
843 $sth->execute($batch_id);
844 my ($status) = $sth->fetchrow_array();
850 =head2 SetImportBatchStatus
852 SetImportBatchStatus($batch_id, $new_status);
856 sub SetImportBatchStatus {
857 my ($batch_id, $new_status) = @_;
859 my $dbh = C4::Context->dbh;
860 my $sth = $dbh->prepare("UPDATE import_batches SET import_status = ? WHERE import_batch_id = ?");
861 $sth->execute($new_status, $batch_id);
866 =head2 GetImportBatchOverlayAction
868 my $overlay_action = GetImportBatchOverlayAction($batch_id);
872 sub GetImportBatchOverlayAction {
875 my $dbh = C4::Context->dbh;
876 my $sth = $dbh->prepare("SELECT overlay_action FROM import_batches WHERE import_batch_id = ?");
877 $sth->execute($batch_id);
878 my ($overlay_action) = $sth->fetchrow_array();
880 return $overlay_action;
885 =head2 SetImportBatchOverlayAction
887 SetImportBatchOverlayAction($batch_id, $new_overlay_action);
891 sub SetImportBatchOverlayAction {
892 my ($batch_id, $new_overlay_action) = @_;
894 my $dbh = C4::Context->dbh;
895 my $sth = $dbh->prepare("UPDATE import_batches SET overlay_action = ? WHERE import_batch_id = ?");
896 $sth->execute($new_overlay_action, $batch_id);
901 =head2 GetImportBatchNoMatchAction
903 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
907 sub GetImportBatchNoMatchAction {
910 my $dbh = C4::Context->dbh;
911 my $sth = $dbh->prepare("SELECT nomatch_action FROM import_batches WHERE import_batch_id = ?");
912 $sth->execute($batch_id);
913 my ($nomatch_action) = $sth->fetchrow_array();
915 return $nomatch_action;
920 =head2 SetImportBatchNoMatchAction
922 SetImportBatchNoMatchAction($batch_id, $new_nomatch_action);
926 sub SetImportBatchNoMatchAction {
927 my ($batch_id, $new_nomatch_action) = @_;
929 my $dbh = C4::Context->dbh;
930 my $sth = $dbh->prepare("UPDATE import_batches SET nomatch_action = ? WHERE import_batch_id = ?");
931 $sth->execute($new_nomatch_action, $batch_id);
936 =head2 GetImportBatchItemAction
938 my $item_action = GetImportBatchItemAction($batch_id);
942 sub GetImportBatchItemAction {
945 my $dbh = C4::Context->dbh;
946 my $sth = $dbh->prepare("SELECT item_action FROM import_batches WHERE import_batch_id = ?");
947 $sth->execute($batch_id);
948 my ($item_action) = $sth->fetchrow_array();
955 =head2 SetImportBatchItemAction
957 SetImportBatchItemAction($batch_id, $new_item_action);
961 sub SetImportBatchItemAction {
962 my ($batch_id, $new_item_action) = @_;
964 my $dbh = C4::Context->dbh;
965 my $sth = $dbh->prepare("UPDATE import_batches SET item_action = ? WHERE import_batch_id = ?");
966 $sth->execute($new_item_action, $batch_id);
971 =head2 GetImportBatchMatcher
973 my $matcher_id = GetImportBatchMatcher($batch_id);
977 sub GetImportBatchMatcher {
980 my $dbh = C4::Context->dbh;
981 my $sth = $dbh->prepare("SELECT matcher_id FROM import_batches WHERE import_batch_id = ?");
982 $sth->execute($batch_id);
983 my ($matcher_id) = $sth->fetchrow_array();
990 =head2 SetImportBatchMatcher
992 SetImportBatchMatcher($batch_id, $new_matcher_id);
996 sub SetImportBatchMatcher {
997 my ($batch_id, $new_matcher_id) = @_;
999 my $dbh = C4::Context->dbh;
1000 my $sth = $dbh->prepare("UPDATE import_batches SET matcher_id = ? WHERE import_batch_id = ?");
1001 $sth->execute($new_matcher_id, $batch_id);
1006 =head2 GetImportRecordOverlayStatus
1008 my $overlay_status = GetImportRecordOverlayStatus($import_record_id);
1012 sub GetImportRecordOverlayStatus {
1013 my ($import_record_id) = @_;
1015 my $dbh = C4::Context->dbh;
1016 my $sth = $dbh->prepare("SELECT overlay_status FROM import_records WHERE import_record_id = ?");
1017 $sth->execute($import_record_id);
1018 my ($overlay_status) = $sth->fetchrow_array();
1020 return $overlay_status;
1025 =head2 SetImportRecordOverlayStatus
1027 SetImportRecordOverlayStatus($import_record_id, $new_overlay_status);
1031 sub SetImportRecordOverlayStatus {
1032 my ($import_record_id, $new_overlay_status) = @_;
1034 my $dbh = C4::Context->dbh;
1035 my $sth = $dbh->prepare("UPDATE import_records SET overlay_status = ? WHERE import_record_id = ?");
1036 $sth->execute($new_overlay_status, $import_record_id);
1041 =head2 GetImportRecordStatus
1043 my $overlay_status = GetImportRecordStatus($import_record_id);
1047 sub GetImportRecordStatus {
1048 my ($import_record_id) = @_;
1050 my $dbh = C4::Context->dbh;
1051 my $sth = $dbh->prepare("SELECT status FROM import_records WHERE import_record_id = ?");
1052 $sth->execute($import_record_id);
1053 my ($overlay_status) = $sth->fetchrow_array();
1055 return $overlay_status;
1060 =head2 SetImportRecordStatus
1062 SetImportRecordStatus($import_record_id, $new_overlay_status);
1066 sub SetImportRecordStatus {
1067 my ($import_record_id, $new_overlay_status) = @_;
1069 my $dbh = C4::Context->dbh;
1070 my $sth = $dbh->prepare("UPDATE import_records SET status = ? WHERE import_record_id = ?");
1071 $sth->execute($new_overlay_status, $import_record_id);
1076 =head2 GetImportRecordMatches
1078 my $results = GetImportRecordMatches($import_record_id, $best_only);
1082 sub GetImportRecordMatches {
1083 my $import_record_id = shift;
1084 my $best_only = @_ ? shift : 0;
1086 my $dbh = C4::Context->dbh;
1087 # FIXME currently biblio only
1088 my $sth = $dbh->prepare_cached("SELECT title, author, biblionumber, score
1090 JOIN import_record_matches USING (import_record_id)
1091 JOIN biblio ON (biblionumber = candidate_match_id)
1092 WHERE import_record_id = ?
1093 ORDER BY score DESC, biblionumber DESC");
1094 $sth->bind_param(1, $import_record_id);
1097 while (my $row = $sth->fetchrow_hashref) {
1098 push @$results, $row;
1108 =head2 SetImportRecordMatches
1110 SetImportRecordMatches($import_record_id, @matches);
1114 sub SetImportRecordMatches {
1115 my $import_record_id = shift;
1118 my $dbh = C4::Context->dbh;
1119 my $delsth = $dbh->prepare("DELETE FROM import_record_matches WHERE import_record_id = ?");
1120 $delsth->execute($import_record_id);
1123 my $sth = $dbh->prepare("INSERT INTO import_record_matches (import_record_id, candidate_match_id, score)
1125 foreach my $match (@matches) {
1126 $sth->execute($import_record_id, $match->{'record_id'}, $match->{'score'});
1131 # internal functions
1133 sub _create_import_record {
1134 my ($batch_id, $record_sequence, $marc_record, $record_type, $encoding, $z3950random) = @_;
1136 my $dbh = C4::Context->dbh;
1137 my $sth = $dbh->prepare("INSERT INTO import_records (import_batch_id, record_sequence, marc, marcxml,
1138 record_type, encoding, z3950random)
1139 VALUES (?, ?, ?, ?, ?, ?, ?)");
1140 $sth->execute($batch_id, $record_sequence, $marc_record->as_usmarc(), $marc_record->as_xml(),
1141 $record_type, $encoding, $z3950random);
1142 my $import_record_id = $dbh->{'mysql_insertid'};
1144 return $import_record_id;
1147 sub _update_import_record_marc {
1148 my ($import_record_id, $marc_record) = @_;
1150 my $dbh = C4::Context->dbh;
1151 my $sth = $dbh->prepare("UPDATE import_records SET marc = ?, marcxml = ?
1152 WHERE import_record_id = ?");
1153 $sth->execute($marc_record->as_usmarc(), $marc_record->as_xml(), $import_record_id);
1157 sub _add_biblio_fields {
1158 my ($import_record_id, $marc_record) = @_;
1160 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1161 my $dbh = C4::Context->dbh;
1162 # FIXME no controlnumber, originalsource
1163 $isbn = C4::Koha::_isbn_cleanup($isbn); # FIXME C4::Koha::_isbn_cleanup should be made public
1164 my $sth = $dbh->prepare("INSERT INTO import_biblios (import_record_id, title, author, isbn, issn) VALUES (?, ?, ?, ?, ?)");
1165 $sth->execute($import_record_id, $title, $author, $isbn, $issn);
1170 sub _update_biblio_fields {
1171 my ($import_record_id, $marc_record) = @_;
1173 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1174 my $dbh = C4::Context->dbh;
1175 # FIXME no controlnumber, originalsource
1176 # FIXME 2 - should regularize normalization of ISBN wherever it is done
1180 my $sth = $dbh->prepare("UPDATE import_biblios SET title = ?, author = ?, isbn = ?, issn = ?
1181 WHERE import_record_id = ?");
1182 $sth->execute($title, $author, $isbn, $issn, $import_record_id);
1186 sub _parse_biblio_fields {
1187 my ($marc_record) = @_;
1189 my $dbh = C4::Context->dbh;
1190 my $bibliofields = TransformMarcToKoha($dbh, $marc_record, '');
1191 return ($bibliofields->{'title'}, $bibliofields->{'author'}, $bibliofields->{'isbn'}, $bibliofields->{'issn'});
1195 sub _update_batch_record_counts {
1196 my ($batch_id) = @_;
1198 my $dbh = C4::Context->dbh;
1199 my $sth = $dbh->prepare_cached("UPDATE import_batches SET num_biblios = (
1202 WHERE import_batch_id = import_batches.import_batch_id
1203 AND record_type = 'biblio')
1204 WHERE import_batch_id = ?");
1205 $sth->bind_param(1, $batch_id);
1208 $sth = $dbh->prepare_cached("UPDATE import_batches SET num_items = (
1211 JOIN import_items USING (import_record_id)
1212 WHERE import_batch_id = import_batches.import_batch_id
1213 AND record_type = 'biblio')
1214 WHERE import_batch_id = ?");
1215 $sth->bind_param(1, $batch_id);
1221 sub _get_commit_action {
1222 my ($overlay_action, $nomatch_action, $item_action, $overlay_status, $import_record_id) = @_;
1224 my ($bib_result, $bib_match, $item_result);
1226 if ($overlay_status ne 'no_match') {
1227 $bib_match = GetBestRecordMatch($import_record_id);
1228 if ($overlay_action eq 'replace') {
1229 $bib_result = defined($bib_match) ? 'replace' : 'create_new';
1230 } elsif ($overlay_action eq 'create_new') {
1231 $bib_result = 'create_new';
1232 } elsif ($overlay_action eq 'ignore') {
1233 $bib_result = 'ignore';
1235 $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_matches') ? 'create_new' : 'ignore';
1237 $bib_result = $nomatch_action;
1238 $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_new') ? 'create_new' : 'ignore';
1241 return ($bib_result, $item_result, $bib_match);
1244 sub _get_revert_action {
1245 my ($overlay_action, $overlay_status, $status) = @_;
1249 if ($status eq 'ignored') {
1250 $bib_result = 'ignore';
1252 if ($overlay_action eq 'create_new') {
1253 $bib_result = 'delete';
1255 $bib_result = ($overlay_status eq 'match_applied') ? 'restore' : 'delete';
1266 Koha Development Team <http://koha-community.org/>
1268 Galen Charlton <galen.charlton@liblime.com>