@@ -, +, @@ Bug 5635 : merge conflict solved bulkmarcimport Bug 5635 : bulkmarcimport.pl Minor fixes Testing existence of isbn before using it Testing existence of data before printing in printlog Adding debugs Bug 5635 : Fixing Imporving YAML for authorities There was one case where the heading would not be precisely good Bug 5635 : bulkmarcimport log correction insert was used both for insert biblio and insertitem using insertitem for items Bug 5635 : Enhancement bulkmarcimport for Agates Adding test parameter Adding insert to allow INSERT only Adding update parameter to allow biblios to be only updated Adding filter on tags/subfields exemples : --filter 995 --filter 98. removes all 98x field --filter 981aSmad removes all 981$a with value Smad Bug 5635 : (MT 2256)Followup bulkmarcimport enhancement yaml file as output in order to be able to create a mapping Bug 5635 : bulkmarcimport : Adding checks on last update date For UNIMARC authorities at import, import only those whose edition date is more recent than the data in database Adding management for multiple heading field Especially usefull to manage multi script headings UTF8 management and encoding for all input/output Bug 5635 : Take care of encoding in bulkmarc import --- misc/migration_tools/bulkmarcimport.pl | 206 ++++++++++++++++++++++++++------ 1 files changed, 169 insertions(+), 37 deletions(-) --- a/misc/migration_tools/bulkmarcimport.pl +++ a/misc/migration_tools/bulkmarcimport.pl @@ -24,16 +24,20 @@ use C4::Koha; use C4::Debug; use C4::Charset; use C4::Items; +use YAML; use Unicode::Normalize; use Time::HiRes qw(gettimeofday); use Getopt::Long; use IO::File; use Pod::Usage; +use open qw( :std :utf8 ); binmode(STDOUT, ":utf8"); + my ( $input_marc_file, $number, $offset) = ('',0,0); -my ($version, $delete, $test_parameter, $skip_marc8_conversion, $char_encoding, $verbose, $commit, $fk_off,$format,$biblios,$authorities,$keepids,$match, $isbn_check, $logfile); +my ($version, $delete, $skip_marc8_conversion, $char_encoding, $verbose, $commit, $fk_off,$format,$biblios,$authorities,$keepids,$match, $isbn_check, $logfile,$yamlfile); my ($sourcetag,$sourcesubfield,$idmapfl); +my ($insert,$filters,$update,$all,$test_parameter); $|=1; @@ -44,7 +48,7 @@ GetOptions( 'o|offset:f' => \$offset, 'h' => \$version, 'd' => \$delete, - 't' => \$test_parameter, + 't|test' => \$test_parameter, 's' => \$skip_marc8_conversion, 'c:s' => \$char_encoding, 'v:s' => \$verbose, @@ -54,17 +58,73 @@ GetOptions( 'k|keepids:s' => \$keepids, 'b|biblios' => \$biblios, 'a|authorities' => \$authorities, + 'filter=s@' => \$filters, + 'insert' => \$insert, + 'update' => \$update, + 'all' => \$all, 'match=s@' => \$match, 'i|isbn' => \$isbn_check, 'x:s' => \$sourcetag, 'y:s' => \$sourcesubfield, 'idmap:s' => \$idmapfl, + 'yaml:s' => \$yamlfile, ); -$biblios=!$authorities||$biblios; +$biblios||= !$authorities; +$insert ||= !$update; +if ($all){ + $insert=1; + $update=1; +} if ($version || ($input_marc_file eq '')) { - pod2usage( -verbose => 2 ); - exit; + print <warnings_off(); $batch->strict_off(); my $i=0; my $commitnum = $commit ? $commit : 50; - +my $yamlhash; # Skip file offset if ( $offset ) { @@ -195,14 +255,17 @@ RECORD: while ( ) { next RECORD; } } + SetUTF8Flag($record); my $isbn; # remove trailing - in isbn (only for biblios, of course) if ($biblios) { if ($marcFlavour eq 'UNIMARC') { if (my $f010 = $record->field('010')) { - $isbn = $f010->subfield('a'); - $isbn =~ s/-//g; - $f010->update('a' => $isbn); + if ($f010->subfield('a')){ + $isbn = $f010->subfield('a'); + $isbn =~ s/-//g; + $f010->update('a' => $isbn); + } } } else { if (my $f020 = $record->field('020')) { @@ -215,27 +278,46 @@ RECORD: while ( ) { } my $id; # search for duplicates (based on Local-number) + my $originalid; + $originalid=GetRecordId($record,$tagid,$subfieldid); if ($match){ require C4::Search; my $query=build_query($match,$record); my $server=($authorities?'authorityserver':'biblioserver'); + $debug && warn $query; my ($error, $results,$totalhits)=C4::Search::SimpleSearch( $query, 0, 3, [$server] ); die "unable to search the database for duplicates : $error" if (defined $error); - #warn "$query $server : $totalhits"; + $debug && warn "$query $server : $totalhits"; if ($results && scalar(@$results)==1){ my $marcrecord = MARC::File::USMARC::decode($results->[0]); + SetUTF8Flag($marcrecord); $id=GetRecordId($marcrecord,$tagid,$subfieldid); - } + if ($authorities && $marcFlavour ) { + #Skip if authority in database is the same as the on in database + if ($marcrecord->field('005')->data >= $record->field('005')->data){ + if ($yamlfile){ + $yamlhash->{$originalid}->{'authid'}=$id; + # On récupère tous les souschamps des champs vedettes d'autorités + my @subfields; + foreach my $field ($marcrecord->field("2..")){ + push @subfields, map{ + ($_->[0]=~/[a-z]/?$_->[1]:()) + } $field->subfields(); + } + $yamlhash->{$originalid}->{'subfields'}=\@subfields; + } + next; + } + } + } elsif ($results && scalar(@$results)>1){ - $debug && warn "more than one match for $query"; - } + $debug && warn "more than one match for $query"; + } else { - $debug && warn "nomatch for $query"; + $debug && warn "nomatch for $query"; } } - my $originalid; if ($keepids){ - $originalid=GetRecordId($record,$tagid,$subfieldid); if ($originalid){ my $storeidfield; if (length($keepids)==3){ @@ -248,14 +330,31 @@ RECORD: while ( ) { $record->delete_field($record->field($tagid)); } } - unless ($test_parameter) { + foreach my $stringfilter (@$filters){ + if (length($stringfilter)==3){ + foreach my $field ($record->field($stringfilter)){ + $record->delete_field($field); + $debug && warn "removed : ",$field->as_string; + } + } + else { + my ($removetag,$removesubfield,$removematch)=($1,$2,$3) + if $stringfilter=~/([0-9]{3})([a-z0-9])(.*)/; + if (($removetag >"010")&& $removesubfield){ + foreach my $field ($record->field($removetag)){ + $field->delete_subfield(code=>"$removesubfield",match=>$removematch); + $debug && warn "Potentially removed : ",$field->subfield($removesubfield); + } + } + } + } if ($authorities){ use C4::AuthoritiesMarc; my $authtypecode=GuessAuthTypeCode($record); my $authid= ($id?$id:GuessAuthId($record)); - if ($authid && GetAuthority($authid)){ + if ($authid && GetAuthority($authid) && $update){ ## Authority has an id and is in database : Replace - eval { ( $authid ) = ModAuthority($authid,$record, $authtypecode) }; + (! $test_parameter) and eval { ( $authid ) = ModAuthority($authid,$record, $authtypecode) }; if ($@){ warn "Problem with authority $authid Cannot Modify"; printlog({id=>$originalid||$id||$authid, op=>"edit",status=>"ERROR"}) if ($logfile); @@ -266,7 +365,7 @@ RECORD: while ( ) { } elsif (defined $authid) { ## An authid is defined but no authority in database : add - eval { ( $authid ) = AddAuthority($record,$authid, $authtypecode) }; + (! $test_parameter) and eval { ( $authid ) = AddAuthority($record,$authid, $authtypecode) }; if ($@){ warn "Problem with authority $authid Cannot Add ".$@; printlog({id=>$originalid||$id||$authid, op=>"insert",status=>"ERROR"}) if ($logfile); @@ -277,7 +376,7 @@ RECORD: while ( ) { } else { ## True insert in database - eval { ( $authid ) = AddAuthority($record,"", $authtypecode) }; + (! $test_parameter) and eval { ( $authid ) = AddAuthority($record,"", $authtypecode) }; if ($@){ warn "Problem with authority $authid Cannot Add".$@; printlog({id=>$originalid||$id||$authid, op=>"insert",status=>"ERROR"}) if ($logfile); @@ -286,6 +385,16 @@ RECORD: while ( ) { printlog({id=>$originalid||$id||$authid, op=>"insert",status=>"ok"}) if ($logfile); } } + if ($yamlfile){ + $yamlhash->{$originalid}->{'authid'}=$authid; + my @subfields; + foreach my $field ($record->field("2..")){ + push @subfields, map{ + ($_->[0]=~/[a-z]/?$_->[1]:()) + } $field->subfields(); + } + $yamlhash->{$originalid}->{'subfields'}=\@subfields; + } } else { my ( $biblionumber, $biblioitemnumber, $itemnumbers_ref, $errors_ref ); @@ -309,21 +418,40 @@ RECORD: while ( ) { } # create biblio, unless we already have it ( either match or isbn ) if ($biblionumber) { - eval{$biblioitemnumber=GetBiblioData($biblionumber)->{biblioitemnumber};} + eval{$biblioitemnumber=GetBiblioData($biblionumber)->{biblioitemnumber};}; + if ($update) { + (! $test_parameter) and eval { ( $biblionumber, $biblioitemnumber ) = ModBiblio($record, $biblionumber,GetFrameworkcode($biblionumber)) }; + if ( $@ ) { + warn "ERROR: Edit biblio $biblionumber failed: $@\n"; + printlog({id=>$id||$originalid||$biblionumber, op=>"update",status=>"ERROR"}) if ($logfile); + next RECORD; + } + else{ + printlog({id=>$id||$originalid||$biblionumber, op=>"update",status=>"ok"}) if ($logfile); + } + } + else { + printlog({id=>$id||$originalid||$biblionumber, op=>"insert",status=>"warning : already in database"}) if ($logfile); + } } else { - eval { ( $biblionumber, $biblioitemnumber ) = AddBiblio($record, '', { defer_marc_save => 1 }) }; + if ($insert){ + (! $test_parameter) and eval { ( $biblionumber, $biblioitemnumber ) = AddBiblio($record, '', { defer_marc_save => 1 }) }; + if ( $@ ) { + warn "ERROR: Adding biblio $biblionumber failed: $@\n"; + printlog({id=>$id||$originalid||$biblionumber, op=>"insert",status=>"ERROR"}) if ($logfile); + next RECORD; + } + else{ + printlog({id=>$id||$originalid||$biblionumber, op=>"insert",status=>"ok"}) if ($logfile); + } + } + else { + printlog({id=>$id||$originalid||$biblionumber, op=>"update",status=>"warning : not in database"}) if ($logfile); + } } - if ( $@ ) { - warn "ERROR: Adding biblio $biblionumber failed: $@\n"; - printlog({id=>$id||$originalid||$biblionumber, op=>"insert",status=>"ERROR"}) if ($logfile); - next RECORD; - } - else{ - printlog({id=>$id||$originalid||$biblionumber, op=>"insert",status=>"ok"}) if ($logfile); - } - eval { ( $itemnumbers_ref, $errors_ref ) = AddItemBatchFromMarc( $record, $biblionumber, $biblioitemnumber, '' ); }; + (! $test_parameter) and eval { ( $itemnumbers_ref, $errors_ref ) = AddItemBatchFromMarc( $record, $biblionumber, $biblioitemnumber, '' ); }; if ( $@ ) { warn "ERROR: Adding items to bib $biblionumber failed: $@\n"; printlog({id=>$id||$originalid||$biblionumber, op=>"insertitem",status=>"ERROR"}) if ($logfile); @@ -331,16 +459,16 @@ RECORD: while ( ) { # the MARC columns in biblioitems were not set. ModBiblioMarc( $record, $biblionumber, '' ); next RECORD; - } + } else{ - printlog({id=>$id||$originalid||$biblionumber, op=>"insert",status=>"ok"}) if ($logfile); + printlog({id=>$id||$originalid||$biblionumber, op=>"insertitem",status=>"ok"}) if ($logfile); } if ($#{ $errors_ref } > -1) { report_item_errors($biblionumber, $errors_ref); } + $yamlhash->{$originalid}=$biblionumber if ($yamlfile); } $dbh->commit() if (0 == $i % $commitnum); - } last if $i == $number; } $dbh->commit(); @@ -361,6 +489,10 @@ if ($logfile){ print $loghandle "$i MARC records done in $timeneeded seconds\n"; $loghandle->close; } +if ($yamlfile){ + open YAML, "> $yamlfile" or die "cannot open $yamlfile \n"; + print YAML Dump($yamlhash); +} exit 0; sub GetRecordId{ @@ -370,7 +502,7 @@ sub GetRecordId{ my $id; if ($tag lt "010"){ return $marcrecord->field($tag)->data() if $marcrecord->field($tag); - } + } elsif ($subfield){ if ($marcrecord->field($tag)){ return $marcrecord->subfield($tag,$subfield); @@ -415,7 +547,7 @@ sub report_item_errors { } sub printlog{ my $logelements=shift; - print $loghandle join (";",@$logelements{qw}),"\n"; + print $loghandle join (";",map{defined $_?$_:""}@$logelements{qw}),"\n"; } --