]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/perlmods/OpenILS/Application/Circ/HoldNotify.pm
3f35826fbbd1d0c13b25c938ed3a0841ef626926
[Evergreen.git] / Open-ILS / src / perlmods / OpenILS / Application / Circ / HoldNotify.pm
1 # ---------------------------------------------------------------
2 # Copyright (C) 2005  Georgia Public Library Service 
3 # Bill Erickson <billserickson@gmail.com>
4
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 # ---------------------------------------------------------------
15
16
17 package OpenILS::Application::Circ::HoldNotify;
18 use base qw/OpenSRF::Application/;
19 use strict; use warnings;
20 use OpenSRF::EX qw(:try);
21 use vars q/$AUTOLOAD/;
22 use OpenILS::Event;
23 use OpenSRF::Utils::Logger qw(:logger);
24 use OpenILS::Utils::CStoreEditor q/:funcs/;
25 use OpenSRF::Utils::SettingsClient;
26 use OpenILS::Application::AppUtils;
27 use OpenILS::Const qw/:const/;
28 use OpenILS::Utils::Fieldmapper;
29 use Email::Send;
30 use Data::Dumper;
31 use OpenSRF::EX qw/:try/;
32 my $U = 'OpenILS::Application::AppUtils';
33
34 use open ':utf8';
35
36
37 __PACKAGE__->register_method(
38         method => 'send_email_notify_pub',
39         api_name => 'open-ils.circ.send_hold_notify.email',
40 );
41
42
43 sub send_email_notify_pub {
44         my( $self, $conn, $auth, $hold_id ) = @_;
45         my $e = new_editor(authtoken => $auth);
46         return $e->event unless $e->checkauth;
47         return $e->event unless $e->allowed('CREATE_HOLD_NOTIFICATION');
48         my $notifier = __PACKAGE__->new(requestor => $e->requestor, hold_id => $hold_id);
49         return $notifier->event if $notifier->event;
50         my $stat = $notifier->send_email_notify;
51 #       $e->commit if $stat == '1';
52         return $stat;
53 }
54
55
56
57
58
59 # ---------------------------------------------------------------
60 # Define the notifier object
61 # ---------------------------------------------------------------
62
63 my @AUTOLOAD_FIELDS = qw/
64         hold
65         copy
66         volume
67         title
68         editor
69         patron
70         event
71         pickup_lib
72         smtp_server
73         settings_client
74 /;
75
76 sub AUTOLOAD {
77         my $self = shift;
78         my $type = ref($self) or die "$self is not an object";
79         my $data = shift;
80         my $name = $AUTOLOAD;
81         $name =~ s/.*://o;   
82
83         unless (grep { $_ eq $name } @AUTOLOAD_FIELDS) {
84                 $logger->error("hold_notify: $type: invalid autoload field: $name");
85                 die "$type: invalid autoload field: $name\n" 
86         }
87
88         {
89                 no strict 'refs';
90                 *{"${type}::${name}"} = sub {
91                         my $s = shift;
92                         my $v = shift;
93                         $s->{$name} = $v if defined $v;
94                         return $s->{$name};
95                 }
96         }
97         return $self->$name($data);
98 }
99
100
101 sub new {
102         my( $class, %args ) = @_;
103         $class = ref($class) || $class;
104         my $self = bless( {}, $class );
105         $self->editor( new_editor( xact => 1, requestor => $args{requestor} ));
106         $logger->debug("circulator: creating new hold-notifier with requestor ".
107                 $self->editor->requestor->id);
108         $self->fetch_data($args{hold_id});
109         return $self;
110 }
111
112 sub send_email_notify {
113         my $self = shift;
114
115         my $sc = OpenSRF::Utils::SettingsClient->new;
116         my $setting = $sc->config_value(
117                 qw/ apps open-ils.circ app_settings notify_hold email / );
118
119         $logger->debug("hold_notify: email enabled setting = $setting");
120
121         if( !$setting or $setting ne 'true' ) {
122       $self->editor->rollback;
123                 $logger->info("hold_notify: not sending hold notify - email notifications disabled");
124                 return 0;
125         }
126
127         unless ($U->is_true($self->hold->email_notify)) {
128       $self->editor->rollback;
129                 $logger->info("hold_notify: not sending hold notification becaue email_notify is false");
130                 return 0;
131         }
132
133         unless( $self->patron->email and $self->patron->email =~ /.+\@.+/ ) { # see if it's remotely email-esque
134       $self->editor->rollback;
135            return OpenILS::Event->new('PATRON_NO_EMAIL_ADDRESS');
136    }
137
138         $logger->info("hold_notify: attempting email notify on hold ".$self->hold->id);
139
140         my $sclient = OpenSRF::Utils::SettingsClient->new;
141         $self->settings_client($sclient);
142         my $template = $sclient->config_value('email_notify', 'template');
143         my $str = $self->flesh_template($self->load_template($template));
144
145         unless( $str ) {
146       $self->editor->rollback;
147                 $logger->error("hold_notify: No email notifiy template found - cannot notify");
148                 return 0;
149         }
150
151    my $reqr = $self->editor->requestor;
152    $self->editor->rollback; # we're done with this transaction
153
154         return 0 unless $self->send_email($str);
155
156         # ------------------------------------------------------------------
157         # If the hold email takes too long to send, the existing editor 
158         # transaction may have timed out.  Create a one-off editor to write 
159         # the notification to the DB.
160         # ------------------------------------------------------------------
161         my $we = new_editor(xact=>1, requestor=>$reqr);
162
163         my $notify = Fieldmapper::action::hold_notification->new;
164         $notify->hold($self->hold->id);
165         $notify->notify_staff($we->requestor->id);
166         $notify->notify_time('now');
167         $notify->method('email');
168         
169         $we->create_action_hold_notification($notify)
170                 or return $we->die_event;
171         $we->commit;
172
173         return 1;
174 }
175
176 sub send_email {
177         my( $self, $text ) = @_;
178
179    # !!! $self->editor xact has been rolled back before we get here
180
181         my $smtp = $self->settings_client->config_value('email_notify', 'smtp_server');
182
183         $logger->info("hold_notify: sending email notice to ".
184                 $self->patron->email." with SMTP server $smtp");
185
186         my $sender = Email::Send->new({mailer => 'SMTP'});
187         $sender->mailer_args([Host => $smtp]);
188
189         my $stat;
190         my $err;
191
192         try {
193                 $stat = $sender->send($text);
194         } catch Error with {
195                 $err = $stat = shift;
196                 $logger->error("hold_notify: Email notify failed with error: $err");
197         };
198
199         if( !$err and $stat and $stat->type eq 'success' ) {
200                 $logger->info("hold_notify: successfully sent hold notification");
201                 return 1;
202         } else {
203                 $logger->warn("hold_notify: unable to send hold notification: ".Dumper($stat));
204                 return 0;
205         }
206
207         return undef;
208 }
209
210
211 # -------------------------------------------------------------------------
212 # Fetches all of the hold-related data
213 # -------------------------------------------------------------------------
214 sub fetch_data {
215         my $self                = shift;
216         my $holdid      = shift;
217         my $e                   = $self->editor;
218
219         $logger->debug("circulator: fetching hold notify data");
220
221         $self->hold($e->retrieve_action_hold_request($holdid)) or return $self->event($e->event);
222         $self->copy($e->retrieve_asset_copy($self->hold->current_copy)) or return $self->event($e->event);
223         $self->volume($e->retrieve_asset_call_number($self->copy->call_number)) or return $self->event($e->event);
224         $self->title($e->retrieve_biblio_record_entry($self->volume->record)) or return $self->event($e->event);
225         $self->patron($e->retrieve_actor_user($self->hold->usr)) or return $self->event($e->event);
226         $self->pickup_lib($e->retrieve_actor_org_unit($self->hold->pickup_lib)) or return $self->event($e->event);
227 }
228
229
230 sub extract_data {
231         my $self = shift;
232         my $e = $self->editor;
233
234         my $patron = $self->patron;
235         my $o_name = $self->pickup_lib->name;
236         my $p_name = $patron->first_given_name .' '.$patron->family_name;
237
238         # try to find a suitable address for the patron
239         my $p_addr;
240         my $p_addrs;
241         unless( $p_addr = 
242                         $e->retrieve_actor_user_address($patron->billing_address)) {
243                 unless( $p_addr = 
244                                 $e->retrieve_actor_user_address($patron->mailing_address)) {
245                         $logger->warn("hold_notify: No address for user ".$patron->id);
246                         $p_addrs = "";
247                 }
248         }
249
250         unless( defined $p_addrs ) {
251                 $p_addrs = 
252                         $p_addr->street1." ".
253                         $p_addr->street2." ".
254                         $p_addr->city." ".
255                         $p_addr->state." ".
256                         $p_addr->post_code;
257         }
258
259         my $l_addr = $e->retrieve_actor_org_address($self->pickup_lib->holds_address);
260         my $l_addrs = (!$l_addr) ? "" : 
261                         $l_addr->street1." ".
262                         $l_addr->street2." ".
263                         $l_addr->city." ".
264                         $l_addr->state." ".
265                         $l_addr->post_code;
266
267         my $title;      
268         my $author;
269
270         if( $self->title->id == OILS_PRECAT_RECORD ) {
271                 $title = ($self->copy->dummy_title) ? 
272                         $self->copy->dummy_title : "";
273                 $author = ($self->copy->dummy_author) ? 
274                         $self->copy->dummy_author : "";
275         } else {
276                 my $mods        = $U->record_to_mvr($self->title);
277                 $title  = ($mods->title) ? $mods->title : "";
278                 $author = ($mods->author) ? $mods->author : "";
279         }
280
281
282         return { 
283                 patron_email => $self->patron->email,
284                 pickup_lib_name => $o_name,
285                 pickup_lib_addr => $l_addrs,
286                 patron_name => $p_name, 
287                 patron_addr => $p_addrs, 
288                 title => $title, 
289                 author => $author, 
290                 call_number => $self->volume->label,
291                 copy_barcode => $self->copy->barcode,
292                 copy_number => $self->copy->copy_number,
293         };
294 }
295
296
297
298 sub load_template {
299         my $self = shift;
300         my $template = shift;
301
302         unless( open(F, $template) ) {
303                 $logger->error("hold_notify: Unable to open hold notification template file: $template");
304                 return undef;
305         }
306
307         # load the template, strip comments
308         my @lines = <F>;
309         close(F);
310
311         my $str = '';
312         for(@lines) {
313         chomp $_;
314         next if $_ =~ /^\s*\#/o;
315         $_ =~ s/\#.*//og;
316         $str .= "$_\n";
317         }
318
319         return $str;
320 }
321
322 sub flesh_template {
323         my( $self, $str ) = @_;
324         return undef unless $str;
325
326         my @time        = CORE::localtime();
327         my $day                 = $time[3];
328         my $month       = $time[4] + 1;
329         my $year        = $time[5] + 1900;
330
331         my $data = $self->extract_data;
332
333         my $email               = $$data{patron_email};
334         my $p_name              = $$data{patron_name};
335         my $p_addr              = $$data{patron_addr};
336         my $o_name              = $$data{pickup_lib_name};
337         my $o_addr              = $$data{pickup_lib_addr};
338         my $title               = $$data{title};
339         my $author              = $$data{author};
340         my $cn                  = $$data{call_number};
341         my $barcode             = $$data{copy_barcode};
342         my $copy_number = $$data{copy_number};
343
344         my $sender = $self->settings_client->config_value('email_notify', 'sender_address');
345         my $reply_to = $self->pickup_lib->email;
346         $reply_to ||= $sender; 
347
348    # if they have an org setting for bounced emails, use that as the sender address
349    if( my $set = $self->editor->search_actor_org_unit_setting(
350          {  name => OILS_SETTING_ORG_BOUNCED_EMAIL, 
351             org_unit => $self->pickup_lib->id } )->[0] ) {
352
353       my $bemail = JSON->JSON2perl($set->value);
354       $sender = $bemail if $bemail;
355    }
356
357    $str =~ s/\${EMAIL_SENDER}/$sender/;
358    $str =~ s/\${EMAIL_RECIPIENT}/$email/;
359    $str =~ s/\${EMAIL_REPLY_TO}/$reply_to/;
360    $str =~ s/\${EMAIL_HEADERS}//;
361
362    $str =~ s/\${DATE}/$year-$month-$day/;
363    $str =~ s/\${LIBRARY}/$o_name/;
364    $str =~ s/\${LIBRARY_ADDRESS}/$o_addr/;
365    $str =~ s/\${PATRON_NAME}/$p_name/;
366    $str =~ s/\${PATRON_ADDRESS}/$p_addr/;
367
368    $str =~ s/\${TITLE}/$title/;
369    $str =~ s/\${AUTHOR}/$author/;
370    $str =~ s/\${CALL_NUMBER}/$cn/;
371    $str =~ s/\${COPY_BARCODE}/$barcode/;
372    $str =~ s/\${COPY_NUMBER}/$copy_number/;
373
374         return $str;
375 }
376
377
378
379
380
381 1;