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