fix MIME::Entity usage for perl 5.18+, RT#77890
[freeside.git] / FS / FS / Template_Mixin.pm
index ddc933e..7dc8139 100644 (file)
@@ -10,6 +10,7 @@ use vars qw( $invoice_lines @buf ); #yuck
 use List::Util qw(sum); #can't import first, it conflicts with cust_main.first
 use Date::Format;
 use Date::Language;
+use Time::Local qw( timelocal );
 use Text::Template 1.20;
 use File::Temp 0.14;
 use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
@@ -562,6 +563,7 @@ sub print_generic {
     'notice_name'     => $notice_name, # escape?
     'current_charges' => sprintf("%.2f", $self->charged),
     'duedate'         => $self->due_date2str('rdate'), #date_format?
+    'duedate_long'    => $self->due_date2str('long'),
 
     #customer info
     'custnum'         => $cust_main->display_custnum,
@@ -601,6 +603,9 @@ sub print_generic {
     'total_pages'     => 1,
 
   );
+
+  #quotations have $name
+  $invoice_data{'name'} = $invoice_data{'payname'};
  
   #localization
   $invoice_data{'emt'} = sub { &$escape_function($self->mt(@_)) };
@@ -1156,14 +1161,27 @@ sub print_generic {
       if ( $invoice_data{finance_section} &&
            $section->{'description'} eq $invoice_data{finance_section} );
 
-    $section->{'subtotal'} = $other_money_char.
-                             sprintf('%.2f', $section->{'subtotal'})
-      if $multisection;
+    if ( $multisection ) {
+
+      if ( ref($section->{'subtotal'}) ) {
+
+        $section->{'subtotal'} =
+          sprintf("$other_money_char%.2f to $other_money_char%.2f",
+                    $section->{'subtotal'}[0],
+                    $section->{'subtotal'}[1]
+                 );
+
+      } else {
+
+        $section->{'subtotal'} = $other_money_char.
+                                 sprintf('%.2f', $section->{'subtotal'})
 
-    # continue some normalization
-    $section->{'amount'}   = $section->{'subtotal'}
-      if $multisection;
+      }
+
+      # continue some normalization
+      $section->{'amount'}   = $section->{'subtotal'}
 
+    }
 
     if ( $section->{'description'} ) {
       push @buf, ( [ &$escape_function($section->{'description'}), '' ],
@@ -1240,11 +1258,13 @@ sub print_generic {
     if $DEBUG > 1;
 
   # create a tax section if we don't yet have one
+  my @items_tax = $self->_items_tax;
   my $tax_description = 'Taxes, Surcharges, and Fees';
   my $tax_section =
     List::Util::first { $_->{description} eq $tax_description } @sections;
   if (!$tax_section) {
     $tax_section = { 'description' => $tax_description };
+    push @sections, $tax_section if $multisection and @items_tax > 0;
   }
   $tax_section->{tax_section} = 1; # mark this section as containing taxes
   # if this is an existing tax section, we're merging the tax items into it.
@@ -1259,9 +1279,6 @@ sub print_generic {
   #$tax_section->{'summarized'} = ''; #why? $summarypage && !$tax_weight ? 'Y' : '';
   #$tax_section->{'sort_weight'} = $tax_weight;
 
-  my @items_tax = $self->_items_tax;
-  push @sections, $tax_section if $multisection and @items_tax > 0;
-
   foreach my $tax ( @items_tax ) {
 
     $taxtotal += $tax->{'amount'};
@@ -1363,7 +1380,16 @@ sub print_generic {
     foreach ( @new_total_items ) {
       my ($item, $amount) = ($_->{'total_item'}, $_->{'total_amount'});
       $_->{'total_item'}   = &$embolden_function( $item );
-      $_->{'total_amount'} = &$embolden_function( $other_money_char.$amount );
+
+      if ( ref($amount) ) {
+        $_->{'total_amount'} = &$embolden_function(
+                                 $other_money_char.$amount->[0]. ' to '.
+                                 $other_money_char.$amount->[1]
+                               );
+      } else {
+        $_->{'total_amount'} = &$embolden_function( $other_money_char.$amount );
+      }
+
       # but if it's multisection, don't append to @total_items. the adjust
       # section has all this stuff
       push @total_items, $_ if !$multisection;
@@ -1642,24 +1668,24 @@ sub print_generic {
   die "no invoice_lines() functions in template?"
     if ( $format eq 'template' && !$wasfunc );
 
-  if ($format eq 'template') {
+  if ( $invoice_lines ) {
+    $invoice_data{'total_pages'} = int( scalar(@buf) / $invoice_lines );
+    $invoice_data{'total_pages'}++
+      if scalar(@buf) % $invoice_lines;
+  }
 
-    if ( $invoice_lines ) {
-      $invoice_data{'total_pages'} = int( scalar(@buf) / $invoice_lines );
-      $invoice_data{'total_pages'}++
-        if scalar(@buf) % $invoice_lines;
+  #setup subroutine for the template
+  $invoice_data{invoice_lines} = sub {
+    my $lines = shift || scalar(@buf);
+    map { 
+      scalar(@buf)
+        ? shift @buf
+        : [ '', '' ];
     }
+    ( 1 .. $lines );
+  };
 
-    #setup subroutine for the template
-    $invoice_data{invoice_lines} = sub {
-      my $lines = shift || scalar(@buf);
-      map { 
-        scalar(@buf)
-          ? shift @buf
-          : [ '', '' ];
-      }
-      ( 1 .. $lines );
-    };
+  if ($format eq 'template') {
 
     my $lines;
     my @collect;
@@ -1925,6 +1951,12 @@ sub due_date {
   my $duedate = '';
   if ( $self->terms =~ /^\s*Net\s*(\d+)\s*$/ ) {
     $duedate = $self->_date() + ( $1 * 86400 );
+  } elsif ( $self->terms =~ /^End of Month$/ ) {
+    my ($mon,$year) = (localtime($self->_date) )[4,5];
+    $mon++;
+    until ( $mon < 12 ) { $mon -= 12; $year++; }
+    my $nextmonth_first = timelocal(0,0,0,1,$mon,$year);
+    $duedate = $nextmonth_first - 86400;
   }
   $duedate;
 }
@@ -1952,8 +1984,12 @@ sub balance_due_msg {
     # _items_total) and not here
     # (yes, or if invoice_sections is enabled; this is just for compatibility)
     if ( $self->due_date ) {
-      $msg .= ' - ' . $self->mt('Please pay by'). ' '.
-        $self->due_date2str('short');
+      my $please_pay_by =
+        $self->conf->config('invoice_pay_by_msg', $self->agentnum)
+        || 'Please pay by [_1]';
+      $msg .= ' - ' . $self->mt($please_pay_by, $self->due_date2str('short')).
+              ' '
+       unless $self->conf->config_bool('invoice_omit_due_date',$self->agentnum);
     } elsif ( $self->terms ) {
       $msg .= ' - '. $self->mt($self->terms);
     }
@@ -2079,6 +2115,7 @@ Returns an argument list to be passed to L<FS::Misc::send_email>.
 =cut
 
 use MIME::Entity;
+use Encode;
 
 sub generate_email {
 
@@ -2155,7 +2192,7 @@ sub generate_email {
         if $DEBUG;
 
       # 'print_text' argument is no longer used
-      @text = $self->print_text(\%args);
+      @text = map Encode::encode_utf8($_), $self->print_text(\%args);
 
     } else {
 
@@ -2250,7 +2287,7 @@ sub generate_email {
                          '    </title>',
                          '  </head>',
                          '  <body bgcolor="#e8e8e8">',
-                         $html,
+                         Encode::encode_utf8($html),
                          '  </body>',
                          '</html>',
                        ],
@@ -2356,7 +2393,7 @@ sub generate_email {
 =item mimebuild_pdf
 
 Returns a list suitable for passing to MIME::Entity->build(), representing
-this invoice as PDF attachment.
+this quotation or invoice as PDF attachment.
 
 =cut
 
@@ -2367,7 +2404,7 @@ sub mimebuild_pdf {
     'Encoding'    => 'base64',
     'Data'        => [ $self->print_pdf(@_) ],
     'Disposition' => 'attachment',
-    'Filename'    => 'invoice-'. $self->invnum. '.pdf',
+    'Filename'    => $self->pdf_filename,
   );
 }
 
@@ -2424,6 +2461,7 @@ sub postal_mail_fsinc {
     'ssl_opts' => { 
       verify_hostname => 0,
       SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE,
+      SSL_version     => 'SSLv3',
     }
   );
   my $response = $ua->request( POST $url, [
@@ -2454,7 +2492,8 @@ sub postal_mail_fsinc {
     'country'          => $bill_location->country,
   ]);
 
-  die "Print connection error: ". $response->message. "\n"
+  die "Print connection error: ". $response->message.
+      ' ('. $response->as_string. ")\n"
     unless $response->is_success;
 
   local $@;
@@ -3186,7 +3225,9 @@ sub _items_cust_bill_pkg {
 
   # for location labels: use default location on the invoice date
   my $default_locationnum;
-  if ( $self->custnum ) {
+  if ( $conf->exists('invoice-all_pkg_addresses') ) {
+    $default_locationnum = 0; # treat them all as non-default
+  } elsif ( $self->custnum ) {
     my $h_cust_main;
     my @h_search = FS::h_cust_main->sql_h_search($self->_date);
     $h_cust_main = qsearchs({
@@ -3336,19 +3377,24 @@ sub _items_cust_bill_pkg {
             && ! $cust_bill_pkg->recur_show_zero;
 
           my @d = ();
-          my $svc_label;
-
-          # always pass the svc_label through to the template, even if 
-          # not displaying it as an ext_description
-          my @svc_labels = map &{$escape_function}($_),
-            $cust_pkg->h_labels_short($self->_date,
-                                      undef,
-                                      'I',
-                                      $self->conf->{locale},
-                                     );
-          $svc_label = $svc_labels[0];
-
-          unless ( $cust_pkg->part_pkg->hide_svc_detail
+          my @svc_labels = ();
+          my $svc_label = '';
+
+          unless ( $part_pkg->hide_svc_detail ) {
+
+            # still pass the svc_label through to the template, even if 
+            # not displaying it as an ext_description
+            @svc_labels = map &{$escape_function}($_),
+              $cust_pkg->h_labels_short($self->_date,
+                                        undef,
+                                        'I',
+                                        $self->conf->{locale},
+                                       );
+            $svc_label = $svc_labels[0];
+
+          }
+
+          unless ( $part_pkg->hide_svc_detail
                 || $cust_bill_pkg->hidden )
           {
 
@@ -3425,6 +3471,7 @@ sub _items_cust_bill_pkg {
 
           my @d = ();
           my @seconds = (); # for display of usage info
+          my @svc_labels = ();
           my $svc_label = '';
 
           #at least until cust_bill_pkg has "past" ranges in addition to
@@ -3434,11 +3481,13 @@ sub _items_cust_bill_pkg {
           push @dates, $prev->sdate if $prev;
           push @dates, undef if !$prev;
 
-          my @svc_labels = map &{$escape_function}($_),
-            $cust_pkg->h_labels_short(@dates,
-                                      'I',
-                                      $self->conf->{locale});
-          $svc_label = $svc_labels[0];
+          unless ( $part_pkg->hide_svc_detail ) {
+            @svc_labels = map &{$escape_function}($_),
+              $cust_pkg->h_labels_short(@dates,
+                                        'I',
+                                        $self->conf->{locale});
+            $svc_label = $svc_labels[0];
+          }
 
           # show service labels, unless...
                     # the package is set not to display them