this should fix credits pushing typeset invoices off the right
[freeside.git] / FS / FS / cust_bill.pm
index df0e32b..408da99 100644 (file)
@@ -660,21 +660,22 @@ sub generate_email {
     my $from = $1 || 'example.com';
     my $content_id = join('.', rand()*(2**32), $$, time). "\@$from";
 
-    my $path = "$FS::UID::conf_dir/conf.$FS::UID::datasrc";
-    my $file;
+    my $logo;
+    my $agentnum = $self->cust_main->agentnum;
     if ( defined($args{'template'}) && length($args{'template'})
-         && -e "$path/logo_". $args{'template'}. ".png"
+         && $conf->exists( 'logo_'. $args{'template'}. '.png', $agentnum )
        )
     {
-      $file = "$path/logo_". $args{'template'}. ".png";
+      $logo = 'logo_'. $args{'template'}. '.png';
     } else {
-      $file = "$path/logo.png";
+      $logo = "logo.png";
     }
+    my $image_data = $conf->config_binary( $logo, $agentnum);
 
     my $image = build MIME::Entity
       'Type'       => 'image/png',
       'Encoding'   => 'base64',
-      'Path'       => $file,
+      'Data'       => $image_data,
       'Filename'   => 'logo.png',
       'Content-ID' => "<$content_id>",
     ;
@@ -843,7 +844,9 @@ sub send {
   my $invoice_from =
     scalar(@_)
       ? shift
-      : ( $self->_agent_invoice_from || $conf->config('invoice_from') );
+      : ( $self->_agent_invoice_from ||    #XXX should go away
+          $conf->config('invoice_from', $self->cust_main->agentnum )
+        );
 
   my $balance_over = ( scalar(@_) && $_[0] !~ /^\s*$/ ) ? shift : 0;
 
@@ -899,7 +902,10 @@ sub email {
   my $invoice_from =
     scalar(@_)
       ? shift
-      : ( $self->_agent_invoice_from || $conf->config('invoice_from') );
+      : ( $self->_agent_invoice_from ||    #XXX should go away
+          $conf->config('invoice_from', $self->cust_main->agentnum )
+        );
+
 
   my @invoicing_list = grep { $_ !~ /^(POST|FAX)$/ } 
                             $self->cust_main->invoicing_list;
@@ -907,10 +913,13 @@ sub email {
   #better to notify this person than silence
   @invoicing_list = ($invoice_from) unless @invoicing_list;
 
+  my $subject = $self->email_subject($template);
+
   my $error = send_email(
     $self->generate_email(
       'from'       => $invoice_from,
       'to'         => [ grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list ],
+      'subject'    => $subject,
       'template'   => $template,
     )
   );
@@ -919,6 +928,24 @@ sub email {
 
 }
 
+sub email_subject {
+  my $self = shift;
+
+  #my $template = scalar(@_) ? shift : '';
+  #per-template?
+
+  my $subject = $conf->config('invoice_subject', $self->cust_main->agentnum)
+                || 'Invoice';
+
+  my $cust_main = $self->cust_main;
+  my $name = $cust_main->name;
+  my $name_short = $cust_main->name_short;
+  my $invoice_number = $self->invnum;
+  my $invoice_date = $self->_date_pretty;
+
+  eval qq("$subject");
+}
+
 =item lpr_data [ TEMPLATENAME ]
 
 Returns the postscript or plaintext for this invoice as an arrayref.
@@ -1611,7 +1638,6 @@ L<Time::Local> and L<Date::Parse> for conversion functions.
 =cut
 
 sub print_latex {
-
   my( $self, $today, $template ) = @_;
 
   my %params = ( 'format' => 'latex' );
@@ -1627,11 +1653,13 @@ sub print_latex {
                            UNLINK   => 0,
                          ) or die "can't open temp file: $!\n";
 
-  if ($template && $conf->exists("logo_${template}.eps")) {
-    print $lh $conf->config_binary("logo_${template}.eps")
+  my $agentnum = $self->cust_main->agentnum;
+
+  if ( $template && $conf->exists("logo_${template}.eps", $agentnum) ) {
+    print $lh $conf->config_binary("logo_${template}.eps", $agentnum)
       or die "can't write temp file: $!\n";
-  }else{
-    print $lh $conf->config_binary('logo.eps')
+  } else {
+    print $lh $conf->config_binary('logo.eps', $agentnum)
       or die "can't write temp file: $!\n";
   }
   close $lh;
@@ -1676,6 +1704,8 @@ unsquelch_cdr - overrides any per customer cdr squelching when true
 
 =cut
 
+#what's with all the sprintf('%10.2f')'s in here?  will it cause any
+# (alignment?) problems to change them all to '%.2f' ?
 sub print_generic {
 
   my( $self, %params ) = @_;
@@ -1689,8 +1719,8 @@ sub print_generic {
 
   my $cust_main = $self->cust_main;
   $cust_main->payname( $cust_main->first. ' '. $cust_main->getfield('last') )
-    unless $cust_main->payname && $cust_main->payby !~ /^(CHEK|DCHK)$/;
-
+    unless $cust_main->payname
+        && $cust_main->payby !~ /^(CARD|DCRD|CHEK|DCHK)$/;
 
   my %delimiters = ( 'latex'    => [ '[@--', '--@]' ],
                      'html'     => [ '<%=', '%>' ],
@@ -1760,6 +1790,7 @@ sub print_generic {
                        s/~/&nbsp;/g;
                        s/\\\\\*?\s*$/<BR>/;
                        s/\\hyphenation\{[\w\s\-]+}//;
+                       s/\\([&])/$1/g;
                        $_;
                      }  @_
                    },
@@ -1854,7 +1885,7 @@ sub print_generic {
                                                )
                          )
           );
-  } elsif ( grep /\S/, $conf->config('company_address') ) {
+  } elsif ( grep /\S/, $conf->config('company_address', $self->cust_main->agentnum) ) {
 
     my $convert_map = $convert_maps{$format}{'returnaddress'};
     $returnaddress = join( "\n", &$convert_map(
@@ -1862,8 +1893,8 @@ sub print_generic {
                                          s/$/\\\\\*/;
                                          $_
                                        }
-                                     ( $conf->config('company_name'),
-                                       $conf->config('company_address'),
+                                     ( $conf->config('company_name', $self->cust_main->agentnum),
+                                       $conf->config('company_address', $self->cust_main->agentnum),
                                      )
                                  )
                      );
@@ -1879,8 +1910,8 @@ sub print_generic {
   }
 
   my %invoice_data = (
-    'company_name'    => scalar( $conf->config('company_name') ),
-    'company_address' => join("\n", $conf->config('company_address') ). "\n",
+    'company_name'    => scalar( $conf->config('company_name', $self->cust_main->agentnum) ),
+    'company_address' => join("\n", $conf->config('company_address', $self->cust_main->agentnum) ). "\n",
     'custnum'         => $cust_main->display_custnum,
     'invnum'          => $self->invnum,
     'date'            => time2str($date_format, $self->_date),
@@ -1898,7 +1929,7 @@ sub print_generic {
     'returnaddress'   => $returnaddress,
     #'quantity'        => 1,
     'terms'           => $self->terms,
-    'template'        => $params{'template'},
+    'template'        => $template, #params{'template'},
     #'notes'           => join("\n", $conf->config('invoice_latexnotes') ),
     # better hang on to conf_dir for a while
     'conf_dir'        => "$FS::UID::conf_dir/conf.$FS::UID::datasrc",
@@ -1959,15 +1990,18 @@ sub print_generic {
   $invoice_data{'previous_balance'} = sprintf("%.2f", $pr_total);
   $invoice_data{'balance'} = sprintf("%.2f", $balance_due);
 
+  my $agentnum = $self->cust_main->agentnum;
+
   #do variable substitution in notes, footer, smallfooter
   foreach my $include (qw( notes footer smallfooter coupon )) {
 
     my $inc_file = $conf->key_orbase("invoice_${format}$include", $template);
     my @inc_src;
 
-    if ( $conf->exists($inc_file) && length( $conf->config($inc_file) ) ) {
+    if ( $conf->exists($inc_file, $agentnum)
+         && length( $conf->config($inc_file, $agentnum) ) ) {
 
-      @inc_src = $conf->config($inc_file);
+      @inc_src = $conf->config($inc_file, $agentnum);
 
     } else {
 
@@ -1979,7 +2013,7 @@ sub print_generic {
                        s/--\@\]/$delimiters{$format}[1]/g;
                        $_;
                      } 
-                 &$convert_map( $conf->config($inc_file) );
+                 &$convert_map( $conf->config($inc_file, $agentnum) );
 
     }
 
@@ -2012,7 +2046,7 @@ sub print_generic {
                     );
   my $money_char = $money_chars{$format};
 
-  my %other_money_chars = ( 'latex'    => '\dollar ',
+  my %other_money_chars = ( 'latex'    => '\dollar ',#XXX should be a config too
                             'html'     => $conf->config('money_char') || '$',
                             'template' => '',
                           );
@@ -2050,33 +2084,37 @@ sub print_generic {
     push @sections, { 'description' => '', 'subtotal' => '' };
   }
 
-  foreach my $line_item ( $conf->exists('disable_previous_balance') 
-                            ? ()
-                            : $self->_items_previous
-                        )
+  unless (    $conf->exists('disable_previous_balance')
+           || $conf->exists('previous_balance-summary_only')
+         )
   {
-    my $detail = {
-      ext_description => [],
-    };
-    $detail->{'ref'} = $line_item->{'pkgnum'};
-    $detail->{'quantity'} = 1;
-    $detail->{'section'} = $previous_section;
-    $detail->{'description'} = &$escape_function($line_item->{'description'});
-    if ( exists $line_item->{'ext_description'} ) {
-      @{$detail->{'ext_description'}} = map {
-        &$escape_function($_);
-      } @{$line_item->{'ext_description'}};
+
+    foreach my $line_item ( $self->_items_previous ) {
+
+      my $detail = {
+        ext_description => [],
+      };
+      $detail->{'ref'} = $line_item->{'pkgnum'};
+      $detail->{'quantity'} = 1;
+      $detail->{'section'} = $previous_section;
+      $detail->{'description'} = &$escape_function($line_item->{'description'});
+      if ( exists $line_item->{'ext_description'} ) {
+        @{$detail->{'ext_description'}} = map {
+          &$escape_function($_);
+        } @{$line_item->{'ext_description'}};
+      }
+      $detail->{'amount'} = ( $old_latex ? '' : $money_char).
+                            $line_item->{'amount'};
+      $detail->{'product_code'} = $line_item->{'pkgpart'} || 'N/A';
+
+      push @detail_items, $detail;
+      push @buf, [ $detail->{'description'},
+                   $money_char. sprintf("%10.2f", $line_item->{'amount'}),
+                 ];
     }
-    $detail->{'amount'} = ( $old_latex ? '' : $money_char).
-                          $line_item->{'amount'};
-    $detail->{'product_code'} = $line_item->{'pkgpart'} || 'N/A';
-  
-    push @detail_items, $detail;
-    push @buf, [ $detail->{'description'},
-                 $money_char. sprintf("%10.2f", $line_item->{'amount'}),
-               ];
+
   }
-  
+
   if ( @pr_cust_bill && !$conf->exists('disable_previous_balance') ) {
     push @buf, ['','-----------'];
     push @buf, [ 'Total Previous Balance',
@@ -2145,26 +2183,36 @@ sub print_generic {
   }
 
   foreach my $tax ( $self->_items_tax ) {
-    my $total = {};
-    $total->{'total_item'} = &$escape_function($tax->{'description'});
+
     $taxtotal += $tax->{'amount'};
-    $total->{'total_amount'} = $other_money_char. $tax->{'amount'};
+
+    my $description = &$escape_function( $tax->{'description'} );
+    my $amount      = sprintf( '%.2f', $tax->{'amount'} );
+
     if ( $multisection ) {
+
       my $money = $old_latex ? '' : $money_char;
       push @detail_items, {
         ext_description => [],
         ref          => '',
         quantity     => '',
-        description  => &$escape_function($tax->{'description'}),
-        amount       => $money. $tax->{'amount'},
+        description  => $description,
+        amount       => $money. $amount,
         product_code => '',
         section      => $tax_section,
       };
-    }else{
-      push @total_items, $total;
+
+    } else {
+
+      push @total_items, {
+        'total_item'   => $description,
+        'total_amount' => $other_money_char. $amount,
+      };
+
     }
-    push @buf,[ $total->{'total_item'},
-                $money_char. sprintf("%10.2f", $total->{'total_amount'}),
+
+    push @buf,[ $description,
+                $money_char. $amount,
               ];
 
   }
@@ -2233,6 +2281,7 @@ sub print_generic {
     # credits
     my $credittotal = 0;
     foreach my $credit ( $self->_items_credits ) {
+
       my $total;
       $total->{'total_item'} = &$escape_function($credit->{'description'});
       $credittotal += $credit->{'amount'};
@@ -2249,26 +2298,15 @@ sub print_generic {
           product_code => '',
           section      => $adjust_section,
         };
-      }else{
+      } else {
         push @total_items, $total;
       }
+
+      push @buf, [ $credit->{'description'}, $money_char.$credit->{'amount'} ];
+
     }
     $invoice_data{'credittotal'} = sprintf('%.2f', $credittotal);
   
-    # credits (again)
-    foreach ( $self->cust_credited ) {
-  
-      #something more elaborate if $_->amount ne $_->cust_credit->credited ?
-
-      my $reason = substr($_->cust_credit->reason,0,32);
-      $reason .= '...' if length($reason) < length($_->cust_credit->reason);
-      $reason = " ($reason) " if $reason;
-      push @buf,[
-        "Credit #". $_->crednum. " (". time2str("%x",$_->cust_credit->_date) .")".        $reason,
-        $money_char. sprintf("%10.2f",$_->amount)
-      ];
-    }
-
     # payments
     my $paymenttotal = 0;
     foreach my $payment ( $self->_items_payments ) {
@@ -2586,7 +2624,18 @@ Returns a string with the invoice number and date, for example:
 
 sub invnum_date_pretty {
   my $self = shift;
-  'Invoice #'. $self->invnum. ' ('. time2str('%x', $self->_date). ')';
+  'Invoice #'. $self->invnum. ' ('. $self->_date_pretty. ')';
+}
+
+=item _date_pretty
+
+Returns a string with the date, for example: "3/20/2008"
+
+=cut
+
+sub _date_pretty {
+  my $self = shift;
+  time2str('%x', $self->_date);
 }
 
 sub _items_sections {
@@ -2712,11 +2761,8 @@ sub _items_previous {
 
 sub _items_pkg {
   my $self = shift;
-  my %options = @_;
-  my $section = $options{'section'};
-  my $desc = $section->{'description'};
   my @cust_bill_pkg = grep { $_->pkgnum } $self->cust_bill_pkg;
-  $self->_items_cust_bill_pkg(\@cust_bill_pkg, %options);
+  $self->_items_cust_bill_pkg(\@cust_bill_pkg, @_);
 }
 
 sub _taxsort {
@@ -2761,6 +2807,8 @@ sub _items_cust_bill_pkg {
       my $cust_pkg = $cust_bill_pkg->cust_pkg;
 
       my $desc = $cust_bill_pkg->desc;
+      $desc = substr($desc, 0, 50). '...'
+        if $format eq 'latex' && length($desc) > 50;
 
       my %details_opt = ( 'format'          => $format,
                           'escape_function' => $escape_function,
@@ -2774,8 +2822,10 @@ sub _items_cust_bill_pkg {
           my $description = $desc;
           $description .= ' Setup' if $cust_bill_pkg->recur != 0;
 
-          my @d = map &{$escape_function}($_),
-                         $cust_pkg->h_labels_short($self->_date);
+          my @d = ();
+          push @d, map &{$escape_function}($_),
+                       $cust_pkg->h_labels_short($self->_date)
+            unless $cust_pkg->part_pkg->hide_svc_detail;
           push @d, $cust_bill_pkg->details(%details_opt)
             if $cust_bill_pkg->recur == 0;
 
@@ -2804,16 +2854,18 @@ sub _items_cust_bill_pkg {
                             " - ". time2str("%x", $cust_bill_pkg->edate). ")";
           }
 
+          my @d = ();
+
           #at least until cust_bill_pkg has "past" ranges in addition to
           #the "future" sdate/edate ones... see #3032
-          my @d = ();
           push @d, map &{$escape_function}($_),
-                         $cust_pkg->h_labels_short($self->_date)
-                                                #$cust_bill_pkg->edate,
-                                                #$cust_bill_pkg->sdate),
-            ;
-  
-          @d = () if ($cust_bill_pkg->itemdesc || $is_summary);
+                       $cust_pkg->h_labels_short($self->_date)
+                                                 #$cust_bill_pkg->edate,
+                                                 #$cust_bill_pkg->sdate)
+            unless $cust_pkg->part_pkg->hide_svc_detail
+                || $cust_bill_pkg->itemdesc
+                || $is_summary;
+
           push @d, $cust_bill_pkg->details(%details_opt)
             unless ($is_summary || $type && $type eq 'R');
   
@@ -2874,10 +2926,10 @@ sub _items_credits {
 
     #something more elaborate if $_->amount ne $_->cust_credit->credited ?
 
-    my $reason = $_->cust_credit->reason;
-    #my $reason = substr($_->cust_credit->reason,0,32);
-    #$reason .= '...' if length($reason) < length($_->cust_credit->reason);
+    my $reason = substr($_->cust_credit->reason,0,32);
+    $reason .= '...' if length($reason) < length($_->cust_credit->reason);
     $reason = " ($reason) " if $reason;
+
     push @b, {
       #'description' => 'Credit ref\#'. $_->crednum.
       #                 " (". time2str("%x",$_->cust_credit->_date) .")".
@@ -2887,12 +2939,6 @@ sub _items_credits {
       'amount'      => sprintf("%.2f",$_->amount),
     };
   }
-  #foreach ( @cr_cust_credit ) {
-  #  push @buf,[
-  #    "Credit #". $_->crednum. " (" . time2str("%x",$_->_date) .")",
-  #    $money_char. sprintf("%10.2f",$_->credited)
-  #  ];
-  #}
 
   @b;