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