diff options
author | mark <mark> | 2011-05-20 20:19:44 +0000 |
---|---|---|
committer | mark <mark> | 2011-05-20 20:19:44 +0000 |
commit | bb119c4cc86e906f698a205437790bd8f96bb3d0 (patch) | |
tree | 5d9f3d66aeb07dba0fa522e28c68ebb5095f71db /FS | |
parent | 7091372fa4580cc041feb25263ac3c1d67c59e3f (diff) |
logging of template-generated mail, #12809
Diffstat (limited to 'FS')
-rw-r--r-- | FS/FS/Conf.pm | 7 | ||||
-rw-r--r-- | FS/FS/Mason.pm | 1 | ||||
-rw-r--r-- | FS/FS/Misc.pm | 36 | ||||
-rw-r--r-- | FS/FS/Schema.pm | 18 | ||||
-rw-r--r-- | FS/FS/cust_msg.pm | 154 | ||||
-rw-r--r-- | FS/FS/msg_template.pm | 30 | ||||
-rw-r--r-- | FS/MANIFEST | 2 | ||||
-rw-r--r-- | FS/t/cust_msg.t | 5 |
8 files changed, 244 insertions, 9 deletions
diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index d5828f0c0..d83ac2f98 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -623,6 +623,13 @@ my %payment_gateway_options = ( }, { + 'key' => 'log_sent_mail', + 'section' => 'notification', + 'description' => 'Enable logging of template-generated email.', + 'type' => 'checkbox', + }, + + { 'key' => 'alert_expiration', 'section' => 'notification', 'description' => 'Enable alerts about billing method expiration (i.e. expiring credit cards).', diff --git a/FS/FS/Mason.pm b/FS/FS/Mason.pm index f97db5421..e8e66e844 100644 --- a/FS/FS/Mason.pm +++ b/FS/FS/Mason.pm @@ -285,6 +285,7 @@ if ( -e $addl_handler_use_file ) { use FS::did_order_item; use FS::msa; use FS::rate_center; + use FS::cust_msg; # Sammath Naur if ( $FS::Mason::addl_handler_use ) { diff --git a/FS/FS/Misc.pm b/FS/FS/Misc.pm index a55f4a912..d5f02de1d 100644 --- a/FS/FS/Misc.pm +++ b/FS/FS/Misc.pm @@ -89,6 +89,11 @@ encoding which, if specified, overrides the default "7bit". (optional) type parameter for multipart/related messages +=item cust_msg + +(optional) L<FS::cust_msg> object. If provided, it will be updated +with the message envelope information, contents, and server response. + =back =cut @@ -171,12 +176,13 @@ sub send_email { } my $message_id = join('.', rand()*(2**32), $$, time). "\@$domain"; + my $time = time; my $message = MIME::Entity->build( 'From' => $options{'from'}, 'To' => join(', ', @to), 'Sender' => $options{'from'}, 'Reply-To' => $options{'from'}, - 'Date' => time2str("%a, %d %b %Y %X %z", time), + 'Date' => time2str("%a, %d %b %Y %X %z", $time), 'Subject' => $options{'subject'}, 'Message-ID' => "<$message_id>", @mimeargs, @@ -238,13 +244,30 @@ sub send_email { eval { sendmail($message, { transport => $transport, from => $options{from}, to => \@to }) }; - + + my $error = ''; if(ref($@) and $@->isa('Email::Sender::Failure')) { - return ($@->code ? $@->code.' ' : '').$@->message + $error = $@->code.' ' if $@->code; + $error .= $@->message; } else { - return $@; + $error = $@; } + + # Logging + my $cust_msg = $options{'cust_msg'}; + if ( $cust_msg ) { + $cust_msg->env_from($options{from}); + $cust_msg->env_to(join(",", @to)); + $cust_msg->header($message->header_as_string); + $cust_msg->body($message->body_as_string); + $cust_msg->_date($time); + $cust_msg->error($error); + $cust_msg->status( $error ? 'failed' : 'sent' ); + $cust_msg->replace; + }; + return $error; + } =item generate_email OPTION => VALUE ... @@ -279,6 +302,10 @@ Will be placed inside an HTML <BODY> tag. Email body (Text alternative). Arrayref of lines, or scalar. +=item cust_msg (optional) + +An L<FS::cust_msg> object. Will be passed through to send_email. + =back Constructs a multipart message from text_body and html_body. @@ -300,6 +327,7 @@ sub generate_email { 'to' => $args{'to'}, 'bcc' => $args{'bcc'}, 'subject' => $args{'subject'}, + 'cust_msg'=> $args{'cust_msg'}, ); #if (ref($args{'to'}) eq 'ARRAY') { diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index eeab4d1a2..819fae9f5 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -3354,6 +3354,24 @@ sub tables_hashref { 'index' => [ ['agentnum'], ] }, + 'cust_msg' => { + 'columns' => [ + 'custmsgnum', 'serial', '', '', '', '', + 'custnum', 'int', '', '', '', '', + 'msgnum', 'int', 'NULL', '', '', '', + '_date', @date_type, '', '', + 'env_from', 'varchar', 'NULL', 255, '', '', + 'env_to', 'varchar', 'NULL', 255, '', '', + 'header', 'blob', 'NULL', '', '', '', + 'body', 'blob', 'NULL', '', '', '', + 'error', 'varchar', 'NULL', 255, '', '', + 'status', 'varchar', '',$char_d, '', '', + ], + 'primary_key' => 'custmsgnum', + 'unique' => [ ], + 'index' => [ ['custnum'], ], + }, + 'svc_cert' => { 'columns' => [ 'svcnum', 'int', '', '', '', '', diff --git a/FS/FS/cust_msg.pm b/FS/FS/cust_msg.pm new file mode 100644 index 000000000..c9cf68663 --- /dev/null +++ b/FS/FS/cust_msg.pm @@ -0,0 +1,154 @@ +package FS::cust_msg; + +use strict; +use base qw( FS::cust_main_Mixin FS::Record ); +use FS::Record qw( qsearch qsearchs ); +use vars qw( @statuses ); + +=head1 NAME + +FS::cust_msg - Object methods for cust_msg records + +=head1 SYNOPSIS + + use FS::cust_msg; + + $record = new FS::cust_msg \%hash; + $record = new FS::cust_msg { 'column' => 'value' }; + + $error = $record->insert; + + $error = $record->check; + +=head1 DESCRIPTION + +An FS::cust_msg object represents a template-generated message sent to +a customer (see L<FS::msg_template>). FS::cust_msg inherits from +FS::Record. The following fields are currently supported: + +=over 4 + +=item custmsgnum - primary key + +=item custnum - customer number + +=item msgnum - template number + +=item _date - the time the message was sent + +=item env_from - envelope From address + +=item env_to - envelope To addresses, including Bcc, separated by newlines + +=item header - message header + +=item body - message body + +=item error - Email::Sender error message (or null for success) + +=back + +=head1 METHODS + +=over 4 + +=item new HASHREF + +Creates a new + +=cut + +# the new method can be inherited from FS::Record, if a table method is defined + +sub table { 'cust_msg'; } + +sub nohistory_fields { ('header', 'body'); } +# history is kind of pointless on this table + +@statuses = qw( prepared sent failed ); + +=item insert + +Adds this record to the database. If there is an error, returns the error +and emits a warning; otherwise returns false. + +=cut + +sub insert { + # warn of all errors here; failing to insert/update one of these should + # cause a warning at worst + my $self = shift; + my $error = $self->SUPER::insert; + warn "[cust_msg] error logging message status: $error\n" if $error; + return $error; +} + +=item delete + +Delete this record from the database. There's no reason to do this. + +=cut + +sub delete { + my $self = shift; + warn "[cust_msg] log entry deleted\n"; + return $self->SUPER::delete; +} + +=item replace OLD_RECORD + +Replaces the OLD_RECORD with this one in the database. If there is an error, +returns the error and emits a warning, otherwise returns false. + +=cut + +sub replace { + my $self = shift; + my $error = $self->SUPER::replace(@_); + warn "[cust_msg] error logging message status: $error\n" if $error; + return $error; +} + +=item check + +Checks all fields to make sure this is a valid example. If there is +an error, returns the error, otherwise returns false. Called by the insert +and replace methods. + +=cut + +# the check method should currently be supplied - FS::Record contains some +# data checking routines + +sub check { + my $self = shift; + + my $error = + $self->ut_numbern('custmsgnum') + || $self->ut_number('custnum') + || $self->ut_foreign_key('custnum', 'cust_main', 'custnum') + || $self->ut_numbern('msgnum') + || $self->ut_foreign_keyn('msgnum', 'msg_template', 'msgnum') + || $self->ut_numbern('_date') + || $self->ut_textn('env_from') + || $self->ut_textn('env_to') + || $self->ut_anything('header') + || $self->ut_anything('body') + || $self->ut_enum('status', \@statuses) + || $self->ut_textn('error') + ; + return $error if $error; + + $self->SUPER::check; +} + +=back + +=head1 SEE ALSO + +L<FS::msg_template>, L<FS::cust_main>, L<FS::Record>. + +=cut + +1; + diff --git a/FS/FS/msg_template.pm b/FS/FS/msg_template.pm index 73284d1e5..4a1e34584 100644 --- a/FS/FS/msg_template.pm +++ b/FS/FS/msg_template.pm @@ -7,11 +7,16 @@ use FS::Misc qw( generate_email send_email ); use FS::Conf; use FS::Record qw( qsearch qsearchs ); +use FS::cust_main; +use FS::cust_msg; + use Date::Format qw( time2str ); use HTML::Entities qw( decode_entities encode_entities ) ; use HTML::FormatText; use HTML::TreeBuilder; -use vars '$DEBUG'; +use vars qw( $DEBUG $conf ); + +FS::UID->install_callback( sub { $conf = new FS::Conf; } ); $DEBUG=0; @@ -188,6 +193,11 @@ The I<from_addr> field in the template takes precedence over this. Destination address. The default is to use the customer's invoicing_list addresses. Multiple addresses may be comma-separated. +=item preview + +Set to true when preparing a message for previewing, rather than to actually +send it. This turns off logging. + =back =cut @@ -298,7 +308,6 @@ sub prepare { } # no warning when preparing with no destination - my $conf = new FS::Conf; my $from_addr = $self->from_addr; if ( !$from_addr ) { @@ -309,8 +318,20 @@ sub prepare { $from_addr ||= scalar( $conf->config('invoice_from', $cust_main->agentnum) ); } + my @cust_msg = (); + if ( $conf->exists('log_sent_mail') and !$opt{'preview'} ) { + my $cust_msg = FS::cust_msg->new({ + 'custnum' => $cust_main->custnum, + 'msgnum' => $self->msgnum, + 'status' => 'prepared', + }); + $cust_msg->insert; + @cust_msg = ('cust_msg' => $cust_msg); + } ( + 'custnum' => $cust_main->custnum, + 'msgnum' => $self->msgnum, 'from' => $from_addr, 'to' => \@to, 'bcc' => $self->bcc_addr || undef, @@ -318,6 +339,7 @@ sub prepare { 'html_body' => $body, 'text_body' => HTML::FormatText->new(leftmargin => 0, rightmargin => 70 )->format( HTML::TreeBuilder->new_from_content($body) ), + @cust_msg, ); } @@ -339,8 +361,7 @@ sub send { # helper sub for package dates my $ymd = sub { $_[0] ? time2str('%Y-%m-%d', $_[0]) : '' }; -# needed for some things -my $conf = new FS::Conf; +#my $conf = new FS::Conf; #return contexts and fill-in values # If you add anything, be sure to add a description in @@ -504,7 +525,6 @@ sub _upgrade_data { [ 'warning_msgnum', 'warning_email', 'warning_email-subject', 'warning_email-from', '' ], ); - my $conf = new FS::Conf; my @agentnums = ('', map {$_->agentnum} qsearch('agent', {})); foreach my $agentnum (@agentnums) { foreach (@fixes) { diff --git a/FS/MANIFEST b/FS/MANIFEST index 3b80da8fc..5e6d992ba 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -594,6 +594,8 @@ FS/msa.pm t/msa.t FS/rate_center.pm t/rate_center.t +FS/cust_msg.pm +t/cust_msg.t FS/Locales.pm t/Locales.t FS/L10N.pm diff --git a/FS/t/cust_msg.t b/FS/t/cust_msg.t new file mode 100644 index 000000000..5d6e439e9 --- /dev/null +++ b/FS/t/cust_msg.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::cust_msg; +$loaded=1; +print "ok 1\n"; |