X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_bill.pm;h=db909309fa041c29f76a2d72673a18e45fcc8500;hb=f39624dd22a91495798f253aa5f122e05a77bc41;hp=ad60b2108d178ad8d88b72b20b6b2ed17383775b;hpb=03c12b4dabfcaabc218f39ee13557edebc13931d;p=freeside.git diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index ad60b2108..db909309f 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -6,6 +6,7 @@ use base qw( FS::cust_bill::Search FS::Template_Mixin use strict; use vars qw( $DEBUG $me ); # but NOT $conf +use Carp; use Fcntl qw(:flock); #for spool_csv use Cwd; use List::Util qw(min max sum); @@ -26,11 +27,9 @@ use FS::cust_pay; use FS::cust_pkg; use FS::cust_credit_bill; use FS::pay_batch; -use FS::cust_bill_event; use FS::cust_event; use FS::part_pkg; use FS::cust_bill_pay; -use FS::part_bill_event; use FS::payby; use FS::bill_batch; use FS::cust_bill_batch; @@ -144,6 +143,16 @@ Invoices are normally created by calling the bill method of a customer object =cut sub table { 'cust_bill'; } +sub template_conf { 'invoice_'; } + +sub has_sections { + my $self = shift; + my $agentnum = $self->cust_main->agentnum; + my $tc = $self->template_conf; + + $self->conf->exists($tc.'sections', $agentnum) || + $self->conf->exists($tc.'sections_by_location', $agentnum); +} # should be the ONLY occurrence of "Invoice" in invoice rendering code. # (except email_subject and invnum_date_pretty) @@ -285,8 +294,6 @@ sub delete { my $dbh = dbh; foreach my $table (qw( - cust_bill_event - cust_event cust_credit_bill cust_bill_pay cust_pay_batch @@ -294,6 +301,7 @@ sub delete { cust_bill_batch cust_bill_pkg )) { + #cust_event # problematic foreach my $linked ( $self->$table() ) { my $error = $linked->delete; @@ -449,16 +457,20 @@ followed by the previous outstanding invoices (as FS::cust_bill objects also). sub previous { my $self = shift; - my $total = 0; - my @cust_bill = sort { $a->_date <=> $b->_date } - 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; + # simple memoize; we use this a lot + if (!$self->get('previous')) { + my $total = 0; + my @cust_bill = sort { $a->_date <=> $b->_date } + grep { $_->owed != 0 } + qsearch( 'cust_bill', { 'custnum' => $self->custnum, + #'_date' => { op=>'<', value=>$self->_date }, + 'invnum' => { op=>'<', value=>$self->invnum }, + } ) + ; + foreach ( @cust_bill ) { $total += $_->owed; } + $self->set('previous', [$total, @cust_bill]); + } + return @{ $self->get('previous') }; } =item enable_previous @@ -565,32 +577,6 @@ sub open_cust_bill_pkg { @open; } -=item cust_bill_event - -Returns the completed invoice events (deprecated, old-style events - see L) for this invoice. - -=cut - -sub cust_bill_event { - my $self = shift; - qsearch( 'cust_bill_event', { 'invnum' => $self->invnum } ); -} - -=item num_cust_bill_event - -Returns the number of completed invoice events (deprecated, old-style events - see L) for this invoice. - -=cut - -sub num_cust_bill_event { - my $self = shift; - my $sql = - "SELECT COUNT(*) FROM cust_bill_event WHERE invnum = ?"; - my $sth = dbh->prepare($sql) or die dbh->errstr. " preparing $sql"; - $sth->execute($self->invnum) or die $sth->errstr. " executing $sql"; - $sth->fetchrow_arrayref->[0]; -} - =item cust_event Returns the new-style customer billing events (see L) for this invoice. @@ -1059,7 +1045,7 @@ sub send { $self->email($opt) if ( grep { $_ !~ /^(POST|FAX)$/ } @invoicing_list or !@invoicing_list ) - && ! $self->invoice_noemail; + && ! $cust_main->invoice_noemail; $self->print($opt) if grep { $_ eq 'POST' } @invoicing_list; #postal @@ -1085,7 +1071,7 @@ sub email { # 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 ); + $conf->invoice_from_full( $self->cust_main->agentnum ); my @invoicing_list = $self->cust_main->invoicing_list_emailonly; @@ -1114,6 +1100,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 ); @@ -1900,7 +1890,19 @@ sub print_csv { if ( lc($opt{'format'}) eq 'billco' ) { my $lineseq = 0; - foreach my $item ( $self->_items_pkg ) { + my %items_opt = ( format => 'template', + escape_function => sub { shift } ); + # I don't know what characters billco actually tolerates in spool entries. + # Text::CSV will take care of delimiters, though. + + my @items = ( $self->_items_pkg(%items_opt), + $self->_items_fee(%items_opt) ); + foreach my $item (@items) { + + my $description = $item->{'description'}; + if ( $item->{'_is_discount'} and exists($item->{ext_description}[0]) ) { + $description .= ': ' . $item->{ext_description}[0]; + } $csv->combine( '', # 1 | N/A-Leave Empty CHAR 2 @@ -1908,7 +1910,7 @@ sub print_csv { $tracctnum, # 3 | Account Number CHAR 15 $self->invnum, # 4 | Invoice Number CHAR 15 $lineseq++, # 5 | Line Sequence (sort order) NUM 6 - $item->{'description'}, # 6 | Transaction Detail CHAR 100 + $description, # 6 | Transaction Detail CHAR 100 $item->{'amount'}, # 7 | Amount NUM* 9 '', # 8 | Line Format Control** CHAR 2 '', # 9 | Grouping Code CHAR 2 @@ -1970,24 +1972,8 @@ sub print_csv { } -=item comp - -Pays this invoice with a compliemntary payment. If there is an error, -returns the error, otherwise returns false. - -=cut - sub comp { - my $self = shift; - my $cust_pay = new FS::cust_pay ( { - 'invnum' => $self->invnum, - 'paid' => $self->owed, - '_date' => '', - 'payby' => 'COMP', - 'payinfo' => $self->cust_main->payinfo, - 'paybatch' => '', - } ); - $cust_pay->insert; + croak 'cust_bill->comp is deprecated (COMP payments are deprecated)'; } =item realtime_card @@ -2193,7 +2179,7 @@ sub _items_extra_usage_sections { my %classnums = (); my %lines = (); - my $maxlength = $conf->config('cust_bill-latex_lineitem_maxlength') || 50; + my $maxlength = $conf->config('cust_bill-latex_lineitem_maxlength') || 40; my %usage_class = map { $_->classnum => $_ } qsearch( 'usage_class', {} ); foreach my $cust_bill_pkg ( $self->cust_bill_pkg ) { @@ -2434,7 +2420,7 @@ sub _items_svc_phone_sections { my %classnums = (); my %lines = (); - my $maxlength = $conf->config('cust_bill-latex_lineitem_maxlength') || 50; + my $maxlength = $conf->config('cust_bill-latex_lineitem_maxlength') || 40; my %usage_class = map { $_->classnum => $_ } qsearch( 'usage_class', {} ); $usage_class{''} ||= new FS::usage_class { 'classname' => '', 'weight' => 0 }; @@ -2733,7 +2719,7 @@ sub _items_previous { sub _items_credits { my( $self, %opt ) = @_; - my $trim_len = $opt{'trim_len'} || 60; + my $trim_len = $opt{'trim_len'} || 40; my @b; #credits @@ -2830,6 +2816,66 @@ sub _items_payments { } +sub _items_total { + my $self = shift; + my $conf = $self->conf; + + my @items; + my ($pr_total) = $self->previous; + my ($previous_charges_desc, $new_charges_desc, $new_charges_amount); + + if ( $conf->exists('previous_balance-exclude_from_total') ) { + # can we do some caching on this stuff? it's going to change infrequently + # in production + $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 => $previous_charges_desc, + total_amount => sprintf('%.2f',$pr_total) + }; + } + $new_charges_desc = $self->mt( + $conf->config('previous_balance-text-total_new_charges') + || 'Total New Charges' + ); + + $new_charges_amount = $self->charged; + + } else { + + $new_charges_desc = $self->mt('Total Charges'); + $new_charges_amount = sprintf('%.2f',$self->charged + $pr_total); + + } + + if ( $conf->exists('invoice_show_prior_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'); + } elsif ( $self->terms ) { + # phrases like "due on receipt" should be localized + $new_charges_desc .= ' - ' . $self->mt($self->terms); + } + } + + push @items, + { total_item => $new_charges_desc, + total_amount => $new_charges_amount, + }; + + @items; +} + + + =item call_details [ OPTION => VALUE ... ] Returns an array of CSV strings representing the call details for this invoice