Bug 15526: Update DB rev (3.22.04.002)
[koha.git] / misc / migration_tools / bulkmarcimport.pl
blobfc68e4013871843449b6697719b74ec65b7839a1
1 #!/usr/bin/perl
2 # Import an iso2709 file into Koha 3
4 use strict;
5 use warnings;
6 #use diagnostics;
7 BEGIN {
8 # find Koha's Perl modules
9 # test carefully before changing this
10 use FindBin;
11 eval { require "$FindBin::Bin/../kohalib.pl" };
14 # Koha modules used
15 use MARC::File::USMARC;
16 use MARC::File::XML;
17 use MARC::Record;
18 use MARC::Batch;
19 use MARC::Charset;
21 use C4::Context;
22 use C4::Biblio;
23 use C4::Koha;
24 use C4::Debug;
25 use C4::Charset;
26 use C4::Items;
27 use YAML;
28 use Unicode::Normalize;
29 use Time::HiRes qw(gettimeofday);
30 use Getopt::Long;
31 use IO::File;
32 use Pod::Usage;
34 use open qw( :std :encoding(UTF-8) );
35 binmode( STDOUT, ":encoding(UTF-8)" );
36 my ( $input_marc_file, $number, $offset) = ('',0,0);
37 my ($version, $delete, $test_parameter, $skip_marc8_conversion, $char_encoding, $verbose, $commit, $fk_off,$format,$biblios,$authorities,$keepids,$match, $isbn_check, $logfile);
38 my ( $insert, $filters, $update, $all, $yamlfile, $authtypes, $append );
39 my $cleanisbn = 1;
40 my ($sourcetag,$sourcesubfield,$idmapfl, $dedup_barcode);
41 my $framework = '';
42 my $localcust;
44 $|=1;
46 GetOptions(
47 'commit:f' => \$commit,
48 'file:s' => \$input_marc_file,
49 'n:f' => \$number,
50 'o|offset:f' => \$offset,
51 'h' => \$version,
52 'd' => \$delete,
53 't|test' => \$test_parameter,
54 's' => \$skip_marc8_conversion,
55 'c:s' => \$char_encoding,
56 'v:+' => \$verbose,
57 'fk' => \$fk_off,
58 'm:s' => \$format,
59 'l:s' => \$logfile,
60 'append' => \$append,
61 'k|keepids:s' => \$keepids,
62 'b|biblios' => \$biblios,
63 'a|authorities' => \$authorities,
64 'authtypes:s' => \$authtypes,
65 'filter=s@' => \$filters,
66 'insert' => \$insert,
67 'update' => \$update,
68 'all' => \$all,
69 'match=s@' => \$match,
70 'i|isbn' => \$isbn_check,
71 'x:s' => \$sourcetag,
72 'y:s' => \$sourcesubfield,
73 'idmap:s' => \$idmapfl,
74 'cleanisbn!' => \$cleanisbn,
75 'yaml:s' => \$yamlfile,
76 'dedupbarcode' => \$dedup_barcode,
77 'framework=s' => \$framework,
78 'custom:s' => \$localcust,
80 $biblios ||= !$authorities;
81 $insert ||= !$update;
82 my $writemode = ($append) ? "a" : "w";
84 if ($all) {
85 $insert = 1;
86 $update = 1;
89 if ($version || ($input_marc_file eq '')) {
90 pod2usage( -verbose => 2 );
91 exit;
94 if(defined $localcust) { #local customize module
95 if(!-e $localcust) {
96 $localcust= $localcust||'LocalChanges'; #default name
97 $localcust=~ s/^.*\/([^\/]+)$/$1/; #extract file name only
98 $localcust=~ s/\.pm$//; #remove extension
99 my $fqcust= $FindBin::Bin."/$localcust.pm"; #try migration_tools dir
100 if(-e $fqcust) {
101 $localcust= $fqcust;
103 else {
104 print "WARNING: customize module $localcust.pm not found!\n";
105 exit 1;
108 require $localcust if $localcust;
109 $localcust=\&customize if $localcust;
112 my $dbh = C4::Context->dbh;
113 my $heading_fields=get_heading_fields();
115 if (defined $idmapfl) {
116 open(IDMAP,">$idmapfl") or die "cannot open $idmapfl \n";
119 if ((not defined $sourcesubfield) && (not defined $sourcetag)){
120 $sourcetag="910";
121 $sourcesubfield="a";
125 # Disable logging for the biblios and authorities import operation. It would unnecessarily
126 # slow the import
128 # Disable the syspref cache so we can change logging settings
129 C4::Context->disable_syspref_cache();
130 # Save current CataloguingLog and AuthoritiesLog sysprefs values
131 my $CataloguingLog = C4::Context->preference( 'CataloguingLog' );
132 my $AuthoritiesLog = C4::Context->preference( 'AuthoritiesLog' );
133 # Disable logging for both
134 C4::Context->set_preference( 'CataloguingLog', 0 );
135 C4::Context->set_preference( 'AuthoritiesLog', 0 );
137 if ($fk_off) {
138 $dbh->do("SET FOREIGN_KEY_CHECKS = 0");
142 if ($delete) {
143 if ($biblios){
144 print "deleting biblios\n";
145 $dbh->do("truncate biblio");
146 $dbh->do("truncate biblioitems");
147 $dbh->do("truncate items");
149 else {
150 print "deleting authorities\n";
151 $dbh->do("truncate auth_header");
153 $dbh->do("truncate zebraqueue");
158 if ($test_parameter) {
159 print "TESTING MODE ONLY\n DOING NOTHING\n===============\n";
162 my $marcFlavour = C4::Context->preference('marcflavour') || 'MARC21';
164 print "Characteristic MARC flavour: $marcFlavour\n" if $verbose;
165 my $starttime = gettimeofday;
166 my $batch;
167 my $fh = IO::File->new($input_marc_file); # don't let MARC::Batch open the file, as it applies the ':utf8' IO layer
168 if (defined $format && $format =~ /XML/i) {
169 # ugly hack follows -- MARC::File::XML, when used by MARC::Batch,
170 # appears to try to convert incoming XML records from MARC-8
171 # to UTF-8. Setting the BinaryEncoding key turns that off
172 # TODO: see what happens to ISO-8859-1 XML files.
173 # TODO: determine if MARC::Batch can be fixed to handle
174 # XML records properly -- it probably should be
175 # be using a proper push or pull XML parser to
176 # extract the records, not using regexes to look
177 # for <record>.*</record>.
178 $MARC::File::XML::_load_args{BinaryEncoding} = 'utf-8';
179 my $recordformat= ($marcFlavour eq "MARC21"?"USMARC":uc($marcFlavour));
180 #UNIMARC Authorities have a different way to manage encoding than UNIMARC biblios.
181 $recordformat=$recordformat."AUTH" if ($authorities and $marcFlavour ne "MARC21");
182 $MARC::File::XML::_load_args{RecordFormat} = $recordformat;
183 $batch = MARC::Batch->new( 'XML', $fh );
184 } else {
185 $batch = MARC::Batch->new( 'USMARC', $fh );
187 $batch->warnings_off();
188 $batch->strict_off();
189 my $i=0;
190 my $commitnum = $commit ? $commit : 50;
191 my $yamlhash;
193 # Skip file offset
194 if ( $offset ) {
195 print "Skipping file offset: $offset records\n";
196 $batch->next() while ($offset--);
199 my ($tagid,$subfieldid);
200 if ($authorities){
201 $tagid='001';
203 else {
204 ( $tagid, $subfieldid ) =
205 GetMarcFromKohaField( "biblio.biblionumber", $framework );
206 $tagid||="001";
209 # the SQL query to search on isbn
210 my $sth_isbn = $dbh->prepare("SELECT biblionumber,biblioitemnumber FROM biblioitems WHERE isbn=?");
212 $dbh->{AutoCommit} = 0;
213 my $loghandle;
214 if ($logfile){
215 $loghandle= IO::File->new($logfile, $writemode) ;
216 print $loghandle "id;operation;status\n";
218 RECORD: while ( ) {
219 my $record;
220 # get records
221 eval { $record = $batch->next() };
222 if ( $@ ) {
223 print "Bad MARC record $i: $@ skipped\n";
224 # FIXME - because MARC::Batch->next() combines grabbing the next
225 # blob and parsing it into one operation, a correctable condition
226 # such as a MARC-8 record claiming that it's UTF-8 can't be recovered
227 # from because we don't have access to the original blob. Note
228 # that the staging import can deal with this condition (via
229 # C4::Charset::MarcToUTF8Record) because it doesn't use MARC::Batch.
230 next;
232 # skip if we get an empty record (that is MARC valid, but will result in AddBiblio failure
233 last unless ( $record );
234 $i++;
235 if( ($verbose//1)==1 ) { #no dot for verbose==2
236 print "." . ( $i % 100==0 ? "\n$i" : '' );
239 # transcode the record to UTF8 if needed & applicable.
240 if ($record->encoding() eq 'MARC-8' and not $skip_marc8_conversion) {
241 # FIXME update condition
242 my ($guessed_charset, $charset_errors);
243 ($record, $guessed_charset, $charset_errors) = MarcToUTF8Record($record, $marcFlavour.(($authorities and $marcFlavour ne "MARC21")?'AUTH':''));
244 if ($guessed_charset eq 'failed') {
245 warn "ERROR: failed to perform character conversion for record $i\n";
246 next RECORD;
249 SetUTF8Flag($record);
250 &$localcust($record) if $localcust;
251 my $isbn;
252 # remove trailing - in isbn (only for biblios, of course)
253 if ($biblios && $cleanisbn) {
254 my $tag = $marcFlavour eq 'UNIMARC' ? '010' : '020';
255 my $field = $record->field($tag);
256 my $isbn = $field && $field->subfield('a');
257 if ( $isbn ) {
258 $isbn =~ s/-//g;
259 $field->update('a' => $isbn);
262 my $id;
263 # search for duplicates (based on Local-number)
264 my $originalid;
265 $originalid = GetRecordId( $record, $tagid, $subfieldid );
266 if ($match) {
267 require C4::Search;
268 my $query = build_query( $match, $record );
269 my $server = ( $authorities ? 'authorityserver' : 'biblioserver' );
270 $debug && warn $query;
271 my ( $error, $results, $totalhits ) = C4::Search::SimpleSearch( $query, 0, 3, [$server] );
272 # changed to warn so able to continue with one broken record
273 if ( defined $error ) {
274 warn "unable to search the database for duplicates : $error";
275 printlog( { id => $id || $originalid || $match, op => "match", status => "ERROR" } ) if ($logfile);
276 next RECORD;
278 $debug && warn "$query $server : $totalhits";
279 if ( $results && scalar(@$results) == 1 ) {
280 my $marcrecord = C4::Search::new_record_from_zebra( $server, $results->[0] );
281 SetUTF8Flag($marcrecord);
282 $id = GetRecordId( $marcrecord, $tagid, $subfieldid );
283 if ( $authorities && $marcFlavour ) {
284 #Skip if authority in database is the same as the on in database
285 if ( $marcrecord->field('005') && $record->field('005') &&
286 $marcrecord->field('005')->data && $record->field('005')->data &&
287 $marcrecord->field('005')->data >= $record->field('005')->data ) {
288 if ($yamlfile) {
289 $yamlhash->{$originalid}->{'authid'} = $id;
291 # we recover all subfields of the heading authorities
292 my @subfields;
293 foreach my $field ( $marcrecord->field("2..") ) {
294 push @subfields, map { ( $_->[0] =~ /[a-z]/ ? $_->[1] : () ) } $field->subfields();
296 $yamlhash->{$originalid}->{'subfields'} = \@subfields;
298 next;
301 } elsif ( $results && scalar(@$results) > 1 ) {
302 $debug && warn "more than one match for $query";
303 } else {
304 $debug && warn "nomatch for $query";
307 if ($keepids && $originalid) {
308 my $storeidfield;
309 if ( length($keepids) == 3 ) {
310 $storeidfield = MARC::Field->new( $keepids, $originalid );
311 } else {
312 $storeidfield = MARC::Field->new( substr( $keepids, 0, 3 ), "", "", substr( $keepids, 3, 1 ), $originalid );
314 $record->insert_fields_ordered($storeidfield);
315 $record->delete_field( $record->field($tagid) );
317 foreach my $stringfilter (@$filters) {
318 if ( length($stringfilter) == 3 ) {
319 foreach my $field ( $record->field($stringfilter) ) {
320 $record->delete_field($field);
321 $debug && warn "removed : ", $field->as_string;
323 } elsif ($stringfilter =~ /([0-9]{3})([a-z0-9])(.*)/) {
324 my $removetag = $1;
325 my $removesubfield = $2;
326 my $removematch = $3;
327 if ( ( $removetag > "010" ) && $removesubfield ) {
328 foreach my $field ( $record->field($removetag) ) {
329 $field->delete_subfield( code => "$removesubfield", match => $removematch );
330 $debug && warn "Potentially removed : ", $field->subfield($removesubfield);
335 unless ($test_parameter) {
336 if ($authorities){
337 use C4::AuthoritiesMarc;
338 my $authtypecode=GuessAuthTypeCode($record, $heading_fields);
339 my $authid= ($id?$id:GuessAuthId($record));
340 if ($authid && GetAuthority($authid) && $update ){
341 ## Authority has an id and is in database : Replace
342 eval { ( $authid ) = ModAuthority($authid,$record, $authtypecode) };
343 if ($@){
344 warn "Problem with authority $authid Cannot Modify";
345 printlog({id=>$originalid||$id||$authid, op=>"edit",status=>"ERROR"}) if ($logfile);
347 else{
348 printlog({id=>$originalid||$id||$authid, op=>"edit",status=>"ok"}) if ($logfile);
351 elsif (defined $authid) {
352 ## An authid is defined but no authority in database : add
353 eval { ( $authid ) = AddAuthority($record,$authid, $authtypecode) };
354 if ($@){
355 warn "Problem with authority $authid Cannot Add ".$@;
356 printlog({id=>$originalid||$id||$authid, op=>"insert",status=>"ERROR"}) if ($logfile);
358 else{
359 printlog({id=>$originalid||$id||$authid, op=>"insert",status=>"ok"}) if ($logfile);
362 else {
363 ## True insert in database
364 eval { ( $authid ) = AddAuthority($record,"", $authtypecode) };
365 if ($@){
366 warn "Problem with authority $authid Cannot Add".$@;
367 printlog({id=>$originalid||$id||$authid, op=>"insert",status=>"ERROR"}) if ($logfile);
369 else{
370 printlog({id=>$originalid||$id||$authid, op=>"insert",status=>"ok"}) if ($logfile);
373 if ($yamlfile) {
374 $yamlhash->{$originalid}->{'authid'} = $authid;
375 my @subfields;
376 foreach my $field ( $record->field("2..") ) {
377 push @subfields, map { ( $_->[0] =~ /[a-z]/ ? $_->[1] : () ) } $field->subfields();
379 $yamlhash->{$originalid}->{'subfields'} = \@subfields;
382 else {
383 my ( $biblionumber, $biblioitemnumber, $itemnumbers_ref, $errors_ref );
384 $biblionumber = $id;
385 # check for duplicate, based on ISBN (skip it if we already have found a duplicate with match parameter
386 if (!$biblionumber && $isbn_check && $isbn) {
387 # warn "search ISBN : $isbn";
388 $sth_isbn->execute($isbn);
389 ($biblionumber,$biblioitemnumber) = $sth_isbn->fetchrow;
391 if (defined $idmapfl) {
392 if ($sourcetag < "010"){
393 if ($record->field($sourcetag)){
394 my $source = $record->field($sourcetag)->data();
395 printf(IDMAP "%s|%s\n",$source,$biblionumber);
397 } else {
398 my $source=$record->subfield($sourcetag,$sourcesubfield);
399 printf(IDMAP "%s|%s\n",$source,$biblionumber);
402 # create biblio, unless we already have it ( either match or isbn )
403 if ($biblionumber) {
404 eval{$biblioitemnumber=GetBiblioData($biblionumber)->{biblioitemnumber};};
405 if ($update) {
406 eval { ( $biblionumber, $biblioitemnumber ) = ModBiblio( $record, $biblionumber, GetFrameworkCode($biblionumber) ) };
407 if ($@) {
408 warn "ERROR: Edit biblio $biblionumber failed: $@\n";
409 printlog( { id => $id || $originalid || $biblionumber, op => "update", status => "ERROR" } ) if ($logfile);
410 next RECORD;
411 } else {
412 printlog( { id => $id || $originalid || $biblionumber, op => "update", status => "ok" } ) if ($logfile);
414 } else {
415 printlog( { id => $id || $originalid || $biblionumber, op => "insert", status => "warning : already in database" } ) if ($logfile);
417 } else {
418 if ($insert) {
419 eval { ( $biblionumber, $biblioitemnumber ) = AddBiblio( $record, '', { defer_marc_save => 1 } ) };
420 if ($@) {
421 warn "ERROR: Adding biblio $biblionumber failed: $@\n";
422 printlog( { id => $id || $originalid || $biblionumber, op => "insert", status => "ERROR" } ) if ($logfile);
423 next RECORD;
424 } else {
425 printlog( { id => $id || $originalid || $biblionumber, op => "insert", status => "ok" } ) if ($logfile);
427 } else {
428 printlog( { id => $id || $originalid || $biblionumber, op => "update", status => "warning : not in database" } ) if ($logfile);
431 eval { ( $itemnumbers_ref, $errors_ref ) = AddItemBatchFromMarc( $record, $biblionumber, $biblioitemnumber, '' ); };
432 my $error_adding = $@;
433 # Work on a clone so that if there are real errors, we can maybe
434 # fix them up later.
435 my $clone_record = $record->clone();
436 C4::Biblio::_strip_item_fields($clone_record, '');
437 # This sets the marc fields if there was an error, and also calls
438 # defer_marc_save.
439 ModBiblioMarc( $clone_record, $biblionumber, $framework );
440 if ( $error_adding ) {
441 warn "ERROR: Adding items to bib $biblionumber failed: $error_adding";
442 printlog({id=>$id||$originalid||$biblionumber, op=>"insertitem",status=>"ERROR"}) if ($logfile);
443 # if we failed because of an exception, assume that
444 # the MARC columns in biblioitems were not set.
445 next RECORD;
447 else{
448 printlog({id=>$id||$originalid||$biblionumber, op=>"insert",status=>"ok"}) if ($logfile);
450 if ($dedup_barcode && grep { exists $_->{error_code} && $_->{error_code} eq 'duplicate_barcode' } @$errors_ref) {
451 # Find the record called 'barcode'
452 my ($tag, $sub) = C4::Biblio::GetMarcFromKohaField('items.barcode', $framework);
453 # Now remove any items that didn't have a duplicate_barcode error,
454 # erase the barcodes on items that did, and re-add those items.
455 my %dupes;
456 foreach my $i (0 .. $#{$errors_ref}) {
457 my $ref = $errors_ref->[$i];
458 if ($ref && ($ref->{error_code} eq 'duplicate_barcode')) {
459 $dupes{$ref->{item_sequence}} = 1;
460 # Delete the error message because we're going to
461 # retry this one.
462 delete $errors_ref->[$i];
465 my $seq = 0;
466 foreach my $field ($record->field($tag)) {
467 $seq++;
468 if ($dupes{$seq}) {
469 # Here we remove the barcode
470 $field->delete_subfield(code => $sub);
471 } else {
472 # otherwise we delete the field because we don't want
473 # two of them
474 $record->delete_fields($field);
477 # Now re-add the record as before, adding errors to the prev list
478 my $more_errors;
479 eval { ( $itemnumbers_ref, $more_errors ) = AddItemBatchFromMarc( $record, $biblionumber, $biblioitemnumber, '' ); };
480 if ( $@ ) {
481 warn "ERROR: Adding items to bib $biblionumber failed: $@\n";
482 printlog({id=>$id||$originalid||$biblionumber, op=>"insertitem",status=>"ERROR"}) if ($logfile);
483 # if we failed because of an exception, assume that
484 # the MARC columns in biblioitems were not set.
485 ModBiblioMarc( $record, $biblionumber, $framework );
486 next RECORD;
487 } else {
488 printlog({id=>$id||$originalid||$biblionumber, op=>"insert",status=>"ok"}) if ($logfile);
490 push @$errors_ref, @{ $more_errors };
492 if ($#{ $errors_ref } > -1) {
493 report_item_errors($biblionumber, $errors_ref);
495 $yamlhash->{$originalid} = $biblionumber if ($yamlfile);
497 $dbh->commit() if (0 == $i % $commitnum);
499 print $record->as_formatted()."\n" if ($verbose//0)==2;
500 last if $i == $number;
502 $dbh->commit();
503 $dbh->{AutoCommit} = 1;
506 if ($fk_off) {
507 $dbh->do("SET FOREIGN_KEY_CHECKS = 1");
510 # Restore CataloguingLog
511 C4::Context->set_preference( 'CataloguingLog', $CataloguingLog );
512 # Restore AuthoritiesLog
513 C4::Context->set_preference( 'AuthoritiesLog', $AuthoritiesLog );
515 my $timeneeded = gettimeofday - $starttime;
516 print "\n$i MARC records done in $timeneeded seconds\n";
517 if ($logfile){
518 print $loghandle "file : $input_marc_file\n";
519 print $loghandle "$i MARC records done in $timeneeded seconds\n";
520 $loghandle->close;
522 if ($yamlfile) {
523 open my $yamlfileout, q{>}, "$yamlfile" or die "cannot open $yamlfile \n";
524 print $yamlfileout Dump($yamlhash);
526 exit 0;
528 sub GetRecordId{
529 my $marcrecord=shift;
530 my $tag=shift;
531 my $subfield=shift;
532 my $id;
533 if ($tag lt "010"){
534 return $marcrecord->field($tag)->data() if $marcrecord->field($tag);
536 elsif ($subfield){
537 if ($marcrecord->field($tag)){
538 return $marcrecord->subfield($tag,$subfield);
541 return $id;
543 sub build_query {
544 my $match = shift;
545 my $record=shift;
546 my @searchstrings;
547 foreach my $matchingpoint (@$match){
548 my $string = build_simplequery($matchingpoint,$record);
549 push @searchstrings,$string if (length($string)>0);
551 my $QParser;
552 $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser'));
553 my $op;
554 if ($QParser) {
555 $op = '&&';
556 } else {
557 $op = 'and';
559 return join(" $op ",@searchstrings);
561 sub build_simplequery {
562 my $element=shift;
563 my $record=shift;
564 my @searchstrings;
565 my ($index,$recorddata)=split /,/,$element;
566 if ($recorddata=~/(\d{3})(.*)/) {
567 my ($tag,$subfields) =($1,$2);
568 foreach my $field ($record->field($tag)){
569 if (length($field->as_string("$subfields"))>0){
570 push @searchstrings,"$index:\"".$field->as_string("$subfields")."\"";
574 my $QParser;
575 $QParser = C4::Context->queryparser if (C4::Context->preference('UseQueryParser'));
576 my $op;
577 if ($QParser) {
578 $op = '&&';
579 } else {
580 $op = 'and';
582 return join(" $op ",@searchstrings);
584 sub report_item_errors {
585 my $biblionumber = shift;
586 my $errors_ref = shift;
588 foreach my $error (@{ $errors_ref }) {
589 next if !$error;
590 my $msg = "Item not added (bib $biblionumber, item tag #$error->{'item_sequence'}, barcode $error->{'item_barcode'}): ";
591 my $error_code = $error->{'error_code'};
592 $error_code =~ s/_/ /g;
593 $msg .= "$error_code $error->{'error_information'}";
594 print $msg, "\n";
597 sub printlog{
598 my $logelements=shift;
599 print $loghandle join( ";", map { defined $_ ? $_ : "" } @$logelements{qw<id op status>} ), "\n";
601 sub get_heading_fields{
602 my $headingfields;
603 if ($authtypes){
604 $headingfields=YAML::LoadFile($authtypes);
605 $headingfields={C4::Context->preference('marcflavour')=>$headingfields};
606 $debug && warn YAML::Dump($headingfields);
608 unless ($headingfields){
609 $headingfields=$dbh->selectall_hashref("SELECT auth_tag_to_report, authtypecode from auth_types",'auth_tag_to_report',{Slice=>{}});
610 $headingfields={C4::Context->preference('marcflavour')=>$headingfields};
612 return $headingfields;
615 =head1 NAME
617 bulkmarcimport.pl - Import bibliographic/authority records into Koha
619 =head1 USAGE
621 $ export KOHA_CONF=/etc/koha.conf
622 $ perl misc/migration_tools/bulkmarcimport.pl -d -commit 1000 \\
623 -file /home/jmf/koha.mrc -n 3000
625 =head1 WARNING
627 Don't use this script before you've entered and checked your MARC parameters
628 tables twice (or more!). Otherwise, the import won't work correctly and you
629 will get invalid data.
631 =head1 DESCRIPTION
633 =over
635 =item B<-h>
637 This version/help screen
639 =item B<-b, -biblios>
641 Type of import: bibliographic records
643 =item B<-a, -authorities>
645 Type of import: authority records
647 =item B<-file>=I<FILE>
649 The I<FILE> to import
651 =item B<-v>
653 Verbose mode. 1 means "some infos", 2 means "MARC dumping"
655 =item B<-fk>
657 Turn off foreign key checks during import.
659 =item B<-n>=I<NUMBER>
661 The I<NUMBER> of records to import. If missing, all the file is imported
663 =item B<-o, -offset>=I<NUMBER>
665 File offset before importing, ie I<NUMBER> of records to skip.
667 =item B<-commit>=I<NUMBER>
669 The I<NUMBER> of records to wait before performing a 'commit' operation
671 =item B<-l>
673 File logs actions done for each record and their status into file
675 =item B<-append>
677 If specified, data will be appended to the logfile. If not, the logfile will be erased for each execution.
679 =item B<-t, -test>
681 Test mode: parses the file, saying what he would do, but doing nothing.
683 =item B<-s>
685 Skip automatic conversion of MARC-8 to UTF-8. This option is provided for
686 debugging.
688 =item B<-c>=I<CHARACTERISTIC>
690 The I<CHARACTERISTIC> MARC flavour. At the moment, only I<MARC21> and
691 I<UNIMARC> are supported. MARC21 by default.
693 =item B<-d>
695 Delete EVERYTHING related to biblio in koha-DB before import. Tables: biblio,
696 biblioitems, items
698 =item B<-m>=I<FORMAT>
700 Input file I<FORMAT>: I<MARCXML> or I<ISO2709> (defaults to ISO2709)
702 =item B<-authtypes>
704 file yamlfile with authoritiesTypes and distinguishable record field in order
705 to store the correct authtype
707 =item B<-yaml>
709 yaml file format a yaml file with ids
711 =item B<-filter>
713 list of fields that will not be imported. Can be any from 000 to 999 or field,
714 subfield and subfield's matching value such as 200avalue
716 =item B<-insert>
718 if set, only insert when possible
720 =item B<-update>
722 if set, only updates (any biblio should have a matching record)
724 =item B<-all>
726 if set, do whatever is required
728 =item B<-k, -keepids>=<FIELD>
730 Field store ids in I<FIELD> (useful for authorities, where 001 contains the
731 authid for Koha, that can contain a very valuable info for authorities coming
732 from LOC or BNF. useless for biblios probably)
734 =item B<-match>=<FIELD>
736 I<FIELD> matchindex,fieldtomatch matchpoint to use to deduplicate fieldtomatch
737 can be either 001 to 999 or field and list of subfields as such 100abcde
739 =item B<-i,-isbn>
741 If set, a search will be done on isbn, and, if the same isbn is found, the
742 biblio is not added. It's another method to deduplicate. B<-match> & B<-isbn>
743 can be both set.
745 =item B<-cleanisbn>
747 Clean ISBN fields from entering biblio records, ie removes hyphens. By default,
748 ISBN are cleaned. --nocleanisbn will keep ISBN unchanged.
750 =item B<-x>=I<TAG>
752 Source bib I<TAG> for reporting the source bib number
754 =item B<-y>=I<SUBFIELD>
756 Source I<SUBFIELD> for reporting the source bib number
758 =item B<-idmap>=I<FILE>
760 I<FILE> for the koha bib and source id
762 =item B<-keepids>
764 Store ids in 009 (useful for authorities, where 001 contains the authid for
765 Koha, that can contain a very valuable info for authorities coming from LOC or
766 BNF. useless for biblios probably)
768 =item B<-dedupbarcode>
770 If set, whenever a duplicate barcode is detected, it is removed and the attempt
771 to add the record is retried, thereby giving the record a blank barcode. This
772 is useful when something has set barcodes to be a biblio ID, or similar
773 (usually other software.)
775 =item B<-framework>
777 This is the code for the framework that the requested records will have attached
778 to them when they are created. If not specified, then the default framework
779 will be used.
781 =item B<-custom>=I<MODULE>
783 This parameter allows you to use a local module with a customize subroutine
784 that is called for each MARC record.
785 If no filename is passed, LocalChanges.pm is assumed to be in the
786 migration_tools subdirectory. You may pass an absolute file name or a file name
787 from the migration_tools directory.
789 =back
791 =cut