Merge branch 'master' of http://manage-gmc.dev.kohalibrary.com/koha-installer
[koha.git] / misc / cronjobs / update_items.pl
1 #!/usr/bin/perl
2 use strict;
3 use warnings;
4 BEGIN {
5     # find Koha's Perl modules
6     # test carefully before changing this
7     use FindBin;
8     eval { require "$FindBin::Bin/../kohalib.pl" };
9 }
10 use C4::Context;
11 use C4::Biblio;
12 use MARC::Record;
13
14 use Getopt::Long;
15 my $USAGE = "
16 USAGE: update_items.pl -[options]
17
18 OPTIONS:
19  -today                         Items with a modified timestamp today
20  -biblionumber <integer>        One biblionumber to update
21  -itemnumber <integer>          One itemnumber to update
22
23 DEVELOPMENT OPTIONS:
24
25 EXAMPLES:
26 \$ ./update_items.pl -today
27 [ update items modified today ]
28
29 \$ ./update_items.pl -biblionumber 2
30 [ update items for biblionumber 2 ]
31 ";
32 my ($today_only,$biblionumber_to_update,$itemnumber_to_update,$help);
33 GetOptions(
34         'today' => \$today_only,
35         'biblionumber:o' => \$biblionumber_to_update,
36         'itemnumber:o' => \$itemnumber_to_update,
37         'h' => \$help,
38 );
39
40 if ($h) {
41     print $USAGE."\n";
42     exit;
43 }
44
45 # This script can be run from cron or on the command line. It updates
46 # a zebra index with modifications for the period covered or the 
47 # biblionumber or itemnumber specified.
48 #
49 # You will need to customize this for your installation
50 # I hope that the comments will help -- Josha Ferraro <jmf@liblime.com>
51 my $dbh = C4::Context->dbh;
52
53 # Get the date, used both for filename and for period we're updating
54 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
55 $year +=1900;
56 $mon +=1;
57 # nice to zero-pad these dates
58 my $pad_mday= sprintf("%0*d", "2",$mday);
59 my $pad_mon = sprintf("%0*d", "2",$mon);
60
61 # FIXME: we should define a syspref for 'how often to run this script'
62 my $period = "$year-$pad_mon-$pad_mday%"; # today only - you'll want to customize this bit
63 print "period: $period\n";
64 my $date = "$year$mon$mday$hour$min$sec";
65
66 # This is the file that zebra will use to update the index at the end of this script
67 my $filename = "records.$date.iso2709";
68 my $biblioserverdir = C4::Context->zebraconfig('biblioserver')->{directory};
69
70 # check that directory exist, otherwise create.
71 unless (-d "$biblioserverdir/specialUpdate") {
72     system("mkdir -p $biblioserverdir/specialUpdate");
73     print "Info: created $biblioserverdir/specialUpdate\n";
74     $created_dir_or_file++;
75 }
76
77 my $outfile = "$biblioserverdir/specialUpdate/$filename";
78
79 # open a filehandle for writing records -- notice it's UTF-8
80 open OUT,">utf8",$outfile or die "can't open filehandle\n";
81
82 # if there aren't any changes, and all we're doing is updating things from today, don't bother
83 print "counting first\n";
84 my $countitems_sth = $dbh->prepare("SELECT COUNT(*) FROM items WHERE timestamp LIKE ?");
85 $countitems_sth->execute($period);
86 my $number_of_items = $countitems_sth->fetchrow();
87 unless ($number_of_items) {
88         print "no recent items to update\n";
89         exit if $today_only;
90 }
91
92 # get all the relevant biblionumbers, we're gonna update every item in these biblionumbers
93 print "finding biblionumbers\n";
94 my $biblionumber_sth;
95 if ($today_only) {
96         $biblionumber_sth = $dbh->prepare("SELECT DISTINCT biblioitems.biblionumber FROM biblioitems LEFT JOIN items ON (biblioitems.biblionumber=items.biblionumber) WHERE items.timestamp LIKE ? AND biblioitems.marcxml IS NOT NULL");
97         $biblionumber_sth->execute($period) or die "problem with query\n";
98 }
99 elsif ($biblionumber_to_update) {
100         $biblionumber_sth = $dbh->prepare("SELECT biblionumber FROM biblioitems WHERE marcxml IS NOT NULL AND biblionumber=?");
101         $biblionumber_sth->execute($biblionumber_to_update) or die "problem with query\n";
102 }
103 my $count;
104
105 print "fetching marc and items data, updating\n";
106 # for each itemnumber, find the biblionumber, get all the items data for that biblio,
107 # update all the items data in biblioitems.marc, and finally, index it in zebra
108
109 #
110 # 1st : find where some informations are hidden : itemnumber, date_due, popularity
111 #
112 my ($itemnumberTag,$itemnumberSubfield) = GetMarcFromKohaField("items.itemnumber","");
113 my ($date_dueTag,$date_dueSubfield) = GetMarcFromKohaField("items.issues","");
114 my (
115 while (my $biblionumber=$biblionumber_sth->fetchrow) {
116         $count++;
117
118         # get this biblio's MARC record
119     my $record = MARCgetbiblio($biblionumber);
120
121         # delete all existing items data from this record FIXME: 952 shouldn't be hardcoded
122         for my $field_to_del ($record->field("952")) {
123                 my $del_count = $record->delete_field($field_to_del);
124                 print "deleted $del_count fields";
125         }
126         # Find out the itemnumbers this biblio has
127         my $itemnumbers_sth = $dbh->prepare("SELECT itemnumber FROM items WHERE biblionumber=?");
128         $itemnumbers_sth->execute($biblionumber);
129         
130         # for each of the items, get all the item data
131         while (my $data = $itemnumbers_sth->fetchrow_hashref) {
132                 my $itemnumber = $data->{itemnumber};
133                 my $item_data_sth = $dbh->prepare("SELECT * FROM items WHERE itemnumber=?");
134                 $item_data_sth->execute($data->{itemnumber});
135                 my $item_data_hashref = $item_data_sth->fetchrow_hashref();
136                 
137                 # create a new MARC::Field object and put a date_due in it (from issues table)
138                 my $date_due_sth = $dbh->prepare("SELECT date_due FROM issues WHERE itemnumber=? AND returndate IS NULL");
139                 $date_due_sth->execute($itemnumber);
140                 my ($date_due) = $date_due_sth->fetchrow();
141                 $date_due = "0000-00-00" unless ($date_due);
142
143                 # FIXME: this should use Frameworks!!! -- I'll do it soon -- JF
144                 my $items_field = MARC::Field->new( 952, " ", " ", "2" => $date_due, );
145
146                 # put all the data into our MARC::Record field, based on the Koha2MARC mappings
147                 for my $label (keys %$item_data_hashref) {
148                         if ($item_data_hashref->{$label}) {
149                                 my $find_tag_subfield_sth = $dbh->prepare("SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE kohafield=?");
150                                 $find_tag_subfield_sth->execute("items.$label");
151                                 my ($tag,$subfield) = $find_tag_subfield_sth->fetchrow;
152                                 if ($tag) {
153                                         $items_field->add_subfields($subfield => $item_data_hashref->{$label} ) unless (!$item_data_hashref->{$label});
154                                         print "added: $label ($tag $subfield): $item_data_hashref->{$label}";
155                                 }
156                                 else {
157                                         # You probably want to update your mappings if you see anything here ... but
158                                         # in some cases it's safe to ignore these warnings
159                                         print "WARN: no items.$label mapping found: $item_data_hashref->{$label}\n";
160                                 }
161                         }
162                 }
163                 # now update our original record, appending this field
164                 $record->insert_fields_ordered($items_field);
165         }
166         # at this point, we have an up-to-date MARC record
167         # put it back in biblioitems.marc
168         my $put_back_sth = $dbh->prepare("UPDATE biblioitems SET marc=? WHERE biblionumber=?");
169         $put_back_sth->execute($record->as_usmarc(),$biblionumber);
170
171         # schedule it for a zebra index update FIXME: we need better error handling
172         print OUT $record->as_usmarc(); 
173 }
174 # FIXME: add time taken
175 print "finished with $count items in\n";
176 # now we're ready to index this change in Zebra and commit it
177 # FIXME: these dirs shouldn't be hardcoded and sudo probably isn't what you use
178 chdir "/koha/zebradb/biblios/tab";
179 my $error = system("sudo zebraidx -g iso2709 -c /koha/etc/zebra-biblios.cfg -d biblios update $outfile");
180 if ($error) {
181         die "update operation failed";
182 }
183 $error = system("sudo zebraidx -g iso2709 -c /koha/etc/zebra-biblios.cfg commit");
184
185 if ($error) {
186         die "commit operation failed";
187 }
188
189 `sudo mv $outfile $outfile.finished`;