using org email as reply-to
[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 my $U = 'OpenILS::Application::AppUtils';
32
33
34 __PACKAGE__->register_method(
35         method => 'send_email_notify_pub',
36         api_name => 'open-ils.circ.send_hold_notify.email',
37 );
38
39
40 sub send_email_notify_pub {
41         my( $self, $conn, $auth, $hold_id ) = @_;
42         my $e = new_editor(authtoken => $auth, xact =>1);
43         return $e->event unless $e->checkauth;
44         return $e->event unless $e->allowed('CREATE_HOLD_NOTIFICATION');
45         my $notifier = __PACKAGE__->new(editor=> $e, hold_id => $hold_id);
46         return $notifier->event if $notifier->event;
47         my $stat = $notifier->send_email_notify;
48         $e->commit if $stat == '1';
49         return $stat;
50 }
51
52
53
54
55
56 # ---------------------------------------------------------------
57 # Define the notifier object
58 # ---------------------------------------------------------------
59
60 my @AUTOLOAD_FIELDS = qw/
61         hold
62         copy
63         volume
64         title
65         editor
66         patron
67         event
68         pickup_lib
69         smtp_server
70         settings_client
71 /;
72
73 sub AUTOLOAD {
74         my $self = shift;
75         my $type = ref($self) or die "$self is not an object";
76         my $data = shift;
77         my $name = $AUTOLOAD;
78         $name =~ s/.*://o;   
79
80         unless (grep { $_ eq $name } @AUTOLOAD_FIELDS) {
81                 $logger->error("$type: invalid autoload field: $name");
82                 die "$type: invalid autoload field: $name\n" 
83         }
84
85         {
86                 no strict 'refs';
87                 *{"${type}::${name}"} = sub {
88                         my $s = shift;
89                         my $v = shift;
90                         $s->{$name} = $v if defined $v;
91                         return $s->{$name};
92                 }
93         }
94         return $self->$name($data);
95 }
96
97
98 sub new {
99         my( $class, %args ) = @_;
100         $class = ref($class) || $class;
101         my $self = bless( {}, $class );
102         $self->editor( ($args{editor}) ? $args{editor} : new_editor());
103         $self->fetch_data($args{hold_id});
104         return $self;
105 }
106
107
108 sub send_email_notify {
109         my $self = shift;
110
111         $logger->info("hold_notify: attempting email notify on hold ".$self->hold->id);
112
113         return OpenILS::Event->new('PATRON_NO_EMAIL_ADDRESS')
114                 unless $self->patron->email and
115                 $self->patron->email =~ /.+\@.+/; # see if it's remotely email-esque
116
117         my $sclient = OpenSRF::Utils::SettingsClient->new;
118         $self->settings_client($sclient);
119         my $template = $sclient->config_value('email_notify', 'template');
120         my $str = $self->flesh_template($self->load_template($template));
121
122         unless( $str ) {
123                 $logger->error("No email notifiy template found - cannot notify");
124                 return 0;
125         }
126
127         $logger->info("hold_notify: fleshed template: $str");
128
129         $self->send_email($str);
130
131         my $notify = Fieldmapper::action::hold_notification->new;
132         $notify->hold($self->hold->id);
133         $notify->notify_staff($self->editor->requestor->id);
134         $notify->notify_time('now');
135         $notify->method('email');
136         
137         $self->editor->create_action_hold_notification($notify)
138                 or return $self->editor->event;
139
140         return 1;
141 }
142
143 sub send_email {
144         my( $self, $text ) = @_;
145
146         my $smtp = $self->settings_client->config_value('email_notify', 'smtp_server');
147
148         $logger->info("hold_notify: sending email notice to ".
149                 $self->patron->email." with SMTP server $smtp");
150
151         my $sender = Email::Send->new({mailer => 'SMTP'});
152         $sender->mailer_args([Host => $smtp]);
153         my $stat = $sender->send($text);
154
155         if( $stat->type eq 'success' ) {
156                 $logger->info("hold_notify: successfully sent hold notification");
157                 return 1;
158         } else {
159                 $logger->warn("hold_notify: unable to send hold notification: ".Dumper($stat));
160                 return 0;
161         }
162
163         return undef;
164 }
165
166
167 # -------------------------------------------------------------------------
168 # Fetches all of the hold-related data
169 # -------------------------------------------------------------------------
170 sub fetch_data {
171         my $self                = shift;
172         my $holdid      = shift;
173         my $e                   = $self->editor;
174
175         $self->hold($e->retrieve_action_hold_request($holdid)) or return $self->event($e->event);
176         $self->copy($e->retrieve_asset_copy($self->hold->current_copy)) or return $self->event($e->event);
177         $self->volume($e->retrieve_asset_call_number($self->copy->call_number)) or return $self->event($e->event);
178         $self->title($e->retrieve_biblio_record_entry($self->volume->record)) or return $self->event($e->event);
179         $self->patron($e->retrieve_actor_user($self->hold->usr)) or return $self->event($e->event);
180         $self->pickup_lib($e->retrieve_actor_org_unit($self->hold->pickup_lib)) or return $self->event($e->event);
181 }
182
183
184 sub extract_data {
185         my $self = shift;
186         my $e = $self->editor;
187
188         my $patron = $self->patron;
189         my $o_name = $self->pickup_lib->name;
190         my $p_name = $patron->first_given_name .' '.$patron->family_name;
191
192         # try to find a suitable address for the patron
193         my $p_addr;
194         my $p_addrs;
195         unless( $p_addr = 
196                         $e->retrieve_actor_user_address($patron->billing_address)) {
197                 unless( $p_addr = 
198                                 $e->retrieve_actor_user_address($patron->mailing_address)) {
199                         $logger->warn("No address for user ".$patron->id);
200                         $p_addrs = "";
201                 }
202         }
203
204         unless( defined $p_addrs ) {
205                 $p_addrs = 
206                         $p_addr->street1." ".
207                         $p_addr->street2." ".
208                         $p_addr->city." ".
209                         $p_addr->state." ".
210                         $p_addr->post_code;
211         }
212
213         my $l_addr = $e->retrieve_actor_org_address($self->pickup_lib->holds_address);
214         my $l_addrs = (!$l_addr) ? "" : 
215                         $l_addr->street1." ".
216                         $l_addr->street2." ".
217                         $l_addr->city." ".
218                         $l_addr->state." ".
219                         $l_addr->post_code;
220
221         my $title;      
222         my $author;
223
224         if( $self->title->id == OILS_PRECAT_RECORD ) {
225                 $title = ($self->copy->dummy_title) ? 
226                         $self->copy->dummy_title : "";
227                 $author = ($self->copy->dummy_author) ? 
228                         $self->copy->dummy_author : "";
229         } else {
230                 my $mods        = $U->record_to_mvr($self->title);
231                 $title  = ($mods->title) ? $mods->title : "";
232                 $author = ($mods->author) ? $mods->author : "";
233         }
234
235
236         return { 
237                 patron_email => $self->patron->email,
238                 pickup_lib_name => $o_name,
239                 pickup_lib_addr => $l_addrs,
240                 patron_name => $p_name, 
241                 patron_addr => $p_addrs, 
242                 title => $title, 
243                 author => $author, 
244                 call_number => $self->volume->label,
245                 copy_barcode => $self->copy->barcode,
246                 copy_number => $self->copy->copy_number,
247         };
248 }
249
250
251
252 sub load_template {
253         my $self = shift;
254         my $template = shift;
255
256         unless( open(F, $template) ) {
257                 $logger->error("Unable to open hold notification template file: $template");
258                 return undef;
259         }
260
261         # load the template, strip comments
262         my @lines = <F>;
263         close(F);
264
265         my $str = '';
266         for(@lines) {
267         chomp $_;
268         next if $_ =~ /^\s*\#/o;
269         $_ =~ s/\#.*//og;
270         $str .= "$_\n";
271         }
272
273         return $str;
274 }
275
276 sub flesh_template {
277         my( $self, $str ) = @_;
278         return undef unless $str;
279
280         my @time        = CORE::localtime();
281         my $day                 = $time[3];
282         my $month       = $time[4] + 1;
283         my $year        = $time[5] + 1900;
284
285         my $data = $self->extract_data;
286
287         my $email               = $$data{patron_email};
288         my $p_name              = $$data{patron_name};
289         my $p_addr              = $$data{patron_addr};
290         my $o_name              = $$data{pickup_lib_name};
291         my $o_addr              = $$data{pickup_lib_addr};
292         my $title               = $$data{title};
293         my $author              = $$data{author};
294         my $cn                  = $$data{call_number};
295         my $barcode             = $$data{copy_barcode};
296         my $copy_number = $$data{copy_number};
297
298         my $sender = $self->settings_client->config_value('email_notify', 'sender_address');
299         my $reply_to = $self->pickup_lib->email;
300         $reply_to ||= $sender; 
301
302
303    $str =~ s/\${EMAIL_SENDER}/$sender/;
304    $str =~ s/\${EMAIL_RECIPIENT}/$email/;
305    $str =~ s/\${EMAIL_REPLY_TO}/$reply_to/;
306    $str =~ s/\${EMAIL_HEADERS}//;
307
308    $str =~ s/\${DATE}/$year-$month-$day/;
309    $str =~ s/\${LIBRARY}/$o_name/;
310    $str =~ s/\${LIBRARY_ADDRESS}/$o_addr/;
311    $str =~ s/\${PATRON_NAME}/$p_name/;
312    $str =~ s/\${PATRON_ADDRESS}/$p_addr/;
313
314    $str =~ s/\${TITLE}/$title/;
315    $str =~ s/\${AUTHOR}/$author/;
316    $str =~ s/\${CALL_NUMBER}/$cn/;
317    $str =~ s/\${COPY_BARCODE}/$barcode/;
318    $str =~ s/\${COPY_NUMBER}/$copy_number/;
319
320         return $str;
321 }
322
323
324
325
326
327 1;