c787374eef89156a8df3c75974b6ad1edae35bce
[srvgit] / misc / maintenance / UNIMARC_sync_date_created_with_marc_biblio.pl
1 #!/usr/bin/perl
2 #
3 # This script should be used only with UNIMARC flavour
4 # It is designed to report some missing information from biblio
5 # table into marc data
6 #
7 use strict;
8 use warnings;
9
10 use Koha::Script;
11 use C4::Biblio qw( GetMarcBiblio ModBiblio );
12 use Getopt::Long qw( GetOptions );
13
14 sub _read_marc_code {
15     my $input = shift;
16     my ( $field, $subfield );
17     if ( $input =~ /^(\d{3})$/ ) {
18         $field = $1;
19     }
20     elsif ( $input =~ /^(\d{3})(\w)$/ ) {
21         $field    = $1;
22         $subfield = $2;
23     }
24     return ( $field, $subfield );
25 }
26
27 my ( $run, $help, $verbose, $where, $date_created_marc, $date_modified_marc );
28 GetOptions(
29     'help|h'                 => \$help,
30     'verbose|v'              => \$verbose,
31     'run'                    => \$run,
32     'where:s'                => \$where,
33     'date-created-marc|c:s'  => \$date_created_marc,
34     'date-modified-marc|m:s' => \$date_modified_marc,
35 );
36 my $debug = 0; # FIXME pass an option for that?
37 $verbose = 1 if $debug;
38
39 # display help ?
40 if ($help) {
41     print_usage();
42     exit 0;
43 }
44
45 $verbose and print "================================\n";
46
47 # date created MARC field/subfield
48 $date_created_marc = '099c' unless $date_created_marc;
49 my ( $c_field, $c_subfield ) = _read_marc_code($date_created_marc);
50 die "date-created-marc '$date_created_marc' is not correct." unless $c_field;
51 die "date-created-marc field is greated that 009, it should have a subfield."
52   if ( $c_field > 9 && !defined $c_subfield );
53 die "date-created-marc field is lower that 010, it should not have a subfield."
54   if ( $c_field < 10 && defined $c_subfield );
55 if ($verbose) {
56     print "Date created on $c_field";
57     print $c_subfield if defined $c_subfield;    # use of defined to allow 0
58     print "\n";
59 }
60
61 # date last modified MARC field/subfield
62 $date_modified_marc = '099d' unless $date_modified_marc;
63 my ( $m_field, $m_subfield ) = _read_marc_code($date_modified_marc);
64 die "date-modified-marc '$date_modified_marc' is not correct." unless $m_field;
65 die "date-modified-marc field is greated that 009, it should have a subfield."
66   if ( $m_field > 9 && !defined $m_subfield );
67 die "date-modified-marc field is lower that 010, it should not have a subfield."
68   if ( $m_field < 10 && defined $m_subfield );
69 die
70 "When date-created-marc and date-modified-marc are on same field, they should have distinct subfields"
71   if ( $c_field eq $m_field )
72   && ( !defined $c_subfield
73     || !defined $m_subfield
74     || $c_subfield eq $m_subfield );
75 if ($verbose) {
76     print "Date last modified on $m_field";
77     print $m_subfield if defined $m_subfield;    # use of defined to allow 0
78     print "\n";
79 }
80
81 my $dbh;
82 my $sth_prepared;
83
84 sub updateMarc {
85     my $id     = shift;
86     my $biblio = GetMarcBiblio({ biblionumber => $id });
87
88     unless ($biblio) {
89         $debug and warn '[ERROR] GetMarcBiblio did not return any biblio.';
90         return;
91     }
92
93     my $c_marc_field = $biblio->field($c_field);
94     my $m_marc_field = $biblio->field($m_field);
95
96     my $c_marc_value;
97     if ($c_marc_field) {
98         $c_marc_value =
99           defined $c_subfield
100           ? $c_marc_field->subfield($c_subfield)
101           : $c_marc_field->data();
102     }
103     $c_marc_value = '' unless defined $c_marc_value;
104
105     my $m_marc_value;
106     if ($m_marc_field) {
107         $m_marc_value =
108           defined $m_subfield
109           ? $m_marc_field->subfield($m_subfield)
110           : $m_marc_field->data();
111     }
112     $m_marc_value ||= '';
113
114     $sth_prepared = $dbh->prepare(
115         q{
116         SELECT
117             DATE_FORMAT(datecreated,'%Y-%m-%d') AS datecreatediso,
118             DATE_FORMAT(timestamp,'%Y-%m-%d') AS datemodifiediso,
119             frameworkcode
120         FROM biblio
121         WHERE biblionumber = ?
122     }
123     ) unless $sth_prepared;
124     $sth_prepared->execute($id);
125     my $bibliorow     = $sth_prepared->fetchrow_hashref;
126     my $frameworkcode = $bibliorow->{'frameworkcode'};
127     my $c_db_value    = $bibliorow->{'datecreatediso'} || '';
128     my $m_db_value    = $bibliorow->{'datemodifiediso'} || '';
129
130     # do nothing if already sync
131     return if ( $c_marc_value eq $c_db_value && $m_marc_value eq $m_db_value );
132
133     # do apply to database ?
134     return 1 unless $run;
135
136     # update MARC record
137
138     # date created field
139     unless ($c_marc_field) {
140         if ( defined $c_subfield ) {
141             $biblio->add_fields(
142                 MARC::Field->new(
143                     $c_field, ' ', ' ', $c_subfield => $c_db_value
144                 )
145             );
146         }
147         else {
148             $biblio->add_fields( MARC::Field->new( $c_field, $c_db_value ) );
149         }
150         $debug and warn "[WARN] $c_field did not exist.";
151         $c_marc_field = $biblio->field($c_field);
152
153         # when on same field
154         if ( $m_field eq $c_field ) {
155             $m_marc_field = $c_marc_field;
156         }
157     }
158     else {
159         if ( defined $c_subfield ) {
160             $c_marc_field->update( $c_subfield, $c_db_value );
161         }
162         else {
163             $c_marc_field->update($c_db_value);
164         }
165     }
166
167     # date last modified field
168     unless ($m_marc_field) {
169         if ( defined $m_subfield ) {
170             $biblio->add_fields(
171                 MARC::Field->new(
172                     $m_field, ' ', ' ', $m_subfield => $m_db_value
173                 )
174             );
175         }
176         else {
177             $biblio->add_fields( MARC::Field->new( $m_field, $m_db_value ) );
178         }
179
180         $debug and warn "[WARN] $m_field did not exist.";
181         $m_marc_field = $biblio->field($m_field);
182     }
183     else {
184         if ( defined $m_subfield ) {
185             $m_marc_field->update( $m_subfield, $m_db_value );
186         }
187         else {
188             $m_marc_field->update($m_db_value);
189         }
190     }
191
192     # apply to databse
193     if ( &ModBiblio( $biblio, $id, $frameworkcode ) ) {
194         return 1;
195     }
196
197     $debug and warn '[ERROR] ModBiblio failed.';
198     return;
199 }
200
201 sub process {
202
203     $dbh = C4::Context->dbh;
204     my $mod_count = 0;
205
206     my $query = q{
207         SELECT biblionumber
208         FROM biblio
209         JOIN biblioitems USING (biblionumber)
210     };
211     $query .= qq{ WHERE $where} if $where;
212     my $sth = $dbh->prepare($query);
213     $sth->execute();
214
215     $verbose and print "Number of concerned biblios: " . $sth->rows . "\n";
216
217     while ( my $biblios = $sth->fetchrow_hashref ) {
218         $verbose and print 'Bib ' . $biblios->{'biblionumber'} . ':';
219         my $ret = updateMarc( $biblios->{'biblionumber'} );
220         if ($ret) {
221             $verbose and print 'modified';
222             $mod_count++;
223         }
224         $verbose and print "\n";
225     }
226
227     $verbose and print "Number of modified biblios: " . $mod_count . "\n";
228 }
229
230 if ( lc( C4::Context->preference('marcflavour') ) eq "unimarc" ) {
231     $verbose
232       and !$run
233       and print "*** Not in run mode, modifications will not be applyed ***\n";
234
235     $verbose and print "================================\n";
236     process();
237 }
238 else {
239     print
240 "This script is UNIMARC only and should be used only on UNIMARC databases\n";
241 }
242
243 sub print_usage {
244     print <<_USAGE_;
245 Synchronizes date created and date last modified from biblio table to MARC data.
246 Does not update biblio if dates are already synchronized.
247 UNIMARC specific.
248
249 Parameters:
250     --help or -h                show this message
251     --verbose or -v             verbose logging
252     --run                       run the command else modifications will not be applied to database
253     --where                     (optional) use this to limit execution to some biblios :
254                                 write a SQL where clause using biblio and/or biblioitems fields
255     --date-created-marc or c    (optional) date created MARC field and optional subfield,
256                                 099c by default
257     --date-modified-marc or m   (optional) date last modified MARC field and optional subfield,
258                                 099d by default
259 _USAGE_
260 }