From: Ivan Kohler Date: Wed, 25 Feb 2015 02:42:54 +0000 (-0800) Subject: Merge branch 'master' of git.freeside.biz:/home/git/freeside X-Git-Url: http://git.freeside.biz/gitweb/?a=commitdiff_plain;h=8142815f404a02df9ba3f92ad8e703a7355c5bcd;hp=957e8ac61c4d3f6f092a006f008f395a237a207d;p=freeside.git Merge branch 'master' of git.freeside.biz:/home/git/freeside --- diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 169f9fe16..c4e5af4e0 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -1,6 +1,7 @@ package FS::Conf; use vars qw($base_dir @config_items @base_items @card_types $DEBUG); +use strict; use Carp; use IO::File; use File::Basename; @@ -733,6 +734,23 @@ my %batch_gateway_options = ( }, ); +my %invoice_mode_options = ( + 'type' => 'select-sub', + 'options_sub' => sub { + my @modes = qsearch({ + 'table' => 'invoice_mode', + 'extra_sql' => ' WHERE '. + $FS::CurrentUser::CurrentUser->agentnums_sql(null => 1), + }); + map { $_->modenum, $_->modename } @modes; + }, + 'option_sub' => sub { + my $mode = FS::invoice_mode->by_key(shift); + $mode ? $mode->modename : '', + }, + 'per_agent' => 1, +); + my @cdr_formats = ( '' => '', 'default' => 'Default', @@ -1562,6 +1580,13 @@ and customer address. Include units.', }, { + 'key' => 'invoice_email_pdf_msgnum', + 'section' => 'invoicing', + 'description' => 'Message template to send as the text and HTML part of PDF invoices. If not selected, a text and HTML version of the invoice will be sent.', + %msg_template_options, + }, + + { 'key' => 'invoice_email_pdf_note', 'section' => 'invoicing', 'description' => 'If defined, this text will replace the default HTML invoice as the body of emailed PDF invoices.', @@ -1714,9 +1739,16 @@ and customer address. Include units.', }, { + 'key' => 'payment_receipt_statement_mode', + 'section' => 'notification', + 'description' => 'Automatic payments will cause a post-payment statement to be sent to the customer. Select the invoice mode to use for this statement. If unspecified, it will use the "_statement" versions of invoice configuration settings, and have the notice name "Statement".', + %invoice_mode_options, + }, + + { 'key' => 'payment_receipt_msgnum', 'section' => 'notification', - 'description' => 'Template to use for payment receipts.', + 'description' => 'Template to use for manual payment receipts.', %msg_template_options, }, @@ -3047,7 +3079,7 @@ and customer address. Include units.', }, 'option_sub' => sub { require FS::Record; require FS::agent_type; - my $agent = FS::Record::qsearchs( + my $agent_type = FS::Record::qsearchs( 'agent_type', { 'typenum'=>shift } ); $agent_type ? $agent_type->atype : ''; diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index db2d3cf71..44f09d627 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -2659,6 +2659,7 @@ sub tables_hashref { 'recur_show_zero', 'char', 'NULL', 1, '', '', 'setup_show_zero', 'char', 'NULL', 1, '', '', 'change_to_pkgnum', 'int', 'NULL', '', '', '', + 'separate_bill', 'char', 'NULL', 1, '', '', ], 'primary_key' => 'pkgnum', 'unique' => [], diff --git a/FS/FS/Template_Mixin.pm b/FS/FS/Template_Mixin.pm index 606c6c86c..9045291fc 100644 --- a/FS/FS/Template_Mixin.pm +++ b/FS/FS/Template_Mixin.pm @@ -2037,10 +2037,6 @@ sender address, required alternate template name, optional -=item print_text - -text attachment arrayref, optional - =item subject email subject, optional @@ -2084,61 +2080,61 @@ sub generate_email { my $tc = $self->template_conf; - if ( $conf->exists($tc.'html') ) { + my @text; # array of lines + my $html; # a big string + my @related_parts; # will contain the text/HTML alternative, and images + my $related; # will contain the multipart/related object - warn "$me creating HTML/text multipart message" - if $DEBUG; + if ( $conf->exists($tc. 'email_pdf') ) { + if ( my $msgnum = $conf->config($tc.'email_pdf_msgnum') ) { - $return{'nobody'} = 1; + warn "$me using '${tc}email_pdf_msgnum' in multipart message" + if $DEBUG; - my $alternative = build MIME::Entity - 'Type' => 'multipart/alternative', - #'Encoding' => '7bit', - 'Disposition' => 'inline' - ; + my $msg_template = FS::msg_template->by_key($msgnum) + or die "${tc}email_pdf_msgnum $msgnum not found\n"; + my %prepared = $msg_template->prepare( + cust_main => $self->cust_main, + object => $self + ); + + @text = split(/(?=\n)/, $prepared{'text_body'}); + $html = $prepared{'html_body'}; - my $data = ''; - if ( $conf->exists($tc. 'email_pdf') - and scalar($conf->config($tc. 'email_pdf_note')) ) { + } elsif ( my @note = $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') - ]; + @text = $conf->config($tc.'email_pdf_note'); + $html = join('
', @text); + + } # else use the plain text invoice + } - } else { + if (!@text) { - 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) ]; - } + warn "$me generating plain text invoice" + if $DEBUG; - } + # 'print_text' argument is no longer used + @text = $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')) ) { + my $text_part = build MIME::Entity ( + 'Type' => 'text/plain', + 'Encoding' => 'quoted-printable', + 'Charset' => 'UTF-8', + #'Encoding' => '7bit', + 'Data' => \@text, + 'Disposition' => 'inline', + ); - $htmldata = join('
', $conf->config($tc.'email_pdf_note') ); + if (!$html) { - } else { + if ( $conf->exists($tc.'html') ) { + warn "$me generating HTML invoice" + if $DEBUG; $args{'from'} =~ /\@([\w\.\-]+)/; my $from = $1 || 'example.com'; @@ -2157,7 +2153,7 @@ sub generate_email { } my $image_data = $conf->config_binary( $logo, $agentnum); - $image = build MIME::Entity + push @related_parts, build MIME::Entity 'Type' => 'image/png', 'Encoding' => 'base64', 'Data' => $image_data, @@ -2167,7 +2163,7 @@ sub generate_email { 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 + push @related_parts, build MIME::Entity 'Type' => 'image/png', 'Encoding' => 'base64', 'Data' => $self->invoice_barcode(0), @@ -2177,7 +2173,26 @@ sub generate_email { $args{'barcode_cid'} = $barcode_content_id; } - $htmldata = $self->print_html({ 'cid'=>$content_id, %args }); + $html = $self->print_html({ 'cid'=>$content_id, %args }); + } + + } + + if ( $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' + ; + + if ( @text ) { + $alternative->add_part($text_part); } $alternative->attach( @@ -2190,7 +2205,7 @@ sub generate_email { ' ', ' ', ' ', - $htmldata, + $html, ' ', '', ], @@ -2198,104 +2213,68 @@ sub generate_email { #'Filename' => 'invoice.pdf', ); + unshift @related_parts, $alternative; - 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; + $related = build MIME::Entity 'Type' => 'multipart/related', + 'Encoding' => '7bit'; - my $pdf = build MIME::Entity $self->mimebuild_pdf(\%args); + #false laziness w/Misc::send_email + $related->head->replace('Content-type', + $related->mime_type. + '; boundary="'. $related->head->multipart_boundary. '"'. + '; type=multipart/alternative' + ); - $return{'mimeparts'} = [ $related, $pdf, @otherparts ]; + $related->add_part($_) foreach @related_parts; - } else { + } - #no other attachment: - # multipart/related - # multipart/alternative - # text/plain - # text/html - # image/png + my @otherparts = (); + if ( ref($self) eq 'FS::cust_bill' && $cust_main->email_csv_cdr ) { - $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'; + 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', + ; - } - - } else { + } - if ( $conf->exists($tc.'email_pdf') ) { - warn "$me creating PDF attachment" - if $DEBUG; + if ( $conf->exists($tc.'email_pdf') ) { - #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')) ) { + #attaching pdf too: + # multipart/mixed + # multipart/related + # multipart/alternative + # text/plain + # text/html + # image/png + # application/pdf - warn "$me using '${tc}email_pdf_note'" - if $DEBUG; - $return{'body'} = [ map { $_ . "\n" } - $conf->config($tc.'email_pdf_note') - ]; + my $pdf = build MIME::Entity $self->mimebuild_pdf(\%args); + push @otherparts, $pdf; + } + if (@otherparts) { + $return{'content-type'} = 'multipart/mixed'; # of the outer container + if ( $html ) { + $return{'mimeparts'} = [ $related, @otherparts ]; + $return{'type'} = 'multipart/related'; # of the first part } 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{'mimeparts'} = [ $text_part, @otherparts ]; + $return{'type'} = 'text/plain'; } - + } elsif ( $html ) { # no PDF or CSV, strip the outer container + $return{'mimeparts'} = \@related_parts; + $return{'content-type'} = 'multipart/related'; + $return{'type'} = 'multipart/alternative'; + } else { # no HTML either + $return{'body'} = \@text; + $return{'content-type'} = 'text/plain'; } %return; diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 8d6966161..a65154ec4 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -1086,6 +1086,10 @@ sub queueable_email { my $self = qsearchs('cust_bill', { 'invnum' => $opt{invnum} } ) or die "invalid invoice number: " . $opt{invnum}; + if ( $opt{mode} ) { + $self->set('mode', $opt{mode}); + } + my %args = map {$_ => $opt{$_}} grep { $opt{$_} } qw( from notice_name no_coupon template ); diff --git a/FS/FS/cust_bill_pkg.pm b/FS/FS/cust_bill_pkg.pm index 352ed6a12..9b9cf925e 100644 --- a/FS/FS/cust_bill_pkg.pm +++ b/FS/FS/cust_bill_pkg.pm @@ -899,7 +899,13 @@ sub usage { my $sql = 'SELECT SUM(COALESCE(amount,0)) FROM cust_bill_pkg_detail '. ' WHERE billpkgnum = '. $self->billpkgnum; - $sql .= " AND classnum = $classnum" if defined($classnum); + if (defined $classnum) { + if ($classnum =~ /^(\d+)$/) { + $sql .= " AND classnum = $1"; + } elsif ($classnum eq '') { + $sql .= " AND classnum IS NULL"; + } + } my $sth = dbh->prepare($sql) or die dbh->errstr; $sth->execute or die $sth->errstr; diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index e4be849c6..671ad214b 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -3133,6 +3133,7 @@ sub charge { my ( $setuptax, $taxclass ); #internal taxes my ( $taxproduct, $override ); #vendor (CCH) taxes my $no_auto = ''; + my $separate_bill = ''; my $cust_pkg_ref = ''; my ( $bill_now, $invoice_terms ) = ( 0, '' ); my $locationnum; @@ -3155,7 +3156,8 @@ sub charge { $bill_now = exists($_[0]->{bill_now}) ? $_[0]->{bill_now} : ''; $invoice_terms = exists($_[0]->{invoice_terms}) ? $_[0]->{invoice_terms} : ''; $locationnum = $_[0]->{locationnum} || $self->ship_locationnum; - } else { + $separate_bill = $_[0]->{separate_bill} || ''; + } else { # yuck $amount = shift; $setup_cost = ''; $quantity = 1; @@ -3223,6 +3225,7 @@ sub charge { 'quantity' => $quantity, 'start_date' => $start_date, 'no_auto' => $no_auto, + 'separate_bill' => $separate_bill, 'locationnum'=> $locationnum, } ); diff --git a/FS/FS/cust_main/Billing.pm b/FS/FS/cust_main/Billing.pm index b3d4e705f..87499a91a 100644 --- a/FS/FS/cust_main/Billing.pm +++ b/FS/FS/cust_main/Billing.pm @@ -518,13 +518,36 @@ sub bill { push @{ $cust_bill_pkg{$pass} }, @transfer_items; # treating this as recur, just because most charges are recur... ${$total_recur{$pass}} += $_->recur foreach @transfer_items; + + # currently not considering separate_bill here, as it's for + # one-time charges only } foreach my $part_pkg ( @part_pkg ) { $cust_pkg->set($_, $hash{$_}) foreach qw ( setup last_bill bill ); - my $pass = ($cust_pkg->no_auto || $part_pkg->no_auto) ? 'no_auto' : ''; + my $pass = ''; + if ( $cust_pkg->separate_bill ) { + # if no_auto is also set, that's fine. we just need to not have + # invoices that are both auto and no_auto, and since the package + # gets an invoice all to itself, it will only be one or the other. + $pass = $cust_pkg->pkgnum; + if (!exists $cust_bill_pkg{$pass}) { # it may not exist yet + push @passes, $pass; + $total_setup{$pass} = do { my $z = 0; \$z }; + $total_recur{$pass} = do { my $z = 0; \$z }; + # it also needs its own tax context + $tax_engines{$pass} = FS::TaxEngine->new( + cust_main => $self, + invoice_time => $invoice_time, + cancel => $options{cancel} + ); + $cust_bill_pkg{$pass} = []; + } + } elsif ( ($cust_pkg->no_auto || $part_pkg->no_auto) ) { + $pass = 'no_auto'; + } my $next_bill = $cust_pkg->getfield('bill') || 0; my $error; @@ -566,13 +589,7 @@ sub bill { } #foreach my $cust_pkg - #if the customer isn't on an automatic payby, everything can go on a single - #invoice anyway? - #if ( $cust_main->payby !~ /^(CARD|CHEK)$/ ) { - #merge everything into one list - #} - - foreach my $pass (@passes) { # keys %cust_bill_pkg ) { + foreach my $pass (@passes) { # keys %cust_bill_pkg ) my @cust_bill_pkg = _omit_zero_value_bundles(@{ $cust_bill_pkg{$pass} }); diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm index e8f9aee8e..8274b3d7a 100644 --- a/FS/FS/cust_pay.pm +++ b/FS/FS/cust_pay.pm @@ -716,13 +716,22 @@ sub send_receipt { 'custnum' => $cust_main->custnum, }; - $error = $queue->insert( + my %opt = ( 'invnum' => $cust_bill->invnum, - 'template' => 'statement', - 'notice_name' => 'Statement', 'no_coupon' => 1, ); + if ( my $mode = $conf->config('payment_receipt_statement_mode') ) { + $opt{'mode'} = $mode; + } else { + # backward compatibility, no good fix for this yet as some people may + # still have "invoice_latex_statement" and such options + $opt{'template'} = 'statement'; + $opt{'notice_name'} = 'Statement'; + } + + $error = $queue->insert(%opt); + } warn "send_receipt: $error\n" if $error; diff --git a/FS/FS/cust_pkg.pm b/FS/FS/cust_pkg.pm index b64d4dc38..ae86ca088 100644 --- a/FS/FS/cust_pkg.pm +++ b/FS/FS/cust_pkg.pm @@ -667,8 +667,9 @@ sub check { || $self->ut_numbern('resume') || $self->ut_numbern('expire') || $self->ut_numbern('dundate') - || $self->ut_enum('no_auto', [ '', 'Y' ]) - || $self->ut_enum('waive_setup', [ '', 'Y' ]) + || $self->ut_flag('no_auto', [ '', 'Y' ]) + || $self->ut_flag('waive_setup', [ '', 'Y' ]) + || $self->ut_flag('separate_bill') || $self->ut_textn('agent_pkgid') || $self->ut_enum('recur_show_zero', [ '', 'Y', 'N', ]) || $self->ut_enum('setup_show_zero', [ '', 'Y', 'N', ]) @@ -1065,7 +1066,8 @@ sub uncancel { setup susp adjourn resume expire start_date contract_end dundate change_date change_pkgpart change_locationnum - manual_flag no_auto quantity agent_pkgid recur_show_zero setup_show_zero + manual_flag no_auto separate_bill quantity agent_pkgid + recur_show_zero setup_show_zero ), }; @@ -2408,6 +2410,7 @@ and, I: - start_date: the date when it will be billed - amount: the setup fee to be charged - quantity: the multiplier for the setup fee +- separate_bill: whether to put the charge on a separate invoice If you pass 'adjust_commission' => 1, and the classnum changes, and there are commission credits linked to this charge, they will be recalculated. @@ -2463,7 +2466,8 @@ sub modify_charge { } if ( !$self->get('setup') ) { - # not yet billed, so allow amount, setup_cost, quantity and start_date + # not yet billed, so allow amount, setup_cost, quantity, start_date, + # and separate_bill if ( exists($opt{'amount'}) and $part_pkg->option('setup_fee') != $opt{'amount'} @@ -2493,6 +2497,12 @@ sub modify_charge { $self->set('start_date', $opt{'start_date'}); } + if ( exists($opt{'separate_bill'}) + and $opt{'separate_bill'} ne $self->separate_bill ) { + + $self->set('separate_bill', $opt{'separate_bill'}); + } + } # else simply ignore them; the UI shouldn't allow editing the fields diff --git a/FS/FS/detail_format.pm b/FS/FS/detail_format.pm index e49a9f94b..be84680f9 100644 --- a/FS/FS/detail_format.pm +++ b/FS/FS/detail_format.pm @@ -63,13 +63,13 @@ sub new { my %opt = @_; my $locale = $opt{'locale'} || ''; - my $conf = FS::Conf->new(locale => $locale); + my $conf = FS::Conf->new({ locale => $locale }); $locale ||= $conf->config('locale') || 'en_US'; my %locale_info = FS::Locales->locale_info($locale); my $language_name = $locale_info{'name'}; - my $self = { conf => FS::Conf->new(locale => $locale), + my $self = { conf => FS::Conf->new({ locale => $locale }), csv => Text::CSV_XS->new({ binary => 1 }), inbound => ($opt{'inbound'} ? 1 : 0), buffer => ($opt{'buffer'} || []), diff --git a/FS/FS/msg_template.pm b/FS/FS/msg_template.pm index 94d478f6f..9599e4f2b 100644 --- a/FS/FS/msg_template.pm +++ b/FS/FS/msg_template.pm @@ -601,8 +601,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 diff --git a/FS/FS/part_pkg_taxproduct.pm b/FS/FS/part_pkg_taxproduct.pm index c12a432a3..e86d0285a 100644 --- a/FS/FS/part_pkg_taxproduct.pm +++ b/FS/FS/part_pkg_taxproduct.pm @@ -153,7 +153,11 @@ sub part_pkg_taxrate { map { $_->taxproductnum } $self->expand_cch_taxproduct ); - $extra_sql .= "AND taxproductnum IN($tpnums)"; + + # if there are no taxproductnums, there are no matching tax classes + return if length($tpnums) == 0; + + $extra_sql .= " AND taxproductnum IN($tpnums)"; my $addl_from = 'LEFT JOIN part_pkg_taxproduct USING ( taxproductnum )'; my $order_by = 'ORDER BY taxclassnum, length(geocode) desc, length(taxproduct) desc'; diff --git a/httemplate/edit/process/quick-charge.cgi b/httemplate/edit/process/quick-charge.cgi index aa6010ef9..c1e7fc159 100644 --- a/httemplate/edit/process/quick-charge.cgi +++ b/httemplate/edit/process/quick-charge.cgi @@ -93,6 +93,7 @@ if ( $param->{'pkgnum'} =~ /^(\d+)$/ ) { #modifying an existing one-time charge 'tax_override' => $override, 'quantity' => $quantity, 'start_date' => $start_date, + 'separate_bill' => scalar($cgi->param('separate_bill')), ); } else { # the usual case: new one-time charge @@ -138,6 +139,7 @@ if ( $param->{'pkgnum'} =~ /^(\d+)$/ ) { #modifying an existing one-time charge : '' ), 'no_auto' => scalar($cgi->param('no_auto')), + 'separate_bill' => scalar($cgi->param('separate_bill')), 'pkg' => scalar($cgi->param('pkg')), 'setuptax' => scalar($cgi->param('setuptax')), 'taxclass' => scalar($cgi->param('taxclass')), diff --git a/httemplate/edit/quick-charge.html b/httemplate/edit/quick-charge.html index 58c1b0a82..78752c081 100644 --- a/httemplate/edit/quick-charge.html +++ b/httemplate/edit/quick-charge.html @@ -169,18 +169,22 @@ function bill_now_changed (what) { noinit => 1, } &> -% } -% unless ($billed) { - - <% mt('Tax exempt') |h %> - param('setuptax') ? 'CHECKED' : '' %>> - + <& /elements/tr-checkbox.html, + label => emt('Invoice this charge separately'), + field => 'separate_bill', + value => 'Y', + curr_value => $cust_pkg->get('separate_bill'), + &> + + <% mt('Tax exempt') |h %> + param('setuptax') ? 'CHECKED' : '' %>> + -<& /elements/tr-select-taxclass.html, 'curr_value' => $part_pkg->get('taxclass') &> + <& /elements/tr-select-taxclass.html, 'curr_value' => $part_pkg->get('taxclass') &> -<& /elements/tr-select-taxproduct.html, 'label' => emt('Tax product'), 'onclick' => 'parent.taxproductmagic(this);', 'curr_value' => $part_pkg->get('taxproductnum') &> -% } + <& /elements/tr-select-taxproduct.html, 'label' => emt('Tax product'), 'onclick' => 'parent.taxproductmagic(this);', 'curr_value' => $part_pkg->get('taxproductnum') &> +% } % } else { # new one-time charge @@ -280,6 +284,12 @@ function bill_now_changed (what) { }); +<& /elements/tr-checkbox.html, + label => emt('Invoice this charge separately'), + field => 'separate_bill', + value => 'Y' +&> + % } % if ( ! $quotationnum && $cust_main->payby =~ /^(CARD|CHEK)$/ ) { diff --git a/httemplate/view/cust_main/packages/package.html b/httemplate/view/cust_main/packages/package.html index e47d891f5..3036f2e84 100644 --- a/httemplate/view/cust_main/packages/package.html +++ b/httemplate/view/cust_main/packages/package.html @@ -370,7 +370,7 @@ sub onetime_change_link { 'actionlabel' => emt('Modify'), 'cust_pkg' => $cust_pkg, 'width' => 690, - 'height' => 380, + 'height' => 440, ); } diff --git a/httemplate/view/cust_main/packages/status.html b/httemplate/view/cust_main/packages/status.html index 36419646c..2bb4befb8 100644 --- a/httemplate/view/cust_main/packages/status.html +++ b/httemplate/view/cust_main/packages/status.html @@ -69,6 +69,8 @@ <% pkg_status_row_noauto( $cust_pkg, %opt ) %> + <% pkg_status_row_separate_bill( $cust_pkg, %opt ) %> + <% pkg_status_row_discount( $cust_pkg, %opt ) %> % unless ( $cust_pkg->order_date eq $cust_pkg->get('susp') ) { #on hold @@ -144,6 +146,8 @@ <% pkg_status_row_noauto( $cust_pkg, %opt ) %> + <% pkg_status_row_separate_bill( $cust_pkg, %opt ) %> + <% pkg_status_row_discount( $cust_pkg, %opt ) %> <% pkg_status_row_if( @@ -174,6 +178,8 @@ <% pkg_status_row_noauto( $cust_pkg, %opt ) %> + <% pkg_status_row_separate_bill( $cust_pkg, %opt ) %> + <% pkg_status_row_discount( $cust_pkg, %opt ) %> <% pkg_status_row_if($cust_pkg, emt('Start billing'), 'start_date', %opt) %> @@ -191,6 +197,8 @@ <% pkg_status_row_noauto( $cust_pkg, %opt ) %> + <% pkg_status_row_separate_bill( $cust_pkg, %opt ) %> + <% pkg_status_row_discount( $cust_pkg, %opt ) %> <% pkg_status_row_if($cust_pkg, emt('Un-cancelled'), 'uncancel', %opt ) %> @@ -224,6 +232,8 @@ <% pkg_status_row_noauto( $cust_pkg, %opt ) %> + <% pkg_status_row_separate_bill( $cust_pkg, %opt ) %> + <% pkg_status_row_discount( $cust_pkg, %opt ) %> <% pkg_status_row($cust_pkg, emt('Setup'), 'setup', %opt) %> @@ -496,6 +506,12 @@ sub pkg_status_row_noauto { pkg_status_row_colspan( $cust_pkg, emt("No automatic $what charge"), ''); } +sub pkg_status_row_separate_bill { + my $cust_pkg = shift; + return '' unless $cust_pkg->separate_bill; + pkg_status_row_colspan( $cust_pkg, emt("Invoiced separately") ); +} + sub pkg_status_row_discount { my( $cust_pkg, %opt ) = @_;