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