Bug 7131: (follow-up) allow overlaying by barcode
[koha.git] / C4 / ImportBatch.pm
blob3bf71e1d432ff796c9e6cf0cca919a5ac9d24d4f
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 under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License along
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 use strict;
21 use warnings;
23 use C4::Context;
24 use C4::Koha;
25 use C4::Biblio;
26 use C4::Items;
27 use C4::Charset;
28 use C4::AuthoritiesMarc;
30 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
32 BEGIN {
33 # set the version for version checking
34 $VERSION = 3.07.00.049;
35 require Exporter;
36 @ISA = qw(Exporter);
37 @EXPORT = qw(
38 GetZ3950BatchId
39 GetWebserviceBatchId
40 GetImportRecordMarc
41 GetImportRecordMarcXML
42 AddImportBatch
43 GetImportBatch
44 AddAuthToBatch
45 AddBiblioToBatch
46 AddItemsToImportBiblio
47 ModAuthorityInBatch
48 ModBiblioInBatch
50 BatchStageMarcRecords
51 BatchFindDuplicates
52 BatchCommitRecords
53 BatchRevertRecords
54 CleanBatch
56 GetAllImportBatches
57 GetStagedWebserviceBatches
58 GetImportBatchRangeDesc
59 GetNumberOfNonZ3950ImportBatches
60 GetImportRecordsRange
61 GetItemNumbersFromImportBatch
63 GetImportBatchStatus
64 SetImportBatchStatus
65 GetImportBatchOverlayAction
66 SetImportBatchOverlayAction
67 GetImportBatchNoMatchAction
68 SetImportBatchNoMatchAction
69 GetImportBatchItemAction
70 SetImportBatchItemAction
71 GetImportBatchMatcher
72 SetImportBatchMatcher
73 GetImportRecordOverlayStatus
74 SetImportRecordOverlayStatus
75 GetImportRecordStatus
76 SetImportRecordStatus
77 GetImportRecordMatches
78 SetImportRecordMatches
82 =head1 NAME
84 C4::ImportBatch - manage batches of imported MARC records
86 =head1 SYNOPSIS
88 use C4::ImportBatch;
90 =head1 FUNCTIONS
92 =head2 GetZ3950BatchId
94 my $batchid = GetZ3950BatchId($z3950server);
96 Retrieves the ID of the import batch for the Z39.50
97 reservoir for the given target. If necessary,
98 creates the import batch.
100 =cut
102 sub GetZ3950BatchId {
103 my ($z3950server) = @_;
105 my $dbh = C4::Context->dbh;
106 my $sth = $dbh->prepare("SELECT import_batch_id FROM import_batches
107 WHERE batch_type = 'z3950'
108 AND file_name = ?");
109 $sth->execute($z3950server);
110 my $rowref = $sth->fetchrow_arrayref();
111 $sth->finish();
112 if (defined $rowref) {
113 return $rowref->[0];
114 } else {
115 my $batch_id = AddImportBatch( {
116 overlay_action => 'create_new',
117 import_status => 'staged',
118 batch_type => 'z3950',
119 file_name => $z3950server,
120 } );
121 return $batch_id;
126 =head2 GetWebserviceBatchId
128 my $batchid = GetWebserviceBatchId();
130 Retrieves the ID of the import batch for webservice.
131 If necessary, creates the import batch.
133 =cut
135 my $WEBSERVICE_BASE_QRY = <<EOQ;
136 SELECT import_batch_id FROM import_batches
137 WHERE batch_type = 'webservice'
138 AND import_status = 'staged'
140 sub GetWebserviceBatchId {
141 my ($params) = @_;
143 my $dbh = C4::Context->dbh;
144 my $sql = $WEBSERVICE_BASE_QRY;
145 my @args;
146 foreach my $field (qw(matcher_id overlay_action nomatch_action item_action)) {
147 if (my $val = $params->{$field}) {
148 $sql .= " AND $field = ?";
149 push @args, $val;
152 my $id = $dbh->selectrow_array($sql, undef, @args);
153 return $id if $id;
155 $params->{batch_type} = 'webservice';
156 $params->{import_status} = 'staged';
157 return AddImportBatch($params);
160 =head2 GetImportRecordMarc
162 my ($marcblob, $encoding) = GetImportRecordMarc($import_record_id);
164 =cut
166 sub GetImportRecordMarc {
167 my ($import_record_id) = @_;
169 my $dbh = C4::Context->dbh;
170 my $sth = $dbh->prepare("SELECT marc, encoding FROM import_records WHERE import_record_id = ?");
171 $sth->execute($import_record_id);
172 my ($marc, $encoding) = $sth->fetchrow();
173 $sth->finish();
174 return $marc, $encoding;
178 =head2 GetImportRecordMarcXML
180 my $marcxml = GetImportRecordMarcXML($import_record_id);
182 =cut
184 sub GetImportRecordMarcXML {
185 my ($import_record_id) = @_;
187 my $dbh = C4::Context->dbh;
188 my $sth = $dbh->prepare("SELECT marcxml FROM import_records WHERE import_record_id = ?");
189 $sth->execute($import_record_id);
190 my ($marcxml) = $sth->fetchrow();
191 $sth->finish();
192 return $marcxml;
196 =head2 AddImportBatch
198 my $batch_id = AddImportBatch($params_hash);
200 =cut
202 sub AddImportBatch {
203 my ($params) = @_;
205 my (@fields, @vals);
206 foreach (qw( matcher_id template_id branchcode
207 overlay_action nomatch_action item_action
208 import_status batch_type file_name comments record_type )) {
209 if (exists $params->{$_}) {
210 push @fields, $_;
211 push @vals, $params->{$_};
214 my $dbh = C4::Context->dbh;
215 $dbh->do("INSERT INTO import_batches (".join( ',', @fields).")
216 VALUES (".join( ',', map '?', @fields).")",
217 undef,
218 @vals);
219 return $dbh->{'mysql_insertid'};
222 =head2 GetImportBatch
224 my $row = GetImportBatch($batch_id);
226 Retrieve a hashref of an import_batches row.
228 =cut
230 sub GetImportBatch {
231 my ($batch_id) = @_;
233 my $dbh = C4::Context->dbh;
234 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches WHERE import_batch_id = ?");
235 $sth->bind_param(1, $batch_id);
236 $sth->execute();
237 my $result = $sth->fetchrow_hashref;
238 $sth->finish();
239 return $result;
243 =head2 AddBiblioToBatch
245 my $import_record_id = AddBiblioToBatch($batch_id, $record_sequence,
246 $marc_record, $encoding, $z3950random, $update_counts);
248 =cut
250 sub AddBiblioToBatch {
251 my $batch_id = shift;
252 my $record_sequence = shift;
253 my $marc_record = shift;
254 my $encoding = shift;
255 my $z3950random = shift;
256 my $update_counts = @_ ? shift : 1;
258 my $import_record_id = _create_import_record($batch_id, $record_sequence, $marc_record, 'biblio', $encoding, $z3950random, C4::Context->preference('marcflavour'));
259 _add_biblio_fields($import_record_id, $marc_record);
260 _update_batch_record_counts($batch_id) if $update_counts;
261 return $import_record_id;
264 =head2 ModBiblioInBatch
266 ModBiblioInBatch($import_record_id, $marc_record);
268 =cut
270 sub ModBiblioInBatch {
271 my ($import_record_id, $marc_record) = @_;
273 _update_import_record_marc($import_record_id, $marc_record, C4::Context->preference('marcflavour'));
274 _update_biblio_fields($import_record_id, $marc_record);
278 =head2 AddAuthToBatch
280 my $import_record_id = AddAuthToBatch($batch_id, $record_sequence,
281 $marc_record, $encoding, $z3950random, $update_counts, [$marc_type]);
283 =cut
285 sub AddAuthToBatch {
286 my $batch_id = shift;
287 my $record_sequence = shift;
288 my $marc_record = shift;
289 my $encoding = shift;
290 my $z3950random = shift;
291 my $update_counts = @_ ? shift : 1;
292 my $marc_type = shift || C4::Context->preference('marcflavour');
294 $marc_type = 'UNIMARCAUTH' if $marc_type eq 'UNIMARC';
296 my $import_record_id = _create_import_record($batch_id, $record_sequence, $marc_record, 'auth', $encoding, $z3950random, $marc_type);
297 _add_auth_fields($import_record_id, $marc_record);
298 _update_batch_record_counts($batch_id) if $update_counts;
299 return $import_record_id;
302 =head2 ModAuthInBatch
304 ModAuthInBatch($import_record_id, $marc_record);
306 =cut
308 sub ModAuthInBatch {
309 my ($import_record_id, $marc_record) = @_;
311 my $marcflavour = C4::Context->preference('marcflavour');
312 _update_import_record_marc($import_record_id, $marc_record, $marcflavour eq 'UNIMARC' ? 'UNIMARCAUTH' : 'USMARC');
316 =head2 BatchStageMarcRecords
318 ($batch_id, $num_records, $num_items, @invalid_records) =
319 BatchStageMarcRecords($record_type, $encoding, $marc_records, $file_name,
320 $comments, $branch_code, $parse_items,
321 $leave_as_staging,
322 $progress_interval, $progress_callback);
324 =cut
326 sub BatchStageMarcRecords {
327 my $record_type = shift;
328 my $encoding = shift;
329 my $marc_records = shift;
330 my $file_name = shift;
331 my $comments = shift;
332 my $branch_code = shift;
333 my $parse_items = shift;
334 my $leave_as_staging = shift;
336 # optional callback to monitor status
337 # of job
338 my $progress_interval = 0;
339 my $progress_callback = undef;
340 if ($#_ == 1) {
341 $progress_interval = shift;
342 $progress_callback = shift;
343 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
344 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
347 my $batch_id = AddImportBatch( {
348 overlay_action => 'create_new',
349 import_status => 'staging',
350 batch_type => 'batch',
351 file_name => $file_name,
352 comments => $comments,
353 record_type => $record_type,
354 } );
355 if ($parse_items) {
356 SetImportBatchItemAction($batch_id, 'always_add');
357 } else {
358 SetImportBatchItemAction($batch_id, 'ignore');
361 my $marc_type = C4::Context->preference('marcflavour');
362 $marc_type .= 'AUTH' if ($marc_type eq 'UNIMARC' && $record_type eq 'auth');
363 my @invalid_records = ();
364 my $num_valid = 0;
365 my $num_items = 0;
366 # FIXME - for now, we're dealing only with bibs
367 my $rec_num = 0;
368 foreach my $marc_blob (split(/\x1D/, $marc_records)) {
369 $marc_blob =~ s/^\s+//g;
370 $marc_blob =~ s/\s+$//g;
371 next unless $marc_blob;
372 $rec_num++;
373 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
374 &$progress_callback($rec_num);
376 my ($marc_record, $charset_guessed, $char_errors) =
377 MarcToUTF8Record($marc_blob, $marc_type, $encoding);
379 $encoding = $charset_guessed unless $encoding;
381 my $import_record_id;
382 if (scalar($marc_record->fields()) == 0) {
383 push @invalid_records, $marc_blob;
384 } else {
386 # Normalize the record so it doesn't have separated diacritics
387 SetUTF8Flag($marc_record);
389 $num_valid++;
390 if ($record_type eq 'biblio') {
391 $import_record_id = AddBiblioToBatch($batch_id, $rec_num, $marc_record, $encoding, int(rand(99999)), 0);
392 if ($parse_items) {
393 my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, 0);
394 $num_items += scalar(@import_items_ids);
396 } elsif ($record_type eq 'auth') {
397 $import_record_id = AddAuthToBatch($batch_id, $rec_num, $marc_record, $encoding, int(rand(99999)), 0, $marc_type);
401 unless ($leave_as_staging) {
402 SetImportBatchStatus($batch_id, 'staged');
404 # FIXME branch_code, number of bibs, number of items
405 _update_batch_record_counts($batch_id);
406 return ($batch_id, $num_valid, $num_items, @invalid_records);
409 =head2 AddItemsToImportBiblio
411 my @import_items_ids = AddItemsToImportBiblio($batch_id,
412 $import_record_id, $marc_record, $update_counts);
414 =cut
416 sub AddItemsToImportBiblio {
417 my $batch_id = shift;
418 my $import_record_id = shift;
419 my $marc_record = shift;
420 my $update_counts = @_ ? shift : 0;
422 my @import_items_ids = ();
424 my $dbh = C4::Context->dbh;
425 my ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",'');
426 foreach my $item_field ($marc_record->field($item_tag)) {
427 my $item_marc = MARC::Record->new();
428 $item_marc->leader("00000 a "); # must set Leader/09 to 'a'
429 $item_marc->append_fields($item_field);
430 $marc_record->delete_field($item_field);
431 my $sth = $dbh->prepare_cached("INSERT INTO import_items (import_record_id, status, marcxml)
432 VALUES (?, ?, ?)");
433 $sth->bind_param(1, $import_record_id);
434 $sth->bind_param(2, 'staged');
435 $sth->bind_param(3, $item_marc->as_xml());
436 $sth->execute();
437 push @import_items_ids, $dbh->{'mysql_insertid'};
438 $sth->finish();
441 if ($#import_items_ids > -1) {
442 _update_batch_record_counts($batch_id) if $update_counts;
443 _update_import_record_marc($import_record_id, $marc_record, C4::Context->preference('marcflavour'));
445 return @import_items_ids;
448 =head2 BatchFindDuplicates
450 my $num_with_matches = BatchFindDuplicates($batch_id, $matcher,
451 $max_matches, $progress_interval, $progress_callback);
453 Goes through the records loaded in the batch and attempts to
454 find duplicates for each one. Sets the matching status
455 of each record to "no_match" or "auto_match" as appropriate.
457 The $max_matches parameter is optional; if it is not supplied,
458 it defaults to 10.
460 The $progress_interval and $progress_callback parameters are
461 optional; if both are supplied, the sub referred to by
462 $progress_callback will be invoked every $progress_interval
463 records using the number of records processed as the
464 singular argument.
466 =cut
468 sub BatchFindDuplicates {
469 my $batch_id = shift;
470 my $matcher = shift;
471 my $max_matches = @_ ? shift : 10;
473 # optional callback to monitor status
474 # of job
475 my $progress_interval = 0;
476 my $progress_callback = undef;
477 if ($#_ == 1) {
478 $progress_interval = shift;
479 $progress_callback = shift;
480 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
481 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
484 my $dbh = C4::Context->dbh;
486 my $sth = $dbh->prepare("SELECT import_record_id, record_type, marc
487 FROM import_records
488 WHERE import_batch_id = ?");
489 $sth->execute($batch_id);
490 my $num_with_matches = 0;
491 my $rec_num = 0;
492 while (my $rowref = $sth->fetchrow_hashref) {
493 $rec_num++;
494 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
495 &$progress_callback($rec_num);
497 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
498 my @matches = ();
499 if (defined $matcher) {
500 @matches = $matcher->get_matches($marc_record, $max_matches);
502 if (scalar(@matches) > 0) {
503 $num_with_matches++;
504 SetImportRecordMatches($rowref->{'import_record_id'}, @matches);
505 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'auto_match');
506 } else {
507 SetImportRecordMatches($rowref->{'import_record_id'}, ());
508 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'no_match');
511 $sth->finish();
512 return $num_with_matches;
515 =head2 BatchCommitRecords
517 my ($num_added, $num_updated, $num_items_added, $num_items_replaced, $num_items_errored, $num_ignored) =
518 BatchCommitRecords($batch_id, $framework,
519 $progress_interval, $progress_callback);
521 =cut
523 sub BatchCommitRecords {
524 my $batch_id = shift;
525 my $framework = shift;
527 # optional callback to monitor status
528 # of job
529 my $progress_interval = 0;
530 my $progress_callback = undef;
531 if ($#_ == 1) {
532 $progress_interval = shift;
533 $progress_callback = shift;
534 $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
535 $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
538 my $record_type;
539 my $num_added = 0;
540 my $num_updated = 0;
541 my $num_items_added = 0;
542 my $num_items_replaced = 0;
543 my $num_items_errored = 0;
544 my $num_ignored = 0;
545 # commit (i.e., save, all records in the batch)
546 SetImportBatchStatus('importing');
547 my $overlay_action = GetImportBatchOverlayAction($batch_id);
548 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
549 my $item_action = GetImportBatchItemAction($batch_id);
550 my $item_tag;
551 my $item_subfield;
552 my $dbh = C4::Context->dbh;
553 my $sth = $dbh->prepare("SELECT import_records.import_record_id, record_type, status, overlay_status, marc, encoding
554 FROM import_records
555 LEFT JOIN import_auths ON (import_records.import_record_id=import_auths.import_record_id)
556 LEFT JOIN import_biblios ON (import_records.import_record_id=import_biblios.import_record_id)
557 WHERE import_batch_id = ?");
558 $sth->execute($batch_id);
559 my $marcflavour = C4::Context->preference('marcflavour');
560 my $rec_num = 0;
561 while (my $rowref = $sth->fetchrow_hashref) {
562 $record_type = $rowref->{'record_type'};
563 $rec_num++;
564 if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
565 &$progress_callback($rec_num);
567 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'imported') {
568 $num_ignored++;
569 next;
572 my $marc_type;
573 if ($marcflavour eq 'UNIMARC' && $record_type eq 'auth') {
574 $marc_type = 'UNIMARCAUTH';
575 } elsif ($marcflavour eq 'UNIMARC') {
576 $marc_type = 'UNIMARC';
577 } else {
578 $marc_type = 'USMARC';
580 my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
582 if ($record_type eq 'biblio') {
583 # remove any item tags - rely on BatchCommitItems
584 ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",'');
585 foreach my $item_field ($marc_record->field($item_tag)) {
586 $marc_record->delete_field($item_field);
590 my ($record_result, $item_result, $record_match) =
591 _get_commit_action($overlay_action, $nomatch_action, $item_action,
592 $rowref->{'overlay_status'}, $rowref->{'import_record_id'}, $record_type);
594 my $recordid;
595 my $query;
596 if ($record_result eq 'create_new') {
597 $num_added++;
598 if ($record_type eq 'biblio') {
599 my $biblioitemnumber;
600 ($recordid, $biblioitemnumber) = AddBiblio($marc_record, $framework);
601 $query = "UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?";
602 if ($item_result eq 'create_new' || $item_result eq 'replace') {
603 my ($bib_items_added, $bib_items_replaced, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid, $item_result);
604 $num_items_added += $bib_items_added;
605 $num_items_replaced += $bib_items_replaced;
606 $num_items_errored += $bib_items_errored;
608 } else {
609 $recordid = AddAuthority($marc_record, undef, GuessAuthTypeCode($marc_record));
610 $query = "UPDATE import_auths SET matched_authid = ? WHERE import_record_id = ?";
612 my $sth = $dbh->prepare_cached($query);
613 $sth->execute($recordid, $rowref->{'import_record_id'});
614 $sth->finish();
615 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
616 } elsif ($record_result eq 'replace') {
617 $num_updated++;
618 $recordid = $record_match;
619 my $oldxml;
620 if ($record_type eq 'biblio') {
621 my ($count, $oldbiblio) = GetBiblio($recordid);
622 $oldxml = GetXmlBiblio($recordid);
624 # remove item fields so that they don't get
625 # added again if record is reverted
626 # 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.
627 my $old_marc = MARC::Record->new_from_xml(StripNonXmlChars($oldxml), 'UTF-8', $rowref->{'encoding'}, $marc_type);
628 foreach my $item_field ($old_marc->field($item_tag)) {
629 $old_marc->delete_field($item_field);
631 $oldxml = $old_marc->as_xml($marc_type);
633 ModBiblio($marc_record, $recordid, $oldbiblio->{'frameworkcode'});
634 $query = "UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?";
636 if ($item_result eq 'create_new' || $item_result eq 'replace') {
637 my ($bib_items_added, $bib_items_replaced, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid, $item_result);
638 $num_items_added += $bib_items_added;
639 $num_items_replaced += $bib_items_replaced;
640 $num_items_errored += $bib_items_errored;
642 } else {
643 $oldxml = GetAuthorityXML($recordid);
645 ModAuthority($recordid, $marc_record, GuessAuthTypeCode($marc_record));
646 $query = "UPDATE import_auths SET matched_authid = ? WHERE import_record_id = ?";
648 my $sth = $dbh->prepare_cached("UPDATE import_records SET marcxml_old = ? WHERE import_record_id = ?");
649 $sth->execute($oldxml, $rowref->{'import_record_id'});
650 $sth->finish();
651 my $sth2 = $dbh->prepare_cached($query);
652 $sth2->execute($recordid, $rowref->{'import_record_id'});
653 $sth2->finish();
654 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
655 SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
656 } elsif ($record_result eq 'ignore') {
657 $recordid = $record_match;
658 $num_ignored++;
659 $recordid = $record_match;
660 if ($record_type eq 'biblio' and defined $recordid and ( $item_result eq 'create_new' || $item_result eq 'replace' ) ) {
661 my ($bib_items_added, $bib_items_replaced, $bib_items_errored) = BatchCommitItems($rowref->{'import_record_id'}, $recordid, $item_result);
662 $num_items_added += $bib_items_added;
663 $num_items_replaced += $bib_items_replaced;
664 $num_items_errored += $bib_items_errored;
665 # still need to record the matched biblionumber so that the
666 # items can be reverted
667 my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
668 $sth2->execute($recordid, $rowref->{'import_record_id'});
669 SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
671 SetImportRecordStatus($rowref->{'import_record_id'}, 'ignored');
674 $sth->finish();
675 SetImportBatchStatus($batch_id, 'imported');
676 return ($num_added, $num_updated, $num_items_added, $num_items_replaced, $num_items_errored, $num_ignored);
679 =head2 BatchCommitItems
681 ($num_items_added, $num_items_errored) =
682 BatchCommitItems($import_record_id, $biblionumber);
684 =cut
686 sub BatchCommitItems {
687 my ( $import_record_id, $biblionumber, $action ) = @_;
689 my $dbh = C4::Context->dbh;
691 my ( $num_items_added, $num_items_errored, $num_items_replaced ) = 0;
692 my $sth = $dbh->prepare( "
693 SELECT import_items_id, import_items.marcxml, encoding
694 FROM import_items
695 JOIN import_records USING (import_record_id)
696 WHERE import_record_id = ?
697 ORDER BY import_items_id
698 " );
699 $sth->bind_param( 1, $import_record_id );
700 $sth->execute();
702 while ( my $row = $sth->fetchrow_hashref() ) {
703 my $item_marc = MARC::Record->new_from_xml( StripNonXmlChars( $row->{'marcxml'} ), 'UTF-8', $row->{'encoding'} );
705 # Delete date_due subfield as to not accidentally delete item checkout due dates
706 my ( $MARCfield, $MARCsubfield ) = GetMarcFromKohaField( 'items.onloan', GetFrameworkCode($biblionumber) );
707 $item_marc->field($MARCfield)->delete_subfield( code => $MARCsubfield );
709 my $item = TransformMarcToKoha( $dbh, $item_marc );
711 my $duplicate_barcode = exists( $item->{'barcode'} ) && GetItemnumberFromBarcode( $item->{'barcode'} );
712 my $duplicate_itemnumber = exists( $item->{'itemnumber'} );
714 my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, itemnumber = ? WHERE import_items_id = ?");
715 if ( $action eq "replace" && $duplicate_itemnumber ) {
716 # Duplicate itemnumbers have precedence, that way we can update barcodes by overlaying
717 ModItemFromMarc( $item_marc, $biblionumber, $item->{itemnumber} );
718 $updsth->bind_param( 1, 'imported' );
719 $updsth->bind_param( 2, $item->{itemnumber} );
720 $updsth->bind_param( 3, $row->{'import_items_id'} );
721 $updsth->execute();
722 $updsth->finish();
723 $num_items_replaced++;
724 } elsif ( $action eq "replace" && $duplicate_barcode ) {
725 my $itemnumber = GetItemnumberFromBarcode( $item->{'barcode'} );
726 ModItemFromMarc( $item_marc, $biblionumber, $itemnumber );
727 $updsth->bind_param( 1, 'imported' );
728 $updsth->bind_param( 2, $item->{itemnumber} );
729 $updsth->bind_param( 3, $row->{'import_items_id'} );
730 $updsth->execute();
731 $updsth->finish();
732 $num_items_replaced++;
733 } elsif ($duplicate_barcode) {
734 $updsth->bind_param( 1, 'error' );
735 $updsth->bind_param( 2, 'duplicate item barcode' );
736 $updsth->bind_param( 3, $row->{'import_items_id'} );
737 $updsth->execute();
738 $num_items_errored++;
739 } else {
740 my ( $item_biblionumber, $biblioitemnumber, $itemnumber ) = AddItemFromMarc( $item_marc, $biblionumber );
741 $updsth->bind_param( 1, 'imported' );
742 $updsth->bind_param( 2, $itemnumber );
743 $updsth->bind_param( 3, $row->{'import_items_id'} );
744 $updsth->execute();
745 $updsth->finish();
746 $num_items_added++;
750 return ( $num_items_added, $num_items_replaced, $num_items_errored );
753 =head2 BatchRevertRecords
755 my ($num_deleted, $num_errors, $num_reverted, $num_items_deleted,
756 $num_ignored) = BatchRevertRecords($batch_id);
758 =cut
760 sub BatchRevertRecords {
761 my $batch_id = shift;
763 my $record_type;
764 my $num_deleted = 0;
765 my $num_errors = 0;
766 my $num_reverted = 0;
767 my $num_ignored = 0;
768 my $num_items_deleted = 0;
769 # commit (i.e., save, all records in the batch)
770 SetImportBatchStatus('reverting');
771 my $overlay_action = GetImportBatchOverlayAction($batch_id);
772 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
773 my $dbh = C4::Context->dbh;
774 my $sth = $dbh->prepare("SELECT import_records.import_record_id, record_type, status, overlay_status, marcxml_old, encoding, matched_biblionumber, matched_authid
775 FROM import_records
776 LEFT JOIN import_auths ON (import_records.import_record_id=import_auths.import_record_id)
777 LEFT JOIN import_biblios ON (import_records.import_record_id=import_biblios.import_record_id)
778 WHERE import_batch_id = ?");
779 $sth->execute($batch_id);
780 my $marc_type;
781 my $marcflavour = C4::Context->preference('marcflavour');
782 while (my $rowref = $sth->fetchrow_hashref) {
783 $record_type = $rowref->{'record_type'};
784 if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'reverted') {
785 $num_ignored++;
786 next;
788 if ($marcflavour eq 'UNIMARC' && $record_type eq 'auth') {
789 $marc_type = 'UNIMARCAUTH';
790 } elsif ($marcflavour eq 'UNIMARC') {
791 $marc_type = 'UNIMARC';
792 } else {
793 $marc_type = 'USMARC';
796 my $record_result = _get_revert_action($overlay_action, $rowref->{'overlay_status'}, $rowref->{'status'});
798 if ($record_result eq 'delete') {
799 my $error = undef;
800 if ($record_type eq 'biblio') {
801 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
802 $error = DelBiblio($rowref->{'matched_biblionumber'});
803 } else {
804 my $deletedauthid = DelAuthority($rowref->{'matched_authid'});
806 if (defined $error) {
807 $num_errors++;
808 } else {
809 $num_deleted++;
810 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
812 } elsif ($record_result eq 'restore') {
813 $num_reverted++;
814 my $old_record = MARC::Record->new_from_xml(StripNonXmlChars($rowref->{'marcxml_old'}), 'UTF-8', $rowref->{'encoding'}, $marc_type);
815 if ($record_type eq 'biblio') {
816 my $biblionumber = $rowref->{'matched_biblionumber'};
817 my ($count, $oldbiblio) = GetBiblio($biblionumber);
818 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
819 ModBiblio($old_record, $biblionumber, $oldbiblio->{'frameworkcode'});
820 } else {
821 my $authid = $rowref->{'matched_authid'};
822 ModAuthority($authid, $old_record, GuessAuthTypeCode($old_record));
824 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
825 } elsif ($record_result eq 'ignore') {
826 if ($record_type eq 'biblio') {
827 $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
829 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
831 my $query;
832 if ($record_type eq 'biblio') {
833 # remove matched_biblionumber only if there is no 'imported' item left
834 $query = "UPDATE import_biblios SET matched_biblionumber = NULL WHERE import_record_id = ?";
835 $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')";
836 } else {
837 $query = "UPDATE import_auths SET matched_authid = NULL WHERE import_record_id = ?";
839 my $sth2 = $dbh->prepare_cached($query);
840 $sth2->execute($rowref->{'import_record_id'});
843 $sth->finish();
844 SetImportBatchStatus($batch_id, 'reverted');
845 return ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored);
848 =head2 BatchRevertItems
850 my $num_items_deleted = BatchRevertItems($import_record_id, $biblionumber);
852 =cut
854 sub BatchRevertItems {
855 my ($import_record_id, $biblionumber) = @_;
857 my $dbh = C4::Context->dbh;
858 my $num_items_deleted = 0;
860 my $sth = $dbh->prepare_cached("SELECT import_items_id, itemnumber
861 FROM import_items
862 JOIN items USING (itemnumber)
863 WHERE import_record_id = ?");
864 $sth->bind_param(1, $import_record_id);
865 $sth->execute();
866 while (my $row = $sth->fetchrow_hashref()) {
867 my $error = DelItemCheck($dbh, $biblionumber, $row->{'itemnumber'});
868 if ($error == 1){
869 my $updsth = $dbh->prepare("UPDATE import_items SET status = ? WHERE import_items_id = ?");
870 $updsth->bind_param(1, 'reverted');
871 $updsth->bind_param(2, $row->{'import_items_id'});
872 $updsth->execute();
873 $updsth->finish();
874 $num_items_deleted++;
876 else {
877 next;
880 $sth->finish();
881 return $num_items_deleted;
884 =head2 CleanBatch
886 CleanBatch($batch_id)
888 Deletes all staged records from the import batch
889 and sets the status of the batch to 'cleaned'. Note
890 that deleting a stage record does *not* affect
891 any record that has been committed to the database.
893 =cut
895 sub CleanBatch {
896 my $batch_id = shift;
897 return unless defined $batch_id;
899 C4::Context->dbh->do('DELETE FROM import_records WHERE import_batch_id = ?', {}, $batch_id);
900 SetImportBatchStatus($batch_id, 'cleaned');
903 =head2 GetAllImportBatches
905 my $results = GetAllImportBatches();
907 Returns a references to an array of hash references corresponding
908 to all import_batches rows (of batch_type 'batch'), sorted in
909 ascending order by import_batch_id.
911 =cut
913 sub GetAllImportBatches {
914 my $dbh = C4::Context->dbh;
915 my $sth = $dbh->prepare_cached("SELECT * FROM import_batches
916 WHERE batch_type IN ('batch', 'webservice')
917 ORDER BY import_batch_id ASC");
919 my $results = [];
920 $sth->execute();
921 while (my $row = $sth->fetchrow_hashref) {
922 push @$results, $row;
924 $sth->finish();
925 return $results;
928 =head2 GetStagedWebserviceBatches
930 my $batch_ids = GetStagedWebserviceBatches();
932 Returns a references to an array of batch id's
933 of batch_type 'webservice' that are not imported
935 =cut
937 my $PENDING_WEBSERVICE_BATCHES_QRY = <<EOQ;
938 SELECT import_batch_id FROM import_batches
939 WHERE batch_type = 'webservice'
940 AND import_status = 'staged'
942 sub GetStagedWebserviceBatches {
943 my $dbh = C4::Context->dbh;
944 return $dbh->selectcol_arrayref($PENDING_WEBSERVICE_BATCHES_QRY);
947 =head2 GetImportBatchRangeDesc
949 my $results = GetImportBatchRangeDesc($offset, $results_per_group);
951 Returns a reference to an array of hash references corresponding to
952 import_batches rows (sorted in descending order by import_batch_id)
953 start at the given offset.
955 =cut
957 sub GetImportBatchRangeDesc {
958 my ($offset, $results_per_group) = @_;
960 my $dbh = C4::Context->dbh;
961 my $query = "SELECT * FROM import_batches
962 WHERE batch_type IN ('batch', 'webservice')
963 ORDER BY import_batch_id DESC";
964 my @params;
965 if ($results_per_group){
966 $query .= " LIMIT ?";
967 push(@params, $results_per_group);
969 if ($offset){
970 $query .= " OFFSET ?";
971 push(@params, $offset);
973 my $sth = $dbh->prepare_cached($query);
974 $sth->execute(@params);
975 my $results = $sth->fetchall_arrayref({});
976 $sth->finish();
977 return $results;
980 =head2 GetItemNumbersFromImportBatch
982 my @itemsnos = GetItemNumbersFromImportBatch($batch_id);
984 =cut
986 sub GetItemNumbersFromImportBatch {
987 my ($batch_id) = @_;
988 my $dbh = C4::Context->dbh;
989 my $sth = $dbh->prepare("SELECT itemnumber FROM import_batches,import_records,import_items WHERE import_batches.import_batch_id=import_records.import_batch_id AND import_records.import_record_id=import_items.import_record_id AND import_batches.import_batch_id=?");
990 $sth->execute($batch_id);
991 my @items ;
992 while ( my ($itm) = $sth->fetchrow_array ) {
993 push @items, $itm;
995 return @items;
998 =head2 GetNumberOfImportBatches
1000 my $count = GetNumberOfImportBatches();
1002 =cut
1004 sub GetNumberOfNonZ3950ImportBatches {
1005 my $dbh = C4::Context->dbh;
1006 my $sth = $dbh->prepare("SELECT COUNT(*) FROM import_batches WHERE batch_type != 'z3950'");
1007 $sth->execute();
1008 my ($count) = $sth->fetchrow_array();
1009 $sth->finish();
1010 return $count;
1013 =head2 GetImportRecordsRange
1015 my $results = GetImportRecordsRange($batch_id, $offset, $results_per_group);
1017 Returns a reference to an array of hash references corresponding to
1018 import_biblios/import_auths/import_records rows for a given batch
1019 starting at the given offset.
1021 =cut
1023 sub GetImportRecordsRange {
1024 my ($batch_id, $offset, $results_per_group, $status) = @_;
1026 my $dbh = C4::Context->dbh;
1027 my $query = "SELECT title, author, isbn, issn, authorized_heading, import_records.import_record_id,
1028 record_sequence, status, overlay_status,
1029 matched_biblionumber, matched_authid, record_type
1030 FROM import_records
1031 LEFT JOIN import_auths ON (import_records.import_record_id=import_auths.import_record_id)
1032 LEFT JOIN import_biblios ON (import_records.import_record_id=import_biblios.import_record_id)
1033 WHERE import_batch_id = ?";
1034 my @params;
1035 push(@params, $batch_id);
1036 if ($status) {
1037 $query .= " AND status=?";
1038 push(@params,$status);
1040 $query.=" ORDER BY import_record_id";
1042 if($results_per_group){
1043 $query .= " LIMIT ?";
1044 push(@params, $results_per_group);
1046 if($offset){
1047 $query .= " OFFSET ?";
1048 push(@params, $offset);
1050 my $sth = $dbh->prepare_cached($query);
1051 $sth->execute(@params);
1052 my $results = $sth->fetchall_arrayref({});
1053 $sth->finish();
1054 return $results;
1058 =head2 GetBestRecordMatch
1060 my $record_id = GetBestRecordMatch($import_record_id);
1062 =cut
1064 sub GetBestRecordMatch {
1065 my ($import_record_id) = @_;
1067 my $dbh = C4::Context->dbh;
1068 my $sth = $dbh->prepare("SELECT candidate_match_id
1069 FROM import_record_matches
1070 JOIN import_records ON ( import_record_matches.import_record_id = import_records.import_record_id )
1071 LEFT JOIN biblio ON ( candidate_match_id = biblio.biblionumber )
1072 LEFT JOIN auth_header ON ( candidate_match_id = auth_header.authid )
1073 WHERE import_record_matches.import_record_id = ? AND
1074 ( (import_records.record_type = 'biblio' AND biblio.biblionumber IS NOT NULL) OR
1075 (import_records.record_type = 'auth' AND auth_header.authid IS NOT NULL) )
1076 ORDER BY score DESC, candidate_match_id DESC");
1077 $sth->execute($import_record_id);
1078 my ($record_id) = $sth->fetchrow_array();
1079 $sth->finish();
1080 return $record_id;
1083 =head2 GetImportBatchStatus
1085 my $status = GetImportBatchStatus($batch_id);
1087 =cut
1089 sub GetImportBatchStatus {
1090 my ($batch_id) = @_;
1092 my $dbh = C4::Context->dbh;
1093 my $sth = $dbh->prepare("SELECT import_status FROM import_batches WHERE import_batch_id = ?");
1094 $sth->execute($batch_id);
1095 my ($status) = $sth->fetchrow_array();
1096 $sth->finish();
1097 return $status;
1101 =head2 SetImportBatchStatus
1103 SetImportBatchStatus($batch_id, $new_status);
1105 =cut
1107 sub SetImportBatchStatus {
1108 my ($batch_id, $new_status) = @_;
1110 my $dbh = C4::Context->dbh;
1111 my $sth = $dbh->prepare("UPDATE import_batches SET import_status = ? WHERE import_batch_id = ?");
1112 $sth->execute($new_status, $batch_id);
1113 $sth->finish();
1117 =head2 GetImportBatchOverlayAction
1119 my $overlay_action = GetImportBatchOverlayAction($batch_id);
1121 =cut
1123 sub GetImportBatchOverlayAction {
1124 my ($batch_id) = @_;
1126 my $dbh = C4::Context->dbh;
1127 my $sth = $dbh->prepare("SELECT overlay_action FROM import_batches WHERE import_batch_id = ?");
1128 $sth->execute($batch_id);
1129 my ($overlay_action) = $sth->fetchrow_array();
1130 $sth->finish();
1131 return $overlay_action;
1136 =head2 SetImportBatchOverlayAction
1138 SetImportBatchOverlayAction($batch_id, $new_overlay_action);
1140 =cut
1142 sub SetImportBatchOverlayAction {
1143 my ($batch_id, $new_overlay_action) = @_;
1145 my $dbh = C4::Context->dbh;
1146 my $sth = $dbh->prepare("UPDATE import_batches SET overlay_action = ? WHERE import_batch_id = ?");
1147 $sth->execute($new_overlay_action, $batch_id);
1148 $sth->finish();
1152 =head2 GetImportBatchNoMatchAction
1154 my $nomatch_action = GetImportBatchNoMatchAction($batch_id);
1156 =cut
1158 sub GetImportBatchNoMatchAction {
1159 my ($batch_id) = @_;
1161 my $dbh = C4::Context->dbh;
1162 my $sth = $dbh->prepare("SELECT nomatch_action FROM import_batches WHERE import_batch_id = ?");
1163 $sth->execute($batch_id);
1164 my ($nomatch_action) = $sth->fetchrow_array();
1165 $sth->finish();
1166 return $nomatch_action;
1171 =head2 SetImportBatchNoMatchAction
1173 SetImportBatchNoMatchAction($batch_id, $new_nomatch_action);
1175 =cut
1177 sub SetImportBatchNoMatchAction {
1178 my ($batch_id, $new_nomatch_action) = @_;
1180 my $dbh = C4::Context->dbh;
1181 my $sth = $dbh->prepare("UPDATE import_batches SET nomatch_action = ? WHERE import_batch_id = ?");
1182 $sth->execute($new_nomatch_action, $batch_id);
1183 $sth->finish();
1187 =head2 GetImportBatchItemAction
1189 my $item_action = GetImportBatchItemAction($batch_id);
1191 =cut
1193 sub GetImportBatchItemAction {
1194 my ($batch_id) = @_;
1196 my $dbh = C4::Context->dbh;
1197 my $sth = $dbh->prepare("SELECT item_action FROM import_batches WHERE import_batch_id = ?");
1198 $sth->execute($batch_id);
1199 my ($item_action) = $sth->fetchrow_array();
1200 $sth->finish();
1201 return $item_action;
1206 =head2 SetImportBatchItemAction
1208 SetImportBatchItemAction($batch_id, $new_item_action);
1210 =cut
1212 sub SetImportBatchItemAction {
1213 my ($batch_id, $new_item_action) = @_;
1215 my $dbh = C4::Context->dbh;
1216 my $sth = $dbh->prepare("UPDATE import_batches SET item_action = ? WHERE import_batch_id = ?");
1217 $sth->execute($new_item_action, $batch_id);
1218 $sth->finish();
1222 =head2 GetImportBatchMatcher
1224 my $matcher_id = GetImportBatchMatcher($batch_id);
1226 =cut
1228 sub GetImportBatchMatcher {
1229 my ($batch_id) = @_;
1231 my $dbh = C4::Context->dbh;
1232 my $sth = $dbh->prepare("SELECT matcher_id FROM import_batches WHERE import_batch_id = ?");
1233 $sth->execute($batch_id);
1234 my ($matcher_id) = $sth->fetchrow_array();
1235 $sth->finish();
1236 return $matcher_id;
1241 =head2 SetImportBatchMatcher
1243 SetImportBatchMatcher($batch_id, $new_matcher_id);
1245 =cut
1247 sub SetImportBatchMatcher {
1248 my ($batch_id, $new_matcher_id) = @_;
1250 my $dbh = C4::Context->dbh;
1251 my $sth = $dbh->prepare("UPDATE import_batches SET matcher_id = ? WHERE import_batch_id = ?");
1252 $sth->execute($new_matcher_id, $batch_id);
1253 $sth->finish();
1257 =head2 GetImportRecordOverlayStatus
1259 my $overlay_status = GetImportRecordOverlayStatus($import_record_id);
1261 =cut
1263 sub GetImportRecordOverlayStatus {
1264 my ($import_record_id) = @_;
1266 my $dbh = C4::Context->dbh;
1267 my $sth = $dbh->prepare("SELECT overlay_status FROM import_records WHERE import_record_id = ?");
1268 $sth->execute($import_record_id);
1269 my ($overlay_status) = $sth->fetchrow_array();
1270 $sth->finish();
1271 return $overlay_status;
1276 =head2 SetImportRecordOverlayStatus
1278 SetImportRecordOverlayStatus($import_record_id, $new_overlay_status);
1280 =cut
1282 sub SetImportRecordOverlayStatus {
1283 my ($import_record_id, $new_overlay_status) = @_;
1285 my $dbh = C4::Context->dbh;
1286 my $sth = $dbh->prepare("UPDATE import_records SET overlay_status = ? WHERE import_record_id = ?");
1287 $sth->execute($new_overlay_status, $import_record_id);
1288 $sth->finish();
1292 =head2 GetImportRecordStatus
1294 my $overlay_status = GetImportRecordStatus($import_record_id);
1296 =cut
1298 sub GetImportRecordStatus {
1299 my ($import_record_id) = @_;
1301 my $dbh = C4::Context->dbh;
1302 my $sth = $dbh->prepare("SELECT status FROM import_records WHERE import_record_id = ?");
1303 $sth->execute($import_record_id);
1304 my ($overlay_status) = $sth->fetchrow_array();
1305 $sth->finish();
1306 return $overlay_status;
1311 =head2 SetImportRecordStatus
1313 SetImportRecordStatus($import_record_id, $new_overlay_status);
1315 =cut
1317 sub SetImportRecordStatus {
1318 my ($import_record_id, $new_overlay_status) = @_;
1320 my $dbh = C4::Context->dbh;
1321 my $sth = $dbh->prepare("UPDATE import_records SET status = ? WHERE import_record_id = ?");
1322 $sth->execute($new_overlay_status, $import_record_id);
1323 $sth->finish();
1327 =head2 GetImportRecordMatches
1329 my $results = GetImportRecordMatches($import_record_id, $best_only);
1331 =cut
1333 sub GetImportRecordMatches {
1334 my $import_record_id = shift;
1335 my $best_only = @_ ? shift : 0;
1337 my $dbh = C4::Context->dbh;
1338 # FIXME currently biblio only
1339 my $sth = $dbh->prepare_cached("SELECT title, author, biblionumber,
1340 candidate_match_id, score, record_type
1341 FROM import_records
1342 JOIN import_record_matches USING (import_record_id)
1343 LEFT JOIN biblio ON (biblionumber = candidate_match_id)
1344 WHERE import_record_id = ?
1345 ORDER BY score DESC, biblionumber DESC");
1346 $sth->bind_param(1, $import_record_id);
1347 my $results = [];
1348 $sth->execute();
1349 while (my $row = $sth->fetchrow_hashref) {
1350 if ($row->{'record_type'} eq 'auth') {
1351 $row->{'authorized_heading'} = C4::AuthoritiesMarc::GetAuthorizedHeading( { authid => $row->{'candidate_match_id'} } );
1353 next if ($row->{'record_type'} eq 'biblio' && not $row->{'biblionumber'});
1354 push @$results, $row;
1355 last if $best_only;
1357 $sth->finish();
1359 return $results;
1364 =head2 SetImportRecordMatches
1366 SetImportRecordMatches($import_record_id, @matches);
1368 =cut
1370 sub SetImportRecordMatches {
1371 my $import_record_id = shift;
1372 my @matches = @_;
1374 my $dbh = C4::Context->dbh;
1375 my $delsth = $dbh->prepare("DELETE FROM import_record_matches WHERE import_record_id = ?");
1376 $delsth->execute($import_record_id);
1377 $delsth->finish();
1379 my $sth = $dbh->prepare("INSERT INTO import_record_matches (import_record_id, candidate_match_id, score)
1380 VALUES (?, ?, ?)");
1381 foreach my $match (@matches) {
1382 $sth->execute($import_record_id, $match->{'record_id'}, $match->{'score'});
1387 # internal functions
1389 sub _create_import_record {
1390 my ($batch_id, $record_sequence, $marc_record, $record_type, $encoding, $z3950random, $marc_type) = @_;
1392 my $dbh = C4::Context->dbh;
1393 my $sth = $dbh->prepare("INSERT INTO import_records (import_batch_id, record_sequence, marc, marcxml,
1394 record_type, encoding, z3950random)
1395 VALUES (?, ?, ?, ?, ?, ?, ?)");
1396 $sth->execute($batch_id, $record_sequence, $marc_record->as_usmarc(), $marc_record->as_xml($marc_type),
1397 $record_type, $encoding, $z3950random);
1398 my $import_record_id = $dbh->{'mysql_insertid'};
1399 $sth->finish();
1400 return $import_record_id;
1403 sub _update_import_record_marc {
1404 my ($import_record_id, $marc_record, $marc_type) = @_;
1406 my $dbh = C4::Context->dbh;
1407 my $sth = $dbh->prepare("UPDATE import_records SET marc = ?, marcxml = ?
1408 WHERE import_record_id = ?");
1409 $sth->execute($marc_record->as_usmarc(), $marc_record->as_xml($marc_type), $import_record_id);
1410 $sth->finish();
1413 sub _add_auth_fields {
1414 my ($import_record_id, $marc_record) = @_;
1416 my $controlnumber;
1417 if ($marc_record->field('001')) {
1418 $controlnumber = $marc_record->field('001')->data();
1420 my $authorized_heading = C4::AuthoritiesMarc::GetAuthorizedHeading({ record => $marc_record });
1421 my $dbh = C4::Context->dbh;
1422 my $sth = $dbh->prepare("INSERT INTO import_auths (import_record_id, control_number, authorized_heading) VALUES (?, ?, ?)");
1423 $sth->execute($import_record_id, $controlnumber, $authorized_heading);
1424 $sth->finish();
1427 sub _add_biblio_fields {
1428 my ($import_record_id, $marc_record) = @_;
1430 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1431 my $dbh = C4::Context->dbh;
1432 # FIXME no controlnumber, originalsource
1433 $isbn = C4::Koha::_isbn_cleanup($isbn); # FIXME C4::Koha::_isbn_cleanup should be made public
1434 my $sth = $dbh->prepare("INSERT INTO import_biblios (import_record_id, title, author, isbn, issn) VALUES (?, ?, ?, ?, ?)");
1435 $sth->execute($import_record_id, $title, $author, $isbn, $issn);
1436 $sth->finish();
1440 sub _update_biblio_fields {
1441 my ($import_record_id, $marc_record) = @_;
1443 my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
1444 my $dbh = C4::Context->dbh;
1445 # FIXME no controlnumber, originalsource
1446 # FIXME 2 - should regularize normalization of ISBN wherever it is done
1447 $isbn =~ s/\(.*$//;
1448 $isbn =~ tr/ -_//;
1449 $isbn = uc $isbn;
1450 my $sth = $dbh->prepare("UPDATE import_biblios SET title = ?, author = ?, isbn = ?, issn = ?
1451 WHERE import_record_id = ?");
1452 $sth->execute($title, $author, $isbn, $issn, $import_record_id);
1453 $sth->finish();
1456 sub _parse_biblio_fields {
1457 my ($marc_record) = @_;
1459 my $dbh = C4::Context->dbh;
1460 my $bibliofields = TransformMarcToKoha($dbh, $marc_record, '');
1461 return ($bibliofields->{'title'}, $bibliofields->{'author'}, $bibliofields->{'isbn'}, $bibliofields->{'issn'});
1465 sub _update_batch_record_counts {
1466 my ($batch_id) = @_;
1468 my $dbh = C4::Context->dbh;
1469 my $sth = $dbh->prepare_cached("UPDATE import_batches SET
1470 num_records = (
1471 SELECT COUNT(*)
1472 FROM import_records
1473 WHERE import_batch_id = import_batches.import_batch_id),
1474 num_items = (
1475 SELECT COUNT(*)
1476 FROM import_records
1477 JOIN import_items USING (import_record_id)
1478 WHERE import_batch_id = import_batches.import_batch_id
1479 AND record_type = 'biblio')
1480 WHERE import_batch_id = ?");
1481 $sth->bind_param(1, $batch_id);
1482 $sth->execute();
1483 $sth->finish();
1486 sub _get_commit_action {
1487 my ($overlay_action, $nomatch_action, $item_action, $overlay_status, $import_record_id, $record_type) = @_;
1489 if ($record_type eq 'biblio') {
1490 my ($bib_result, $bib_match, $item_result);
1492 if ($overlay_status ne 'no_match') {
1493 $bib_match = GetBestRecordMatch($import_record_id);
1494 if ($overlay_action eq 'replace') {
1495 $bib_result = defined($bib_match) ? 'replace' : 'create_new';
1496 } elsif ($overlay_action eq 'create_new') {
1497 $bib_result = 'create_new';
1498 } elsif ($overlay_action eq 'ignore') {
1499 $bib_result = 'ignore';
1501 if($item_action eq 'always_add' or $item_action eq 'add_only_for_matches'){
1502 $item_result = 'create_new';
1504 elsif($item_action eq 'replace'){
1505 $item_result = 'replace';
1507 else {
1508 $item_result = 'ignore';
1510 } else {
1511 $bib_result = $nomatch_action;
1512 $item_result = ($item_action eq 'always_add' or $item_action eq 'add_only_for_new') ? 'create_new' : 'ignore';
1514 return ($bib_result, $item_result, $bib_match);
1515 } else { # must be auths
1516 my ($auth_result, $auth_match);
1518 if ($overlay_status ne 'no_match') {
1519 $auth_match = GetBestRecordMatch($import_record_id);
1520 if ($overlay_action eq 'replace') {
1521 $auth_result = defined($auth_match) ? 'replace' : 'create_new';
1522 } elsif ($overlay_action eq 'create_new') {
1523 $auth_result = 'create_new';
1524 } elsif ($overlay_action eq 'ignore') {
1525 $auth_result = 'ignore';
1527 } else {
1528 $auth_result = $nomatch_action;
1531 return ($auth_result, undef, $auth_match);
1536 sub _get_revert_action {
1537 my ($overlay_action, $overlay_status, $status) = @_;
1539 my $bib_result;
1541 if ($status eq 'ignored') {
1542 $bib_result = 'ignore';
1543 } else {
1544 if ($overlay_action eq 'create_new') {
1545 $bib_result = 'delete';
1546 } else {
1547 $bib_result = ($overlay_status eq 'match_applied') ? 'restore' : 'delete';
1550 return $bib_result;
1554 __END__
1556 =head1 AUTHOR
1558 Koha Development Team <http://koha-community.org/>
1560 Galen Charlton <galen.charlton@liblime.com>
1562 =cut