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, int(rand(99999)), 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, int(rand(99999)), 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;
428 _update_import_record_marc($import_record_id, $marc_record, C4::Context->preference('marcflavour'));
430 return @import_items_ids;
433 =head2 BatchFindDuplicates
435 my $num_with_matches = BatchFindDuplicates($batch_id, $matcher,
436 $max_matches, $progress_interval, $progress_callback);
438 Goes through the records loaded in the batch and attempts to
439 find duplicates for each one. Sets the matching status
440 of each record to "no_match" or "auto_match" as appropriate.
442 The $max_matches parameter is optional; if it is not supplied,
445 The $progress_interval and $progress_callback parameters are
446 optional; if both are supplied, the sub referred to by
447 $progress_callback will be invoked every $progress_interval
448 records using the number of records processed as the
453 sub BatchFindDuplicates {
454 my $batch_id = shift;
456 my $max_matches = @_ ? shift : 10;
458 # optional callback to monitor status
460 my $progress_interval = 0;
461 my $progress_callback = undef;
463 $progress_interval = shift;
464 $progress_callback = shift;
465 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
466 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
469 my $dbh = C4::Context->dbh;
471 my $sth = $dbh->prepare("SELECT import_record_id, record_type, marc
473 WHERE import_batch_id = ?");
474 $sth->execute($batch_id);
475 my $num_with_matches = 0;
477 while (my $rowref = $sth->fetchrow_hashref) {
479 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
480 &$progress_callback($rec_num);
482 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
484 if (defined $matcher) {
485 @matches = $matcher->get_matches($marc_record, $max_matches);
487 if (scalar(@matches) > 0) {
489 SetImportRecordMatches($rowref->{'import_record_id'}, @matches);
490 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'auto_match');
492 SetImportRecordMatches($rowref->{'import_record_id'}, ());
493 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'no_match');
497 return $num_with_matches;
500 =head2 BatchCommitRecords
502 my ($num_added, $num_updated, $num_items_added, $num_items_replaced, $num_items_errored, $num_ignored) =
503 BatchCommitRecords($batch_id, $framework,
504 $progress_interval, $progress_callback);
508 sub BatchCommitRecords {
509 my $batch_id = shift;
510 my $framework = shift;
512 my $schema = Koha::Database->schema;
514 # optional callback to monitor status
516 my $progress_interval = 0;
517 my $progress_callback = undef;
519 $progress_interval = shift;
520 $progress_callback = shift;
521 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
522 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
528 my $num_items_added = 0;
529 my $num_items_replaced = 0;
530 my $num_items_errored = 0;
532 # commit (i.e., save, all records in the batch)
533 SetImportBatchStatus($batch_id, 'importing');
534 my $overlay_action = GetImportBatchOverlayAction($batch_id);
535 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
536 my $item_action = GetImportBatchItemAction($batch_id);
539 my $dbh = C4::Context->dbh;
540 my $sth = $dbh->prepare("SELECT import_records.import_record_id, record_type, status, overlay_status, marc, encoding
542 LEFT JOIN import_auths ON (import_records.import_record_id=import_auths.import_record_id)
543 LEFT JOIN import_biblios ON (import_records.import_record_id=import_biblios.import_record_id)
544 WHERE import_batch_id = ?");
545 $sth->execute($batch_id);
546 my $marcflavour = C4::Context->preference('marcflavour');
548 my $userenv = C4::Context->userenv;
549 my $logged_in_patron = Koha::Patrons->find( $userenv->{number} );
553 $schema->txn_begin; # We commit in a transaction
554 while (my $rowref = $sth->fetchrow_hashref) {
555 $record_type = $rowref->{'record_type'};
559 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
560 # report progress and commit
562 &$progress_callback( $rec_num );
565 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'imported') {
571 if ($marcflavour eq 'UNIMARC' && $record_type eq 'auth') {
572 $marc_type = 'UNIMARCAUTH';
573 } elsif ($marcflavour eq 'UNIMARC') {
574 $marc_type = 'UNIMARC';
576 $marc_type = 'USMARC';
578 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
580 if ($record_type eq 'biblio') {
581 # remove any item tags - rely on BatchCommitItems
582 ($item_tag,$item_subfield) = &GetMarcFromKohaField( "items.itemnumber" );
583 foreach my $item_field ($marc_record->field($item_tag)) {
584 $marc_record->delete_field($item_field);
588 my ($record_result, $item_result, $record_match) =
589 _get_commit_action($overlay_action, $nomatch_action, $item_action,
590 $rowref->{'overlay_status'}, $rowref->{'import_record_id'}, $record_type);
594 if ($record_result eq 'create_new') {
596 if ($record_type eq 'biblio') {
597 my $biblioitemnumber;
598 ($recordid, $biblioitemnumber) = AddBiblio($marc_record, $framework);
599 $query = "UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?"; # FIXME call SetMatchedBiblionumber instead
600 if ($item_result eq 'create_new' || $item_result eq 'replace') {
601 my ($bib_items_added, $bib_items_replaced, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid, $item_result);
602 $num_items_added += $bib_items_added;
603 $num_items_replaced += $bib_items_replaced;
604 $num_items_errored += $bib_items_errored;
607 $recordid = AddAuthority($marc_record, undef, GuessAuthTypeCode($marc_record));
608 $query = "UPDATE import_auths SET matched_authid = ? WHERE import_record_id = ?";
610 my $sth = $dbh->prepare_cached($query);
611 $sth->execute($recordid, $rowref->{'import_record_id'});
613 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
614 } elsif ($record_result eq 'replace') {
616 $recordid = $record_match;
618 if ($record_type eq 'biblio') {
619 my $oldbiblio = Koha::Biblios->find( $recordid );
620 $oldxml = GetXmlBiblio($recordid);
622 # remove item fields so that they don't get
623 # added again if record is reverted
624 # 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.
625 my $old_marc = MARC::Record->new_from_xml(StripNonXmlChars($oldxml), 'UTF-8', $rowref->{'encoding'}, $marc_type);
626 foreach my $item_field ($old_marc->field($item_tag)) {
627 $old_marc->delete_field($item_field);
629 $oldxml = $old_marc->as_xml($marc_type);
631 my $context = { source => 'batchimport' };
632 if ($logged_in_patron) {
633 $context->{categorycode} = $logged_in_patron->categorycode;
634 $context->{userid} = $logged_in_patron->userid;
637 ModBiblio($marc_record, $recordid, $oldbiblio->frameworkcode, {
638 overlay_context => $context
640 $query = "UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?"; # FIXME call SetMatchedBiblionumber instead
642 if ($item_result eq 'create_new' || $item_result eq 'replace') {
643 my ($bib_items_added, $bib_items_replaced, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid, $item_result);
644 $num_items_added += $bib_items_added;
645 $num_items_replaced += $bib_items_replaced;
646 $num_items_errored += $bib_items_errored;
649 $oldxml = GetAuthorityXML($recordid);
651 ModAuthority($recordid, $marc_record, GuessAuthTypeCode($marc_record));
652 $query = "UPDATE import_auths SET matched_authid = ? WHERE import_record_id = ?";
654 my $sth = $dbh->prepare_cached("UPDATE import_records SET marcxml_old = ? WHERE import_record_id = ?");
655 $sth->execute($oldxml, $rowref->{'import_record_id'});
657 my $sth2 = $dbh->prepare_cached($query);
658 $sth2->execute($recordid, $rowref->{'import_record_id'});
660 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
661 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
662 } elsif ($record_result eq 'ignore') {
663 $recordid = $record_match;
665 if ($record_type eq 'biblio' and defined $recordid and ( $item_result eq 'create_new' || $item_result eq 'replace' ) ) {
666 my ($bib_items_added, $bib_items_replaced, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid, $item_result);
667 $num_items_added += $bib_items_added;
668 $num_items_replaced += $bib_items_replaced;
669 $num_items_errored += $bib_items_errored;
670 # still need to record the matched biblionumber so that the
671 # items can be reverted
672 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?"); # FIXME call SetMatchedBiblionumber instead
673 $sth2->execute($recordid, $rowref->{'import_record_id'});
674 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
676 SetImportRecordStatus($rowref->{'import_record_id'}, 'ignored');
679 $schema->txn_commit; # Commit final records that may not have hit callback threshold
681 SetImportBatchStatus($batch_id, 'imported');
682 return ($num_added, $num_updated, $num_items_added, $num_items_replaced, $num_items_errored, $num_ignored);
685 =head2 BatchCommitItems
687 ($num_items_added, $num_items_errored) =
688 BatchCommitItems($import_record_id, $biblionumber);
692 sub BatchCommitItems {
693 my ( $import_record_id, $biblionumber, $action ) = @_;
695 my $dbh = C4::Context->dbh;
697 my $num_items_added = 0;
698 my $num_items_errored = 0;
699 my $num_items_replaced = 0;
701 my $sth = $dbh->prepare( "
702 SELECT import_items_id, import_items.marcxml, encoding
704 JOIN import_records USING (import_record_id)
705 WHERE import_record_id = ?
706 ORDER BY import_items_id
708 $sth->bind_param( 1, $import_record_id );
711 while ( my $row = $sth->fetchrow_hashref() ) {
712 my $item_marc = MARC::Record->new_from_xml( StripNonXmlChars( $row->{'marcxml'} ), 'UTF-8', $row->{'encoding'} );
714 # Delete date_due subfield as to not accidentally delete item checkout due dates
715 my ( $MARCfield, $MARCsubfield ) = GetMarcFromKohaField( 'items.onloan' );
716 $item_marc->field($MARCfield)->delete_subfield( code => $MARCsubfield );
718 my $item = TransformMarcToKoha( $item_marc );
720 my $duplicate_barcode = exists( $item->{'barcode'} ) && Koha::Items->find({ barcode => $item->{'barcode'} });
721 my $duplicate_itemnumber = exists( $item->{'itemnumber'} );
723 my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, itemnumber = ?, import_error = ? WHERE import_items_id = ?");
724 if ( $action eq "replace" && $duplicate_itemnumber ) {
725 # Duplicate itemnumbers have precedence, that way we can update barcodes by overlaying
726 ModItemFromMarc( $item_marc, $biblionumber, $item->{itemnumber} );
727 $updsth->bind_param( 1, 'imported' );
728 $updsth->bind_param( 2, $item->{itemnumber} );
729 $updsth->bind_param( 3, undef );
730 $updsth->bind_param( 4, $row->{'import_items_id'} );
733 $num_items_replaced++;
734 } elsif ( $action eq "replace" && $duplicate_barcode ) {
735 my $itemnumber = $duplicate_barcode->itemnumber;
736 ModItemFromMarc( $item_marc, $biblionumber, $itemnumber );
737 $updsth->bind_param( 1, 'imported' );
738 $updsth->bind_param( 2, $item->{itemnumber} );
739 $updsth->bind_param( 3, undef );
740 $updsth->bind_param( 4, $row->{'import_items_id'} );
743 $num_items_replaced++;
744 } elsif ($duplicate_barcode) {
745 $updsth->bind_param( 1, 'error' );
746 $updsth->bind_param( 2, undef );
747 $updsth->bind_param( 3, 'duplicate item barcode' );
748 $updsth->bind_param( 4, $row->{'import_items_id'} );
750 $num_items_errored++;
752 # Remove the itemnumber if it exists, we want to create a new item
753 my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField( "items.itemnumber" );
754 $item_marc->field($itemtag)->delete_subfield( code => $itemsubfield );
756 my ( $item_biblionumber, $biblioitemnumber, $itemnumber ) = AddItemFromMarc( $item_marc, $biblionumber );
758 $updsth->bind_param( 1, 'imported' );
759 $updsth->bind_param( 2, $itemnumber );
760 $updsth->bind_param( 3, undef );
761 $updsth->bind_param( 4, $row->{'import_items_id'} );
769 return ( $num_items_added, $num_items_replaced, $num_items_errored );
772 =head2 BatchRevertRecords
774 my ($num_deleted, $num_errors, $num_reverted, $num_items_deleted,
775 $num_ignored) = BatchRevertRecords($batch_id);
779 sub BatchRevertRecords {
780 my $batch_id = shift;
782 my $logger = Koha::Logger->get( { category => 'C4.ImportBatch' } );
784 $logger->trace("C4::ImportBatch::BatchRevertRecords( $batch_id )");
789 my $num_reverted = 0;
791 my $num_items_deleted = 0;
792 # commit (i.e., save, all records in the batch)
793 SetImportBatchStatus($batch_id, 'reverting');
794 my $overlay_action = GetImportBatchOverlayAction($batch_id);
795 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
796 my $dbh = C4::Context->dbh;
797 my $sth = $dbh->prepare("SELECT import_records.import_record_id, record_type, status, overlay_status, marcxml_old, encoding, matched_biblionumber, matched_authid
799 LEFT JOIN import_auths ON (import_records.import_record_id=import_auths.import_record_id)
800 LEFT JOIN import_biblios ON (import_records.import_record_id=import_biblios.import_record_id)
801 WHERE import_batch_id = ?");
802 $sth->execute($batch_id);
804 my $marcflavour = C4::Context->preference('marcflavour');
805 while (my $rowref = $sth->fetchrow_hashref) {
806 $record_type = $rowref->{'record_type'};
807 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'reverted') {
811 if ($marcflavour eq 'UNIMARC' && $record_type eq 'auth') {
812 $marc_type = 'UNIMARCAUTH';
813 } elsif ($marcflavour eq 'UNIMARC') {
814 $marc_type = 'UNIMARC';
816 $marc_type = 'USMARC';
819 my $record_result = _get_revert_action($overlay_action, $rowref->{'overlay_status'}, $rowref->{'status'});
821 if ($record_result eq 'delete') {
823 if ($record_type eq 'biblio') {
824 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
825 $error = DelBiblio($rowref->{'matched_biblionumber'});
827 DelAuthority({ authid => $rowref->{'matched_authid'} });
829 if (defined $error) {
833 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
835 } elsif ($record_result eq 'restore') {
837 my $old_record = MARC::Record->new_from_xml(StripNonXmlChars($rowref->{'marcxml_old'}), 'UTF-8', $rowref->{'encoding'}, $marc_type);
838 if ($record_type eq 'biblio') {
839 my $biblionumber = $rowref->{'matched_biblionumber'};
840 my $oldbiblio = Koha::Biblios->find( $biblionumber );
842 $logger->info("C4::ImportBatch::BatchRevertRecords: Biblio record $biblionumber does not exist, restoration of this record was skipped") unless $oldbiblio;
843 next unless $oldbiblio; # Record has since been deleted. Deleted records should stay deleted.
845 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
846 ModBiblio($old_record, $biblionumber, $oldbiblio->frameworkcode);
848 my $authid = $rowref->{'matched_authid'};
849 ModAuthority($authid, $old_record, GuessAuthTypeCode($old_record));
851 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
852 } elsif ($record_result eq 'ignore') {
853 if ($record_type eq 'biblio') {
854 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
856 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
859 if ($record_type eq 'biblio') {
860 # remove matched_biblionumber only if there is no 'imported' item left
861 $query = "UPDATE import_biblios SET matched_biblionumber = NULL WHERE import_record_id = ?"; # FIXME Remove me
862 $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')";
864 $query = "UPDATE import_auths SET matched_authid = NULL WHERE import_record_id = ?";
866 my $sth2 = $dbh->prepare_cached($query);
867 $sth2->execute($rowref->{'import_record_id'});
871 SetImportBatchStatus($batch_id, 'reverted');
872 return ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored);
875 =head2 BatchRevertItems
877 my $num_items_deleted = BatchRevertItems($import_record_id, $biblionumber);
881 sub BatchRevertItems {
882 my ($import_record_id, $biblionumber) = @_;
884 my $dbh = C4::Context->dbh;
885 my $num_items_deleted = 0;
887 my $sth = $dbh->prepare_cached("SELECT import_items_id, itemnumber
889 JOIN items USING (itemnumber)
890 WHERE import_record_id = ?");
891 $sth->bind_param(1, $import_record_id);
893 while (my $row = $sth->fetchrow_hashref()) {
894 my $item = Koha::Items->find($row->{itemnumber});
895 if ($item->safe_delete){
896 my $updsth = $dbh->prepare("UPDATE import_items SET status = ? WHERE import_items_id = ?");
897 $updsth->bind_param(1, 'reverted');
898 $updsth->bind_param(2, $row->{'import_items_id'});
901 $num_items_deleted++;
908 return $num_items_deleted;
913 CleanBatch($batch_id)
915 Deletes all staged records from the import batch
916 and sets the status of the batch to 'cleaned'. Note
917 that deleting a stage record does *not* affect
918 any record that has been committed to the database.
923 my $batch_id = shift;
924 return unless defined $batch_id;
926 C4::Context->dbh->do('DELETE FROM import_records WHERE import_batch_id = ?', {}, $batch_id);
927 SetImportBatchStatus($batch_id, 'cleaned');
932 DeleteBatch($batch_id)
934 Deletes the record from the database. This can only be done
935 once the batch has been cleaned.
940 my $batch_id = shift;
941 return unless defined $batch_id;
943 my $dbh = C4::Context->dbh;
944 my $sth = $dbh->prepare('DELETE FROM import_batches WHERE import_batch_id = ?');
945 $sth->execute( $batch_id );
948 =head2 GetAllImportBatches
950 my $results = GetAllImportBatches();
952 Returns a references to an array of hash references corresponding
953 to all import_batches rows (of batch_type 'batch'), sorted in
954 ascending order by import_batch_id.
958 sub GetAllImportBatches {
959 my $dbh = C4::Context->dbh;
960 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches
961 WHERE batch_type IN ('batch', 'webservice')
962 ORDER BY import_batch_id ASC");
966 while (my $row = $sth->fetchrow_hashref) {
967 push @$results, $row;
973 =head2 GetStagedWebserviceBatches
975 my $batch_ids = GetStagedWebserviceBatches();
977 Returns a references to an array of batch id's
978 of batch_type 'webservice' that are not imported
982 my $PENDING_WEBSERVICE_BATCHES_QRY = <<EOQ;
983 SELECT import_batch_id FROM import_batches
984 WHERE batch_type = 'webservice'
985 AND import_status = 'staged'
987 sub GetStagedWebserviceBatches {
988 my $dbh = C4::Context->dbh;
989 return $dbh->selectcol_arrayref($PENDING_WEBSERVICE_BATCHES_QRY);
992 =head2 GetImportBatchRangeDesc
994 my $results = GetImportBatchRangeDesc($offset, $results_per_group);
996 Returns a reference to an array of hash references corresponding to
997 import_batches rows (sorted in descending order by import_batch_id)
998 start at the given offset.
1002 sub GetImportBatchRangeDesc {
1003 my ($offset, $results_per_group) = @_;
1005 my $dbh = C4::Context->dbh;
1006 my $query = "SELECT b.*, p.name as profile FROM import_batches b
1007 LEFT JOIN import_batch_profiles p
1008 ON b.profile_id = p.id
1009 WHERE b.batch_type IN ('batch', 'webservice')
1010 ORDER BY b.import_batch_id DESC";
1012 if ($results_per_group){
1013 $query .= " LIMIT ?";
1014 push(@params, $results_per_group);
1017 $query .= " OFFSET ?";
1018 push(@params, $offset);
1020 my $sth = $dbh->prepare_cached($query);
1021 $sth->execute(@params);
1022 my $results = $sth->fetchall_arrayref({});
1027 =head2 GetItemNumbersFromImportBatch
1029 my @itemsnos = GetItemNumbersFromImportBatch($batch_id);
1033 sub GetItemNumbersFromImportBatch {
1034 my ($batch_id) = @_;
1035 my $dbh = C4::Context->dbh;
1037 SELECT itemnumber FROM import_items
1038 INNER JOIN items USING (itemnumber)
1039 INNER JOIN import_records USING (import_record_id)
1040 WHERE import_batch_id = ?|;
1041 my $sth = $dbh->prepare( $sql );
1042 $sth->execute($batch_id);
1044 while ( my ($itm) = $sth->fetchrow_array ) {
1050 =head2 GetNumberOfImportBatches
1052 my $count = GetNumberOfImportBatches();
1056 sub GetNumberOfNonZ3950ImportBatches {
1057 my $dbh = C4::Context->dbh;
1058 my $sth = $dbh->prepare("SELECT COUNT(*) FROM import_batches WHERE batch_type != 'z3950'");
1060 my ($count) = $sth->fetchrow_array();
1065 =head2 GetImportBiblios
1067 my $results = GetImportBiblios($importid);
1071 sub GetImportBiblios {
1072 my ($import_record_id) = @_;
1074 my $dbh = C4::Context->dbh;
1075 my $query = "SELECT * FROM import_biblios WHERE import_record_id = ?";
1076 return $dbh->selectall_arrayref(
1084 =head2 GetImportRecordsRange
1086 my $results = GetImportRecordsRange($batch_id, $offset, $results_per_group);
1088 Returns a reference to an array of hash references corresponding to
1089 import_biblios/import_auths/import_records rows for a given batch
1090 starting at the given offset.
1094 sub GetImportRecordsRange {
1095 my ( $batch_id, $offset, $results_per_group, $status, $parameters ) = @_;
1097 my $dbh = C4::Context->dbh;
1099 my $order_by = $parameters->{order_by} || 'import_record_id';
1100 ( $order_by ) = grep( { $_ eq $order_by } qw( import_record_id title status overlay_status ) ) ? $order_by : 'import_record_id';
1102 my $order_by_direction =
1103 uc( $parameters->{order_by_direction} // 'ASC' ) eq 'DESC' ? 'DESC' : 'ASC';
1105 $order_by .= " $order_by_direction, authorized_heading" if $order_by eq 'title';
1107 my $query = "SELECT title, author, isbn, issn, authorized_heading, import_records.import_record_id,
1108 record_sequence, status, overlay_status,
1109 matched_biblionumber, matched_authid, record_type
1111 LEFT JOIN import_auths ON (import_records.import_record_id=import_auths.import_record_id)
1112 LEFT JOIN import_biblios ON (import_records.import_record_id=import_biblios.import_record_id)
1113 WHERE import_batch_id = ?";
1115 push(@params, $batch_id);
1117 $query .= " AND status=?";
1118 push(@params,$status);
1121 $query.=" ORDER BY $order_by $order_by_direction";
1123 if($results_per_group){
1124 $query .= " LIMIT ?";
1125 push(@params, $results_per_group);
1128 $query .= " OFFSET ?";
1129 push(@params, $offset);
1131 my $sth = $dbh->prepare_cached($query);
1132 $sth->execute(@params);
1133 my $results = $sth->fetchall_arrayref({});
1139 =head2 GetBestRecordMatch
1141 my $record_id = GetBestRecordMatch($import_record_id);
1145 sub GetBestRecordMatch {
1146 my ($import_record_id) = @_;
1148 my $dbh = C4::Context->dbh;
1149 my $sth = $dbh->prepare("SELECT candidate_match_id
1150 FROM import_record_matches
1151 JOIN import_records ON ( import_record_matches.import_record_id = import_records.import_record_id )
1152 LEFT JOIN biblio ON ( candidate_match_id = biblio.biblionumber )
1153 LEFT JOIN auth_header ON ( candidate_match_id = auth_header.authid )
1154 WHERE import_record_matches.import_record_id = ? AND
1155 ( (import_records.record_type = 'biblio' AND biblio.biblionumber IS NOT NULL) OR
1156 (import_records.record_type = 'auth' AND auth_header.authid IS NOT NULL) )
1158 ORDER BY score DESC, candidate_match_id DESC");
1159 $sth->execute($import_record_id);
1160 my ($record_id) = $sth->fetchrow_array();
1165 =head2 GetImportBatchStatus
1167 my $status = GetImportBatchStatus($batch_id);
1171 sub GetImportBatchStatus {
1172 my ($batch_id) = @_;
1174 my $dbh = C4::Context->dbh;
1175 my $sth = $dbh->prepare("SELECT import_status FROM import_batches WHERE import_batch_id = ?");
1176 $sth->execute($batch_id);
1177 my ($status) = $sth->fetchrow_array();
1183 =head2 SetImportBatchStatus
1185 SetImportBatchStatus($batch_id, $new_status);
1189 sub SetImportBatchStatus {
1190 my ($batch_id, $new_status) = @_;
1192 my $dbh = C4::Context->dbh;
1193 my $sth = $dbh->prepare("UPDATE import_batches SET import_status = ? WHERE import_batch_id = ?");
1194 $sth->execute($new_status, $batch_id);
1199 =head2 SetMatchedBiblionumber
1201 SetMatchedBiblionumber($import_record_id, $biblionumber);
1205 sub SetMatchedBiblionumber {
1206 my ($import_record_id, $biblionumber) = @_;
1208 my $dbh = C4::Context->dbh;
1210 q|UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?|,
1211 undef, $biblionumber, $import_record_id
1215 =head2 GetImportBatchOverlayAction
1217 my $overlay_action = GetImportBatchOverlayAction($batch_id);
1221 sub GetImportBatchOverlayAction {
1222 my ($batch_id) = @_;
1224 my $dbh = C4::Context->dbh;
1225 my $sth = $dbh->prepare("SELECT overlay_action FROM import_batches WHERE import_batch_id = ?");
1226 $sth->execute($batch_id);
1227 my ($overlay_action) = $sth->fetchrow_array();
1229 return $overlay_action;
1234 =head2 SetImportBatchOverlayAction
1236 SetImportBatchOverlayAction($batch_id, $new_overlay_action);
1240 sub SetImportBatchOverlayAction {
1241 my ($batch_id, $new_overlay_action) = @_;
1243 my $dbh = C4::Context->dbh;
1244 my $sth = $dbh->prepare("UPDATE import_batches SET overlay_action = ? WHERE import_batch_id = ?");
1245 $sth->execute($new_overlay_action, $batch_id);
1250 =head2 GetImportBatchNoMatchAction
1252 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
1256 sub GetImportBatchNoMatchAction {
1257 my ($batch_id) = @_;
1259 my $dbh = C4::Context->dbh;
1260 my $sth = $dbh->prepare("SELECT nomatch_action FROM import_batches WHERE import_batch_id = ?");
1261 $sth->execute($batch_id);
1262 my ($nomatch_action) = $sth->fetchrow_array();
1264 return $nomatch_action;
1269 =head2 SetImportBatchNoMatchAction
1271 SetImportBatchNoMatchAction($batch_id, $new_nomatch_action);
1275 sub SetImportBatchNoMatchAction {
1276 my ($batch_id, $new_nomatch_action) = @_;
1278 my $dbh = C4::Context->dbh;
1279 my $sth = $dbh->prepare("UPDATE import_batches SET nomatch_action = ? WHERE import_batch_id = ?");
1280 $sth->execute($new_nomatch_action, $batch_id);
1285 =head2 GetImportBatchItemAction
1287 my $item_action = GetImportBatchItemAction($batch_id);
1291 sub GetImportBatchItemAction {
1292 my ($batch_id) = @_;
1294 my $dbh = C4::Context->dbh;
1295 my $sth = $dbh->prepare("SELECT item_action FROM import_batches WHERE import_batch_id = ?");
1296 $sth->execute($batch_id);
1297 my ($item_action) = $sth->fetchrow_array();
1299 return $item_action;
1304 =head2 SetImportBatchItemAction
1306 SetImportBatchItemAction($batch_id, $new_item_action);
1310 sub SetImportBatchItemAction {
1311 my ($batch_id, $new_item_action) = @_;
1313 my $dbh = C4::Context->dbh;
1314 my $sth = $dbh->prepare("UPDATE import_batches SET item_action = ? WHERE import_batch_id = ?");
1315 $sth->execute($new_item_action, $batch_id);
1320 =head2 GetImportBatchMatcher
1322 my $matcher_id = GetImportBatchMatcher($batch_id);
1326 sub GetImportBatchMatcher {
1327 my ($batch_id) = @_;
1329 my $dbh = C4::Context->dbh;
1330 my $sth = $dbh->prepare("SELECT matcher_id FROM import_batches WHERE import_batch_id = ?");
1331 $sth->execute($batch_id);
1332 my ($matcher_id) = $sth->fetchrow_array();
1339 =head2 SetImportBatchMatcher
1341 SetImportBatchMatcher($batch_id, $new_matcher_id);
1345 sub SetImportBatchMatcher {
1346 my ($batch_id, $new_matcher_id) = @_;
1348 my $dbh = C4::Context->dbh;
1349 my $sth = $dbh->prepare("UPDATE import_batches SET matcher_id = ? WHERE import_batch_id = ?");
1350 $sth->execute($new_matcher_id, $batch_id);
1355 =head2 GetImportRecordOverlayStatus
1357 my $overlay_status = GetImportRecordOverlayStatus($import_record_id);
1361 sub GetImportRecordOverlayStatus {
1362 my ($import_record_id) = @_;
1364 my $dbh = C4::Context->dbh;
1365 my $sth = $dbh->prepare("SELECT overlay_status FROM import_records WHERE import_record_id = ?");
1366 $sth->execute($import_record_id);
1367 my ($overlay_status) = $sth->fetchrow_array();
1369 return $overlay_status;
1374 =head2 SetImportRecordOverlayStatus
1376 SetImportRecordOverlayStatus($import_record_id, $new_overlay_status);
1380 sub SetImportRecordOverlayStatus {
1381 my ($import_record_id, $new_overlay_status) = @_;
1383 my $dbh = C4::Context->dbh;
1384 my $sth = $dbh->prepare("UPDATE import_records SET overlay_status = ? WHERE import_record_id = ?");
1385 $sth->execute($new_overlay_status, $import_record_id);
1390 =head2 GetImportRecordStatus
1392 my $status = GetImportRecordStatus($import_record_id);
1396 sub GetImportRecordStatus {
1397 my ($import_record_id) = @_;
1399 my $dbh = C4::Context->dbh;
1400 my $sth = $dbh->prepare("SELECT status FROM import_records WHERE import_record_id = ?");
1401 $sth->execute($import_record_id);
1402 my ($status) = $sth->fetchrow_array();
1409 =head2 SetImportRecordStatus
1411 SetImportRecordStatus($import_record_id, $new_status);
1415 sub SetImportRecordStatus {
1416 my ($import_record_id, $new_status) = @_;
1418 my $dbh = C4::Context->dbh;
1419 my $sth = $dbh->prepare("UPDATE import_records SET status = ? WHERE import_record_id = ?");
1420 $sth->execute($new_status, $import_record_id);
1425 =head2 GetImportRecordMatches
1427 my $results = GetImportRecordMatches($import_record_id, $best_only);
1431 sub GetImportRecordMatches {
1432 my $import_record_id = shift;
1433 my $best_only = @_ ? shift : 0;
1435 my $dbh = C4::Context->dbh;
1436 # FIXME currently biblio only
1437 my $sth = $dbh->prepare_cached("SELECT title, author, biblionumber,
1438 candidate_match_id, score, record_type,
1441 JOIN import_record_matches USING (import_record_id)
1442 LEFT JOIN biblio ON (biblionumber = candidate_match_id)
1443 WHERE import_record_id = ?
1444 ORDER BY score DESC, biblionumber DESC");
1445 $sth->bind_param(1, $import_record_id);
1448 while (my $row = $sth->fetchrow_hashref) {
1449 if ($row->{'record_type'} eq 'auth') {
1450 $row->{'authorized_heading'} = C4::AuthoritiesMarc::GetAuthorizedHeading( { authid => $row->{'candidate_match_id'} } );
1452 next if ($row->{'record_type'} eq 'biblio' && not $row->{'biblionumber'});
1453 push @$results, $row;
1462 =head2 SetImportRecordMatches
1464 SetImportRecordMatches($import_record_id, @matches);
1468 sub SetImportRecordMatches {
1469 my $import_record_id = shift;
1472 my $dbh = C4::Context->dbh;
1473 my $delsth = $dbh->prepare("DELETE FROM import_record_matches WHERE import_record_id = ?");
1474 $delsth->execute($import_record_id);
1477 my $sth = $dbh->prepare("INSERT INTO import_record_matches (import_record_id, candidate_match_id, score, chosen)
1478 VALUES (?, ?, ?, ?)");
1479 my $chosen = 1; #The first match is defaulted to be chosen
1480 foreach my $match (@matches) {
1481 $sth->execute($import_record_id, $match->{'record_id'}, $match->{'score'}, $chosen);
1482 $chosen = 0; #After the first we do not default to other matches
1486 =head2 RecordsFromISO2709File
1488 my ($errors, $records) = C4::ImportBatch::RecordsFromISO2709File($input_file, $record_type, $encoding);
1490 Reads ISO2709 binary porridge from the given file and creates MARC::Record-objects out of it.
1492 @PARAM1, String, absolute path to the ISO2709 file.
1493 @PARAM2, String, see stage_file.pl
1494 @PARAM3, String, should be utf8
1496 Returns two array refs.
1500 sub RecordsFromISO2709File {
1501 my ($input_file, $record_type, $encoding) = @_;
1504 my $marc_type = C4::Context->preference('marcflavour');
1505 $marc_type .= 'AUTH' if ($marc_type eq 'UNIMARC' && $record_type eq 'auth');
1507 open my $fh, '<', $input_file or die "$0: cannot open input file $input_file: $!\n";
1513 next unless $_; # skip if record has only whitespace, as might occur
1514 # if file includes newlines between each MARC record
1515 my ($marc_record, $charset_guessed, $char_errors) = MarcToUTF8Record($_, $marc_type, $encoding);
1516 push @marc_records, $marc_record;
1517 if ($charset_guessed ne $encoding) {
1519 "Unexpected charset $charset_guessed, expecting $encoding";
1523 return ( \@errors, \@marc_records );
1526 =head2 RecordsFromMARCXMLFile
1528 my ($errors, $records) = C4::ImportBatch::RecordsFromMARCXMLFile($input_file, $encoding);
1530 Creates MARC::Record-objects out of the given MARCXML-file.
1532 @PARAM1, String, absolute path to the ISO2709 file.
1533 @PARAM2, String, should be utf8
1535 Returns two array refs.
1539 sub RecordsFromMARCXMLFile {
1540 my ( $filename, $encoding ) = @_;
1541 my $batch = MARC::File::XML->in( $filename );
1542 my ( @marcRecords, @errors, $record );
1544 eval { $record = $batch->next( $encoding ); };
1548 push @marcRecords, $record if $record;
1550 return (\@errors, \@marcRecords);
1553 =head2 RecordsFromMarcPlugin
1555 Converts text of input_file into array of MARC records with to_marc plugin
1559 sub RecordsFromMarcPlugin {
1560 my ($input_file, $plugin_class, $encoding) = @_;
1561 my ( $text, @return );
1562 return \@return if !$input_file || !$plugin_class;
1565 open my $fh, '<', $input_file or die "$0: cannot open input file $input_file: $!\n";
1575 # Convert to large MARC blob with plugin
1576 $text = Koha::Plugins::Handler->run({
1577 class => $plugin_class,
1578 method => 'to_marc',
1579 params => { data => $text },
1582 # Convert to array of MARC records
1584 my $marc_type = C4::Context->preference('marcflavour');
1585 foreach my $blob ( split(/\x1D/, $text) ) {
1586 next if $blob =~ /^\s*$/;
1587 my ($marcrecord) = MarcToUTF8Record($blob, $marc_type, $encoding);
1588 push @return, $marcrecord;
1594 # internal functions
1596 sub _create_import_record {
1597 my ($batch_id, $record_sequence, $marc_record, $record_type, $encoding, $marc_type) = @_;
1599 my $dbh = C4::Context->dbh;
1600 my $sth = $dbh->prepare("INSERT INTO import_records (import_batch_id, record_sequence, marc, marcxml, marcxml_old,
1601 record_type, encoding)
1602 VALUES (?, ?, ?, ?, ?, ?, ?)");
1603 $sth->execute($batch_id, $record_sequence, $marc_record->as_usmarc(), $marc_record->as_xml($marc_type), '',
1604 $record_type, $encoding);
1605 my $import_record_id = $dbh->{'mysql_insertid'};
1607 return $import_record_id;
1610 sub _update_import_record_marc {
1611 my ($import_record_id, $marc_record, $marc_type) = @_;
1613 my $dbh = C4::Context->dbh;
1614 my $sth = $dbh->prepare("UPDATE import_records SET marc = ?, marcxml = ?
1615 WHERE import_record_id = ?");
1616 $sth->execute($marc_record->as_usmarc(), $marc_record->as_xml($marc_type), $import_record_id);
1620 sub _add_auth_fields {
1621 my ($import_record_id, $marc_record) = @_;
1624 if ($marc_record->field('001')) {
1625 $controlnumber = $marc_record->field('001')->data();
1627 my $authorized_heading = C4::AuthoritiesMarc::GetAuthorizedHeading({ record => $marc_record });
1628 my $dbh = C4::Context->dbh;
1629 my $sth = $dbh->prepare("INSERT INTO import_auths (import_record_id, control_number, authorized_heading) VALUES (?, ?, ?)");
1630 $sth->execute($import_record_id, $controlnumber, $authorized_heading);
1634 sub _add_biblio_fields {
1635 my ($import_record_id, $marc_record) = @_;
1637 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1638 my $dbh = C4::Context->dbh;
1639 # FIXME no controlnumber, originalsource
1640 $isbn = C4::Koha::GetNormalizedISBN($isbn);
1641 my $sth = $dbh->prepare("INSERT INTO import_biblios (import_record_id, title, author, isbn, issn) VALUES (?, ?, ?, ?, ?)");
1642 $sth->execute($import_record_id, $title, $author, $isbn, $issn) or die $sth->errstr;
1647 sub _update_biblio_fields {
1648 my ($import_record_id, $marc_record) = @_;
1650 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1651 my $dbh = C4::Context->dbh;
1652 # FIXME no controlnumber, originalsource
1653 # FIXME 2 - should regularize normalization of ISBN wherever it is done
1657 my $sth = $dbh->prepare("UPDATE import_biblios SET title = ?, author = ?, isbn = ?, issn = ?
1658 WHERE import_record_id = ?");
1659 $sth->execute($title, $author, $isbn, $issn, $import_record_id);
1663 sub _parse_biblio_fields {
1664 my ($marc_record) = @_;
1666 my $dbh = C4::Context->dbh;
1667 my $bibliofields = TransformMarcToKoha($marc_record, '');
1668 return ($bibliofields->{'title'}, $bibliofields->{'author'}, $bibliofields->{'isbn'}, $bibliofields->{'issn'});
1672 sub _update_batch_record_counts {
1673 my ($batch_id) = @_;
1675 my $dbh = C4::Context->dbh;
1676 my $sth = $dbh->prepare_cached("UPDATE import_batches SET
1680 WHERE import_batch_id = import_batches.import_batch_id),
1684 JOIN import_items USING (import_record_id)
1685 WHERE import_batch_id = import_batches.import_batch_id
1686 AND record_type = 'biblio')
1687 WHERE import_batch_id = ?");
1688 $sth->bind_param(1, $batch_id);
1693 sub _get_commit_action {
1694 my ($overlay_action, $nomatch_action, $item_action, $overlay_status, $import_record_id, $record_type) = @_;
1696 if ($record_type eq 'biblio') {
1697 my ($bib_result, $bib_match, $item_result);
1699 $bib_match = GetBestRecordMatch($import_record_id);
1700 if ($overlay_status ne 'no_match' && defined($bib_match)) {
1702 $bib_result = $overlay_action;
1704 if($item_action eq 'always_add' or $item_action eq 'add_only_for_matches'){
1705 $item_result = 'create_new';
1706 } elsif($item_action eq 'replace'){
1707 $item_result = 'replace';
1709 $item_result = 'ignore';
1713 $bib_result = $nomatch_action;
1714 $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_new') ? 'create_new' : 'ignore';
1716 return ($bib_result, $item_result, $bib_match);
1717 } else { # must be auths
1718 my ($auth_result, $auth_match);
1720 $auth_match = GetBestRecordMatch($import_record_id);
1721 if ($overlay_status ne 'no_match' && defined($auth_match)) {
1722 $auth_result = $overlay_action;
1724 $auth_result = $nomatch_action;
1727 return ($auth_result, undef, $auth_match);
1732 sub _get_revert_action {
1733 my ($overlay_action, $overlay_status, $status) = @_;
1737 if ($status eq 'ignored') {
1738 $bib_result = 'ignore';
1740 if ($overlay_action eq 'create_new') {
1741 $bib_result = 'delete';
1743 $bib_result = ($overlay_status eq 'match_applied') ? 'restore' : 'delete';
1754 Koha Development Team <http://koha-community.org/>
1756 Galen Charlton <galen.charlton@liblime.com>