1 package C4::ImportBatch;
3 # Copyright (C) 2007 LibLime, 2012 C & P Bibliography Services
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
24 use C4::Koha qw( GetNormalizedISBN );
33 use C4::Items qw( AddItemFromMarc ModItemFromMarc );
34 use C4::Charset qw( MarcToUTF8Record SetUTF8Flag StripNonXmlChars );
35 use C4::AuthoritiesMarc qw( AddAuthority GuessAuthTypeCode GetAuthorityXML ModAuthority DelAuthority );
36 use C4::MarcModificationTemplates qw( ModifyRecordWithTemplate );
38 use Koha::Plugins::Handler;
41 our (@ISA, @EXPORT_OK);
53 AddItemsToImportBiblio
64 GetStagedWebserviceBatches
65 GetImportBatchRangeDesc
66 GetNumberOfNonZ3950ImportBatches
69 GetItemNumbersFromImportBatch
73 GetImportBatchOverlayAction
74 SetImportBatchOverlayAction
75 GetImportBatchNoMatchAction
76 SetImportBatchNoMatchAction
77 GetImportBatchItemAction
78 SetImportBatchItemAction
81 GetImportRecordOverlayStatus
82 SetImportRecordOverlayStatus
85 SetMatchedBiblionumber
86 GetImportRecordMatches
87 SetImportRecordMatches
89 RecordsFromMARCXMLFile
90 RecordsFromISO2709File
97 C4::ImportBatch - manage batches of imported MARC records
105 =head2 GetZ3950BatchId
107 my $batchid = GetZ3950BatchId($z3950server);
109 Retrieves the ID of the import batch for the Z39.50
110 reservoir for the given target. If necessary,
111 creates the import batch.
115 sub GetZ3950BatchId {
116 my ($z3950server) = @_;
118 my $dbh = C4::Context->dbh;
119 my $sth = $dbh->prepare("SELECT import_batch_id FROM import_batches
120 WHERE batch_type = 'z3950'
122 $sth->execute($z3950server);
123 my $rowref = $sth->fetchrow_arrayref();
125 if (defined $rowref) {
128 my $batch_id = AddImportBatch( {
129 overlay_action => 'create_new',
130 import_status => 'staged',
131 batch_type => 'z3950',
132 file_name => $z3950server,
139 =head2 GetWebserviceBatchId
141 my $batchid = GetWebserviceBatchId();
143 Retrieves the ID of the import batch for webservice.
144 If necessary, creates the import batch.
148 my $WEBSERVICE_BASE_QRY = <<EOQ;
149 SELECT import_batch_id FROM import_batches
150 WHERE batch_type = 'webservice'
151 AND import_status = 'staged'
153 sub GetWebserviceBatchId {
156 my $dbh = C4::Context->dbh;
157 my $sql = $WEBSERVICE_BASE_QRY;
159 foreach my $field (qw(matcher_id overlay_action nomatch_action item_action)) {
160 if (my $val = $params->{$field}) {
161 $sql .= " AND $field = ?";
165 my $id = $dbh->selectrow_array($sql, undef, @args);
168 $params->{batch_type} = 'webservice';
169 $params->{import_status} = 'staged';
170 return AddImportBatch($params);
173 =head2 GetImportRecordMarc
175 my ($marcblob, $encoding) = GetImportRecordMarc($import_record_id);
179 sub GetImportRecordMarc {
180 my ($import_record_id) = @_;
182 my $dbh = C4::Context->dbh;
183 my ( $marc, $encoding ) = $dbh->selectrow_array(q|
184 SELECT marc, encoding
186 WHERE import_record_id = ?
187 |, undef, $import_record_id );
189 return $marc, $encoding;
192 sub EmbedItemsInImportBiblio {
193 my ( $record, $import_record_id ) = @_;
194 my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber" );
195 my $dbh = C4::Context->dbh;
196 my $import_items = $dbh->selectall_arrayref(q|
197 SELECT import_items.marcxml
199 WHERE import_record_id = ?
200 |, { Slice => {} }, $import_record_id );
202 for my $import_item ( @$import_items ) {
203 my $item_marc = MARC::Record::new_from_xml($import_item->{marcxml}, 'UTF-8');
204 push @item_fields, $item_marc->field($itemtag);
206 $record->append_fields(@item_fields);
210 =head2 AddImportBatch
212 my $batch_id = AddImportBatch($params_hash);
220 foreach (qw( matcher_id template_id branchcode
221 overlay_action nomatch_action item_action
222 import_status batch_type file_name comments record_type )) {
223 if (exists $params->{$_}) {
225 push @vals, $params->{$_};
228 my $dbh = C4::Context->dbh;
229 $dbh->do("INSERT INTO import_batches (".join( ',', @fields).")
230 VALUES (".join( ',', map '?', @fields).")",
233 return $dbh->{'mysql_insertid'};
236 =head2 GetImportBatch
238 my $row = GetImportBatch($batch_id);
240 Retrieve a hashref of an import_batches row.
247 my $dbh = C4::Context->dbh;
248 my $sth = $dbh->prepare_cached("SELECT b.*, p.name as profile FROM import_batches b LEFT JOIN import_batch_profiles p ON p.id = b.profile_id WHERE import_batch_id = ?");
249 $sth->bind_param(1, $batch_id);
251 my $result = $sth->fetchrow_hashref;
257 =head2 AddBiblioToBatch
259 my $import_record_id = AddBiblioToBatch($batch_id, $record_sequence,
260 $marc_record, $encoding, $update_counts);
264 sub AddBiblioToBatch {
265 my $batch_id = shift;
266 my $record_sequence = shift;
267 my $marc_record = shift;
268 my $encoding = shift;
269 my $update_counts = @_ ? shift : 1;
271 my $import_record_id = _create_import_record($batch_id, $record_sequence, $marc_record, 'biblio', $encoding, C4::Context->preference('marcflavour'));
272 _add_biblio_fields($import_record_id, $marc_record);
273 _update_batch_record_counts($batch_id) if $update_counts;
274 return $import_record_id;
277 =head2 AddAuthToBatch
279 my $import_record_id = AddAuthToBatch($batch_id, $record_sequence,
280 $marc_record, $encoding, $update_counts, [$marc_type]);
285 my $batch_id = shift;
286 my $record_sequence = shift;
287 my $marc_record = shift;
288 my $encoding = shift;
289 my $update_counts = @_ ? shift : 1;
290 my $marc_type = shift || C4::Context->preference('marcflavour');
292 $marc_type = 'UNIMARCAUTH' if $marc_type eq 'UNIMARC';
294 my $import_record_id = _create_import_record($batch_id, $record_sequence, $marc_record, 'auth', $encoding, $marc_type);
295 _add_auth_fields($import_record_id, $marc_record);
296 _update_batch_record_counts($batch_id) if $update_counts;
297 return $import_record_id;
300 =head2 BatchStageMarcRecords
302 ( $batch_id, $num_records, $num_items, @invalid_records ) =
303 BatchStageMarcRecords(
304 $record_type, $encoding,
305 $marc_records, $file_name,
306 $marc_modification_template, $comments,
307 $branch_code, $parse_items,
308 $leave_as_staging, $progress_interval,
314 sub BatchStageMarcRecords {
315 my $record_type = shift;
316 my $encoding = shift;
317 my $marc_records = shift;
318 my $file_name = shift;
319 my $marc_modification_template = shift;
320 my $comments = shift;
321 my $branch_code = shift;
322 my $parse_items = shift;
323 my $leave_as_staging = shift;
325 # optional callback to monitor status
327 my $progress_interval = 0;
328 my $progress_callback = undef;
330 $progress_interval = shift;
331 $progress_callback = shift;
332 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
333 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
336 my $batch_id = AddImportBatch( {
337 overlay_action => 'create_new',
338 import_status => 'staging',
339 batch_type => 'batch',
340 file_name => $file_name,
341 comments => $comments,
342 record_type => $record_type,
345 SetImportBatchItemAction($batch_id, 'always_add');
347 SetImportBatchItemAction($batch_id, 'ignore');
351 my $marc_type = C4::Context->preference('marcflavour');
352 $marc_type .= 'AUTH' if ($marc_type eq 'UNIMARC' && $record_type eq 'auth');
353 my @invalid_records = ();
356 # FIXME - for now, we're dealing only with bibs
358 foreach my $marc_record (@$marc_records) {
360 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
361 &$progress_callback($rec_num);
364 ModifyRecordWithTemplate( $marc_modification_template, $marc_record ) if ( $marc_modification_template );
366 my $import_record_id;
367 if (scalar($marc_record->fields()) == 0) {
368 push @invalid_records, $marc_record;
371 # Normalize the record so it doesn't have separated diacritics
372 SetUTF8Flag($marc_record);
375 if ($record_type eq 'biblio') {
376 $import_record_id = AddBiblioToBatch($batch_id, $rec_num, $marc_record, $encoding, 0);
378 my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, 0);
379 $num_items += scalar(@import_items_ids);
381 } elsif ($record_type eq 'auth') {
382 $import_record_id = AddAuthToBatch($batch_id, $rec_num, $marc_record, $encoding, 0, $marc_type);
386 unless ($leave_as_staging) {
387 SetImportBatchStatus($batch_id, 'staged');
389 # FIXME branch_code, number of bibs, number of items
390 _update_batch_record_counts($batch_id);
391 return ($batch_id, $num_valid, $num_items, @invalid_records);
394 =head2 AddItemsToImportBiblio
396 my @import_items_ids = AddItemsToImportBiblio($batch_id,
397 $import_record_id, $marc_record, $update_counts);
401 sub AddItemsToImportBiblio {
402 my $batch_id = shift;
403 my $import_record_id = shift;
404 my $marc_record = shift;
405 my $update_counts = @_ ? shift : 0;
407 my @import_items_ids = ();
409 my $dbh = C4::Context->dbh;
410 my ($item_tag,$item_subfield) = &GetMarcFromKohaField( "items.itemnumber" );
411 foreach my $item_field ($marc_record->field($item_tag)) {
412 my $item_marc = MARC::Record->new();
413 $item_marc->leader("00000 a "); # must set Leader/09 to 'a'
414 $item_marc->append_fields($item_field);
415 $marc_record->delete_field($item_field);
416 my $sth = $dbh->prepare_cached("INSERT INTO import_items (import_record_id, status, marcxml)
418 $sth->bind_param(1, $import_record_id);
419 $sth->bind_param(2, 'staged');
420 $sth->bind_param(3, $item_marc->as_xml("USMARC"));
422 push @import_items_ids, $dbh->{'mysql_insertid'};
426 if ($#import_items_ids > -1) {
427 _update_batch_record_counts($batch_id) if $update_counts;
429 return @import_items_ids;
432 =head2 BatchFindDuplicates
434 my $num_with_matches = BatchFindDuplicates($batch_id, $matcher,
435 $max_matches, $progress_interval, $progress_callback);
437 Goes through the records loaded in the batch and attempts to
438 find duplicates for each one. Sets the matching status
439 of each record to "no_match" or "auto_match" as appropriate.
441 The $max_matches parameter is optional; if it is not supplied,
444 The $progress_interval and $progress_callback parameters are
445 optional; if both are supplied, the sub referred to by
446 $progress_callback will be invoked every $progress_interval
447 records using the number of records processed as the
452 sub BatchFindDuplicates {
453 my $batch_id = shift;
455 my $max_matches = @_ ? shift : 10;
457 # optional callback to monitor status
459 my $progress_interval = 0;
460 my $progress_callback = undef;
462 $progress_interval = shift;
463 $progress_callback = shift;
464 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
465 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
468 my $dbh = C4::Context->dbh;
470 my $sth = $dbh->prepare("SELECT import_record_id, record_type, marc
472 WHERE import_batch_id = ?");
473 $sth->execute($batch_id);
474 my $num_with_matches = 0;
476 while (my $rowref = $sth->fetchrow_hashref) {
478 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
479 &$progress_callback($rec_num);
481 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
483 if (defined $matcher) {
484 @matches = $matcher->get_matches($marc_record, $max_matches);
486 if (scalar(@matches) > 0) {
488 SetImportRecordMatches($rowref->{'import_record_id'}, @matches);
489 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'auto_match');
491 SetImportRecordMatches($rowref->{'import_record_id'}, ());
492 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'no_match');
496 return $num_with_matches;
499 =head2 BatchCommitRecords
501 my ($num_added, $num_updated, $num_items_added, $num_items_replaced, $num_items_errored, $num_ignored) =
502 BatchCommitRecords($batch_id, $framework,
503 $progress_interval, $progress_callback);
507 sub BatchCommitRecords {
508 my $batch_id = shift;
509 my $framework = shift;
511 my $schema = Koha::Database->schema;
513 # optional callback to monitor status
515 my $progress_interval = 0;
516 my $progress_callback = undef;
518 $progress_interval = shift;
519 $progress_callback = shift;
520 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
521 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
527 my $num_items_added = 0;
528 my $num_items_replaced = 0;
529 my $num_items_errored = 0;
531 # commit (i.e., save, all records in the batch)
532 SetImportBatchStatus($batch_id, 'importing');
533 my $overlay_action = GetImportBatchOverlayAction($batch_id);
534 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
535 my $item_action = GetImportBatchItemAction($batch_id);
538 my $dbh = C4::Context->dbh;
539 my $sth = $dbh->prepare("SELECT import_records.import_record_id, record_type, status, overlay_status, marc, encoding
541 LEFT JOIN import_auths ON (import_records.import_record_id=import_auths.import_record_id)
542 LEFT JOIN import_biblios ON (import_records.import_record_id=import_biblios.import_record_id)
543 WHERE import_batch_id = ?");
544 $sth->execute($batch_id);
545 my $marcflavour = C4::Context->preference('marcflavour');
547 my $userenv = C4::Context->userenv;
548 my $logged_in_patron = Koha::Patrons->find( $userenv->{number} );
552 $schema->txn_begin; # We commit in a transaction
553 while (my $rowref = $sth->fetchrow_hashref) {
554 $record_type = $rowref->{'record_type'};
558 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
559 # report progress and commit
561 &$progress_callback( $rec_num );
564 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'imported') {
570 if ($marcflavour eq 'UNIMARC' && $record_type eq 'auth') {
571 $marc_type = 'UNIMARCAUTH';
572 } elsif ($marcflavour eq 'UNIMARC') {
573 $marc_type = 'UNIMARC';
575 $marc_type = 'USMARC';
577 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
579 if ($record_type eq 'biblio') {
580 # remove any item tags - rely on BatchCommitItems
581 ($item_tag,$item_subfield) = &GetMarcFromKohaField( "items.itemnumber" );
582 foreach my $item_field ($marc_record->field($item_tag)) {
583 $marc_record->delete_field($item_field);
587 my ($record_result, $item_result, $record_match) =
588 _get_commit_action($overlay_action, $nomatch_action, $item_action,
589 $rowref->{'overlay_status'}, $rowref->{'import_record_id'}, $record_type);
593 if ($record_result eq 'create_new') {
595 if ($record_type eq 'biblio') {
596 my $biblioitemnumber;
597 ($recordid, $biblioitemnumber) = AddBiblio($marc_record, $framework);
598 $query = "UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?"; # FIXME call SetMatchedBiblionumber instead
599 if ($item_result eq 'create_new' || $item_result eq 'replace') {
600 my ($bib_items_added, $bib_items_replaced, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid, $item_result);
601 $num_items_added += $bib_items_added;
602 $num_items_replaced += $bib_items_replaced;
603 $num_items_errored += $bib_items_errored;
606 $recordid = AddAuthority($marc_record, undef, GuessAuthTypeCode($marc_record));
607 $query = "UPDATE import_auths SET matched_authid = ? WHERE import_record_id = ?";
609 my $sth = $dbh->prepare_cached($query);
610 $sth->execute($recordid, $rowref->{'import_record_id'});
612 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
613 } elsif ($record_result eq 'replace') {
615 $recordid = $record_match;
617 if ($record_type eq 'biblio') {
618 my $oldbiblio = Koha::Biblios->find( $recordid );
619 $oldxml = GetXmlBiblio($recordid);
621 # remove item fields so that they don't get
622 # added again if record is reverted
623 # FIXME: GetXmlBiblio output should not contain item info any more! So the next foreach should not be needed. Does not hurt either; may remove old 952s that should not have been there anymore.
624 my $old_marc = MARC::Record->new_from_xml(StripNonXmlChars($oldxml), 'UTF-8', $rowref->{'encoding'}, $marc_type);
625 foreach my $item_field ($old_marc->field($item_tag)) {
626 $old_marc->delete_field($item_field);
628 $oldxml = $old_marc->as_xml($marc_type);
630 my $context = { source => 'batchimport' };
631 if ($logged_in_patron) {
632 $context->{categorycode} = $logged_in_patron->categorycode;
633 $context->{userid} = $logged_in_patron->userid;
636 ModBiblio($marc_record, $recordid, $oldbiblio->frameworkcode, {
637 overlay_context => $context
639 $query = "UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?"; # FIXME call SetMatchedBiblionumber instead
641 if ($item_result eq 'create_new' || $item_result eq 'replace') {
642 my ($bib_items_added, $bib_items_replaced, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid, $item_result);
643 $num_items_added += $bib_items_added;
644 $num_items_replaced += $bib_items_replaced;
645 $num_items_errored += $bib_items_errored;
648 $oldxml = GetAuthorityXML($recordid);
650 ModAuthority($recordid, $marc_record, GuessAuthTypeCode($marc_record));
651 $query = "UPDATE import_auths SET matched_authid = ? WHERE import_record_id = ?";
653 my $sth = $dbh->prepare_cached("UPDATE import_records SET marcxml_old = ? WHERE import_record_id = ?");
654 $sth->execute($oldxml, $rowref->{'import_record_id'});
656 my $sth2 = $dbh->prepare_cached($query);
657 $sth2->execute($recordid, $rowref->{'import_record_id'});
659 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
660 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
661 } elsif ($record_result eq 'ignore') {
662 $recordid = $record_match;
664 if ($record_type eq 'biblio' and defined $recordid and ( $item_result eq 'create_new' || $item_result eq 'replace' ) ) {
665 my ($bib_items_added, $bib_items_replaced, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid, $item_result);
666 $num_items_added += $bib_items_added;
667 $num_items_replaced += $bib_items_replaced;
668 $num_items_errored += $bib_items_errored;
669 # still need to record the matched biblionumber so that the
670 # items can be reverted
671 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?"); # FIXME call SetMatchedBiblionumber instead
672 $sth2->execute($recordid, $rowref->{'import_record_id'});
673 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
675 SetImportRecordStatus($rowref->{'import_record_id'}, 'ignored');
678 $schema->txn_commit; # Commit final records that may not have hit callback threshold
680 SetImportBatchStatus($batch_id, 'imported');
681 return ($num_added, $num_updated, $num_items_added, $num_items_replaced, $num_items_errored, $num_ignored);
684 =head2 BatchCommitItems
686 ($num_items_added, $num_items_errored) =
687 BatchCommitItems($import_record_id, $biblionumber);
691 sub BatchCommitItems {
692 my ( $import_record_id, $biblionumber, $action ) = @_;
694 my $dbh = C4::Context->dbh;
696 my $num_items_added = 0;
697 my $num_items_errored = 0;
698 my $num_items_replaced = 0;
700 my $sth = $dbh->prepare( "
701 SELECT import_items_id, import_items.marcxml, encoding
703 JOIN import_records USING (import_record_id)
704 WHERE import_record_id = ?
705 ORDER BY import_items_id
707 $sth->bind_param( 1, $import_record_id );
710 while ( my $row = $sth->fetchrow_hashref() ) {
711 my $item_marc = MARC::Record->new_from_xml( StripNonXmlChars( $row->{'marcxml'} ), 'UTF-8', $row->{'encoding'} );
713 # Delete date_due subfield as to not accidentally delete item checkout due dates
714 my ( $MARCfield, $MARCsubfield ) = GetMarcFromKohaField( 'items.onloan' );
715 $item_marc->field($MARCfield)->delete_subfield( code => $MARCsubfield );
717 my $item = TransformMarcToKoha( $item_marc );
719 my $duplicate_barcode = exists( $item->{'barcode'} ) && Koha::Items->find({ barcode => $item->{'barcode'} });
720 my $duplicate_itemnumber = exists( $item->{'itemnumber'} );
722 my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, itemnumber = ?, import_error = ? WHERE import_items_id = ?");
723 if ( $action eq "replace" && $duplicate_itemnumber ) {
724 # Duplicate itemnumbers have precedence, that way we can update barcodes by overlaying
725 ModItemFromMarc( $item_marc, $biblionumber, $item->{itemnumber} );
726 $updsth->bind_param( 1, 'imported' );
727 $updsth->bind_param( 2, $item->{itemnumber} );
728 $updsth->bind_param( 3, undef );
729 $updsth->bind_param( 4, $row->{'import_items_id'} );
732 $num_items_replaced++;
733 } elsif ( $action eq "replace" && $duplicate_barcode ) {
734 my $itemnumber = $duplicate_barcode->itemnumber;
735 ModItemFromMarc( $item_marc, $biblionumber, $itemnumber );
736 $updsth->bind_param( 1, 'imported' );
737 $updsth->bind_param( 2, $item->{itemnumber} );
738 $updsth->bind_param( 3, undef );
739 $updsth->bind_param( 4, $row->{'import_items_id'} );
742 $num_items_replaced++;
743 } elsif ($duplicate_barcode) {
744 $updsth->bind_param( 1, 'error' );
745 $updsth->bind_param( 2, undef );
746 $updsth->bind_param( 3, 'duplicate item barcode' );
747 $updsth->bind_param( 4, $row->{'import_items_id'} );
749 $num_items_errored++;
751 # Remove the itemnumber if it exists, we want to create a new item
752 my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber" );
753 $item_marc->field($itemtag)->delete_subfield( code => $itemsubfield );
755 my ( $item_biblionumber, $biblioitemnumber, $itemnumber ) = AddItemFromMarc( $item_marc, $biblionumber );
757 $updsth->bind_param( 1, 'imported' );
758 $updsth->bind_param( 2, $itemnumber );
759 $updsth->bind_param( 3, undef );
760 $updsth->bind_param( 4, $row->{'import_items_id'} );
768 return ( $num_items_added, $num_items_replaced, $num_items_errored );
771 =head2 BatchRevertRecords
773 my ($num_deleted, $num_errors, $num_reverted, $num_items_deleted,
774 $num_ignored) = BatchRevertRecords($batch_id);
778 sub BatchRevertRecords {
779 my $batch_id = shift;
781 my $logger = Koha::Logger->get( { category => 'C4.ImportBatch' } );
783 $logger->trace("C4::ImportBatch::BatchRevertRecords( $batch_id )");
788 my $num_reverted = 0;
790 my $num_items_deleted = 0;
791 # commit (i.e., save, all records in the batch)
792 SetImportBatchStatus($batch_id, 'reverting');
793 my $overlay_action = GetImportBatchOverlayAction($batch_id);
794 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
795 my $dbh = C4::Context->dbh;
796 my $sth = $dbh->prepare("SELECT import_records.import_record_id, record_type, status, overlay_status, marcxml_old, encoding, matched_biblionumber, matched_authid
798 LEFT JOIN import_auths ON (import_records.import_record_id=import_auths.import_record_id)
799 LEFT JOIN import_biblios ON (import_records.import_record_id=import_biblios.import_record_id)
800 WHERE import_batch_id = ?");
801 $sth->execute($batch_id);
803 my $marcflavour = C4::Context->preference('marcflavour');
804 while (my $rowref = $sth->fetchrow_hashref) {
805 $record_type = $rowref->{'record_type'};
806 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'reverted') {
810 if ($marcflavour eq 'UNIMARC' && $record_type eq 'auth') {
811 $marc_type = 'UNIMARCAUTH';
812 } elsif ($marcflavour eq 'UNIMARC') {
813 $marc_type = 'UNIMARC';
815 $marc_type = 'USMARC';
818 my $record_result = _get_revert_action($overlay_action, $rowref->{'overlay_status'}, $rowref->{'status'});
820 if ($record_result eq 'delete') {
822 if ($record_type eq 'biblio') {
823 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
824 $error = DelBiblio($rowref->{'matched_biblionumber'});
826 DelAuthority({ authid => $rowref->{'matched_authid'} });
828 if (defined $error) {
832 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
834 } elsif ($record_result eq 'restore') {
836 my $old_record = MARC::Record->new_from_xml(StripNonXmlChars($rowref->{'marcxml_old'}), 'UTF-8', $rowref->{'encoding'}, $marc_type);
837 if ($record_type eq 'biblio') {
838 my $biblionumber = $rowref->{'matched_biblionumber'};
839 my $oldbiblio = Koha::Biblios->find( $biblionumber );
841 $logger->info("C4::ImportBatch::BatchRevertRecords: Biblio record $biblionumber does not exist, restoration of this record was skipped") unless $oldbiblio;
842 next unless $oldbiblio; # Record has since been deleted. Deleted records should stay deleted.
844 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
845 ModBiblio($old_record, $biblionumber, $oldbiblio->frameworkcode);
847 my $authid = $rowref->{'matched_authid'};
848 ModAuthority($authid, $old_record, GuessAuthTypeCode($old_record));
850 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
851 } elsif ($record_result eq 'ignore') {
852 if ($record_type eq 'biblio') {
853 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
855 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
858 if ($record_type eq 'biblio') {
859 # remove matched_biblionumber only if there is no 'imported' item left
860 $query = "UPDATE import_biblios SET matched_biblionumber = NULL WHERE import_record_id = ?"; # FIXME Remove me
861 $query = "UPDATE import_biblios SET matched_biblionumber = NULL WHERE import_record_id = ? AND NOT EXISTS (SELECT * FROM import_items WHERE import_items.import_record_id=import_biblios.import_record_id and status='imported')";
863 $query = "UPDATE import_auths SET matched_authid = NULL WHERE import_record_id = ?";
865 my $sth2 = $dbh->prepare_cached($query);
866 $sth2->execute($rowref->{'import_record_id'});
870 SetImportBatchStatus($batch_id, 'reverted');
871 return ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored);
874 =head2 BatchRevertItems
876 my $num_items_deleted = BatchRevertItems($import_record_id, $biblionumber);
880 sub BatchRevertItems {
881 my ($import_record_id, $biblionumber) = @_;
883 my $dbh = C4::Context->dbh;
884 my $num_items_deleted = 0;
886 my $sth = $dbh->prepare_cached("SELECT import_items_id, itemnumber
888 JOIN items USING (itemnumber)
889 WHERE import_record_id = ?");
890 $sth->bind_param(1, $import_record_id);
892 while (my $row = $sth->fetchrow_hashref()) {
893 my $item = Koha::Items->find($row->{itemnumber});
894 if ($item->safe_delete){
895 my $updsth = $dbh->prepare("UPDATE import_items SET status = ? WHERE import_items_id = ?");
896 $updsth->bind_param(1, 'reverted');
897 $updsth->bind_param(2, $row->{'import_items_id'});
900 $num_items_deleted++;
907 return $num_items_deleted;
912 CleanBatch($batch_id)
914 Deletes all staged records from the import batch
915 and sets the status of the batch to 'cleaned'. Note
916 that deleting a stage record does *not* affect
917 any record that has been committed to the database.
922 my $batch_id = shift;
923 return unless defined $batch_id;
925 C4::Context->dbh->do('DELETE FROM import_records WHERE import_batch_id = ?', {}, $batch_id);
926 SetImportBatchStatus($batch_id, 'cleaned');
931 DeleteBatch($batch_id)
933 Deletes the record from the database. This can only be done
934 once the batch has been cleaned.
939 my $batch_id = shift;
940 return unless defined $batch_id;
942 my $dbh = C4::Context->dbh;
943 my $sth = $dbh->prepare('DELETE FROM import_batches WHERE import_batch_id = ?');
944 $sth->execute( $batch_id );
947 =head2 GetAllImportBatches
949 my $results = GetAllImportBatches();
951 Returns a references to an array of hash references corresponding
952 to all import_batches rows (of batch_type 'batch'), sorted in
953 ascending order by import_batch_id.
957 sub GetAllImportBatches {
958 my $dbh = C4::Context->dbh;
959 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches
960 WHERE batch_type IN ('batch', 'webservice')
961 ORDER BY import_batch_id ASC");
965 while (my $row = $sth->fetchrow_hashref) {
966 push @$results, $row;
972 =head2 GetStagedWebserviceBatches
974 my $batch_ids = GetStagedWebserviceBatches();
976 Returns a references to an array of batch id's
977 of batch_type 'webservice' that are not imported
981 my $PENDING_WEBSERVICE_BATCHES_QRY = <<EOQ;
982 SELECT import_batch_id FROM import_batches
983 WHERE batch_type = 'webservice'
984 AND import_status = 'staged'
986 sub GetStagedWebserviceBatches {
987 my $dbh = C4::Context->dbh;
988 return $dbh->selectcol_arrayref($PENDING_WEBSERVICE_BATCHES_QRY);
991 =head2 GetImportBatchRangeDesc
993 my $results = GetImportBatchRangeDesc($offset, $results_per_group);
995 Returns a reference to an array of hash references corresponding to
996 import_batches rows (sorted in descending order by import_batch_id)
997 start at the given offset.
1001 sub GetImportBatchRangeDesc {
1002 my ($offset, $results_per_group) = @_;
1004 my $dbh = C4::Context->dbh;
1005 my $query = "SELECT b.*, p.name as profile FROM import_batches b
1006 LEFT JOIN import_batch_profiles p
1007 ON b.profile_id = p.id
1008 WHERE b.batch_type IN ('batch', 'webservice')
1009 ORDER BY b.import_batch_id DESC";
1011 if ($results_per_group){
1012 $query .= " LIMIT ?";
1013 push(@params, $results_per_group);
1016 $query .= " OFFSET ?";
1017 push(@params, $offset);
1019 my $sth = $dbh->prepare_cached($query);
1020 $sth->execute(@params);
1021 my $results = $sth->fetchall_arrayref({});
1026 =head2 GetItemNumbersFromImportBatch
1028 my @itemsnos = GetItemNumbersFromImportBatch($batch_id);
1032 sub GetItemNumbersFromImportBatch {
1033 my ($batch_id) = @_;
1034 my $dbh = C4::Context->dbh;
1036 SELECT itemnumber FROM import_items
1037 INNER JOIN items USING (itemnumber)
1038 INNER JOIN import_records USING (import_record_id)
1039 WHERE import_batch_id = ?|;
1040 my $sth = $dbh->prepare( $sql );
1041 $sth->execute($batch_id);
1043 while ( my ($itm) = $sth->fetchrow_array ) {
1049 =head2 GetNumberOfImportBatches
1051 my $count = GetNumberOfImportBatches();
1055 sub GetNumberOfNonZ3950ImportBatches {
1056 my $dbh = C4::Context->dbh;
1057 my $sth = $dbh->prepare("SELECT COUNT(*) FROM import_batches WHERE batch_type != 'z3950'");
1059 my ($count) = $sth->fetchrow_array();
1064 =head2 GetImportBiblios
1066 my $results = GetImportBiblios($importid);
1070 sub GetImportBiblios {
1071 my ($import_record_id) = @_;
1073 my $dbh = C4::Context->dbh;
1074 my $query = "SELECT * FROM import_biblios WHERE import_record_id = ?";
1075 return $dbh->selectall_arrayref(
1083 =head2 GetImportRecordsRange
1085 my $results = GetImportRecordsRange($batch_id, $offset, $results_per_group);
1087 Returns a reference to an array of hash references corresponding to
1088 import_biblios/import_auths/import_records rows for a given batch
1089 starting at the given offset.
1093 sub GetImportRecordsRange {
1094 my ( $batch_id, $offset, $results_per_group, $status, $parameters ) = @_;
1096 my $dbh = C4::Context->dbh;
1098 my $order_by = $parameters->{order_by} || 'import_record_id';
1099 ( $order_by ) = grep( { $_ eq $order_by } qw( import_record_id title status overlay_status ) ) ? $order_by : 'import_record_id';
1101 my $order_by_direction =
1102 uc( $parameters->{order_by_direction} // 'ASC' ) eq 'DESC' ? 'DESC' : 'ASC';
1104 $order_by .= " $order_by_direction, authorized_heading" if $order_by eq 'title';
1106 my $query = "SELECT title, author, isbn, issn, authorized_heading, import_records.import_record_id,
1107 record_sequence, status, overlay_status,
1108 matched_biblionumber, matched_authid, record_type
1110 LEFT JOIN import_auths ON (import_records.import_record_id=import_auths.import_record_id)
1111 LEFT JOIN import_biblios ON (import_records.import_record_id=import_biblios.import_record_id)
1112 WHERE import_batch_id = ?";
1114 push(@params, $batch_id);
1116 $query .= " AND status=?";
1117 push(@params,$status);
1120 $query.=" ORDER BY $order_by $order_by_direction";
1122 if($results_per_group){
1123 $query .= " LIMIT ?";
1124 push(@params, $results_per_group);
1127 $query .= " OFFSET ?";
1128 push(@params, $offset);
1130 my $sth = $dbh->prepare_cached($query);
1131 $sth->execute(@params);
1132 my $results = $sth->fetchall_arrayref({});
1138 =head2 GetBestRecordMatch
1140 my $record_id = GetBestRecordMatch($import_record_id);
1144 sub GetBestRecordMatch {
1145 my ($import_record_id) = @_;
1147 my $dbh = C4::Context->dbh;
1148 my $sth = $dbh->prepare("SELECT candidate_match_id
1149 FROM import_record_matches
1150 JOIN import_records ON ( import_record_matches.import_record_id = import_records.import_record_id )
1151 LEFT JOIN biblio ON ( candidate_match_id = biblio.biblionumber )
1152 LEFT JOIN auth_header ON ( candidate_match_id = auth_header.authid )
1153 WHERE import_record_matches.import_record_id = ? AND
1154 ( (import_records.record_type = 'biblio' AND biblio.biblionumber IS NOT NULL) OR
1155 (import_records.record_type = 'auth' AND auth_header.authid IS NOT NULL) )
1157 ORDER BY score DESC, candidate_match_id DESC");
1158 $sth->execute($import_record_id);
1159 my ($record_id) = $sth->fetchrow_array();
1164 =head2 GetImportBatchStatus
1166 my $status = GetImportBatchStatus($batch_id);
1170 sub GetImportBatchStatus {
1171 my ($batch_id) = @_;
1173 my $dbh = C4::Context->dbh;
1174 my $sth = $dbh->prepare("SELECT import_status FROM import_batches WHERE import_batch_id = ?");
1175 $sth->execute($batch_id);
1176 my ($status) = $sth->fetchrow_array();
1182 =head2 SetImportBatchStatus
1184 SetImportBatchStatus($batch_id, $new_status);
1188 sub SetImportBatchStatus {
1189 my ($batch_id, $new_status) = @_;
1191 my $dbh = C4::Context->dbh;
1192 my $sth = $dbh->prepare("UPDATE import_batches SET import_status = ? WHERE import_batch_id = ?");
1193 $sth->execute($new_status, $batch_id);
1198 =head2 SetMatchedBiblionumber
1200 SetMatchedBiblionumber($import_record_id, $biblionumber);
1204 sub SetMatchedBiblionumber {
1205 my ($import_record_id, $biblionumber) = @_;
1207 my $dbh = C4::Context->dbh;
1209 q|UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?|,
1210 undef, $biblionumber, $import_record_id
1214 =head2 GetImportBatchOverlayAction
1216 my $overlay_action = GetImportBatchOverlayAction($batch_id);
1220 sub GetImportBatchOverlayAction {
1221 my ($batch_id) = @_;
1223 my $dbh = C4::Context->dbh;
1224 my $sth = $dbh->prepare("SELECT overlay_action FROM import_batches WHERE import_batch_id = ?");
1225 $sth->execute($batch_id);
1226 my ($overlay_action) = $sth->fetchrow_array();
1228 return $overlay_action;
1233 =head2 SetImportBatchOverlayAction
1235 SetImportBatchOverlayAction($batch_id, $new_overlay_action);
1239 sub SetImportBatchOverlayAction {
1240 my ($batch_id, $new_overlay_action) = @_;
1242 my $dbh = C4::Context->dbh;
1243 my $sth = $dbh->prepare("UPDATE import_batches SET overlay_action = ? WHERE import_batch_id = ?");
1244 $sth->execute($new_overlay_action, $batch_id);
1249 =head2 GetImportBatchNoMatchAction
1251 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
1255 sub GetImportBatchNoMatchAction {
1256 my ($batch_id) = @_;
1258 my $dbh = C4::Context->dbh;
1259 my $sth = $dbh->prepare("SELECT nomatch_action FROM import_batches WHERE import_batch_id = ?");
1260 $sth->execute($batch_id);
1261 my ($nomatch_action) = $sth->fetchrow_array();
1263 return $nomatch_action;
1268 =head2 SetImportBatchNoMatchAction
1270 SetImportBatchNoMatchAction($batch_id, $new_nomatch_action);
1274 sub SetImportBatchNoMatchAction {
1275 my ($batch_id, $new_nomatch_action) = @_;
1277 my $dbh = C4::Context->dbh;
1278 my $sth = $dbh->prepare("UPDATE import_batches SET nomatch_action = ? WHERE import_batch_id = ?");
1279 $sth->execute($new_nomatch_action, $batch_id);
1284 =head2 GetImportBatchItemAction
1286 my $item_action = GetImportBatchItemAction($batch_id);
1290 sub GetImportBatchItemAction {
1291 my ($batch_id) = @_;
1293 my $dbh = C4::Context->dbh;
1294 my $sth = $dbh->prepare("SELECT item_action FROM import_batches WHERE import_batch_id = ?");
1295 $sth->execute($batch_id);
1296 my ($item_action) = $sth->fetchrow_array();
1298 return $item_action;
1303 =head2 SetImportBatchItemAction
1305 SetImportBatchItemAction($batch_id, $new_item_action);
1309 sub SetImportBatchItemAction {
1310 my ($batch_id, $new_item_action) = @_;
1312 my $dbh = C4::Context->dbh;
1313 my $sth = $dbh->prepare("UPDATE import_batches SET item_action = ? WHERE import_batch_id = ?");
1314 $sth->execute($new_item_action, $batch_id);
1319 =head2 GetImportBatchMatcher
1321 my $matcher_id = GetImportBatchMatcher($batch_id);
1325 sub GetImportBatchMatcher {
1326 my ($batch_id) = @_;
1328 my $dbh = C4::Context->dbh;
1329 my $sth = $dbh->prepare("SELECT matcher_id FROM import_batches WHERE import_batch_id = ?");
1330 $sth->execute($batch_id);
1331 my ($matcher_id) = $sth->fetchrow_array();
1338 =head2 SetImportBatchMatcher
1340 SetImportBatchMatcher($batch_id, $new_matcher_id);
1344 sub SetImportBatchMatcher {
1345 my ($batch_id, $new_matcher_id) = @_;
1347 my $dbh = C4::Context->dbh;
1348 my $sth = $dbh->prepare("UPDATE import_batches SET matcher_id = ? WHERE import_batch_id = ?");
1349 $sth->execute($new_matcher_id, $batch_id);
1354 =head2 GetImportRecordOverlayStatus
1356 my $overlay_status = GetImportRecordOverlayStatus($import_record_id);
1360 sub GetImportRecordOverlayStatus {
1361 my ($import_record_id) = @_;
1363 my $dbh = C4::Context->dbh;
1364 my $sth = $dbh->prepare("SELECT overlay_status FROM import_records WHERE import_record_id = ?");
1365 $sth->execute($import_record_id);
1366 my ($overlay_status) = $sth->fetchrow_array();
1368 return $overlay_status;
1373 =head2 SetImportRecordOverlayStatus
1375 SetImportRecordOverlayStatus($import_record_id, $new_overlay_status);
1379 sub SetImportRecordOverlayStatus {
1380 my ($import_record_id, $new_overlay_status) = @_;
1382 my $dbh = C4::Context->dbh;
1383 my $sth = $dbh->prepare("UPDATE import_records SET overlay_status = ? WHERE import_record_id = ?");
1384 $sth->execute($new_overlay_status, $import_record_id);
1389 =head2 GetImportRecordStatus
1391 my $status = GetImportRecordStatus($import_record_id);
1395 sub GetImportRecordStatus {
1396 my ($import_record_id) = @_;
1398 my $dbh = C4::Context->dbh;
1399 my $sth = $dbh->prepare("SELECT status FROM import_records WHERE import_record_id = ?");
1400 $sth->execute($import_record_id);
1401 my ($status) = $sth->fetchrow_array();
1408 =head2 SetImportRecordStatus
1410 SetImportRecordStatus($import_record_id, $new_status);
1414 sub SetImportRecordStatus {
1415 my ($import_record_id, $new_status) = @_;
1417 my $dbh = C4::Context->dbh;
1418 my $sth = $dbh->prepare("UPDATE import_records SET status = ? WHERE import_record_id = ?");
1419 $sth->execute($new_status, $import_record_id);
1424 =head2 GetImportRecordMatches
1426 my $results = GetImportRecordMatches($import_record_id, $best_only);
1430 sub GetImportRecordMatches {
1431 my $import_record_id = shift;
1432 my $best_only = @_ ? shift : 0;
1434 my $dbh = C4::Context->dbh;
1435 # FIXME currently biblio only
1436 my $sth = $dbh->prepare_cached("SELECT title, author, biblionumber,
1437 candidate_match_id, score, record_type,
1440 JOIN import_record_matches USING (import_record_id)
1441 LEFT JOIN biblio ON (biblionumber = candidate_match_id)
1442 WHERE import_record_id = ?
1443 ORDER BY score DESC, biblionumber DESC");
1444 $sth->bind_param(1, $import_record_id);
1447 while (my $row = $sth->fetchrow_hashref) {
1448 if ($row->{'record_type'} eq 'auth') {
1449 $row->{'authorized_heading'} = C4::AuthoritiesMarc::GetAuthorizedHeading( { authid => $row->{'candidate_match_id'} } );
1451 next if ($row->{'record_type'} eq 'biblio' && not $row->{'biblionumber'});
1452 push @$results, $row;
1461 =head2 SetImportRecordMatches
1463 SetImportRecordMatches($import_record_id, @matches);
1467 sub SetImportRecordMatches {
1468 my $import_record_id = shift;
1471 my $dbh = C4::Context->dbh;
1472 my $delsth = $dbh->prepare("DELETE FROM import_record_matches WHERE import_record_id = ?");
1473 $delsth->execute($import_record_id);
1476 my $sth = $dbh->prepare("INSERT INTO import_record_matches (import_record_id, candidate_match_id, score, chosen)
1477 VALUES (?, ?, ?, ?)");
1478 my $chosen = 1; #The first match is defaulted to be chosen
1479 foreach my $match (@matches) {
1480 $sth->execute($import_record_id, $match->{'record_id'}, $match->{'score'}, $chosen);
1481 $chosen = 0; #After the first we do not default to other matches
1485 =head2 RecordsFromISO2709File
1487 my ($errors, $records) = C4::ImportBatch::RecordsFromISO2709File($input_file, $record_type, $encoding);
1489 Reads ISO2709 binary porridge from the given file and creates MARC::Record-objects out of it.
1491 @PARAM1, String, absolute path to the ISO2709 file.
1492 @PARAM2, String, see stage_file.pl
1493 @PARAM3, String, should be utf8
1495 Returns two array refs.
1499 sub RecordsFromISO2709File {
1500 my ($input_file, $record_type, $encoding) = @_;
1503 my $marc_type = C4::Context->preference('marcflavour');
1504 $marc_type .= 'AUTH' if ($marc_type eq 'UNIMARC' && $record_type eq 'auth');
1506 open my $fh, '<', $input_file or die "$0: cannot open input file $input_file: $!\n";
1512 next unless $_; # skip if record has only whitespace, as might occur
1513 # if file includes newlines between each MARC record
1514 my ($marc_record, $charset_guessed, $char_errors) = MarcToUTF8Record($_, $marc_type, $encoding);
1515 push @marc_records, $marc_record;
1516 if ($charset_guessed ne $encoding) {
1518 "Unexpected charset $charset_guessed, expecting $encoding";
1522 return ( \@errors, \@marc_records );
1525 =head2 RecordsFromMARCXMLFile
1527 my ($errors, $records) = C4::ImportBatch::RecordsFromMARCXMLFile($input_file, $encoding);
1529 Creates MARC::Record-objects out of the given MARCXML-file.
1531 @PARAM1, String, absolute path to the ISO2709 file.
1532 @PARAM2, String, should be utf8
1534 Returns two array refs.
1538 sub RecordsFromMARCXMLFile {
1539 my ( $filename, $encoding ) = @_;
1540 my $batch = MARC::File::XML->in( $filename );
1541 my ( @marcRecords, @errors, $record );
1543 eval { $record = $batch->next( $encoding ); };
1547 push @marcRecords, $record if $record;
1549 return (\@errors, \@marcRecords);
1552 =head2 RecordsFromMarcPlugin
1554 Converts text of input_file into array of MARC records with to_marc plugin
1558 sub RecordsFromMarcPlugin {
1559 my ($input_file, $plugin_class, $encoding) = @_;
1560 my ( $text, @return );
1561 return \@return if !$input_file || !$plugin_class;
1564 open my $fh, '<', $input_file or die "$0: cannot open input file $input_file: $!\n";
1574 # Convert to large MARC blob with plugin
1575 $text = Koha::Plugins::Handler->run({
1576 class => $plugin_class,
1577 method => 'to_marc',
1578 params => { data => $text },
1581 # Convert to array of MARC records
1583 my $marc_type = C4::Context->preference('marcflavour');
1584 foreach my $blob ( split(/\x1D/, $text) ) {
1585 next if $blob =~ /^\s*$/;
1586 my ($marcrecord) = MarcToUTF8Record($blob, $marc_type, $encoding);
1587 push @return, $marcrecord;
1593 # internal functions
1595 sub _create_import_record {
1596 my ($batch_id, $record_sequence, $marc_record, $record_type, $encoding, $marc_type) = @_;
1598 my $dbh = C4::Context->dbh;
1599 my $sth = $dbh->prepare("INSERT INTO import_records (import_batch_id, record_sequence, marc, marcxml, marcxml_old,
1600 record_type, encoding)
1601 VALUES (?, ?, ?, ?, ?, ?, ?)");
1602 $sth->execute($batch_id, $record_sequence, $marc_record->as_usmarc(), $marc_record->as_xml($marc_type), '',
1603 $record_type, $encoding);
1604 my $import_record_id = $dbh->{'mysql_insertid'};
1606 return $import_record_id;
1609 sub _add_auth_fields {
1610 my ($import_record_id, $marc_record) = @_;
1613 if ($marc_record->field('001')) {
1614 $controlnumber = $marc_record->field('001')->data();
1616 my $authorized_heading = C4::AuthoritiesMarc::GetAuthorizedHeading({ record => $marc_record });
1617 my $dbh = C4::Context->dbh;
1618 my $sth = $dbh->prepare("INSERT INTO import_auths (import_record_id, control_number, authorized_heading) VALUES (?, ?, ?)");
1619 $sth->execute($import_record_id, $controlnumber, $authorized_heading);
1623 sub _add_biblio_fields {
1624 my ($import_record_id, $marc_record) = @_;
1626 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1627 my $dbh = C4::Context->dbh;
1628 # FIXME no controlnumber, originalsource
1629 $isbn = C4::Koha::GetNormalizedISBN($isbn);
1630 my $sth = $dbh->prepare("INSERT INTO import_biblios (import_record_id, title, author, isbn, issn) VALUES (?, ?, ?, ?, ?)");
1631 $sth->execute($import_record_id, $title, $author, $isbn, $issn) or die $sth->errstr;
1636 sub _update_biblio_fields {
1637 my ($import_record_id, $marc_record) = @_;
1639 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1640 my $dbh = C4::Context->dbh;
1641 # FIXME no controlnumber, originalsource
1642 # FIXME 2 - should regularize normalization of ISBN wherever it is done
1646 my $sth = $dbh->prepare("UPDATE import_biblios SET title = ?, author = ?, isbn = ?, issn = ?
1647 WHERE import_record_id = ?");
1648 $sth->execute($title, $author, $isbn, $issn, $import_record_id);
1652 sub _parse_biblio_fields {
1653 my ($marc_record) = @_;
1655 my $dbh = C4::Context->dbh;
1656 my $bibliofields = TransformMarcToKoha($marc_record, '');
1657 return ($bibliofields->{'title'}, $bibliofields->{'author'}, $bibliofields->{'isbn'}, $bibliofields->{'issn'});
1661 sub _update_batch_record_counts {
1662 my ($batch_id) = @_;
1664 my $dbh = C4::Context->dbh;
1665 my $sth = $dbh->prepare_cached("UPDATE import_batches SET
1669 WHERE import_batch_id = import_batches.import_batch_id),
1673 JOIN import_items USING (import_record_id)
1674 WHERE import_batch_id = import_batches.import_batch_id
1675 AND record_type = 'biblio')
1676 WHERE import_batch_id = ?");
1677 $sth->bind_param(1, $batch_id);
1682 sub _get_commit_action {
1683 my ($overlay_action, $nomatch_action, $item_action, $overlay_status, $import_record_id, $record_type) = @_;
1685 if ($record_type eq 'biblio') {
1686 my ($bib_result, $bib_match, $item_result);
1688 $bib_match = GetBestRecordMatch($import_record_id);
1689 if ($overlay_status ne 'no_match' && defined($bib_match)) {
1691 $bib_result = $overlay_action;
1693 if($item_action eq 'always_add' or $item_action eq 'add_only_for_matches'){
1694 $item_result = 'create_new';
1695 } elsif($item_action eq 'replace'){
1696 $item_result = 'replace';
1698 $item_result = 'ignore';
1702 $bib_result = $nomatch_action;
1703 $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_new') ? 'create_new' : 'ignore';
1705 return ($bib_result, $item_result, $bib_match);
1706 } else { # must be auths
1707 my ($auth_result, $auth_match);
1709 $auth_match = GetBestRecordMatch($import_record_id);
1710 if ($overlay_status ne 'no_match' && defined($auth_match)) {
1711 $auth_result = $overlay_action;
1713 $auth_result = $nomatch_action;
1716 return ($auth_result, undef, $auth_match);
1721 sub _get_revert_action {
1722 my ($overlay_action, $overlay_status, $status) = @_;
1726 if ($status eq 'ignored') {
1727 $bib_result = 'ignore';
1729 if ($overlay_action eq 'create_new') {
1730 $bib_result = 'delete';
1732 $bib_result = ($overlay_status eq 'match_applied') ? 'restore' : 'delete';
1743 Koha Development Team <http://koha-community.org/>
1745 Galen Charlton <galen.charlton@liblime.com>