RT#34078: Payment History Report / Statement
[freeside.git] / FS / FS / msg_template.pm
index f45fb2a..fe8cbeb 100644 (file)
@@ -269,7 +269,19 @@ invoicing_list addresses.  Multiple addresses may be comma-separated.
 
 =item substitutions
 
-A hash reference of additional substitutions
+A hash reference of additional string substitutions
+
+=item sub_param
+
+A hash reference, keys are the names of existing substitutions,
+values are an addition parameter object to pass to the subroutine
+for that substitution, e.g.
+
+       'sub_param' => {
+         'payment_history' => {
+           'start_date' => 1434764295,
+         },
+       },
 
 =back
 
@@ -278,16 +290,17 @@ A hash reference of additional substitutions
 sub prepare {
   my( $self, %opt ) = @_;
 
-  my $cust_main = $opt{'cust_main'} or die 'cust_main required';
+  my $cust_main = $opt{'cust_main'}; # or die 'cust_main required';
   my $object = $opt{'object'} or die 'object required';
 
   # localization
-  my $locale = $cust_main->locale || '';
+  my $locale = $cust_main && $cust_main->locale || '';
   warn "no locale for cust#".$cust_main->custnum."; using default content\n"
-    if $DEBUG and !$locale;
-  my $content = $self->content($cust_main->locale);
-  warn "preparing template '".$self->msgname."' to cust#".$cust_main->custnum."\n"
-    if($DEBUG);
+    if $DEBUG and $cust_main && !$locale;
+  my $content = $self->content($locale);
+
+  warn "preparing template '".$self->msgname."\n"
+    if $DEBUG;
 
   my $subs = $self->substitutions;
 
@@ -295,7 +308,8 @@ sub prepare {
   # create substitution table
   ###  
   my %hash;
-  my @objects = ($cust_main);
+  my @objects = ();
+  push @objects, $cust_main if $cust_main;
   my @prefixes = ('');
   my $svc;
   if( ref $object ) {
@@ -325,7 +339,10 @@ sub prepare {
       }
       elsif( ref($name) eq 'ARRAY' ) {
         # [ foo => sub { ... } ]
-        $hash{$prefix.($name->[0])} = $name->[1]->($obj);
+        my @subparam = ();
+        push(@subparam, $opt{'sub_param'}->{$name->[0]})
+          if $opt{'sub_param'} && $opt{'sub_param'}->{$name->[0]};
+        $hash{$prefix.($name->[0])} = $name->[1]->($obj,@subparam);
       }
       else {
         warn "bad msg_template substitution: '$name'\n";
@@ -338,7 +355,10 @@ sub prepare {
     $hash{$_} = $opt{substitutions}->{$_} foreach keys %{$opt{substitutions}};
   }
 
-  $_ = encode_entities($_ || '') foreach values(%hash);
+  foreach my $key (keys %hash) {
+    next if $self->no_encode($key);
+    $hash{$key} = encode_entities($_ || '');
+  };
 
   ###
   # clean up template
@@ -385,20 +405,22 @@ sub prepare {
   my @to;
   if ( exists($opt{'to'}) ) {
     @to = split(/\s*,\s*/, $opt{'to'});
-  }
-  else {
+  } elsif ( $cust_main ) {
     @to = $cust_main->invoicing_list_emailonly;
+  } else {
+    die 'no To: address or cust_main object specified';
   }
-  # no warning when preparing with no destination
 
   my $from_addr = $self->from_addr;
 
   if ( !$from_addr ) {
+
+    my $agentnum = $cust_main ? $cust_main->agentnum : '';
+
     if ( $opt{'from_config'} ) {
-      $from_addr = scalar( $conf->config($opt{'from_config'}, 
-                                         $cust_main->agentnum) );
+      $from_addr = $conf->config($opt{'from_config'}, $agentnum);
     }
-    $from_addr ||= $conf->invoice_from_full($cust_main->agentnum);
+    $from_addr ||= $conf->invoice_from_full($agentnum);
   }
 #  my @cust_msg = ();
 #  if ( $conf->exists('log_sent_mail') and !$opt{'preview'} ) {
@@ -416,11 +438,11 @@ sub prepare {
                       ->format( HTML::TreeBuilder->new_from_content($body) )
                   );
   (
-    'custnum' => $cust_main->custnum,
-    'msgnum'  => $self->msgnum,
-    'from' => $from_addr,
-    'to'   => \@to,
-    'bcc'  => $self->bcc_addr || undef,
+    'custnum'   => ( $cust_main ? $cust_main->custnum : ''),
+    'msgnum'    => $self->msgnum,
+    'from'      => $from_addr,
+    'to'        => \@to,
+    'bcc'       => $self->bcc_addr || undef,
     'subject'   => $subject,
     'html_body' => $body,
     'text_body' => $text_body
@@ -463,9 +485,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 +527,13 @@ my $usage_warning = sub {
 
 #my $conf = new FS::Conf;
 
+# for substitutions that handle their own encoding
+sub no_encode {
+  my $self = shift;
+  my $field = shift;
+  return ($field eq 'payment_history');
+}
+
 #return contexts and fill-in values
 # If you add anything, be sure to add a description in 
 # httemplate/edit/msg_template.html.
@@ -561,6 +592,12 @@ sub substitutions {
       [ selfservice_server_base_url => sub { 
           $conf->config('selfservice_server-base_url') #, shift->agentnum) 
         } ],
+      [ payment_history => sub {
+          my $cust_main = shift;
+          my $param = shift || {};
+          #html works, see no_encode method
+          return '<PRE>' . encode_entities($cust_main->payment_history_text($param)) . '</PRE>';
+        } ],
     ],
     # next_bill_date
     'cust_pkg'  => [qw( 
@@ -597,8 +634,9 @@ sub substitutions {
       _date
       _date_pretty
       due_date
-      due_date2str
-    )],
+    ),
+      [ due_date2str      => sub { shift->due_date2str('short') } ],
+    ],
     #XXX not really thinking about cust_bill substitutions quite yet
     
     # for welcome and limit warning messages