[freeside-commits] branch master updated. 03c12b4dabfcaabc218f39ee13557edebc13931d

Ivan ivan at 420.am
Sun Jan 18 18:13:23 PST 2015


The branch, master has been updated
       via  03c12b4dabfcaabc218f39ee13557edebc13931d (commit)
      from  0b6bd6405107c1abf8f2c5e2bc1b569870a02309 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 03c12b4dabfcaabc218f39ee13557edebc13931d
Author: Ivan Kohler <ivan at freeside.biz>
Date:   Sun Jan 18 18:13:16 2015 -0800

    email quotations, RT#22232, RT#20688

diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm
index 2a11e5e..e584f00 100644
--- a/FS/FS/Conf.pm
+++ b/FS/FS/Conf.pm
@@ -1239,6 +1239,15 @@ sub reason_type_options {
   },
 
   {
+    'key'         => 'quotation_from',
+    'section'     => '',
+    'description' => 'Return address on email quotations',
+    'type'        => 'text',
+    'per_agent'   => 1,
+  },
+
+
+  {
     'key'         => 'invoice_subject',
     'section'     => 'invoicing',
     'description' => 'Subject: header on email invoices.  Defaults to "Invoice".  The following substitutions are available: $name, $name_short, $invoice_number, and $invoice_date.',
@@ -1248,6 +1257,15 @@ sub reason_type_options {
   },
 
   {
+    'key'         => 'quotation_subject',
+    'section'     => '',
+    'description' => 'Subject: header on email quotations.  Defaults to "Quotation".', #  The following substitutions are available: $name, $name_short, $invoice_number, and $invoice_date.',
+    'type'        => 'text',
+    #'per_agent'   => 1,
+    'per_locale'  => 1,
+  },
+
+  {
     'key'         => 'invoice_usesummary',
     'section'     => 'invoicing',
     'description' => 'Indicates that html and latex invoices should be in summary style and make use of invoice_latexsummary.',
@@ -1502,14 +1520,28 @@ and customer address. Include units.',
   {
     'key'         => 'invoice_email_pdf',
     'section'     => 'invoicing',
-    'description' => 'Send PDF invoice as an attachment to emailed invoices.  By default, includes the plain text invoice as the email body, unless invoice_email_pdf_note is set.',
+    'description' => 'Send PDF invoice as an attachment to emailed invoices.  By default, includes the HTML invoice as the email body, unless invoice_email_pdf_note is set.',
+    'type'        => 'checkbox'
+  },
+
+  {
+    'key'         => 'quotation_email_pdf',
+    'section'     => '',
+    'description' => 'Send PDF quotations as an attachment to emailed quotations.  By default, includes the HTML quotation as the email body, unless quotation_email_pdf_note is set.',
     'type'        => 'checkbox'
   },
 
   {
     'key'         => 'invoice_email_pdf_note',
     'section'     => 'invoicing',
-    'description' => 'If defined, this text will replace the default plain text invoice as the body of emailed PDF invoices.',
+    'description' => 'If defined, this text will replace the default HTML invoice as the body of emailed PDF invoices.',
+    'type'        => 'textarea'
+  },
+
+  {
+    'key'         => 'quotation_email_pdf_note',
+    'section'     => '',
+    'description' => 'If defined, this text will replace the default HTML quotation as the body of emailed PDF quotations.',
     'type'        => 'textarea'
   },
 
diff --git a/FS/FS/Template_Mixin.pm b/FS/FS/Template_Mixin.pm
index ebc977a..1fed7f1 100644
--- a/FS/FS/Template_Mixin.pm
+++ b/FS/FS/Template_Mixin.pm
@@ -16,6 +16,7 @@ use HTML::Entities;
 use Locale::Country;
 use Cwd;
 use FS::UID;
+use FS::Misc qw( send_email );
 use FS::Record qw( qsearch qsearchs );
 use FS::Conf;
 use FS::Misc qw( generate_ps generate_pdf );
@@ -1845,6 +1846,10 @@ sub _translate_old_latex_format {
   (@template);
 }
 
+=item terms
+
+=cut
+
 sub terms {
   my $self = shift;
   my $conf = $self->conf;
@@ -1867,6 +1872,10 @@ sub terms {
   $conf->config('invoice_default_terms', $agentnum) || '';
 }
 
+=item due_date
+
+=cut
+
 sub due_date {
   my $self = shift;
   my $duedate = '';
@@ -1876,11 +1885,19 @@ sub due_date {
   $duedate;
 }
 
+=item due_date2str
+
+=cut
+
 sub due_date2str {
   my $self = shift;
   $self->due_date ? $self->time2str_local(shift, $self->due_date) : '';
 }
 
+=item balance_due_msg
+
+=cut
+
 sub balance_due_msg {
   my $self = shift;
   my $msg = $self->mt('Balance Due');
@@ -1894,6 +1911,10 @@ sub balance_due_msg {
   $msg;
 }
 
+=item balance_due_date
+
+=cut
+
 sub balance_due_date {
   my $self = shift;
   my $conf = $self->conf;
@@ -1934,6 +1955,348 @@ sub _date_pretty_unlocalized {
   time2str($date_format, $self->_date);
 }
 
+=item email HASHREF
+
+Emails this template.
+
+Options are passed as a hashref.  Available options:
+
+=over 4
+
+=item from
+
+If specified, overrides the default From: address.
+
+=item notice_name
+
+If specified, overrides the name of the sent document ("Invoice" or "Quotation")
+
+=item template
+
+(Deprecated) If specified, is the name of a suffix for alternate template files.
+
+=back
+
+Options accepted by generate_email can also be used.
+
+=cut
+
+sub email {
+  my $self = shift;
+  my $opt = shift || {};
+  if ($opt and !ref($opt)) {
+    die ref($self). '->email called with positional parameters';
+  }
+
+  return if $self->hide;
+
+  my $error = send_email(
+    $self->generate_email(
+      'subject'     => $self->email_subject($opt->{template}),
+      %$opt, # template, etc.
+    )
+  );
+
+  die "can't email: $error\n" if $error;
+}
+
+=item generate_email OPTION => VALUE ...
+
+Options:
+
+=over 4
+
+=item from
+
+sender address, required
+
+=item template
+
+alternate template name, optional
+
+=item print_text
+
+text attachment arrayref, optional
+
+=item subject
+
+email subject, optional
+
+=item notice_name
+
+notice name instead of "Invoice", optional
+
+=back
+
+Returns an argument list to be passed to L<FS::Misc::send_email>.
+
+=cut
+
+use MIME::Entity;
+
+sub generate_email {
+
+  my $self = shift;
+  my %args = @_;
+  my $conf = $self->conf;
+
+  my $me = '[FS::Template_Mixin::generate_email]';
+
+  my %return = (
+    'from'      => $args{'from'},
+    'subject'   => ($args{'subject'} || $self->email_subject),
+    'custnum'   => $self->custnum,
+    'msgtype'   => 'invoice',
+  );
+
+  $args{'unsquelch_cdr'} = $conf->exists('voip-cdr_email');
+
+  my $cust_main = $self->cust_main;
+
+  if (ref($args{'to'}) eq 'ARRAY') {
+    $return{'to'} = $args{'to'};
+  } elsif ( $cust_main ) {
+    $return{'to'} = [ $cust_main->invoicing_list_emailonly ];
+  }
+
+  my $tc = $self->template_conf;
+
+  if ( $conf->exists($tc.'html') ) {
+
+    warn "$me creating HTML/text multipart message"
+      if $DEBUG;
+
+    $return{'nobody'} = 1;
+
+    my $alternative = build MIME::Entity
+      'Type'        => 'multipart/alternative',
+      #'Encoding'    => '7bit',
+      'Disposition' => 'inline'
+    ;
+
+    my $data = '';
+    if ( $conf->exists($tc. 'email_pdf')
+         and scalar($conf->config($tc. 'email_pdf_note')) ) {
+
+      warn "$me using '${tc}email_pdf_note' in multipart message"
+        if $DEBUG;
+      $data = [ map { $_ . "\n" }
+                    $conf->config($tc.'email_pdf_note')
+              ];
+
+    } else {
+
+      warn "$me not using '${tc}email_pdf_note' in multipart message"
+        if $DEBUG;
+      if ( ref($args{'print_text'}) eq 'ARRAY' ) {
+        $data = $args{'print_text'};
+      } elsif ( $conf->exists($tc.'template') ) { #plaintext invoice_template
+        $data = [ $self->print_text(\%args) ];
+      }
+
+    }
+
+    if ( $data ) {
+      $alternative->attach(
+        'Type'        => 'text/plain',
+        'Encoding'    => 'quoted-printable',
+        'Charset'     => 'UTF-8',
+        #'Encoding'    => '7bit',
+        'Data'        => $data,
+        'Disposition' => 'inline',
+      );
+    }
+
+    my $htmldata;
+    my $image = '';
+    my $barcode = '';
+    if ( $conf->exists($tc.'email_pdf')
+         and scalar($conf->config($tc.'email_pdf_note')) ) {
+
+      $htmldata = join('<BR>', $conf->config($tc.'email_pdf_note') );
+
+    } else {
+
+      $args{'from'} =~ /\@([\w\.\-]+)/;
+      my $from = $1 || 'example.com';
+      my $content_id = join('.', rand()*(2**32), $$, time). "\@$from";
+
+      my $logo;
+      my $agentnum = $cust_main ? $cust_main->agentnum
+                                : $self->prospect_main->agentnum;
+      if ( defined($args{'template'}) && length($args{'template'})
+           && $conf->exists( 'logo_'. $args{'template'}. '.png', $agentnum )
+         )
+      {
+        $logo = 'logo_'. $args{'template'}. '.png';
+      } else {
+        $logo = "logo.png";
+      }
+      my $image_data = $conf->config_binary( $logo, $agentnum);
+
+      $image = build MIME::Entity
+        'Type'       => 'image/png',
+        'Encoding'   => 'base64',
+        'Data'       => $image_data,
+        'Filename'   => 'logo.png',
+        'Content-ID' => "<$content_id>",
+      ;
+   
+      if ( ref($self) eq 'FS::cust_bill' && $conf->exists('invoice-barcode') ) {
+        my $barcode_content_id = join('.', rand()*(2**32), $$, time). "\@$from";
+        $barcode = build MIME::Entity
+          'Type'       => 'image/png',
+          'Encoding'   => 'base64',
+          'Data'       => $self->invoice_barcode(0),
+          'Filename'   => 'barcode.png',
+          'Content-ID' => "<$barcode_content_id>",
+        ;
+        $args{'barcode_cid'} = $barcode_content_id;
+      }
+
+      $htmldata = $self->print_html({ 'cid'=>$content_id, %args });
+    }
+
+    $alternative->attach(
+      'Type'        => 'text/html',
+      'Encoding'    => 'quoted-printable',
+      'Data'        => [ '<html>',
+                         '  <head>',
+                         '    <title>',
+                         '      '. encode_entities($return{'subject'}), 
+                         '    </title>',
+                         '  </head>',
+                         '  <body bgcolor="#e8e8e8">',
+                         $htmldata,
+                         '  </body>',
+                         '</html>',
+                       ],
+      'Disposition' => 'inline',
+      #'Filename'    => 'invoice.pdf',
+    );
+
+
+    my @otherparts = ();
+    if ( ref($self) eq 'FS::cust_bill' && $cust_main->email_csv_cdr ) {
+
+      push @otherparts, build MIME::Entity
+        'Type'        => 'text/csv',
+        'Encoding'    => '7bit',
+        'Data'        => [ map { "$_\n" }
+                             $self->call_details('prepend_billed_number' => 1)
+                         ],
+        'Disposition' => 'attachment',
+        'Filename'    => 'usage-'. $self->invnum. '.csv',
+      ;
+
+    }
+
+    if ( $conf->exists($tc.'email_pdf') ) {
+
+      #attaching pdf too:
+      # multipart/mixed
+      #   multipart/related
+      #     multipart/alternative
+      #       text/plain
+      #       text/html
+      #     image/png
+      #   application/pdf
+
+      my $related = build MIME::Entity 'Type'     => 'multipart/related',
+                                       'Encoding' => '7bit';
+
+      #false laziness w/Misc::send_email
+      $related->head->replace('Content-type',
+        $related->mime_type.
+        '; boundary="'. $related->head->multipart_boundary. '"'.
+        '; type=multipart/alternative'
+      );
+
+      $related->add_part($alternative);
+
+      $related->add_part($image) if $image;
+
+      my $pdf = build MIME::Entity $self->mimebuild_pdf(\%args);
+
+      $return{'mimeparts'} = [ $related, $pdf, @otherparts ];
+
+    } else {
+
+      #no other attachment:
+      # multipart/related
+      #   multipart/alternative
+      #     text/plain
+      #     text/html
+      #   image/png
+
+      $return{'content-type'} = 'multipart/related';
+      if ($conf->exists('invoice-barcode') && $barcode) {
+        $return{'mimeparts'} = [ $alternative, $image, $barcode, @otherparts ];
+      } else {
+        $return{'mimeparts'} = [ $alternative, $image, @otherparts ];
+      }
+      $return{'type'} = 'multipart/alternative'; #Content-Type of first part...
+      #$return{'disposition'} = 'inline';
+
+    }
+  
+  } else {
+
+    if ( $conf->exists($tc.'email_pdf') ) {
+      warn "$me creating PDF attachment"
+        if $DEBUG;
+
+      #mime parts arguments a la MIME::Entity->build().
+      $return{'mimeparts'} = [
+        { $self->mimebuild_pdf(\%args) }
+      ];
+    }
+  
+    if ( $conf->exists($tc.'email_pdf')
+         and scalar($conf->config($tc.'email_pdf_note')) ) {
+
+      warn "$me using '${tc}email_pdf_note'"
+        if $DEBUG;
+      $return{'body'} = [ map { $_ . "\n" }
+                              $conf->config($tc.'email_pdf_note')
+                        ];
+
+    } else {
+
+      warn "$me not using '${tc}email_pdf_note'"
+        if $DEBUG;
+      if ( ref($args{'print_text'}) eq 'ARRAY' ) {
+        $return{'body'} = $args{'print_text'};
+      } else {
+        $return{'body'} = [ $self->print_text(\%args) ];
+      }
+
+    }
+
+  }
+
+  %return;
+
+}
+
+=item mimebuild_pdf
+
+Returns a list suitable for passing to MIME::Entity->build(), representing
+this invoice as PDF attachment.
+
+=cut
+
+sub mimebuild_pdf {
+  my $self = shift;
+  (
+    'Type'        => 'application/pdf',
+    'Encoding'    => 'base64',
+    'Data'        => [ $self->print_pdf(@_) ],
+    'Disposition' => 'attachment',
+    'Filename'    => 'invoice-'. $self->invnum. '.pdf',
+  );
+}
+
 =item _items_sections OPTIONS
 
 Generate section information for all items appearing on this invoice.
@@ -3065,7 +3428,7 @@ sub _items_cust_bill_pkg {
              ) > 0 ) {
              @discounts = ();
           }
-          if( @discounts ) {
+          if ( @discounts ) {
             warn "$me _items_cust_bill_pkg including discounts for ".
               $cust_bill_pkg->billpkgnum."\n"
               if $DEBUG;
diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm
index d811c1a..ad60b21 100644
--- a/FS/FS/cust_bill.pm
+++ b/FS/FS/cust_bill.pm
@@ -15,7 +15,7 @@ use HTML::Entities;
 use Storable qw( freeze thaw );
 use GD::Barcode;
 use FS::UID qw( datasrc );
-use FS::Misc qw( send_email send_fax do_print );
+use FS::Misc qw( send_fax do_print );
 use FS::Record qw( qsearch qsearchs dbh );
 use FS::cust_statement;
 use FS::cust_bill_pkg;
@@ -1024,301 +1024,6 @@ sub apply_payments_and_credits {
 
 }
 
-=item generate_email OPTION => VALUE ...
-
-Options:
-
-=over 4
-
-=item from
-
-sender address, required
-
-=item template
-
-alternate template name, optional
-
-=item print_text
-
-text attachment arrayref, optional
-
-=item subject
-
-email subject, optional
-
-=item notice_name
-
-notice name instead of "Invoice", optional
-
-=back
-
-Returns an argument list to be passed to L<FS::Misc::send_email>.
-
-=cut
-
-use MIME::Entity;
-
-sub generate_email {
-
-  my $self = shift;
-  my %args = @_;
-  my $conf = $self->conf;
-
-  my $me = '[FS::cust_bill::generate_email]';
-
-  my %return = (
-    'from'      => $args{'from'},
-    'subject'   => ($args{'subject'} || $self->email_subject),
-    'custnum'   => $self->custnum,
-    'msgtype'   => 'invoice',
-  );
-
-  $args{'unsquelch_cdr'} = $conf->exists('voip-cdr_email');
-
-  my $cust_main = $self->cust_main;
-
-  if (ref($args{'to'}) eq 'ARRAY') {
-    $return{'to'} = $args{'to'};
-  } else {
-    $return{'to'} = [ grep { $_ !~ /^(POST|FAX)$/ }
-                           $cust_main->invoicing_list
-                    ];
-  }
-
-  if ( $conf->exists('invoice_html') ) {
-
-    warn "$me creating HTML/text multipart message"
-      if $DEBUG;
-
-    $return{'nobody'} = 1;
-
-    my $alternative = build MIME::Entity
-      'Type'        => 'multipart/alternative',
-      #'Encoding'    => '7bit',
-      'Disposition' => 'inline'
-    ;
-
-    my $data;
-    if ( $conf->exists('invoice_email_pdf')
-         and scalar($conf->config('invoice_email_pdf_note')) ) {
-
-      warn "$me using 'invoice_email_pdf_note' in multipart message"
-        if $DEBUG;
-      $data = [ map { $_ . "\n" }
-                    $conf->config('invoice_email_pdf_note')
-              ];
-
-    } else {
-
-      warn "$me not using 'invoice_email_pdf_note' in multipart message"
-        if $DEBUG;
-      if ( ref($args{'print_text'}) eq 'ARRAY' ) {
-        $data = $args{'print_text'};
-      } else {
-        $data = [ $self->print_text(\%args) ];
-      }
-
-    }
-
-    $alternative->attach(
-      'Type'        => 'text/plain',
-      'Encoding'    => 'quoted-printable',
-      'Charset'     => 'UTF-8',
-      #'Encoding'    => '7bit',
-      'Data'        => $data,
-      'Disposition' => 'inline',
-    );
-
-
-    my $htmldata;
-    my $image = '';
-    my $barcode = '';
-    if ( $conf->exists('invoice_email_pdf')
-         and scalar($conf->config('invoice_email_pdf_note')) ) {
-
-      $htmldata = join('<BR>', $conf->config('invoice_email_pdf_note') );
-
-    } else {
-
-      $args{'from'} =~ /\@([\w\.\-]+)/;
-      my $from = $1 || 'example.com';
-      my $content_id = join('.', rand()*(2**32), $$, time). "\@$from";
-
-      my $logo;
-      my $agentnum = $cust_main->agentnum;
-      if ( defined($args{'template'}) && length($args{'template'})
-           && $conf->exists( 'logo_'. $args{'template'}. '.png', $agentnum )
-         )
-      {
-        $logo = 'logo_'. $args{'template'}. '.png';
-      } else {
-        $logo = "logo.png";
-      }
-      my $image_data = $conf->config_binary( $logo, $agentnum);
-
-      $image = build MIME::Entity
-        'Type'       => 'image/png',
-        'Encoding'   => 'base64',
-        'Data'       => $image_data,
-        'Filename'   => 'logo.png',
-        'Content-ID' => "<$content_id>",
-      ;
-   
-      if ($conf->exists('invoice-barcode')) {
-        my $barcode_content_id = join('.', rand()*(2**32), $$, time). "\@$from";
-        $barcode = build MIME::Entity
-          'Type'       => 'image/png',
-          'Encoding'   => 'base64',
-          'Data'       => $self->invoice_barcode(0),
-          'Filename'   => 'barcode.png',
-          'Content-ID' => "<$barcode_content_id>",
-        ;
-        $args{'barcode_cid'} = $barcode_content_id;
-      }
-
-      $htmldata = $self->print_html({ 'cid'=>$content_id, %args });
-    }
-
-    $alternative->attach(
-      'Type'        => 'text/html',
-      'Encoding'    => 'quoted-printable',
-      'Data'        => [ '<html>',
-                         '  <head>',
-                         '    <title>',
-                         '      '. encode_entities($return{'subject'}), 
-                         '    </title>',
-                         '  </head>',
-                         '  <body bgcolor="#e8e8e8">',
-                         $htmldata,
-                         '  </body>',
-                         '</html>',
-                       ],
-      'Disposition' => 'inline',
-      #'Filename'    => 'invoice.pdf',
-    );
-
-
-    my @otherparts = ();
-    if ( $cust_main->email_csv_cdr ) {
-
-      push @otherparts, build MIME::Entity
-        'Type'        => 'text/csv',
-        'Encoding'    => '7bit',
-        'Data'        => [ map { "$_\n" }
-                             $self->call_details('prepend_billed_number' => 1)
-                         ],
-        'Disposition' => 'attachment',
-        'Filename'    => 'usage-'. $self->invnum. '.csv',
-      ;
-
-    }
-
-    if ( $conf->exists('invoice_email_pdf') ) {
-
-      #attaching pdf too:
-      # multipart/mixed
-      #   multipart/related
-      #     multipart/alternative
-      #       text/plain
-      #       text/html
-      #     image/png
-      #   application/pdf
-
-      my $related = build MIME::Entity 'Type'     => 'multipart/related',
-                                       'Encoding' => '7bit';
-
-      #false laziness w/Misc::send_email
-      $related->head->replace('Content-type',
-        $related->mime_type.
-        '; boundary="'. $related->head->multipart_boundary. '"'.
-        '; type=multipart/alternative'
-      );
-
-      $related->add_part($alternative);
-
-      $related->add_part($image) if $image;
-
-      my $pdf = build MIME::Entity $self->mimebuild_pdf(\%args);
-
-      $return{'mimeparts'} = [ $related, $pdf, @otherparts ];
-
-    } else {
-
-      #no other attachment:
-      # multipart/related
-      #   multipart/alternative
-      #     text/plain
-      #     text/html
-      #   image/png
-
-      $return{'content-type'} = 'multipart/related';
-      if ($conf->exists('invoice-barcode') && $barcode) {
-        $return{'mimeparts'} = [ $alternative, $image, $barcode, @otherparts ];
-      } else {
-        $return{'mimeparts'} = [ $alternative, $image, @otherparts ];
-      }
-      $return{'type'} = 'multipart/alternative'; #Content-Type of first part...
-      #$return{'disposition'} = 'inline';
-
-    }
-  
-  } else {
-
-    if ( $conf->exists('invoice_email_pdf') ) {
-      warn "$me creating PDF attachment"
-        if $DEBUG;
-
-      #mime parts arguments a la MIME::Entity->build().
-      $return{'mimeparts'} = [
-        { $self->mimebuild_pdf(\%args) }
-      ];
-    }
-  
-    if ( $conf->exists('invoice_email_pdf')
-         and scalar($conf->config('invoice_email_pdf_note')) ) {
-
-      warn "$me using 'invoice_email_pdf_note'"
-        if $DEBUG;
-      $return{'body'} = [ map { $_ . "\n" }
-                              $conf->config('invoice_email_pdf_note')
-                        ];
-
-    } else {
-
-      warn "$me not using 'invoice_email_pdf_note'"
-        if $DEBUG;
-      if ( ref($args{'print_text'}) eq 'ARRAY' ) {
-        $return{'body'} = $args{'print_text'};
-      } else {
-        $return{'body'} = [ $self->print_text(\%args) ];
-      }
-
-    }
-
-  }
-
-  %return;
-
-}
-
-=item mimebuild_pdf
-
-Returns a list suitable for passing to MIME::Entity->build(), representing
-this invoice as PDF attachment.
-
-=cut
-
-sub mimebuild_pdf {
-  my $self = shift;
-  (
-    'Type'        => 'application/pdf',
-    'Encoding'    => 'base64',
-    'Data'        => [ $self->print_pdf(@_) ],
-    'Disposition' => 'attachment',
-    'Filename'    => 'invoice-'. $self->invnum. '.pdf',
-  );
-}
-
 =item send HASHREF
 
 Sends this invoice to the destinations configured for this customer: sends
@@ -1331,7 +1036,7 @@ I<template>: a suffix for alternate invoices
 
 I<agentnum>: obsolete, now does nothing.
 
-I<invoice_from> overrides the default email invoice From: address.
+I<from> overrides the default email invoice From: address.
 
 I<amount>: obsolete, does nothing
 
@@ -1367,55 +1072,22 @@ sub send {
 
 }
 
-=item email HASHREF | [ TEMPLATE [ , INVOICE_FROM ] ] 
-
-Sends this invoice to the customer's email destination(s).
-
-Options must be passed as a hashref.  Positional parameters are no longer
-allowed.
-
-I<template>, if specified, is the name of a suffix for alternate invoices.
-
-I<invoice_from>, if specified, overrides the default email invoice From: 
-address.
-
-I<notice_name> is the name of the sent document.
-
-=cut
-
-sub queueable_email {
-  my %opt = @_;
-
-  my $self = qsearchs('cust_bill', { 'invnum' => $opt{invnum} } )
-    or die "invalid invoice number: " . $opt{invnum};
-
-  my %args = map {$_ => $opt{$_}} 
-             grep { $opt{$_} }
-              qw( invoice_from notice_name no_coupon template );
-
-  my $error = $self->email( \%args );
-  die $error if $error;
-
-}
-
 sub email {
   my $self = shift;
-  return if $self->hide;
-  my $conf = $self->conf;
   my $opt = shift || {};
   if ($opt and !ref($opt)) {
-    die "FS::cust_bill::email called with positional parameters";
+    die ref($self). '->email called with positional parameters';
   }
 
-  my $template = $opt->{template};
-  my $from = delete $opt->{invoice_from};
+  my $conf = $self->conf;
+
+  my $from = delete $opt->{from};
 
   # this is where we set the From: address
   $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;
+  my @invoicing_list = $self->cust_main->invoicing_list_emailonly;
 
   if ( ! @invoicing_list ) { #no recipients
     if ( $conf->exists('cust_bill-no_recipients-error') ) {
@@ -1426,19 +1098,28 @@ sub email {
     }
   }
 
-  # this is where we set the Subject:
-  my $subject = $self->email_subject($template);
+  $self->SUPER::email( {
+    'from' => $from,
+    'to'   => \@invoicing_list,
+    %$opt,
+  });
 
-  my $error = send_email(
-    $self->generate_email(
-      'from'        => $from,
-      'to'          => [ grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list ],
-      'subject'     => $subject,
-      %$opt, # template, etc.
-    )
-  );
-  die "can't email invoice: $error\n" if $error;
-  #die "$error\n" if $error;
+}
+
+#this stays here for now because its explicitly used as
+# FS::cust_bill::queueable_email
+sub queueable_email {
+  my %opt = @_;
+
+  my $self = qsearchs('cust_bill', { 'invnum' => $opt{invnum} } )
+    or die "invalid invoice number: " . $opt{invnum};
+
+  my %args = map {$_ => $opt{$_}} 
+             grep { $opt{$_} }
+              qw( from notice_name no_coupon template );
+
+  my $error = $self->email( \%args );
+  die $error if $error;
 
 }
 
diff --git a/FS/FS/cust_event.pm b/FS/FS/cust_event.pm
index b5436d0..d7a35a7 100644
--- a/FS/FS/cust_event.pm
+++ b/FS/FS/cust_event.pm
@@ -481,9 +481,10 @@ sub re_X {
     my $modenum = $part_event->option('modenum') || '';
     my $invoice_from = $part_event->option('agent_invoice_from') || '';
     $cust_X->set('mode' => $modenum);
-    $cust_X->$method( { template      => $template,
-                        modenum       => $modenum,
-                        invoice_from  => $invoice_from } );
+    $cust_X->$method( { template => $template,
+                        modenum  => $modenum,
+                        from     => $invoice_from,
+                    } );
 
     if ( $job ) { #progressbar foo
       $num++;
diff --git a/FS/FS/part_event/Action/cust_bill_send_agent.pm b/FS/FS/part_event/Action/cust_bill_send_agent.pm
index bbb757b..cb13b1f 100644
--- a/FS/FS/part_event/Action/cust_bill_send_agent.pm
+++ b/FS/FS/part_event/Action/cust_bill_send_agent.pm
@@ -45,8 +45,8 @@ sub do_action {
 
   $cust_bill->set('mode' => $self->option('modenum'));
   $cust_bill->send(
-    'template'      => $self->option('agent_templatename'),
-    'invoice_from'  => $self->option('agent_invoice_from'),
+    'template' => $self->option('agent_templatename'),
+    'from'     => $self->option('agent_invoice_from'),
   );
 }
 
diff --git a/FS/FS/quotation.pm b/FS/FS/quotation.pm
index 5710b38..44b72f4 100644
--- a/FS/FS/quotation.pm
+++ b/FS/FS/quotation.pm
@@ -167,6 +167,53 @@ sub _total {
 
 }
 
+sub email {
+  my $self = shift;
+  my $opt = shift || {};
+  if ($opt and !ref($opt)) {
+    die ref($self). '->email called with positional parameters';
+  }
+
+  my $conf = $self->conf;
+
+  my $from = delete $opt->{from};
+
+  # this is where we set the From: address
+  $from ||= $conf->config('quotation_from', $self->cust_or_prospect->agentnum )
+         || $conf->config('invoice_from',   $self->cust_or_prospect->agentnum );
+
+  $self->SUPER::email( {
+    'from' => $from,
+    %$opt,
+  });
+
+}
+
+sub email_subject {
+  my $self = shift;
+
+  my $subject =
+    $self->conf->config('quotation_subject') #, $self->cust_main->agentnum)
+      || 'Quotation';
+
+  #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 cust_or_prosect
+
+=cut
+
+sub cust_or_prospect {
+  my $self = shift;
+  $self->custnum ? $self->cust_main : $self->prospect_main;
+}
+
 =item cust_or_prospect_label_link P
 
 HTML links to either the customer or prospect.
diff --git a/httemplate/elements/footer-popup.html b/httemplate/elements/footer-popup.html
new file mode 100644
index 0000000..6029d76
--- /dev/null
+++ b/httemplate/elements/footer-popup.html
@@ -0,0 +1,2 @@
+  </BODY>
+</HTML>
diff --git a/httemplate/misc/email-quotation.html b/httemplate/misc/email-quotation.html
new file mode 100644
index 0000000..b93b80b
--- /dev/null
+++ b/httemplate/misc/email-quotation.html
@@ -0,0 +1,71 @@
+<& /elements/header-popup.html, mt('Select recipients') &>
+
+<% include('/elements/error.html') %>
+
+<FORM NAME="OneTrueForm" METHOD="POST" ACTION="process/email-quotation.html" onSubmit="document.OneTrueForm.submit.disabled=true; document.OneTrueForm.submit.style.display='none'; document.getElementById('emailingwait').style.display='';">
+<INPUT TYPE="hidden" NAME="quotationnum" VALUE="<% $quotationnum %>">
+
+<% ntable("#cccccc", 2) %>
+
+% my $emails = 0;
+
+% if ( my $cust_main = $quotation->cust_main ) {
+%   foreach my $email ( $cust_main->invoicing_list_emailonly ) {
+%     $emails++;
+      <& .emailrow, $email &>
+%   }
+% }
+
+% my @contact = $quotation->custnum ? $quotation->cust_main->cust_contact
+%                                   : $quotation->prospect_main->contact;
+% foreach my $contact ( @contact ) {
+%    foreach my $contact_email ( $contact->contact_email ) {
+%      $emails++;
+       <& .emailrow, $contact_email->emailaddress, $contact->firstlast &>
+%    }
+% }
+
+<%def .emailrow>
+% my( $email, $name ) = @_;
+% if ( $name ) { 
+%   $name = "$name <$email>";
+% } else { 
+%   $name = $email;
+% }
+  <TR>
+    <TD><INPUT TYPE="checkbox" NAME="emailaddress" VALUE="<% $email |h %>"></TD>
+    <TD><% $name |h %></TD>
+  </TR>
+</%def>
+
+</TABLE>
+
+<BR>
+
+<CENTER>
+% if ( $emails ) {
+  <BUTTON TYPE="submit" NAME="submit" ID="submit">Email quotation</BUTTON>
+  <DIV ID="emailingwait" STYLE="display:none">
+    <IMG SRC="<%$p%>images/wait-orange.gif"> <B>Sending...</B>
+  </DIV>
+% } else {
+  <FONT SIZE="+1" COLOR="#ff0000"><% mt('Add a contact email address first') |h %></FONT>
+% }
+</CENTER>
+
+</FORM>
+
+<& /elements/footer-popup.html &>
+<%init>
+
+#die "access denied"
+#  unless $FS::CurrentUser::CurrentUser->access_right('Generate quotation'); #separate rights to generate vs send/email?
+
+$cgi->param('quotationnum') =~ /^(\d+)$/ or die "Illegal quotationnum";
+my $quotationnum = $1;
+
+#XXX agent-virt
+my $quotation = qsearchs('quotation', { 'quotationnum'=>$quotationnum })
+  or die "Unknown quotationnum";
+
+</%init>
diff --git a/httemplate/misc/process/email-quotation.html b/httemplate/misc/process/email-quotation.html
new file mode 100755
index 0000000..e7fef4a
--- /dev/null
+++ b/httemplate/misc/process/email-quotation.html
@@ -0,0 +1,20 @@
+<& /elements/header-popup.html, mt('Email sent') &>
+<SCRIPT TYPE="text/javascript">
+  setTimeout("parent.cClick()", 3000);
+</SCRIPT>
+<& /elements/footer-popup.html &>
+<%init>
+
+#die "access denied"
+#  unless $FS::CurrentUser::CurrentUser->access_right('Generate quotation'); #separate rights to generate vs send/email?
+
+$cgi->param('quotationnum') =~ /^(\d+)$/ or die "Illegal quotationnum";
+my $quotationnum = $1;
+
+#XXX agent-virt
+my $quotation = qsearchs('quotation', { 'quotationnum'=>$quotationnum })
+  or die "Unknown quotationnum";
+
+$quotation->email({ 'to' => [ $cgi->param('emailaddress') ] });
+
+</%init>
diff --git a/httemplate/view/quotation.html b/httemplate/view/quotation.html
index b8dc1d1..81c7cdd 100755
--- a/httemplate/view/quotation.html
+++ b/httemplate/view/quotation.html
@@ -1,5 +1,7 @@
 <& /elements/header.html, mt('Quotation View'), $menubar &>
 
+<& /elements/init_overlib.html &>
+
 <SCRIPT TYPE="text/javascript">
 function areyousure(href, message) {
   if (confirm(message) == true)
@@ -20,9 +22,14 @@ function areyousure(href, message) {
 
 %   if ( 1 ) { #if ( $curuser->access_right('Send quotations') )
 
-%     #if ( grep { $_ ne 'POST' } $cust_bill->cust_main->invoicing_list ) { 
-%#      <A HREF="<% $p %>misc/email-quotation.html?<% $link %>"><% mt('Email this quotation') |h %></A>
-%     #} 
+      <& /elements/popup_link.html,
+           'action'      => "${p}misc/email-quotation.html".
+                              "?quotationnum=$quotationnum",
+           'label'       => emt('Email this quotation'),
+           'actionlabel' => emt('Select recipients'),
+           #'width'       => 540,
+           #'height'      => 336,
+      &>
 
 %#      <A HREF="<% $p %>misc/send-invoice.cgi?method=print;<% $link %>"><% mt('Re-print this invoice') |h %></A>
 

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/Conf.pm                                   |   36 ++-
 FS/FS/Template_Mixin.pm                         |  365 +++++++++++++++++++++-
 FS/FS/cust_bill.pm                              |  375 ++---------------------
 FS/FS/cust_event.pm                             |    7 +-
 FS/FS/part_event/Action/cust_bill_send_agent.pm |    4 +-
 FS/FS/quotation.pm                              |   47 +++
 httemplate/elements/footer-popup.html           |    2 +
 httemplate/misc/email-quotation.html            |   71 +++++
 httemplate/misc/process/email-quotation.html    |   20 ++
 httemplate/view/quotation.html                  |   13 +-
 10 files changed, 582 insertions(+), 358 deletions(-)
 create mode 100644 httemplate/elements/footer-popup.html
 create mode 100644 httemplate/misc/email-quotation.html
 create mode 100755 httemplate/misc/process/email-quotation.html




More information about the freeside-commits mailing list