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