X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=blobdiff_plain;f=FS%2FFS%2Fcust_bill.pm;h=f10a5d0c42226818e45a8c35dc735be9cc353536;hp=cec79353982af404d50e5a01abfab45d5852ab1b;hb=08b36523ebbf6e2995878f26bfac988f32f7a218;hpb=cf49d3c860a2000cfc23a0e0db472a7d6fc58935 diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index cec793539..f10a5d0c4 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -1,7 +1,7 @@ package FS::cust_bill; use strict; -use vars qw( @ISA $DEBUG $me $conf $money_char ); +use vars qw( @ISA $DEBUG $me $conf $money_char $date_format $rdate_format ); use vars qw( $invoice_lines @buf ); #yuck use Fcntl qw(:flock); #for spool_csv use List::Util qw(min max); @@ -43,7 +43,9 @@ $me = '[FS::cust_bill]'; #ask FS::UID to run this stuff for us later FS::UID->install_callback( sub { $conf = new FS::Conf; - $money_char = $conf->config('money_char') || '$'; + $money_char = $conf->config('money_char') || '$'; + $date_format = $conf->config('date_format') || '%x'; + $rdate_format = $conf->config('date_format') || '%m/%d/%Y'; } ); =head1 NAME @@ -354,11 +356,24 @@ this invoice. sub cust_pkg { my $self = shift; - my @cust_pkg = map { $_->cust_pkg } $self->cust_bill_pkg; + my @cust_pkg = map { $_->pkgnum > 0 ? $_->cust_pkg : () } + $self->cust_bill_pkg; my %saw = (); grep { ! $saw{$_->pkgnum}++ } @cust_pkg; } +=item no_auto + +Returns true if any of the packages (or their definitions) corresponding to the +line items for this invoice have the no_auto flag set. + +=cut + +sub no_auto { + my $self = shift; + grep { $_->no_auto || $_->part_pkg->no_auto } $self->cust_pkg; +} + =item open_cust_bill_pkg Returns the open line items for this invoice. @@ -1897,6 +1912,14 @@ sub realtime_bop { $cust_main->realtime_bop($method, $amount, 'description' => $description, 'invnum' => $self->invnum, +#this didn't do what we want, it just calls apply_payments_and_credits +# 'apply' => 1, + 'apply_to_invoice' => 1, + #what we want: + #this changes application behavior: auto payments + #triggered against a specific invoice are now applied + #to that invoice instead of oldest open. + #seem okay to me... ); } @@ -2292,7 +2315,7 @@ sub print_generic { 'template' => $template, #params{'template'}, 'notice_name' => ($params{'notice_name'} || 'Invoice'),#escape_function? 'current_charges' => sprintf("%.2f", $self->charged), - 'duedate' => $self->due_date2str('%m/%d/%Y'), #date_format? + 'duedate' => $self->due_date2str($rdate_format), #date_format? #customer info 'custnum' => $cust_main->display_custnum, @@ -2306,6 +2329,7 @@ sub print_generic { 'unitprices' => $conf->exists('invoice-unitprice'), 'smallernotes' => $conf->exists('invoice-smallernotes'), 'smallerfooter' => $conf->exists('invoice-smallerfooter'), + 'balance_due_below_line' => $conf->exists('balance_due_below_line'), # better hang on to conf_dir for a while (for old templates) 'conf_dir' => "$FS::UID::conf_dir/conf.$FS::UID::datasrc", @@ -2459,6 +2483,11 @@ sub print_generic { sprintf('%.2f', $pr_total), 'summarized' => $summarypage ? 'Y' : '', }; + $previous_section->{posttotal} = '0 / 30 / 60/ 90 days overdue '. + join(' / ', map { $cust_main->balance_date_range(@$_) } + $self->_prior_month30s + ) + if $conf->exists('invoice_include_aging'); my $taxtotal = 0; my $tax_section = { 'description' => 'Taxes, Surcharges, and Fees', @@ -2485,6 +2514,7 @@ sub print_generic { my $unsquelched = $params{unsquelch_cdr} || $cust_main->squelch_cdr ne 'Y'; my $multisection = $conf->exists('invoice_sections', $cust_main->agentnum); + $invoice_data{'multisection'} = $multisection; my $late_sections = []; my $extra_sections = []; my $extra_lines = (); @@ -2572,6 +2602,7 @@ sub print_generic { ); } + my $multilocation = scalar($cust_main->cust_location); #too expensive? my %options = (); $options{'section'} = $section if $multisection; $options{'format'} = $format; @@ -2581,6 +2612,7 @@ sub print_generic { $options{'summary_page'} = $summarypage; $options{'skip_usage'} = scalar(@$extra_sections) && !grep{$section == $_} @$extra_sections; + $options{'multilocation'} = $multilocation; foreach my $line_item ( $self->_items_pkg(%options) ) { my $detail = { @@ -2622,7 +2654,9 @@ sub print_generic { $invoice_data{current_less_finance} = sprintf('%.2f', $self->charged - $invoice_data{finance_amount} ); - if ( $multisection && !$conf->exists('disable_previous_balance') ) { + if ( $multisection && !$conf->exists('disable_previous_balance') + || $conf->exists('previous_balance-summary_only') ) + { unshift @sections, $previous_section if $pr_total; } @@ -2689,17 +2723,19 @@ sub print_generic { { my $total = {}; - $total->{'total_item'} = &$embolden_function('Total'); + my $item = 'Total'; + $item = $conf->config('previous_balance-exclude_from_total') + || 'Total New Charges' + if $conf->exists('previous_balance-exclude_from_total'); + my $amount = $self->charged + + ( $conf->exists('disable_previous_balance') || + $conf->exists('previous_balance-exclude_from_total') + ? 0 + : $pr_total + ); + $total->{'total_item'} = &$embolden_function($item); $total->{'total_amount'} = - &$embolden_function( - $other_money_char. - sprintf( '%.2f', - $self->charged + ( $conf->exists('disable_previous_balance') - ? 0 - : $pr_total - ) - ) - ); + &$embolden_function( $other_money_char. sprintf( '%.2f', $amount ) ); if ( $multisection ) { if ( $adjust_section->{'sort_weight'} ) { $adjust_section->{'posttotal'} = 'Balance Forward '. $other_money_char. @@ -2712,14 +2748,9 @@ sub print_generic { push @total_items, $total; } push @buf,['','-----------']; - push @buf,['Total Charges', + push @buf,[$item, $money_char. - sprintf( '%10.2f', $self->charged + - ( $conf->exists('disable_previous_balance') - ? 0 - : $pr_total - ) - ) + sprintf( '%10.2f', $amount ) ]; push @buf,['','']; } @@ -2927,6 +2958,22 @@ sub print_generic { } } +# helper routine for generating date ranges +sub _prior_month30s { + my $self = shift; + my @ranges = ( + [ 1, 2592000 ], # 0-30 days ago + [ 2592000, 5184000 ], # 30-60 days ago + [ 5184000, 7776000 ], # 60-90 days ago + [ 7776000, 0 ], # 90+ days ago + ); + + map { [ $_->[0] ? $self->_date - $_->[0] - 1 : '', + $_->[1] ? $self->_date - $_->[1] - 1 : '', + ] } + @ranges; +} + =item print_ps HASHREF | [ TIME [ , TEMPLATE ] ] Returns an postscript invoice, as a scalar. @@ -3127,7 +3174,7 @@ sub balance_due_msg { my $msg = 'Balance Due'; return $msg unless $self->terms; if ( $self->due_date ) { - $msg .= ' - Please pay by '. $self->due_date2str('%x'); + $msg .= ' - Please pay by '. $self->due_date2str($date_format); } elsif ( $self->terms ) { $msg .= ' - '. $self->terms; } @@ -3139,7 +3186,7 @@ sub balance_due_date { my $duedate = ''; if ( $conf->exists('invoice_default_terms') && $conf->config('invoice_default_terms')=~ /^\s*Net\s*(\d+)\s*$/ ) { - $duedate = time2str("%m/%d/%Y", $self->_date + ($1*86400) ); + $duedate = time2str($rdate_format, $self->_date + ($1*86400) ); } $duedate; } @@ -3164,7 +3211,7 @@ Returns a string with the date, for example: "3/20/2008" sub _date_pretty { my $self = shift; - time2str('%x', $self->_date); + time2str($date_format, $self->_date); } use vars qw(%pkg_category_cache); @@ -3797,9 +3844,11 @@ sub _items_previous { my( $pr_total, @pr_cust_bill ) = $self->previous; #previous balance my @b = (); foreach ( @pr_cust_bill ) { + my $date = $conf->exists('invoice_show_prior_due_date') + ? 'due '. $_->due_date2str($date_format) + : time2str($date_format, $_->_date); push @b, { - 'description' => 'Previous Balance, Invoice #'. $_->invnum. - ' ('. time2str('%x',$_->_date). ')', + 'description' => 'Previous Balance, Invoice #'. $_->invnum. " ($date)", #'pkgpart' => 'N/A', 'pkgnum' => 'N/A', 'amount' => sprintf("%.2f", $_->owed), @@ -3875,13 +3924,14 @@ sub _items_cust_bill_pkg { my $unsquelched = $opt{unsquelched} || ''; my $section = $opt{section}->{description} if $opt{section}; my $summary_page = $opt{summary_page} || ''; + my $multilocation = $opt{multilocation} || ''; my @b = (); my ($s, $r, $u) = ( undef, undef, undef ); foreach my $cust_bill_pkg ( @$cust_bill_pkg ) { - foreach ( $s, $r, ($opt{skip_usage} ? $u : () ) ) { + foreach ( $s, $r, ($opt{skip_usage} ? () : $u ) ) { if ( $_ && !$cust_bill_pkg->hidden ) { $_->{amount} = sprintf( "%.2f", $_->{amount} ), $_->{amount} =~ s/^\-0\.00$/0.00/; @@ -3922,10 +3972,18 @@ sub _items_cust_bill_pkg { $description .= ' Setup' if $cust_bill_pkg->recur != 0; my @d = (); - push @d, map &{$escape_function}($_), - $cust_pkg->h_labels_short($self->_date) - unless $cust_pkg->part_pkg->hide_svc_detail - || $cust_bill_pkg->hidden; + unless ( $cust_pkg->part_pkg->hide_svc_detail + || $cust_bill_pkg->hidden ) + { + push @d, map &{$escape_function}($_), + $cust_pkg->h_labels_short($self->_date); + if ( $multilocation ) { + my $loc = $cust_pkg->location_label; + $loc = substr($desc, 0, 50). '...' + if $format eq 'latex' && length($loc) > 50; + push @d, &{$escape_function}($loc); + } + } push @d, $cust_bill_pkg->details(%details_opt) if $cust_bill_pkg->recur == 0; @@ -3957,8 +4015,8 @@ sub _items_cust_bill_pkg { ? "Usage charges" : $desc; unless ( $conf->exists('disable_line_item_date_ranges') ) { - $description .= " (" . time2str("%x", $cust_bill_pkg->sdate). - " - ". time2str("%x", $cust_bill_pkg->edate). ")"; + $description .= " (" . time2str($date_format, $cust_bill_pkg->sdate). + " - ". time2str($date_format, $cust_bill_pkg->edate). ")"; } my @d = (); @@ -3969,14 +4027,23 @@ sub _items_cust_bill_pkg { my $prev = $cust_bill_pkg->previous_cust_bill_pkg; push @dates, $prev->sdate if $prev; - push @d, map &{$escape_function}($_), - $cust_pkg->h_labels_short(@dates) - #$cust_bill_pkg->edate, - #$cust_bill_pkg->sdate) - unless $cust_pkg->part_pkg->hide_svc_detail + unless ( $cust_pkg->part_pkg->hide_svc_detail || $cust_bill_pkg->itemdesc || $cust_bill_pkg->hidden - || $is_summary && $type && $type eq 'U'; + || $is_summary && $type && $type eq 'U' ) + { + push @d, map &{$escape_function}($_), + $cust_pkg->h_labels_short(@dates) + #$cust_bill_pkg->edate, + #$cust_bill_pkg->sdate) + ; + if ( $multilocation ) { + my $loc = $cust_pkg->location_label; + $loc = substr($desc, 0, 50). '...' + if $format eq 'latex' && length($loc) > 50; + push @d, &{$escape_function}($loc); + } + } push @d, $cust_bill_pkg->details(%details_opt) unless ($is_summary || $type && $type eq 'R'); @@ -4041,8 +4108,8 @@ sub _items_cust_bill_pkg { if ( $cust_bill_pkg->recur != 0 ) { push @b, { 'description' => "$desc (". - time2str("%x", $cust_bill_pkg->sdate). ' - '. - time2str("%x", $cust_bill_pkg->edate). ')', + time2str($date_format, $cust_bill_pkg->sdate). ' - '. + time2str($date_format, $cust_bill_pkg->edate). ')', 'amount' => sprintf("%.2f", $cust_bill_pkg->recur), }; } @@ -4053,7 +4120,7 @@ sub _items_cust_bill_pkg { } - foreach ( $s, $r, ($opt{skip_usage} ? $u : () ) ) { + foreach ( $s, $r, ($opt{skip_usage} ? () : $u ) ) { if ( $_ ) { $_->{amount} = sprintf( "%.2f", $_->{amount} ), $_->{amount} =~ s/^\-0\.00$/0.00/; @@ -4086,7 +4153,7 @@ sub _items_credits { # " (". time2str("%x",$_->cust_credit->_date) .")". # $reason, 'description' => 'Credit applied '. - time2str("%x",$_->cust_credit->_date). $reason, + time2str($date_format,$_->cust_credit->_date). $reason, 'amount' => sprintf("%.2f",$_->amount), }; } @@ -4106,7 +4173,7 @@ sub _items_payments { push @b, { 'description' => "Payment received ". - time2str("%x",$_->cust_pay->_date ), + time2str($date_format,$_->cust_pay->_date ), 'amount' => sprintf("%.2f", $_->amount ) }; } @@ -4275,7 +4342,10 @@ Returns an SQL fragment to retreive the amount owed (charged minus credited and sub owed_sql { my $class = shift; - 'charged - '. $class->paid_sql. ' - '. $class->credited_sql; + my ($start, $end) = @_; + 'charged - '. + $class->paid_sql($start, $end). ' - '. + $class->credited_sql($start, $end); } =item net_sql @@ -4286,7 +4356,8 @@ Returns an SQL fragment to retreive the net amount (charged minus credited). sub net_sql { my $class = shift; - 'charged - '. $class->credited_sql; + my ($start, $end) = @_; + 'charged - '. $class->credited_sql($start, $end); } =item paid_sql @@ -4296,9 +4367,11 @@ Returns an SQL fragment to retreive the amount paid against this invoice. =cut sub paid_sql { - #my $class = shift; + my ($class, $start, $end) = @_; + $start &&= "AND cust_bill_pay._date <= $start"; + $end &&= "AND cust_bill_pay._date > $end"; "( SELECT COALESCE(SUM(amount),0) FROM cust_bill_pay - WHERE cust_bill.invnum = cust_bill_pay.invnum )"; + WHERE cust_bill.invnum = cust_bill_pay.invnum $start $end )"; } =item credited_sql @@ -4308,9 +4381,11 @@ Returns an SQL fragment to retreive the amount credited against this invoice. =cut sub credited_sql { - #my $class = shift; + my ($class, $start, $end) = shift; + $start &&= "AND cust_credit_bill._date <= $start"; + $end &&= "AND cust_credit_bill._date > $end"; "( SELECT COALESCE(SUM(amount),0) FROM cust_credit_bill - WHERE cust_bill.invnum = cust_credit_bill.invnum )"; + WHERE cust_bill.invnum = cust_credit_bill.invnum $start $end )"; } =item search_sql_where HASHREF