X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_bill.pm;h=2d937a8277d6bd14be5d2946bb4c4fc084f628e5;hb=a90d069b1f1d814a91bf7cb3eb0d7ac9fdec7e08;hp=0de124c55e4e87b793916cf17db07b03ec7826b5;hpb=0369284202cb5f0beeaf8a829ac98db925422e75;p=freeside.git diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 0de124c55..2d937a827 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -215,6 +215,7 @@ FS::cust_bill_pkg_void). sub void { my $self = shift; my $reason = scalar(@_) ? shift : ''; + my $reprocess_cdrs = scalar(@_) ? shift : ''; local $SIG{HUP} = 'IGNORE'; local $SIG{INT} = 'IGNORE'; @@ -238,7 +239,7 @@ sub void { } foreach my $cust_bill_pkg ( $self->cust_bill_pkg ) { - my $error = $cust_bill_pkg->void($reason); + my $error = $cust_bill_pkg->void($reason, $reprocess_cdrs); if ( $error ) { $dbh->rollback if $oldAutoCommit; return $error; @@ -486,7 +487,13 @@ Returns the line items (see L) for this invoice. sub cust_bill_pkg { my $self = shift; qsearch( - { 'table' => 'cust_bill_pkg', + { + 'select' => 'cust_bill_pkg.*, pkg_category.categoryname', + 'table' => 'cust_bill_pkg', + 'addl_from' => ' LEFT JOIN cust_pkg USING ( pkgnum ) '. + ' LEFT JOIN part_pkg USING ( pkgpart ) '. + ' LEFT JOIN pkg_class USING ( classnum ) '. + ' LEFT JOIN pkg_category USING ( categorynum ) ', 'hashref' => { 'invnum' => $self->invnum }, 'order_by' => 'ORDER BY billpkgnum', } @@ -913,6 +920,7 @@ sub hide { =item apply_payments_and_credits [ OPTION => VALUE ... ] Applies unapplied payments and credits to this invoice. +Payments with the no_auto_apply flag set will not be applied. A hash of optional arguments may be passed. Currently "manual" is supported. If true, a payment receipt is sent instead of a statement when @@ -939,7 +947,9 @@ sub apply_payments_and_credits { $self->select_for_update; #mutex - my @payments = grep { $_->unapplied > 0 } $self->cust_main->cust_pay; + my @payments = grep { $_->unapplied > 0 } + grep { !$_->no_auto_apply } + $self->cust_main->cust_pay; my @credits = grep { $_->credited > 0 } $self->cust_main->cust_credit; if ( $conf->exists('pkg-balances') ) { @@ -1125,9 +1135,8 @@ 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}); - } + $self->set('mode', $opt{mode}) + if $opt{mode}; my %args = map {$_ => $opt{$_}} grep { $opt{$_} } @@ -1157,6 +1166,11 @@ sub email_subject { eval qq("$subject"); } +sub pdf_filename { + my $self = shift; + 'Invoice-'. $self->invnum. '.pdf'; +} + =item lpr_data HASHREF Returns the postscript or plaintext for this invoice as an arrayref. @@ -1268,6 +1282,10 @@ sub batch_invoice { batchnum => $bill_batch->batchnum, invnum => $self->invnum, }); + if ( $self->mode ) { + $opt->{mode} ||= $self->mode; + $opt->{mode} = $opt->{mode}->modenum if ref $opt->{mode}; + } return $cust_bill_batch->insert($opt); } @@ -2696,10 +2714,12 @@ sub _items_usage_class_summary { my %opt = @_; my $escape = $opt{escape} || sub { $_[0] }; + my $money_char = $opt{money_char}; my $invnum = $self->invnum; my @classes = qsearch({ 'table' => 'usage_class', - 'select' => 'classnum, classname, SUM(amount) AS amount', + 'select' => 'classnum, classname, SUM(amount) AS amount,'. + ' COUNT(*) AS calls, SUM(duration) AS duration', 'addl_from' => ' LEFT JOIN cust_bill_pkg_detail USING (classnum)' . ' LEFT JOIN cust_bill_pkg USING (billpkgnum)', 'extra_sql' => " WHERE cust_bill_pkg.invnum = $invnum". @@ -2710,17 +2730,21 @@ sub _items_usage_class_summary { my @l; my $section = { description => &{$escape}($self->mt('Usage Summary')), - no_subtotal => 1, usage_section => 1, + subtotal => 0, }; foreach my $class (@classes) { + $section->{subtotal} += $class->get('amount'); push @l, { 'description' => &{$escape}($class->classname), - 'amount' => sprintf('%.2f', $class->amount), + 'amount' => $money_char.sprintf('%.2f', $class->get('amount')), + 'quantity' => $class->get('calls'), + 'duration' => $class->get('duration'), 'usage_classnum' => $class->classnum, 'section' => $section, }; } + $section->{subtotal} = $money_char.sprintf('%.2f', $section->{subtotal}); return @l; } @@ -2862,38 +2886,50 @@ sub _items_total { my @items; my ($pr_total) = $self->previous; - my ($new_charges_desc, $new_charges_amount); + my ($previous_charges_desc, $new_charges_desc, $new_charges_amount); if ( $conf->exists('previous_balance-exclude_from_total') ) { + # if enabled, specifically add a line for the previous balance total + $previous_charges_desc = $self->mt( + $conf->config('previous_balance-text') || 'Previous Balance' + ); + # then return separate lines for previous balance and total new charges if ( $pr_total ) { push @items, - { total_item => $self->mt('Previous Balance'), + { total_item => $previous_charges_desc, total_amount => sprintf('%.2f',$pr_total) }; } + } + + if ( $conf->exists('previous_balance-exclude_from_total') + or !$self->enable_previous ) { + # show new charges only + $new_charges_desc = $self->mt( - $conf->config('previous_balance-exclude_from_total') + $conf->config('previous_balance-text-total_new_charges') || 'Total New Charges' - ); # localize 'Total New Charges' or whatever's in the config + ); $new_charges_amount = $self->charged; } else { + # show new charges + previous invoice total $new_charges_desc = $self->mt('Total Charges'); - $new_charges_amount = sprintf('%.2f',$self->charged + $pr_total); + if ( $self->enable_previous ) { + $new_charges_amount = sprintf('%.2f', $self->charged + $pr_total); + } else { + $new_charges_amount = sprintf('%.2f', $self->charged); + } } - - if ( $conf->exists('invoice_show_prior_due_date') ) { + if ( $conf->exists('invoice_show_prior_due_date') && !$conf->exists('invoice_omit_due_date') ) { # then the due date should be shown with Total New Charges, # and should NOT be shown with the Balance Due message. if ( $self->due_date ) { - # localize the "Please pay by" message and the date itself - # (grammar issues with this, yeah) - $new_charges_desc .= ' - ' . $self->mt('Please pay by') . ' ' . - $self->due_date2str('short'); + $new_charges_desc .= $self->invoice_pay_by_msg; } elsif ( $self->terms ) { # phrases like "due on receipt" should be localized $new_charges_desc .= ' - ' . $self->mt($self->terms); @@ -2910,6 +2946,23 @@ sub _items_total { +=item has_call_details + +Returns true if this invoice has call details. + +=cut + +sub has_call_details { + my $self = shift; + $self->scalar_sql(" + SELECT 1 FROM cust_bill_pkg_detail + LEFT JOIN cust_bill_pkg USING (billpkgnum) + WHERE cust_bill_pkg_detail.format = 'C' + AND cust_bill_pkg.invnum = ? + LIMIT 1 + ", $self->invnum); +} + =item call_details [ OPTION => VALUE ... ] Returns an array of CSV strings representing the call details for this invoice @@ -3007,6 +3060,9 @@ sub process_re_X { } +# this is called from search/cust_bill.html and given all its search +# parameters, so it needs to perform the same search. + sub re_X { # spool_invoice ftp_invoice fax_invoice print_invoice my($method, $job, %param ) = @_; @@ -3016,22 +3072,15 @@ sub re_X { } #some false laziness w/search/cust_bill.html - my $distinct = ''; - my $orderby = 'ORDER BY cust_bill._date'; - - my $extra_sql = ' WHERE '. FS::cust_bill->search_sql_where(\%param); - - my $addl_from = 'LEFT JOIN cust_main USING ( custnum )'; - - my @cust_bill = qsearch( { - #'select' => "cust_bill.*", - 'table' => 'cust_bill', - 'addl_from' => $addl_from, - 'hashref' => {}, - 'extra_sql' => $extra_sql, - 'order_by' => $orderby, - 'debug' => 1, - } ); + $param{'order_by'} = 'cust_bill._date'; + + my $query = FS::cust_bill->search(\%param); + delete $query->{'count_query'}; + delete $query->{'count_addl'}; + + $query->{debug} = 1; # was in here before, is obviously useful + + my @cust_bill = qsearch( $query ); $method .= '_invoice' unless $method eq 'email' || $method eq 'print';