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