X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_bill.pm;h=dad54348eac778ce46fef8799c0b18a730c89fa1;hb=eccc8de2366e2e004a37761b8da2b447ec861ecb;hp=c48c80627b3531bd317dc66fd0c0238f31902cef;hpb=2c2da653a3d39945d8d2c244d102ccbee862053b;p=freeside.git diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index c48c80627..dad54348e 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -6,7 +6,7 @@ use vars qw( $DEBUG $me $date_format ); # but NOT $conf use Fcntl qw(:flock); #for spool_csv use Cwd; -use List::Util qw(min max); +use List::Util qw(min max sum); use Date::Format; use File::Temp 0.14; use HTML::Entities; @@ -1819,13 +1819,16 @@ L). =item agent_spools - if set to a true value, will spool to per-agent files rather than a single global file -=item ftp_targetnum - if set to an FTP target (see L), will +=item upload_targetnum - if set to a target (see L), will append to that spool. L will then send the spool file to that destination. =item balanceover - if set, only spools the invoice if the total amount owed on this invoice and all older invoices is greater than the specified amount. +=item time - the "current time". Controls the printing of past due messages +in the ICS format. + =back =cut @@ -1833,6 +1836,7 @@ this invoice and all older invoices is greater than the specified amount. sub spool_csv { my($self, %opt) = @_; + my $time = $opt{'time'} || time; my $cust_main = $self->cust_main; if ( $opt{'dest'} ) { @@ -1850,7 +1854,7 @@ sub spool_csv { my $spooldir = "/usr/local/etc/freeside/export.". datasrc. "/cust_bill"; mkdir $spooldir, 0700 unless -d $spooldir; - my $tracctnum = $self->invnum. time2str('-%Y%m%d%H%M%S', time); + my $tracctnum = $self->invnum. time2str('-%Y%m%d%H%M%S', $time); my $file; if ( $opt{'agent_spools'} ) { @@ -1859,8 +1863,8 @@ sub spool_csv { $file = 'spool'; } - if ( $opt{'ftp_targetnum'} ) { - $spooldir .= '/target'.$opt{'ftp_targetnum'}; + if ( $opt{'upload_targetnum'} ) { + $spooldir .= '/target'.$opt{'upload_targetnum'}; mkdir $spooldir, 0700 unless -d $spooldir; } # otherwise it just goes into export.xxx/cust_bill @@ -1870,7 +1874,7 @@ sub spool_csv { $file = "$spooldir/$file.csv"; - my ( $header, $detail ) = $self->print_csv(%opt, 'tracctnum' => $tracctnum ); + my ( $header, $detail ) = $self->print_csv(%opt, 'tracctnum' => $tracctnum); open(CSV, ">>$file") or die "can't open $file: $!"; flock(CSV, LOCK_EX); @@ -1890,7 +1894,7 @@ sub spool_csv { seek(CSV, 0, 2); } - print CSV $detail; + print CSV $detail if defined($detail); flock(CSV, LOCK_UN); close CSV; @@ -2051,8 +2055,11 @@ sub print_csv { my $cust_main = $self->cust_main; my $csv = Text::CSV_XS->new({'always_quote'=>1}); + my $format = lc($opt{'format'}); - if ( lc($opt{'format'}) eq 'billco' ) { + my $time = $opt{'time'} || time; + + if ( $format eq 'billco' ) { my $taxtotal = 0; $taxtotal += $_->{'amount'} foreach $self->_items_tax; @@ -2105,7 +2112,7 @@ sub print_csv { '0', # 29 | Other Taxes & Fees*** NUM* 9 ); - } elsif ( lc($opt{'format'}) eq 'oneline' ) { #name? + } elsif ( $format eq 'oneline' ) { #name my ($previous_balance) = $self->previous; my $totaldue = sprintf('%.2f', $self->owed + $previous_balance); @@ -2136,10 +2143,10 @@ sub print_csv { @items, ); - } elsif ( lc($opt{'format'}) eq 'bridgestone' ) { + } elsif ( $format eq 'bridgestone' ) { # bypass the CSV stuff and just return this - my $longdate = time2str('%B %d, %Y', time); #current time, right? + my $longdate = time2str('%B %d, %Y', $time); #current time, right? my $zip = $cust_main->zip; $zip =~ s/\D//; my $prefix = $self->conf->config('bridgestone-prefix', $cust_main->agentnum) @@ -2161,7 +2168,120 @@ sub print_csv { '' #detail ); - } else { + } elsif ( $format eq 'ics' ) { + + my $bill = $cust_main->bill_location; + my $zip = $bill->zip; + my $zip4 = ''; + + $zip =~ s/\D//; + if ( $zip =~ /^(\d{5})(\d{4})$/ ) { + $zip = $1; + $zip4 = $2; + } + + # minor false laziness with print_generic + my ($previous_balance) = $self->previous; + my $balance_due = $self->owed + $previous_balance; + my $payment_total = sum(0, map { $_->{'amount'} } $self->_items_payments); + my $credit_total = sum(0, map { $_->{'amount'} } $self->_items_credits); + + my $past_due = ''; + if ( $self->due_date and $time >= $self->due_date ) { + $past_due = sprintf('Past due:$%0.2f Due Immediately', $balance_due); + } + + # again, bypass CSV + my $header = sprintf( + '%-10s%-30s%-48s%-2s%-50s%-30s%-30s%-25s%-2s%-5s%-4s%-8s%-8s%-10s%-10s%-10s%-10s%-10s%-10s%-480s%-35s', + $cust_main->display_custnum, #BID + uc($cust_main->first), #FNAME + uc($cust_main->last), #LNAME + '00', #BATCH, should this ever be anything else? + uc($cust_main->company), #COMP + uc($bill->address1), #STREET1 + uc($bill->address2), #STREET2 + uc($bill->city), #CITY + uc($bill->state), #STATE + $zip, + $zip4, + time2str('%Y%m%d', $self->_date), #BILL_DATE + $self->due_date2str('%Y%m%d'), #DUE_DATE, + ( map {sprintf('%0.2f', $_)} + $balance_due, #AMNT_DUE + $previous_balance, #PREV_BAL + $payment_total, #PYMT_RCVD + $credit_total, #CREDITS + $previous_balance, #BEG_BAL--is this correct? + $self->charged, #NEW_CHRG + ), + 'img01', #MRKT_MSG? + $past_due, #PAST_MSG + ); + + my @details; + my %svc_class = ('' => ''); # maybe cache this more persistently? + + foreach my $cust_bill_pkg ( $self->cust_bill_pkg ) { + + my $show_pkgnum = $cust_bill_pkg->pkgnum || ''; + my $cust_pkg = $cust_bill_pkg->cust_pkg if $show_pkgnum; + + if ( $cust_pkg ) { + + my @dates = ( $self->_date, undef ); + if ( my $prev = $cust_bill_pkg->previous_cust_bill_pkg ) { + $dates[1] = $prev->sdate; #questionable + } + + # generate an 01 detail for each service + my @svcs = $cust_pkg->h_cust_svc(@dates, 'I'); + foreach my $cust_svc ( @svcs ) { + $show_pkgnum = ''; # hide it if we're showing svcnums + + my $svcpart = $cust_svc->svcpart; + if (!exists($svc_class{$svcpart})) { + my $classnum = $cust_svc->part_svc->classnum; + my $part_svc_class = FS::part_svc_class->by_key($classnum) + if $classnum; + $svc_class{$svcpart} = $part_svc_class ? + $part_svc_class->classname : + ''; + } + + push @details, sprintf('01%-9s%-20s%-47s', + $cust_svc->svcnum, + $svc_class{$svcpart}, + $cust_svc->svc_x->label, + ); + } #foreach $cust_svc + } #if $cust_pkg + + my $desc = $cust_bill_pkg->desc; # itemdesc or part_pkg.pkg + if ($cust_bill_pkg->recur > 0) { + $desc .= ' '.time2str('%d-%b-%Y', $cust_bill_pkg->sdate).' to '. + time2str('%d-%b-%Y', $cust_bill_pkg->edate - 86400); + } + push @details, sprintf('02%-6s%-60s%-10s', + $show_pkgnum, + $desc, + sprintf('%0.2f', $cust_bill_pkg->setup + $cust_bill_pkg->recur), + ); + } #foreach $cust_bill_pkg + + # Tag this row so that we know whether this is one page (1), two pages + # (2), # or "big" (B). The tag will be stripped off before uploading. + if ( scalar(@details) < 12 ) { + push @details, '1'; + } elsif ( scalar(@details) < 58 ) { + push @details, '2'; + } else { + push @details, 'B'; + } + + return join('', $header, @details, "\n"); + + } else { # default $csv->combine( 'cust_bill',