X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fmsg_template.pm;h=50a9b3f27665a653829b47dc7b5a0266cdc47645;hb=755159a8654a2eda89badd1498f8def3a472cb15;hp=2f5e4762aa6235fd806fe92d6c3c58fac051bc5f;hpb=ea877a775f49883683a26c01da366993804e840d;p=freeside.git diff --git a/FS/FS/msg_template.pm b/FS/FS/msg_template.pm index 2f5e4762a..50a9b3f27 100644 --- a/FS/FS/msg_template.pm +++ b/FS/FS/msg_template.pm @@ -16,6 +16,7 @@ use Date::Format qw( time2str ); use HTML::Entities qw( decode_entities encode_entities ) ; use HTML::FormatText; use HTML::TreeBuilder; +use Encode; use File::Temp; use IPC::Run qw(run); @@ -382,12 +383,26 @@ sub prepare { my @to; if ( exists($opt{'to'}) ) { + @to = split(/\s*,\s*/, $opt{'to'}); + + } elsif ( $cust_main ) { + + my @classes; + if ( $opt{'to_contact_classnum'} ) { + my $classnum = $opt{'to_contact_classnum'}; + @classes = ref($classnum) ? @$classnum : split(',', $classnum); + } + if (!@classes) { + @classes = ( 'invoice' ); + } + @to = $cust_main->contact_list_email(@classes); + + } else { + + die 'no To: address or cust_main object specified'; + } - else { - @to = $cust_main->invoicing_list_emailonly; - } - # no warning when preparing with no destination my $from_addr = $self->from_addr; @@ -396,8 +411,7 @@ sub prepare { $from_addr = scalar( $conf->config($opt{'from_config'}, $cust_main->agentnum) ); } - $from_addr ||= scalar( $conf->config('invoice_from', - $cust_main->agentnum) ); + $from_addr ||= $conf->invoice_from_full($cust_main->agentnum); } # my @cust_msg = (); # if ( $conf->exists('log_sent_mail') and !$opt{'preview'} ) { @@ -410,6 +424,10 @@ sub prepare { # @cust_msg = ('cust_msg' => $cust_msg); # } + my $text_body = encode('UTF-8', + HTML::FormatText->new(leftmargin => 0, rightmargin => 70) + ->format( HTML::TreeBuilder->new_from_content($body) ) + ); ( 'custnum' => $cust_main->custnum, 'msgnum' => $self->msgnum, @@ -418,8 +436,7 @@ sub prepare { 'bcc' => $self->bcc_addr || undef, 'subject' => $subject, 'html_body' => $body, - 'text_body' => HTML::FormatText->new(leftmargin => 0, rightmargin => 70 - )->format( HTML::TreeBuilder->new_from_content($body) ), + 'text_body' => $text_body, ); } @@ -427,7 +444,8 @@ sub prepare { =item send OPTION => VALUE Fills in the template and sends it to the customer. Options are as for -'prepare'. +'prepare', plus 'attach', a L (or arrayref of them) to attach +to the message. =cut @@ -435,7 +453,20 @@ Fills in the template and sends it to the customer. Options are as for # preview it, etc. sub send { my $self = shift; - send_email(generate_email($self->prepare(@_))); + my %opt = @_; + + my %email = generate_email($self->prepare(%opt)); + if ( $opt{'attach'} ) { + my @attach; + if (ref($opt{'attach'}) eq 'ARRAY') { + @attach = @{ $opt{'attach'} }; + } else { + @attach = $opt{'attach'}; + } + push @{ $email{mimeparts} }, @attach; + } + + send_email(%email); } =item render OPTION => VALUE ... @@ -459,9 +490,11 @@ sub render { # Graphics/stylesheets should probably go in /var/www on the Freeside # machine. + my $script_path = `/usr/bin/which freeside-wkhtmltopdf`; + chomp $script_path; my $kit = PDF::WebKit->new(\$html); #%options # hack to use our wrapper script - $kit->configure(sub { shift->wkhtmltopdf('freeside-wkhtmltopdf') }); + $kit->configure(sub { shift->wkhtmltopdf($script_path) }); $kit->to_pdf; } @@ -503,6 +536,17 @@ my $usage_warning = sub { # If you add anything, be sure to add a description in # httemplate/edit/msg_template.html. sub substitutions { + my $payinfo_sub = sub { + my $obj = shift; + ($obj->payby eq 'CARD' || $obj->payby eq 'CHEK') + ? $obj->paymask + : $obj->decrypt($obj->payinfo) + }; + my $payinfo_end = sub { + my $obj = shift; + my $payinfo = &$payinfo_sub($obj); + substr($payinfo, -4); + }; { 'cust_main' => [qw( display_custnum agentnum agent_name @@ -554,6 +598,9 @@ sub substitutions { [ company_phonenum => sub { $conf->config('company_phonenum', shift->agentnum) } ], + [ selfservice_server_base_url => sub { + $conf->config('selfservice_server-base_url') #, shift->agentnum) + } ], ], # next_bill_date 'cust_pkg' => [qw( @@ -588,7 +635,11 @@ sub substitutions { 'cust_bill' => [qw( invnum _date - )], + _date_pretty + due_date + ), + [ due_date2str => sub { shift->due_date2str('short') } ], + ], #XXX not really thinking about cust_bill substitutions quite yet # for welcome and limit warning messages @@ -642,11 +693,17 @@ sub substitutions { # overrides the one in cust_main in cases where a cust_pay is passed [ payby => sub { FS::payby->shortname(shift->payby) } ], [ date => sub { time2str("%a %B %o, %Y", shift->_date) } ], - [ payinfo => sub { - my $cust_pay = shift; - ($cust_pay->payby eq 'CARD' || $cust_pay->payby eq 'CHEK') ? - $cust_pay->paymask : $cust_pay->decrypt($cust_pay->payinfo) - } ], + [ 'payinfo' => $payinfo_sub ], + [ 'payinfo_end' => $payinfo_end ], + ], + # for refund receipts + 'cust_refund' => [ + 'refundnum', + [ refund => sub { sprintf("%.2f", shift->refund) } ], + [ payby => sub { FS::payby->shortname(shift->payby) } ], + [ date => sub { time2str("%a %B %o, %Y", shift->_date) } ], + [ 'payinfo' => $payinfo_sub ], + [ 'payinfo_end' => $payinfo_end ], ], # for payment decline messages # try to support all cust_pay fields @@ -658,11 +715,8 @@ sub substitutions { [ paid => sub { sprintf("%.2f", shift->paid) } ], [ payby => sub { FS::payby->shortname(shift->payby) } ], [ date => sub { time2str("%a %B %o, %Y", shift->_date) } ], - [ payinfo => sub { - my $pending = shift; - ($pending->payby eq 'CARD' || $pending->payby eq 'CHEK') ? - $pending->paymask : $pending->decrypt($pending->payinfo) - } ], + [ 'payinfo' => $payinfo_sub ], + [ 'payinfo_end' => $payinfo_end ], ], }; } @@ -696,6 +750,10 @@ sub agent { sub _upgrade_data { my ($self, %opts) = @_; + ### + # First move any historical templates in config to real message templates + ### + my @fixes = ( [ 'alerter_msgnum', 'alerter_template', '', '', '' ], [ 'cancel_msgnum', 'cancelmessage', 'cancelsubject', '', '' ], @@ -728,7 +786,70 @@ sub _upgrade_data { $conf->delete($subject, $agentnum) if $subject; } } + + if ( $conf->exists('alert_expiration', $agentnum) ) { + my $msgnum = $conf->exists('alerter_msgnum', $agentnum); + my $template = FS::msg_template->by_key($msgnum) if $msgnum; + if (!$template) { + warn "template for alerter_msgnum $msgnum not found\n"; + next; + } + # this is now a set of billing events + foreach my $days (30, 15, 5) { + my $event = FS::part_event->new({ + 'agentnum' => $agentnum, + 'event' => "Card expiration warning - $days days", + 'eventtable' => 'cust_main', + 'check_freq' => '1d', + 'action' => 'notice', + 'disabled' => 'Y', #initialize first + }); + my $error = $event->insert( 'msgnum' => $msgnum ); + if ($error) { + warn "error creating expiration alert event:\n$error\n\n"; + next; + } + # make it work like before: + # only send each warning once before the card expires, + # only warn active customers, + # only warn customers with CARD/DCRD, + # only warn customers who get email invoices + my %conds = ( + 'once_every' => { 'run_delay' => '30d' }, + 'cust_paydate_within' => { 'within' => $days.'d' }, + 'cust_status' => { 'status' => { 'active' => 1 } }, + 'payby' => { 'payby' => { 'CARD' => 1, + 'DCRD' => 1, } + }, + 'message_email' => {}, + ); + foreach (keys %conds) { + my $condition = FS::part_event_condition->new({ + 'conditionname' => $_, + 'eventpart' => $event->eventpart, + }); + $error = $condition->insert( %{ $conds{$_} }); + if ( $error ) { + warn "error creating expiration alert event:\n$error\n\n"; + next; + } + } + $error = $event->initialize; + if ( $error ) { + warn "expiration alert event was created, but not initialized:\n$error\n\n"; + } + } # foreach $days + $conf->delete('alerter_msgnum', $agentnum); + $conf->delete('alert_expiration', $agentnum); + + } # if alerter_msgnum + } + + ### + # Move subject and body from msg_template to template_content + ### + foreach my $msg_template ( qsearch('msg_template', {}) ) { if ( $msg_template->subject || $msg_template->body ) { # create new default content @@ -752,6 +873,35 @@ sub _upgrade_data { die $error if $error; } } + + ### + # Add new-style default templates if missing + ### + $self->_populate_initial_data; + +} + +sub _populate_initial_data { #class method + #my($class, %opts) = @_; + #my $class = shift; + + eval "use FS::msg_template::InitialData;"; + die $@ if $@; + + my $initial_data = FS::msg_template::InitialData->_initial_data; + + foreach my $hash ( @$initial_data ) { + + next if $hash->{_conf} && $conf->config( $hash->{_conf} ); + + my $msg_template = new FS::msg_template($hash); + my $error = $msg_template->insert( @{ $hash->{_insert_args} || [] } ); + die $error if $error; + + $conf->set( $hash->{_conf}, $msg_template->msgnum ) if $hash->{_conf}; + + } + } sub eviscerate {