]> git.evergreen-ils.org Git - Evergreen.git/blob - Evergreen/src/support-scripts/eg_gen_overdue.pl
fixed escape ordering bug
[Evergreen.git] / Evergreen / src / support-scripts / eg_gen_overdue.pl
1 #!/usr/bin/perl
2 # ---------------------------------------------------------------
3 # Generates the overdue notices XML file
4 # ./eg_gen_overdue.pl <bootstap> 0
5 #               generates today's notices
6 # ./eg_gen_overdue.pl <bootstap> 1 0
7 #               generates notices for today - 1 and today
8 # ./eg_gen_overdue.pl <bootstap> 2 1 0  
9 # ./eg_gen_overdue.pl <bootstap> 3 2 1 0  etc...
10 # ---------------------------------------------------------------
11
12
13
14 use strict; use warnings;
15 require '../../../Open-ILS/src/support-scripts/oils_header.pl';
16 use vars qw/$logger $apputils/;
17 use Data::Dumper;
18 use OpenILS::Const qw/:const/;
19 use DateTime;
20 use DateTime::Format::ISO8601;
21 use OpenSRF::Utils qw/:datetime/;
22 use Unicode::Normalize;
23
24 my $bsconfig = shift || die "usage: $0 <bootstrap_config>\n";
25 my @goback = @ARGV;
26 @goback = (0) unless @goback;
27 osrf_connect($bsconfig);
28 my $e = OpenILS::Utils::CStoreEditor->new;
29
30 my @date = CORE::localtime;
31 my $sec  = $date[0];
32 my $min  = $date[1];
33 my $hour = $date[2];
34 my $day  = $date[3];
35 my $mon  = $date[4] + 1;
36 my $year = $date[5] + 1900;
37
38 my %USER_CACHE;
39 my %ORG_CACHE;
40
41
42 print <<XML;
43 <?xml version='1.0' encoding='UTF-8'?>
44 <file type="notice" date="$day/$mon/$year" time="$hour:$min:$sec">
45         <agency name="PINES">
46 XML
47
48 print_notices($_) for @goback;
49
50 print <<XML;
51         </agency>
52 </file>
53 XML
54
55
56 # -----------------------------------------------------------------------
57 # -----------------------------------------------------------------------
58
59
60 sub print_notices {
61         my $goback = shift || 0;
62
63         for my $day ( qw/ 7 14 30 / ) {
64                 my ($start, $end) = make_date_range($day + $goback);
65                 $logger->debug("OD_notice: process date range $start -> $end");
66
67                 my $circs = $e->search_action_circulation(
68                         [
69                                 {
70                                         stop_fines => undef,
71                                         due_date => { between => [ $start, $end ] }
72                                 },
73                                 {
74                                         order_by => { circ => 'usr, circ_lib' }
75                                 }
76                         ],
77                         { idlist => 1 }
78                 );
79
80                 process_circs( $circs, "${day}day" );
81         }
82 }
83
84
85 sub process_circs {
86         my $circs = shift;
87         my $range = shift;
88
89         return unless @$circs;
90
91         $logger->debug("OD_notice: processing range $range and circs @$circs");
92
93         my $org; 
94         my $patron;
95         my @current;
96
97         for my $circ (@$circs) {
98                 $circ = $e->retrieve_action_circulation($circ);
99
100                 if( !defined $org or 
101                                 $circ->circ_lib != $org  or $circ->usr ne $patron ) {
102                         $org = $circ->circ_lib;
103                         $patron = $circ->usr;
104                         print_notice( $range, \@current ) if @current;
105                         @current = ();
106                 }
107
108                 push( @current, $circ );
109         }
110
111         print_notice( $range, \@current );
112 }
113
114 sub make_date_range {
115         my $daysback = shift;
116
117         my $date = DateTime->from_epoch( 
118                 epoch => ( CORE::time - ($daysback * 24 * 60 * 60) ) );
119
120         $date->set_hour(0);
121         $date->set_minute(0);
122         $date->set_second(0);
123         my $start = "$date";
124
125         $date->set_hour(23);
126         $date->set_minute(59);
127         $date->set_second(59);
128
129         return ($start, "$date");
130 }
131
132
133 sub print_notice {
134         my( $range, $circs ) = @_;
135         return unless @$circs;
136         my $org = $circs->[0]->circ_lib;
137         my $usr = $circs->[0]->usr;
138         $logger->debug("OD_notice: printing $range user:$usr org:$org");
139         print "\t\t<notice type='overdue' count='$range'>\n";
140         print_patron_chunk($usr);
141         print_org_chunk($org);
142         print_circ_chunk($_) for @$circs;
143         print "\t\t</notice>\n";
144 }
145
146
147
148 sub print_patron_chunk {
149         my $user_id = shift;
150
151         my $patron = $USER_CACHE{$user_id};
152
153         if( ! $patron ) {
154                 $logger->debug("OD_notice:   fetching patron $user_id");
155
156                 $patron = $e->retrieve_actor_user(
157                         [
158                                 $user_id,
159                                 {
160                                         flesh => 1,
161                                         flesh_fields => { 
162                                                 'au' => [qw/ card billing_address mailing_address /] 
163                                         }
164                                 }
165                         ]
166                 ) or return handle_event($e->event);
167
168                 $USER_CACHE{$user_id} = $patron;
169         }
170
171         my $bc = $patron->card->barcode;
172         my $fn = $patron->first_given_name;
173         my $mn = $patron->second_given_name;
174         my $ln = $patron->family_name;
175
176         my ( $s1, $s2, $city, $state, $zip );
177         my $baddr = $patron->billing_address || $patron->mailing_address;
178         if( $baddr ) {
179                 $s1             = $baddr->street1;
180                 $s2             = $baddr->street2;
181                 $city           = $baddr->city;
182                 $state  = $baddr->state;
183                 $zip            = $baddr->post_code;
184         }
185
186         $bc = entityize($bc);
187         $fn = entityize($fn);
188         $mn = entityize($mn);
189         $ln = entityize($ln);
190         $s1 = entityize($s1);
191         $s2 = entityize($s2);
192         $city  = entityize($city);
193         $state = entityize($state);
194         $zip     = entityize($zip);
195
196         
197         print <<"       XML";
198                         <patron>
199                                 <id type="barcode">$bc</id>
200                                 <fullname>$fn $mn $ln</fullname>
201                                 <street1>$s1 $s2</street1>
202                                 <city_state_zip>$city, $state $zip</city_state_zip>
203                         </patron>
204         XML
205
206 }
207
208 sub print_org_chunk {
209         my $org_id = shift;
210
211         my $org = $ORG_CACHE{$org_id};
212
213         if( ! $org ) {
214                 $logger->debug("OD_notice:   fetching org $org_id");
215
216                 $org = $e->retrieve_actor_org_unit(
217                         [
218                                 $org_id,
219                                 {
220                                         flesh => 1, 
221                                         flesh_fields => 
222                                                 { aou => [ qw/billing_address mailing_address/ ] }
223                                 }
224                         ]
225                 ) or return handle_event($e->event);
226
227                 $ORG_CACHE{$org_id} = $org;
228         }
229
230         my $name = $org->name;
231
232         my( $phone, $s1, $s2, $city, $state, $zip );
233         my $baddr = $org->billing_address || $org->mailing_address;
234         if( $baddr ) {
235                 $s1             = $baddr->street1;
236                 $s2             = $baddr->street2;
237                 $city           = $baddr->city;
238                 $state  = $baddr->state;
239                 $zip            = $baddr->post_code;
240         }
241
242         $name  = entityize($name);
243         $phone = entityize($phone);
244         $s1      = entityize($s1);
245         $s2      = entityize($s2);
246         $city  = entityize($city);
247         $state = entityize($state);
248         $zip     = entityize($zip);
249
250
251         print <<"       XML";
252                         <library>
253                                 <libname>$name</libname>
254                                 <libphone>$phone</libphone>
255                                 <libstreet1>$s1 $s2</libstreet1>
256                                 <libcity_state_zip>$city, $state $zip</libcity_state_zip>
257                         </library>
258         XML
259 }
260
261 sub print_circ_chunk {
262         my $circ = shift;
263
264         my $title;
265         my $author;
266         my $cn;
267
268         my $d = $circ->due_date;
269         $d =~ s/[T ].*//og; # just for logging
270         $logger->debug("OD_notice:   processing circ ".$circ->id." $d");
271
272         my $due = DateTime::Format::ISO8601->new->parse_datetime(
273                 clense_ISO8601($circ->due_date));
274
275         my $day  = $due->day;
276         my $mon  = $due->month;
277         my $year = $due->year;
278
279         my $copy = $e->retrieve_asset_copy($circ->target_copy)
280                 or return handle_event($e->event);
281
282         my $bc = $copy->barcode;
283
284         if( $copy->call_number == OILS_PRECAT_CALL_NUMBER ) {
285                 $title = $copy->dummy_title || "";
286                 $author = $copy->dummy_author || "";
287
288         } else {
289
290                 my $volume = $e->retrieve_asset_call_number(
291                         [
292                                 $copy->call_number,
293                                 {
294                                         flesh => 1,
295                                         flesh_fields => {
296                                                 acn => [ qw/record/ ]
297                                         }
298                                 }
299                         ]
300                 ) or return handle_event($e->event);
301
302                 $cn = $volume->label;
303                 my $mods = $apputils->record_to_mvr($volume->record);
304                 if( $mods ) {
305                         $title = $mods->title || "";
306                         $author = $mods->author || "";
307                 }
308         }
309
310         $title = entityize($title);
311         $author = entityize($author);
312         $cn = entityize($cn);
313         $bc = entityize($bc);
314
315         print <<"       XML";
316                         <item>
317                                 <title>$title</title>
318                                 <author>$author</author>
319                                 <duedate>$day/$mon/$year</duedate>
320                                 <callno>$cn</callno>
321                                 <barcode>$bc</barcode>
322                         </item>
323         XML
324 }
325
326
327
328 sub handle_event {
329         my $evt = shift;
330         warn "OD_notice: ".Dumper($evt) . "\n";
331         $logger->error("OD_notice: ".Dumper($evt));
332 }
333
334
335 sub entityize {
336         my $stuff = shift || return "";
337         $stuff =~ s/\</&lt;/og;
338         $stuff =~ s/\>/&gt;/og;
339         $stuff =~ s/\&/&amp;/og;
340         $stuff = NFC($stuff);
341         $stuff =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe;
342         return $stuff;
343 }
344
345
346
347