59c328494d93c829f35c6943efa900ed78bbafb5
[koha.git] / C4 / ImportBatch.pm
1 package C4::ImportBatch;
2
3 # Copyright (C) 2007 LibLime
4 #
5 # This file is part of Koha.
6 #
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.
11 #
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.
15 #
16 # You should have received a copy of the GNU General Public License along with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA  02111-1307 USA
19
20 use strict;
21 use C4::Context;
22 use C4::Koha;
23 use C4::Biblio;
24 use C4::Matcher;
25 require Exporter;
26
27
28 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
29
30 # set the version for version checking
31 $VERSION = 3.00;
32
33 =head1 NAME
34
35 C4::ImportBatch - manage batches of imported MARC records
36
37 =head1 SYNOPSIS
38
39 =over 4
40
41 use C4::ImportBatch;
42
43 =back
44
45 =head1 FUNCTIONS
46
47 =cut
48
49 @ISA    = qw(Exporter);
50 @EXPORT = qw(
51     GetZ3950BatchId
52     GetImportRecordMarc
53     AddImportBatch
54     GetImportBatch
55     AddBiblioToBatch
56     ModBiblioInBatch
57
58     BatchStageMarcRecords
59     BatchFindBibDuplicates
60     BatchCommitBibRecords
61     BatchRevertBibRecords
62
63     GetAllImportBatches
64     GetImportBatchRangeDesc
65     GetNumberOfNonZ3950ImportBatches
66     GetImportBibliosRange
67     
68     GetImportBatchStatus
69     SetImportBatchStatus
70     GetImportBatchOverlayAction
71     SetImportBatchOverlayAction
72     GetImportRecordOverlayStatus
73     SetImportRecordOverlayStatus
74     GetImportRecordStatus
75     SetImportRecordStatus
76     GetImportRecordMatches
77     SetImportRecordMatches
78 );
79
80 =head2 GetZ3950BatchId
81
82 =over 4
83
84 my $batchid = GetZ3950BatchId($z3950server);
85
86 =back
87
88 Retrieves the ID of the import batch for the Z39.50
89 reservoir for the given target.  If necessary,
90 creates the import batch.
91
92 =cut
93
94 sub GetZ3950BatchId {
95     my ($z3950server) = @_;
96
97     my $dbh = C4::Context->dbh;
98     my $sth = $dbh->prepare("SELECT import_batch_id FROM import_batches
99                              WHERE  batch_type = 'z3950'
100                              AND    file_name = ?");
101     $sth->execute($z3950server);
102     my $rowref = $sth->fetchrow_arrayref();
103     $sth->finish();
104     if (defined $rowref) {
105         return $rowref->[0];
106     } else {
107         my $batch_id = AddImportBatch('create_new', 'staged', 'z3950', $z3950server, '');
108         return $batch_id;
109     }
110     
111 }
112
113 =head2 GetImportRecordMarc
114
115 =over 4
116
117 my ($marcblob, $encoding) = GetImportRecordMarc($import_record_id);
118
119 =back
120
121 =cut
122
123 sub GetImportRecordMarc {
124     my ($import_record_id) = @_;
125
126     my $dbh = C4::Context->dbh;
127     my $sth = $dbh->prepare("SELECT marc, encoding FROM import_records WHERE import_record_id = ?");
128     $sth->execute($import_record_id);
129     my ($marc, $encoding) = $sth->fetchrow();
130     $sth->finish();
131     return $marc;
132
133 }
134
135 =head2 AddImportBatch
136
137 =over 4
138
139 my $batch_id = AddImportBatch($overlay_action, $import_status, $type, $file_name, $comments);
140
141 =back
142
143 =cut
144
145 sub AddImportBatch {
146     my ($overlay_action, $import_status, $type, $file_name, $comments) = @_;
147
148     my $dbh = C4::Context->dbh;
149     my $sth = $dbh->prepare("INSERT INTO import_batches (overlay_action, import_status, batch_type,
150                                                          file_name, comments)
151                                     VALUES (?, ?, ?, ?, ?)");
152     $sth->execute($overlay_action, $import_status, $type, $file_name, $comments);
153     my $batch_id = $dbh->{'mysql_insertid'};
154     $sth->finish();
155
156     return $batch_id;
157
158 }
159
160 =head2 GetImportBatch 
161
162 =over 4
163
164 my $row = GetImportBatch($batch_id);
165
166 =back
167
168 Retrieve a hashref of an import_batches row.
169
170 =cut
171
172 sub GetImportBatch {
173     my ($batch_id) = @_;
174
175     my $dbh = C4::Context->dbh;
176     my $sth = $dbh->prepare_cached("SELECT * FROM import_batches WHERE import_batch_id = ?");
177     $sth->bind_param(1, $batch_id);
178     $sth->execute();
179     my $result = $sth->fetchrow_hashref;
180     $sth->finish();
181     return $result;
182
183 }
184
185 =head2 AddBiblioToBatch 
186
187 =over 4
188
189 my $import_record_id = AddBiblioToBatch($batch_id, $record_sequence, $marc_record, $encoding, $z3950random, $update_counts);
190
191 =back
192
193 =cut
194
195 sub AddBiblioToBatch {
196     my $batch_id = shift;
197     my $record_sequence = shift;
198     my $marc_record = shift;
199     my $encoding = shift;
200     my $z3950random = shift;
201     my $update_counts = @_ ? shift : 1;
202
203     my $import_record_id = _create_import_record($batch_id, $record_sequence, $marc_record, 'biblio', $encoding, $z3950random);
204     _add_biblio_fields($import_record_id, $marc_record);
205     _update_batch_record_counts($batch_id) if $update_counts;
206     return $import_record_id;
207 }
208
209 =head2 ModBiblioInBatch
210
211 =over 4
212
213 ModBiblioInBatch($import_record_id, $marc_record);
214
215 =back
216
217 =cut
218
219 sub ModBiblioInBatch {
220     my ($import_record_id, $marc_record) = @_;
221
222     _update_import_record_marc($import_record_id, $marc_record);
223     _update_biblio_fields($import_record_id, $marc_record);
224
225 }
226
227 =head2 BatchStageMarcRecords
228
229 =over 4
230
231 ($batch_id, $num_records, $num_items, @invalid_records) = 
232     BatchStageMarcRecords($marc_flavor, $marc_records, $file_name, 
233                           $comments, $branch_code, $parse_items,
234                           $leave_as_staging);
235
236 =back
237
238 =cut
239
240 sub  BatchStageMarcRecords {
241     my ($marc_flavor, $marc_records, $file_name, $comments, $branch_code, $parse_items, $leave_as_staging) = @_;
242
243     my $batch_id = AddImportBatch('create_new', 'staging', 'batch', $file_name, $comments);
244     my @invalid_records = ();
245     my $num_valid = 0;
246     my $num_items = 0;
247     # FIXME - for now, we're dealing only with bibs
248     my $rec_num = 0;
249     foreach my $marc_blob (split(/\x1D/, $marc_records)) {
250         $rec_num++;
251         my $marc_record = FixEncoding($marc_blob, "\x1D");
252         my $import_record_id;
253         if (scalar($marc_record->fields()) == 0) {
254             push @invalid_records, $marc_blob;
255         } else {
256             $num_valid++;
257             $import_record_id = AddBiblioToBatch($batch_id, $rec_num, $marc_record, $marc_flavor, int(rand(99999)), 0);
258             if ($parse_items) {
259                 my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, 0);
260                 $num_items += scalar(@import_items_ids);
261             }
262         }
263     }
264     unless ($leave_as_staging) {
265         SetImportBatchStatus($batch_id, 'staged');
266     }
267     # FIXME branch_code, number of bibs, number of items
268     _update_batch_record_counts($batch_id);
269     return ($batch_id, $num_valid, $num_items, @invalid_records);
270 }
271
272 =head2 AddItemsToImportBiblio
273
274 =over 4
275
276 my @import_items_ids = AddItemsToImportBiblio($batch_id, $import_record_id, $marc_record, $update_counts);
277
278 =back
279
280 =cut
281
282 sub AddItemsToImportBiblio {
283     my $batch_id = shift;
284     my $import_record_id = shift;
285     my $marc_record = shift;
286     my $update_counts = @_ ? shift : 0;
287
288     my @import_items_ids = ();
289    
290     my $dbh = C4::Context->dbh; 
291     my ($item_tag,$item_subfield) = &GetMarcFromKohaField("items.itemnumber",'');
292     foreach my $item_field ($marc_record->field($item_tag)) {
293         my $item_marc = MARC::Record->new();
294         $item_marc->append_fields($item_field);
295         $marc_record->delete_field($item_field);
296         my $sth = $dbh->prepare_cached("INSERT INTO import_items (import_record_id, status, marcxml)
297                                         VALUES (?, ?, ?)");
298         $sth->bind_param(1, $import_record_id);
299         $sth->bind_param(2, 'staged');
300         $sth->bind_param(3, $item_marc->as_xml());
301         $sth->execute();
302         push @import_items_ids, $dbh->{'mysql_insertid'};
303         $sth->finish();
304     }
305
306     if ($#import_items_ids > -1) {
307         _update_batch_record_counts($batch_id) if $update_counts;
308         _update_import_record_marc($import_record_id, $marc_record);
309     }
310     return @import_items_ids;
311 }
312
313 =head2 BatchFindBibDuplicates
314
315 =over 4
316
317 my $num_with_matches = BatchFindBibDuplicates($batch_id, $matcher, $max_matches);
318
319 =back
320
321 Goes through the records loaded in the batch and attempts to 
322 find duplicates for each one.  Sets the overlay action to
323 "replace" if it was "create_new", and sets the overlay status
324 of each record to "no_match" or "auto_match" as appropriate.
325
326 The $max_matches parameter is optional; if it is not supplied,
327 it defaults to 10.
328
329 =cut
330
331 sub BatchFindBibDuplicates {
332     my $batch_id = shift;
333     my $matcher = shift;
334     my $max_matches = @_ ? shift : 10;
335
336     my $dbh = C4::Context->dbh;
337     my $old_overlay_action = GetImportBatchOverlayAction($batch_id);
338     if ($old_overlay_action eq "create_new") {
339         SetImportBatchOverlayAction($batch_id, 'replace');
340     }
341
342     my $sth = $dbh->prepare("SELECT import_record_id, marc
343                              FROM import_records
344                              JOIN import_biblios USING (import_record_id)
345                              WHERE import_batch_id = ?");
346     $sth->execute($batch_id);
347     my $num_with_matches = 0;
348     while (my $rowref = $sth->fetchrow_hashref) {
349         my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
350         my @matches = $matcher->get_matches($marc_record, $max_matches);
351         if (scalar(@matches) > 0) {
352             $num_with_matches++;
353             SetImportRecordMatches($rowref->{'import_record_id'}, @matches);
354             SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'auto_match');
355         } else {
356             SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'no_match');
357         }
358     }
359     $sth->finish();
360     return $num_with_matches;
361 }
362
363 =head2 BatchCommitBibRecords
364
365 =over 4
366
367 my ($num_added, $num_updated, $num_items_added, $num_ignored) = 
368     BatchCommitBibRecords($batch_id, $progress_interval, $progress_callback);
369
370 =back
371
372 =cut
373
374 sub BatchCommitBibRecords {
375     my $batch_id = shift;
376
377     # optional callback to monitor status 
378     # of job
379     my $progress_interval = 0;
380     my $progress_callback = undef;
381     if ($#_ == 1) {
382         $progress_interval = shift;
383         $progress_callback = shift;
384         $progress_interval = 0 unless $progress_interval =~ /^\d+$/ and $progress_interval > 0;
385         $progress_interval = 0 unless 'CODE' eq ref $progress_callback;
386     }
387
388     my $num_added = 0;
389     my $num_updated = 0;
390     my $num_items_added = 0;
391     my $num_ignored = 0;
392     # commit (i.e., save, all records in the batch)
393     # FIXME biblio only at the moment
394     SetImportBatchStatus('importing');
395     my $overlay_action = GetImportBatchOverlayAction($batch_id);
396     my $dbh = C4::Context->dbh;
397     my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marc
398                              FROM import_records
399                              JOIN import_biblios USING (import_record_id)
400                              WHERE import_batch_id = ?");
401     $sth->execute($batch_id);
402     my $rec_num = 0;
403     while (my $rowref = $sth->fetchrow_hashref) {
404         $rec_num++;
405         if ($progress_interval and (0 == ($rec_num % $progress_interval))) {
406             &$progress_callback($rec_num);
407         }
408         if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'imported') {
409             $num_ignored++;
410         }
411         my $marc_record = MARC::Record->new_from_usmarc($rowref->{'marc'});
412         if ($overlay_action eq 'create_new' or
413             ($overlay_action eq 'replace' and $rowref->{'overlay_status'} eq 'no_match')) {
414             $num_added++;
415             my ($biblionumber, $biblioitemnumber) = AddBiblio($marc_record, '');
416             my $sth = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
417             $sth->execute($biblionumber, $rowref->{'import_record_id'});
418             $sth->finish();
419             $num_items_added += BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
420             SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
421         } else {
422             $num_updated++;
423             my $biblionumber = GetBestRecordMatch($rowref->{'import_record_id'});
424             my ($count, $oldbiblio) = GetBiblio($biblionumber);
425             my $oldxml = GetXmlBiblio($biblionumber);
426             ModBiblio($marc_record, $biblionumber, $oldbiblio->{'frameworkcode'});
427             my $sth = $dbh->prepare_cached("UPDATE import_records SET marcxml_old = ? WHERE import_record_id = ?");
428             $sth->execute($oldxml, $rowref->{'import_record_id'});
429             $sth->finish();
430             my $sth2 = $dbh->prepare_cached("UPDATE import_biblios SET matched_biblionumber = ? WHERE import_record_id = ?");
431             $sth2->execute($biblionumber, $rowref->{'import_record_id'});
432             $sth2->finish();
433             $num_items_added += BatchCommitItems($rowref->{'import_record_id'}, $biblionumber);
434             SetImportRecordOverlayStatus($rowref->{'import_record_id'}, 'match_applied');
435             SetImportRecordStatus($rowref->{'import_record_id'}, 'imported');
436         }
437     }
438     $sth->finish();
439     SetImportBatchStatus($batch_id, 'imported');
440     return ($num_added, $num_updated, $num_items_added, $num_ignored);
441 }
442
443 =head2 BatchCommitItems
444
445 =over 4
446
447 $num_items_added = BatchCommitItems($import_record_id, $biblionumber);
448
449 =back
450
451 =cut
452
453 sub BatchCommitItems {
454     my ($import_record_id, $biblionumber) = @_;
455
456     my $dbh = C4::Context->dbh;
457
458     my $num_items_added = 0;
459     my $sth = $dbh->prepare("SELECT import_items_id, import_items.marcxml, encoding
460                              FROM import_items
461                              JOIN import_records USING (import_record_id)
462                              WHERE import_record_id = ?
463                              ORDER BY import_items_id");
464     $sth->bind_param(1, $import_record_id);
465     $sth->execute();
466     while (my $row = $sth->fetchrow_hashref()) {
467         my $item_marc = MARC::Record->new_from_xml($row->{'marcxml'}, 'UTF-8', $row->{'encoding'});
468         my ($item_biblionumber, $biblionumber, $itemnumber) = AddItem($item_marc, $biblionumber);
469         my $updsth = $dbh->prepare("UPDATE import_items SET status = ?, itemnumber = ? WHERE import_items_id = ?");
470         $updsth->bind_param(1, 'imported');
471         $updsth->bind_param(2, $itemnumber);
472         $updsth->bind_param(3, $row->{'import_items_id'});
473         $updsth->execute();
474         $updsth->finish();
475         $num_items_added++;
476     }
477     $sth->finish();
478     return $num_items_added;
479 }
480
481 =head2 BatchRevertBibRecords
482
483 =over 4
484
485 my ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored) = BatchRevertBibRecords($batch_id);
486
487 =back
488
489 =cut
490
491 sub BatchRevertBibRecords {
492     my $batch_id = shift;
493
494     my $num_deleted = 0;
495     my $num_errors = 0;
496     my $num_reverted = 0;
497     my $num_items_deleted = 0;
498     my $num_ignored = 0;
499     # commit (i.e., save, all records in the batch)
500     # FIXME biblio only at the moment
501     SetImportBatchStatus('reverting');
502     my $overlay_action = GetImportBatchOverlayAction($batch_id);
503     my $dbh = C4::Context->dbh;
504     my $sth = $dbh->prepare("SELECT import_record_id, status, overlay_status, marcxml_old, encoding, matched_biblionumber
505                              FROM import_records
506                              JOIN import_biblios USING (import_record_id)
507                              WHERE import_batch_id = ?");
508     $sth->execute($batch_id);
509     while (my $rowref = $sth->fetchrow_hashref) {
510         if ($rowref->{'status'} eq 'error' or $rowref->{'status'} eq 'reverted') {
511             $num_ignored++;
512         }
513         if ($overlay_action eq 'create_new' or
514             ($overlay_action eq 'replace' and $rowref->{'overlay_status'} eq 'no_match')) {
515             $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
516             my $error = DelBiblio($rowref->{'matched_biblionumber'});
517             if (defined $error) {
518                 $num_errors++;
519             } else {
520                 $num_deleted++;
521                 SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
522             }
523         } else {
524             $num_reverted++;
525             my $old_record = MARC::Record->new_from_xml($rowref->{'marcxml_old'}, 'UTF-8', $rowref->{'encoding'});
526             my $biblionumber = $rowref->{'matched_biblionumber'};
527             my ($count, $oldbiblio) = GetBiblio($biblionumber);
528             $num_items_deleted += BatchRevertItems($rowref->{'import_record_id'}, $rowref->{'matched_biblionumber'});
529             ModBiblio($old_record, $biblionumber, $oldbiblio->{'frameworkcode'});
530             SetImportRecordStatus($rowref->{'import_record_id'}, 'reverted');
531         }
532     }
533     $sth->finish();
534     SetImportBatchStatus($batch_id, 'reverted');
535     return ($num_deleted, $num_errors, $num_reverted, $num_items_deleted, $num_ignored);
536 }
537
538 =head2 BatchRevertItems
539
540 =over 4
541
542 my $num_items_deleted = BatchRevertItems($import_record_id, $biblionumber);
543
544 =back
545
546 =cut
547
548 sub BatchRevertItems {
549     my ($import_record_id, $biblionumber) = @_;
550
551     my $dbh = C4::Context->dbh;
552     my $num_items_deleted = 0;
553
554     my $sth = $dbh->prepare_cached("SELECT import_items_id, itemnumber
555                                    FROM import_items
556                                    WHERE import_record_id = ?");
557     $sth->bind_param(1, $import_record_id);
558     $sth->execute();
559     while (my $row = $sth->fetchrow_hashref()) {
560         DelItem($dbh, $biblionumber, $row->{'itemnumber'});
561         my $updsth = $dbh->prepare("UPDATE import_items SET status = ? WHERE import_items_id = ?");
562         $updsth->bind_param(1, 'reverted');
563         $updsth->bind_param(2, $row->{'import_items_id'});
564         $updsth->execute();
565         $updsth->finish();
566         $num_items_deleted++;
567     }
568     $sth->finish();
569     return $num_items_deleted;
570 }
571
572 =head2 GetAllImportBatches
573
574 =over 4
575
576 my $results = GetAllImportBatches();
577
578 =back
579
580 Returns a references to an array of hash references corresponding
581 to all import_batches rows (of batch_type 'batch'), sorted in 
582 ascending order by import_batch_id.
583
584 =cut
585
586 sub  GetAllImportBatches {
587     my $dbh = C4::Context->dbh;
588     my $sth = $dbh->prepare_cached("SELECT * FROM import_batches
589                                     WHERE batch_type = 'batch'
590                                     ORDER BY import_batch_id ASC");
591
592     my $results = [];
593     $sth->execute();
594     while (my $row = $sth->fetchrow_hashref) {
595         push @$results, $row;
596     }
597     $sth->finish();
598     return $results;
599 }
600
601 =head2 GetImportBatchRangeDesc
602
603 =over 4
604
605 my $results = GetImportBatchRangeDesc($offset, $results_per_group);
606
607 =back
608
609 Returns a reference to an array of hash references corresponding to
610 import_batches rows (sorted in descending order by import_batch_id)
611 start at the given offset.
612
613 =cut
614
615 sub GetImportBatchRangeDesc {
616     my ($offset, $results_per_group) = @_;
617
618     my $dbh = C4::Context->dbh;
619     my $sth = $dbh->prepare_cached("SELECT * FROM import_batches
620                                     WHERE batch_type = 'batch'
621                                     ORDER BY import_batch_id DESC
622                                     LIMIT ? OFFSET ?");
623     $sth->bind_param(1, $results_per_group);
624     $sth->bind_param(2, $offset);
625
626     my $results = [];
627     $sth->execute();
628     while (my $row = $sth->fetchrow_hashref) {
629         push @$results, $row;
630     }
631     $sth->finish();
632     return $results;
633 }
634
635 =head2 GetNumberOfImportBatches 
636
637 =over 4
638
639 my $count = GetNumberOfImportBatches();
640
641 =back
642
643 =cut
644
645 sub GetNumberOfNonZ3950ImportBatches {
646     my $dbh = C4::Context->dbh;
647     my $sth = $dbh->prepare("SELECT COUNT(*) FROM import_batches WHERE batch_type='batch'");
648     $sth->execute();
649     my ($count) = $sth->fetchrow_array();
650     $sth->finish();
651     return $count;
652 }
653
654 =head2 GetImportBibliosRange
655
656 =over 4
657
658 my $results = GetImportBibliosRange($batch_id, $offset, $results_per_group);
659
660 =back
661
662 Returns a reference to an array of hash references corresponding to
663 import_biblios/import_records rows for a given batch
664 starting at the given offset.
665
666 =cut
667
668 sub GetImportBibliosRange {
669     my ($batch_id, $offset, $results_per_group) = @_;
670
671     my $dbh = C4::Context->dbh;
672     my $sth = $dbh->prepare_cached("SELECT title, author, isbn, issn, import_record_id, record_sequence,
673                                            status, overlay_status
674                                     FROM   import_records
675                                     JOIN   import_biblios USING (import_record_id)
676                                     WHERE  import_batch_id = ?
677                                     ORDER BY import_record_id LIMIT ? OFFSET ?");
678     $sth->bind_param(1, $batch_id);
679     $sth->bind_param(2, $results_per_group);
680     $sth->bind_param(3, $offset);
681     my $results = [];
682     $sth->execute();
683     while (my $row = $sth->fetchrow_hashref) {
684         push @$results, $row;
685     }
686     $sth->finish();
687     return $results;
688
689 }
690
691 =head2 GetBestRecordMatch
692
693 =over 4
694
695 my $record_id = GetBestRecordMatch($import_record_id);
696
697 =back
698
699 =cut
700
701 sub GetBestRecordMatch {
702     my ($import_record_id) = @_;
703
704     my $dbh = C4::Context->dbh;
705     my $sth = $dbh->prepare("SELECT candidate_match_id
706                              FROM   import_record_matches
707                              WHERE  import_record_id = ?
708                              ORDER BY score DESC, candidate_match_id DESC");
709     $sth->execute($import_record_id);
710     my ($record_id) = $sth->fetchrow_array();
711     $sth->finish();
712     return $record_id;
713 }
714
715 =head2 GetImportBatchStatus
716
717 =over 4
718
719 my $status = GetImportBatchStatus($batch_id);
720
721 =back
722
723 =cut
724
725 sub GetImportBatchStatus {
726     my ($batch_id) = @_;
727
728     my $dbh = C4::Context->dbh;
729     my $sth = $dbh->prepare("SELECT import_status FROM import_batches WHERE batch_id = ?");
730     $sth->execute($batch_id);
731     my ($status) = $sth->fetchrow_array();
732     $sth->finish();
733     return;
734
735 }
736
737
738 =head2 SetImportBatchStatus
739
740 =over 4
741
742 SetImportBatchStatus($batch_id, $new_status);
743
744 =back
745
746 =cut
747
748 sub SetImportBatchStatus {
749     my ($batch_id, $new_status) = @_;
750
751     my $dbh = C4::Context->dbh;
752     my $sth = $dbh->prepare("UPDATE import_batches SET import_status = ? WHERE import_batch_id = ?");
753     $sth->execute($new_status, $batch_id);
754     $sth->finish();
755
756 }
757
758 =head2 GetImportBatchOverlayAction
759
760 =over 4
761
762 my $overlay_action = GetImportBatchOverlayAction($batch_id);
763
764 =back
765
766 =cut
767
768 sub GetImportBatchOverlayAction {
769     my ($batch_id) = @_;
770
771     my $dbh = C4::Context->dbh;
772     my $sth = $dbh->prepare("SELECT overlay_action FROM import_batches WHERE import_batch_id = ?");
773     $sth->execute($batch_id);
774     my ($overlay_action) = $sth->fetchrow_array();
775     $sth->finish();
776     return $overlay_action;
777
778 }
779
780
781 =head2 SetImportBatchOverlayAction
782
783 =over 4
784
785 SetImportBatchOverlayAction($batch_id, $new_overlay_action);
786
787 =back
788
789 =cut
790
791 sub SetImportBatchOverlayAction {
792     my ($batch_id, $new_overlay_action) = @_;
793
794     my $dbh = C4::Context->dbh;
795     my $sth = $dbh->prepare("UPDATE import_batches SET overlay_action = ? WHERE import_batch_id = ?");
796     $sth->execute($new_overlay_action, $batch_id);
797     $sth->finish();
798
799 }
800
801 =head2 GetImportRecordOverlayStatus
802
803 =over 4
804
805 my $overlay_status = GetImportRecordOverlayStatus($import_record_id);
806
807 =back
808
809 =cut
810
811 sub GetImportRecordOverlayStatus {
812     my ($import_record_id) = @_;
813
814     my $dbh = C4::Context->dbh;
815     my $sth = $dbh->prepare("SELECT overlay_status FROM import_records WHERE import_record_id = ?");
816     $sth->execute($import_record_id);
817     my ($overlay_status) = $sth->fetchrow_array();
818     $sth->finish();
819     return $overlay_status;
820
821 }
822
823
824 =head2 SetImportRecordOverlayStatus
825
826 =over 4
827
828 SetImportRecordOverlayStatus($import_record_id, $new_overlay_status);
829
830 =back
831
832 =cut
833
834 sub SetImportRecordOverlayStatus {
835     my ($import_record_id, $new_overlay_status) = @_;
836
837     my $dbh = C4::Context->dbh;
838     my $sth = $dbh->prepare("UPDATE import_records SET overlay_status = ? WHERE import_record_id = ?");
839     $sth->execute($new_overlay_status, $import_record_id);
840     $sth->finish();
841
842 }
843
844 =head2 GetImportRecordStatus
845
846 =over 4
847
848 my $overlay_status = GetImportRecordStatus($import_record_id);
849
850 =back
851
852 =cut
853
854 sub GetImportRecordStatus {
855     my ($import_record_id) = @_;
856
857     my $dbh = C4::Context->dbh;
858     my $sth = $dbh->prepare("SELECT status FROM import_records WHERE import_record_id = ?");
859     $sth->execute($import_record_id);
860     my ($overlay_status) = $sth->fetchrow_array();
861     $sth->finish();
862     return $overlay_status;
863
864 }
865
866
867 =head2 SetImportRecordStatus
868
869 =over 4
870
871 SetImportRecordStatus($import_record_id, $new_overlay_status);
872
873 =back
874
875 =cut
876
877 sub SetImportRecordStatus {
878     my ($import_record_id, $new_overlay_status) = @_;
879
880     my $dbh = C4::Context->dbh;
881     my $sth = $dbh->prepare("UPDATE import_records SET status = ? WHERE import_record_id = ?");
882     $sth->execute($new_overlay_status, $import_record_id);
883     $sth->finish();
884
885 }
886
887 =head2 GetImportRecordMatches
888
889 =over 4
890
891 my $results = GetImportRecordMatches($import_record_id, $best_only);
892
893 =back
894
895 =cut
896
897 sub GetImportRecordMatches {
898     my $import_record_id = shift;
899     my $best_only = @_ ? shift : 0;
900
901     my $dbh = C4::Context->dbh;
902     # FIXME currently biblio only
903     my $sth = $dbh->prepare_cached("SELECT title, author, biblionumber, score
904                                     FROM import_records
905                                     JOIN import_record_matches USING (import_record_id)
906                                     JOIN biblio ON (biblionumber = candidate_match_id)
907                                     WHERE import_record_id = ?
908                                     ORDER BY score DESC, biblionumber DESC");
909     $sth->bind_param(1, $import_record_id);
910     my $results = [];
911     $sth->execute();
912     while (my $row = $sth->fetchrow_hashref) {
913         push @$results, $row;
914         last if $best_only;
915     }
916     $sth->finish();
917
918     return $results;
919     
920 }
921
922
923 =head2 SetImportRecordMatches
924
925 =over 4
926
927 SetImportRecordMatches($import_record_id, @matches);
928
929 =back
930
931 =cut
932
933 sub SetImportRecordMatches {
934     my $import_record_id = shift;
935     my @matches = @_;
936
937     my $dbh = C4::Context->dbh;
938     my $delsth = $dbh->prepare("DELETE FROM import_record_matches WHERE import_record_id = ?");
939     $delsth->execute($import_record_id);
940     $delsth->finish();
941
942     my $sth = $dbh->prepare("INSERT INTO import_record_matches (import_record_id, candidate_match_id, score)
943                                     VALUES (?, ?, ?)");
944     foreach my $match (@matches) {
945         $sth->execute($import_record_id, $match->{'record_id'}, $match->{'score'});
946     }
947 }
948
949
950 # internal functions
951
952 sub _create_import_record {
953     my ($batch_id, $record_sequence, $marc_record, $record_type, $encoding, $z3950random) = @_;
954     
955     my $dbh = C4::Context->dbh;
956     my $sth = $dbh->prepare("INSERT INTO import_records (import_batch_id, record_sequence, marc, marcxml, 
957                                                          record_type, encoding, z3950random)
958                                     VALUES (?, ?, ?, ?, ?, ?, ?)");
959     $sth->execute($batch_id, $record_sequence, $marc_record->as_usmarc(), $marc_record->as_xml(),
960                   $record_type, $encoding, $z3950random);
961     my $import_record_id = $dbh->{'mysql_insertid'};
962     $sth->finish();
963     return $import_record_id;
964 }
965
966 sub _update_import_record_marc {
967     my ($import_record_id, $marc_record) = @_;
968
969     my $dbh = C4::Context->dbh;
970     my $sth = $dbh->prepare("UPDATE import_records SET marc = ?, marcxml = ?
971                              WHERE  import_record_id = ?");
972     $sth->execute($marc_record->as_usmarc(), $marc_record->as_xml(), $import_record_id);
973     $sth->finish();
974 }
975
976 sub _add_biblio_fields {
977     my ($import_record_id, $marc_record) = @_;
978
979     my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
980     my $dbh = C4::Context->dbh;
981     # FIXME no controlnumber, originalsource
982     # FIXME 2 - should regularize normalization of ISBN wherever it is done
983     $isbn =~ s/\(.*$//;
984     $isbn =~ tr/ -_//;  
985     $isbn = uc $isbn;
986     my $sth = $dbh->prepare("INSERT INTO import_biblios (import_record_id, title, author, isbn, issn) VALUES (?, ?, ?, ?, ?)");
987     $sth->execute($import_record_id, $title, $author, $isbn, $issn);
988     $sth->finish();
989                 
990 }
991
992 sub _update_biblio_fields {
993     my ($import_record_id, $marc_record) = @_;
994
995     my ($title, $author, $isbn, $issn) = _parse_biblio_fields($marc_record);
996     my $dbh = C4::Context->dbh;
997     # FIXME no controlnumber, originalsource
998     # FIXME 2 - should regularize normalization of ISBN wherever it is done
999     $isbn =~ s/\(.*$//;
1000     $isbn =~ tr/ -_//;
1001     $isbn = uc $isbn;
1002     my $sth = $dbh->prepare("UPDATE import_biblios SET title = ?, author = ?, isbn = ?, issn = ?
1003                              WHERE  import_record_id = ?");
1004     $sth->execute($title, $author, $isbn, $issn, $import_record_id);
1005     $sth->finish();
1006 }
1007
1008 sub _parse_biblio_fields {
1009     my ($marc_record) = @_;
1010
1011     my $dbh = C4::Context->dbh;
1012     my $bibliofields = TransformMarcToKoha($dbh, $marc_record, '');
1013     return ($bibliofields->{'title'}, $bibliofields->{'author'}, $bibliofields->{'isbn'}, $bibliofields->{'issn'});
1014
1015 }
1016
1017 sub _update_batch_record_counts {
1018     my ($batch_id) = @_;
1019
1020     my $dbh = C4::Context->dbh;
1021     my $sth = $dbh->prepare_cached("UPDATE import_batches SET num_biblios = (
1022                                     SELECT COUNT(*)
1023                                     FROM import_records
1024                                     WHERE import_batch_id = import_batches.import_batch_id
1025                                     AND record_type = 'biblio')
1026                                     WHERE import_batch_id = ?");
1027     $sth->bind_param(1, $batch_id);
1028     $sth->execute();
1029     $sth->finish();
1030     $sth = $dbh->prepare_cached("UPDATE import_batches SET num_items = (
1031                                     SELECT COUNT(*)
1032                                     FROM import_records
1033                                     JOIN import_items USING (import_record_id)
1034                                     WHERE import_batch_id = import_batches.import_batch_id
1035                                     AND record_type = 'biblio')
1036                                     WHERE import_batch_id = ?");
1037     $sth->bind_param(1, $batch_id);
1038     $sth->execute();
1039     $sth->finish();
1040
1041 }
1042
1043 1;
1044
1045 =head1 AUTHOR
1046
1047 Koha Development Team <info@koha.org>
1048
1049 Galen Charlton <galen.charlton@liblime.com>
1050
1051 =cut