X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_bill.pm;h=e56ddf72d64c495c91059a3a7f99c4b3b191eced;hb=49d30c8722afe66013eeca25b7fb2937d2f34307;hp=96dce2c351e3423be4c5138f7c9a8852e5cf953e;hpb=d586d4ce13fa284146e885f153dba3ae029358a1;p=freeside.git diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 96dce2c35..e56ddf72d 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -377,6 +377,25 @@ sub display_invnum { } } +=item previous_bill + +Returns the customer's last invoice before this one. + +=cut + +sub previous_bill { + my $self = shift; + if ( !$self->get('previous_bill') ) { + $self->set('previous_bill', qsearchs({ + 'table' => 'cust_bill', + 'hashref' => { 'custnum' => $self->custnum, + '_date' => { op=>'<', value=>$self->_date } }, + 'order_by' => 'ORDER BY _date DESC LIMIT 1', + }) ); + } + $self->get('previous_bill'); +} + =item previous Returns a list consisting of the total previous balance for this customer, @@ -388,8 +407,11 @@ sub previous { my $self = shift; my $total = 0; my @cust_bill = sort { $a->_date <=> $b->_date } - grep { $_->owed != 0 && $_->_date < $self->_date } - qsearch( 'cust_bill', { 'custnum' => $self->custnum } ) + grep { $_->owed != 0 } + qsearch( 'cust_bill', { 'custnum' => $self->custnum, + #'_date' => { op=>'<', value=>$self->_date }, + 'invnum' => { op=>'<', value=>$self->invnum }, + } ) ; foreach ( @cust_bill ) { $total += $_->owed; } $total, @cust_bill; @@ -1538,7 +1560,10 @@ sub print { $self->batch_invoice(\%opt); } else { - do_print $self->lpr_data(\%opt); + do_print( + $self->lpr_data(\%opt), + 'agentnum' => $self->cust_main->agentnum, + ); } } @@ -2024,12 +2049,16 @@ sub print_csv { } elsif ( lc($opt{'format'}) eq 'oneline' ) { #name? my ($previous_balance) = $self->previous; + $previous_balance = sprintf('%.2f', $previous_balance); my $totaldue = sprintf('%.2f', $self->owed + $previous_balance); my @items = map { - ($_->{pkgnum} || ''), - $_->{description}, - $_->{amount} - } $self->_items_pkg; + $_->{pkgnum}, + $_->{description}, + $_->{amount} + } + $self->_items_pkg, #_items_nontax? no sections or anything + # with this format + $self->_items_tax; $csv->combine( $cust_main->agentnum, @@ -2037,6 +2066,7 @@ sub print_csv { $self->custnum, $cust_main->first, $cust_main->last, + $cust_main->company, $cust_main->address1, $cust_main->address2, $cust_main->city, @@ -2048,6 +2078,8 @@ sub print_csv { $self->invnum, $self->charged, $totaldue, + $previous_balance, + $self->due_date2str("%x"), @items, ); @@ -2713,6 +2745,7 @@ sub print_generic { #invoice info 'invnum' => $self->invnum, + '_date' => $self->_date, 'date' => time2str($date_format, $self->_date), 'today' => time2str($date_format_long, $today), 'terms' => $self->terms, @@ -2860,10 +2893,9 @@ sub print_generic { # info from customer's last invoice before this one, for some # summary formats $invoice_data{'last_bill'} = {}; - my $last_bill = $pr_cust_bill[-1]; - if ( $last_bill ) { + if ( $self->previous_bill ) { $invoice_data{'last_bill'} = { - '_date' => $last_bill->_date, #unformatted + '_date' => $self->previous_bill->_date, #unformatted # all we need for now }; } @@ -2969,6 +3001,7 @@ sub print_generic { my $taxtotal = 0; my $tax_section = { 'description' => $self->mt('Taxes, Surcharges, and Fees'), 'subtotal' => $taxtotal, # adjusted below + 'tax_section' => 1, }; my $tax_weight = _pkg_category($tax_section->{description}) ? _pkg_category($tax_section->{description})->weight @@ -2978,10 +3011,11 @@ sub print_generic { my $adjusttotal = 0; - my $adjust_section = { 'description' => - $self->mt('Credits, Payments, and Adjustments'), - 'subtotal' => 0, # adjusted below - }; + my $adjust_section = { + 'description' => $self->mt('Credits, Payments, and Adjustments'), + 'adjust_section' => 1, + 'subtotal' => 0, # adjusted below + }; my $adjust_weight = _pkg_category($adjust_section->{description}) ? _pkg_category($adjust_section->{description})->weight : 0; @@ -3064,6 +3098,7 @@ sub print_generic { ext_description => [], }; $detail->{'ref'} = $line_item->{'pkgnum'}; + $detail->{'pkgpart'} = $line_item->{'pkgpart'}; $detail->{'quantity'} = 1; $detail->{'section'} = $multisection ? $previous_section : $default_section; @@ -3162,6 +3197,7 @@ sub print_generic { ext_description => [], }; $detail->{'ref'} = $line_item->{'pkgnum'}; + $detail->{'pkgpart'} = $line_item->{'pkgpart'}; $detail->{'quantity'} = $line_item->{'quantity'}; $detail->{'section'} = $section; $detail->{'description'} = &$escape_function($line_item->{'description'}); @@ -3177,6 +3213,7 @@ sub print_generic { $detail->{'sdate'} = $line_item->{'sdate'}; $detail->{'edate'} = $line_item->{'edate'}; $detail->{'seconds'} = $line_item->{'seconds'}; + $detail->{'svc_label'} = $line_item->{'svc_label'}; push @detail_items, $detail; push @buf, ( [ $detail->{'description'}, @@ -3298,7 +3335,7 @@ sub print_generic { $adjust_section->{'pretotal'} = $self->mt('New charges total').' '. $other_money_char. sprintf('%.2f', $self->charged ); } - }else{ + } else { push @total_items, $total; } push @buf,['','-----------']; @@ -3390,10 +3427,11 @@ sub print_generic { $total->{'total_item'} = &$embolden_function($self->balance_due_msg); $total->{'total_amount'} = &$embolden_function( - $other_money_char. sprintf('%.2f', $summarypage - ? $self->charged + - $self->billing_balance - : $self->owed + $pr_total + $other_money_char. sprintf('%.2f', #why? $summarypage + # ? $self->charged + + # $self->billing_balance + # : + $self->owed + $pr_total ) ); if ( $multisection && !$adjust_section->{sort_weight} ) { @@ -3464,6 +3502,10 @@ sub print_generic { } } @discounts_avail; } + # debugging hook: call this with 'diag' => 1 to just get a hash of + # the invoice variables + return \%invoice_data if ( $params{'diag'} ); + # All sections and items are built; now fill in templates. my @includelist = (); push @includelist, 'summary' if $summarypage; @@ -4984,9 +5026,14 @@ sub _items_cust_bill_pkg { my $cust_pkg = $cust_bill_pkg->cust_pkg; + # which pkgpart to show for display purposes? + my $pkgpart = $cust_bill_pkg->pkgpart_override || $cust_pkg->pkgpart; + # start/end dates for invoice formats that do nonstandard # things with them - my %item_dates = map { $_ => $cust_bill_pkg->$_ } ('sdate', 'edate'); + my %item_dates = (); + %item_dates = map { $_ => $cust_bill_pkg->$_ } ('sdate', 'edate') + unless $cust_pkg->part_pkg->option('disable_line_item_date_ranges',1); if ( (!$type || $type eq 'S') && ( $cust_bill_pkg->setup != 0 @@ -5005,13 +5052,16 @@ sub _items_cust_bill_pkg { || $cust_bill_pkg->recur_show_zero; my @d = (); + my $svc_label; unless ( $cust_pkg->part_pkg->hide_svc_detail || $cust_bill_pkg->hidden ) { - push @d, map &{$escape_function}($_), - $cust_pkg->h_labels_short($self->_date, undef, 'I') + my @svc_labels = map &{$escape_function}($_), + $cust_pkg->h_labels_short($self->_date, undef, 'I'); + push @d, @svc_labels unless $cust_bill_pkg->pkgpart_override; #don't redisplay services + $svc_label = $svc_labels[0]; if ( $multilocation ) { my $loc = $cust_pkg->location_label; @@ -5033,13 +5083,14 @@ sub _items_cust_bill_pkg { $s = { _is_setup => 1, description => $description, - #pkgpart => $part_pkg->pkgpart, + pkgpart => $pkgpart, pkgnum => $cust_bill_pkg->pkgnum, amount => $cust_bill_pkg->setup, setup_show_zero => $cust_bill_pkg->setup_show_zero, unit_amount => $cust_bill_pkg->unitsetup, quantity => $cust_bill_pkg->quantity, ext_description => \@d, + svc_label => ($svc_label || ''), }; }; @@ -5062,14 +5113,23 @@ sub _items_cust_bill_pkg { my $description = ($is_summary && $type && $type eq 'U') ? "Usage charges" : $desc; + my $part_pkg = $cust_pkg->part_pkg; + #pry be a bit more efficient to look some of this conf stuff up # outside the loop unless ( $conf->exists('disable_line_item_date_ranges') - || $cust_pkg->part_pkg->option('disable_line_item_date_ranges',1) + || $part_pkg->option('disable_line_item_date_ranges',1) + || ! $cust_bill_pkg->sdate + || ! $cust_bill_pkg->edate ) { my $time_period; - my $date_style = $conf->config( 'cust_bill-line_item-date_style', + my $date_style = ''; + $date_style = $conf->config( 'cust_bill-line_item-date_style-non_monthly', + $cust_main->agentnum + ) + if $part_pkg && $part_pkg->freq !~ /^1m?$/; + $date_style ||= $conf->config( 'cust_bill-line_item-date_style', $cust_main->agentnum ); if ( defined($date_style) && $date_style eq 'month_of' ) { @@ -5089,6 +5149,7 @@ sub _items_cust_bill_pkg { my @d = (); my @seconds = (); # for display of usage info + my $svc_label = ''; #at least until cust_bill_pkg has "past" ranges in addition to #the "future" sdate/edate ones... see #3032 @@ -5106,11 +5167,11 @@ sub _items_cust_bill_pkg { warn "$me _items_cust_bill_pkg adding service details\n" if $DEBUG > 1; - push @d, map &{$escape_function}($_), - $cust_pkg->h_labels_short(@dates, 'I') - #$cust_bill_pkg->edate, - #$cust_bill_pkg->sdate) + my @svc_labels = map &{$escape_function}($_), + $cust_pkg->h_labels_short(@dates, 'I'); + push @d, @svc_labels unless $cust_bill_pkg->pkgpart_override; #don't redisplay services + $svc_label = $svc_labels[0]; warn "$me _items_cust_bill_pkg done adding service details\n" if $DEBUG > 1; @@ -5181,7 +5242,7 @@ sub _items_cust_bill_pkg { } else { $r = { description => $description, - #pkgpart => $part_pkg->pkgpart, + pkgpart => $pkgpart, pkgnum => $cust_bill_pkg->pkgnum, amount => $amount, recur_show_zero => $cust_bill_pkg->recur_show_zero, @@ -5189,6 +5250,7 @@ sub _items_cust_bill_pkg { quantity => $cust_bill_pkg->quantity, %item_dates, ext_description => \@d, + svc_label => ($svc_label || ''), }; $r->{'seconds'} = \@seconds if grep {defined $_} @seconds; } @@ -5205,7 +5267,7 @@ sub _items_cust_bill_pkg { } else { $u = { description => $description, - #pkgpart => $part_pkg->pkgpart, + pkgpart => $pkgpart, pkgnum => $cust_bill_pkg->pkgnum, amount => $amount, recur_show_zero => $cust_bill_pkg->recur_show_zero, @@ -5274,12 +5336,25 @@ sub _items_credits { my @b; #credits - foreach ( $self->cust_credited ) { + my @objects; + if ( $self->conf->exists('previous_balance-payments_since') ) { + my $date = 0; + $date = $self->previous_bill->_date if $self->previous_bill; + @objects = qsearch('cust_credit', { + 'custnum' => $self->custnum, + '_date' => {op => '>=', value => $date}, + }); + # hard to do this in the qsearch... + @objects = grep { $_->_date < $self->_date } @objects; + } else { + @objects = $self->cust_credited; + } - #something more elaborate if $_->amount ne $_->cust_credit->credited ? + foreach my $obj ( @objects ) { + my $cust_credit = $obj->isa('FS::cust_credit') ? $obj : $obj->cust_credit; - my $reason = substr($_->cust_credit->reason, 0, $trim_len); - $reason .= '...' if length($reason) < length($_->cust_credit->reason); + my $reason = substr($cust_credit->reason, 0, $trim_len); + $reason .= '...' if length($reason) < length($cust_credit->reason); $reason = " ($reason) " if $reason; push @b, { @@ -5287,8 +5362,8 @@ sub _items_credits { # " (". time2str("%x",$_->cust_credit->_date) .")". # $reason, 'description' => $self->mt('Credit applied').' '. - time2str($date_format,$_->cust_credit->_date). $reason, - 'amount' => sprintf("%.2f",$_->amount), + time2str($date_format,$obj->_date). $reason, + 'amount' => sprintf("%.2f",$obj->amount), }; } @@ -5300,15 +5375,31 @@ sub _items_payments { my $self = shift; my @b; - #get & print payments - foreach ( $self->cust_bill_pay ) { + my $detailed = $self->conf->exists('invoice_payment_details'); + my @objects; + if ( $self->conf->exists('previous_balance-payments_since') ) { + my $date = 0; + $date = $self->previous_bill->_date if $self->previous_bill; + @objects = qsearch('cust_pay', { + 'custnum' => $self->custnum, + '_date' => {op => '>=', value => $date}, + }); + @objects = grep { $_->_date < $self->_date } @objects; + } else { + @objects = $self->cust_bill_pay; + } - #something more elaborate if $_->amount ne ->cust_pay->paid ? + foreach my $obj (@objects) { + my $cust_pay = $obj->isa('FS::cust_pay') ? $obj : $obj->cust_pay; + my $desc = $self->mt('Payment received').' '. + time2str($date_format, $cust_pay->_date ); + $desc .= $self->mt(' via ') . + $cust_pay->payby_payinfo_pretty( $self->cust_main->locale ) + if $detailed; push @b, { - 'description' => $self->mt('Payment received').' '. - time2str($date_format,$_->cust_pay->_date ), - 'amount' => sprintf("%.2f", $_->amount ) + 'description' => $desc, + 'amount' => sprintf("%.2f", $obj->amount ) }; } @@ -5656,6 +5747,15 @@ sub search_sql_where { push @search, "cust_bill.custnum = $1"; } + #customer classnum + if ( $param->{'cust_classnum'} ) { + my $classnums = $param->{'cust_classnum'}; + $classnums = [ $classnums ] if !ref($classnums); + $classnums = [ grep /^\d+$/, @$classnums ]; + push @search, 'cust_main.classnum in ('.join(',',@$classnums).')' + if @$classnums; + } + #_date if ( $param->{_date} ) { my($beginning, $ending) = @{$param->{_date}};