X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_bill.pm;h=62d67c1f84bd8ca38e00a44b833ba5963c4c3de7;hb=6af1b1bfa25e5ececef5e0dcd38b55917121cee2;hp=6e3b2b2f851068f5d5518809c96681e1fadc6ecc;hpb=3213e7c1e281dbdba8baa980028482df3b9c1873;p=freeside.git diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 6e3b2b2f8..62d67c1f8 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 $conf $money_char ); +use vars qw( @ISA $DEBUG $me $conf $money_char ); use vars qw( $invoice_lines @buf ); #yuck use Fcntl qw(:flock); #for spool_csv use IPC::Run3; @@ -13,7 +13,7 @@ use HTML::Entities; use Locale::Country; use FS::UID qw( datasrc ); use FS::Misc qw( send_email send_fax ); -use FS::Record qw( qsearch qsearchs ); +use FS::Record qw( qsearch qsearchs dbh ); use FS::cust_main_Mixin; use FS::cust_main; use FS::cust_bill_pkg; @@ -21,15 +21,19 @@ use FS::cust_credit; use FS::cust_pay; use FS::cust_pkg; use FS::cust_credit_bill; +use FS::pay_batch; use FS::cust_pay_batch; use FS::cust_bill_event; use FS::part_pkg; use FS::cust_bill_pay; +use FS::cust_bill_pay_batch; use FS::part_bill_event; +use FS::payby qw( payby2bop ); @ISA = qw( FS::cust_main_Mixin FS::Record ); $DEBUG = 0; +$me = '[FS::cust_bill]'; #ask FS::UID to run this stuff for us later FS::UID->install_callback( sub { @@ -121,8 +125,14 @@ returns the error, otherwise returns false. =item delete -Currently unimplemented. I don't remove invoices because there would then be -no record you ever posted this invoice (which is bad, no?) +This method now works but you probably shouldn't use it. Instead, apply a +credit against the invoice. + +Using this method to delete invoices outright is really, really bad. There +would be no record you ever posted this invoice, and there are no check to +make sure charged = 0 or that there are no associated cust_bill_pkg records. + +Really, don't use it. =cut @@ -142,14 +152,20 @@ collect method of a customer object (see L). =cut -sub replace { +#replace can be inherited from Record.pm + +# replace_check is now the preferred way to #implement replace data checks +# (so $object->replace() works without an argument) + +sub replace_check { my( $new, $old ) = ( shift, shift ); return "Can't change custnum!" unless $old->custnum == $new->custnum; #return "Can't change _date!" unless $old->_date eq $new->_date; return "Can't change _date!" unless $old->_date == $new->_date; - return "Can't change charged!" unless $old->charged == $new->charged; + return "Can't change charged!" unless $old->charged == $new->charged + || $old->charged == 0; - $new->SUPER::replace($old); + ''; } =item check @@ -212,6 +228,33 @@ sub cust_bill_pkg { qsearch( 'cust_bill_pkg', { 'invnum' => $self->invnum } ); } +=item open_cust_bill_pkg + +Returns the open line items for this invoice. + +Note that cust_bill_pkg with both setup and recur fees are returned as two +separate line items, each with only one fee. + +=cut + +# modeled after cust_main::open_cust_bill +sub open_cust_bill_pkg { + my $self = shift; + + # grep { $_->owed > 0 } $self->cust_bill_pkg + + my %other = ( 'recur' => 'setup', + 'setup' => 'recur', ); + my @open = (); + foreach my $field ( qw( recur setup )) { + push @open, map { $_->set( $other{$field}, 0 ); $_; } + grep { $_->owed($field) > 0 } + $self->cust_bill_pkg; + } + + @open; +} + =item cust_bill_event Returns the completed invoice events (see L) for this @@ -824,6 +867,8 @@ Options are: =item agent_spools - if set to a true value, will spool to per-agent files rather than a single global file +=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. + =back =cut @@ -840,6 +885,11 @@ sub spool_csv { || ! keys %invoicing_list; } + if ( $opt{'balanceover'} ) { + return 'N/A' + if $cust_main->total_owed_date($self->_date) < $opt{'balanceover'}; + } + my $spooldir = "/usr/local/etc/freeside/export.". datasrc. "/cust_bill"; mkdir $spooldir, 0700 unless -d $spooldir; @@ -1261,11 +1311,42 @@ L). =cut sub batch_card { - my $self = shift; + my ($self, %options) = @_; my $cust_main = $self->cust_main; + my $amount = sprintf("%.2f", $cust_main->balance - $cust_main->in_transit_payments); + return '' unless $amount > 0; + + if ($options{'realtime'}) { + return $cust_main->realtime_bop ( $FS::payby::payby2bop->{$cust_main->payby}, $amount, + %options, + ); + } + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + my $pay_batch = qsearchs('pay_batch', {'status' => 'O'}); + + unless ( $pay_batch ) { + $pay_batch = new FS::pay_batch; + $pay_batch->setfield('status' => 'O'); + my $error = $pay_batch->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + die "error creating new batch: $error\n"; + } + } + + my $old_cust_pay_batch = qsearchs('cust_pay_batch', { + 'batchnum' => $pay_batch->getfield('batchnum'), + 'custnum' => $cust_main->getfield('custnum'), + } ); + my $cust_pay_batch = new FS::cust_pay_batch ( { - 'invnum' => $self->getfield('invnum'), + 'batchnum' => $pay_batch->getfield('batchnum'), + 'invnum' => $self->getfield('invnum'), # is there a better value? 'custnum' => $cust_main->getfield('custnum'), 'last' => $cust_main->getfield('last'), 'first' => $cust_main->getfield('first'), @@ -1275,14 +1356,53 @@ sub batch_card { 'state' => $cust_main->getfield('state'), 'zip' => $cust_main->getfield('zip'), 'country' => $cust_main->getfield('country'), - 'cardnum' => $cust_main->payinfo, + 'payby' => $cust_main->payby, + 'payinfo' => $cust_main->payinfo, 'exp' => $cust_main->getfield('paydate'), 'payname' => $cust_main->getfield('payname'), - 'amount' => $self->owed, + 'amount' => $amount, # consolidating } ); - my $error = $cust_pay_batch->insert; - die $error if $error; + + $cust_pay_batch->paybatchnum($old_cust_pay_batch->paybatchnum) + if $old_cust_pay_batch; + my $error; + if ($old_cust_pay_batch) { + $error = $cust_pay_batch->replace($old_cust_pay_batch) + } else { + $error = $cust_pay_batch->insert; + } + + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + die $error; + } + + my $unapplied = $cust_main->total_credited + $cust_main->total_unapplied_payments + $cust_main->in_transit_payments; + foreach my $cust_bill ($cust_main->open_cust_bill) { + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + my $cust_bill_pay_batch = new FS::cust_bill_pay_batch { + 'invnum' => $cust_bill->invnum, + 'paybatchnum' => $cust_pay_batch->paybatchnum, + 'amount' => $cust_bill->owed, + '_date' => time, + }; + if ($unapplied >= $cust_bill_pay_batch->amount){ + $unapplied -= $cust_bill_pay_batch->amount; + next; + }else{ + $cust_bill_pay_batch->amount(sprintf ( "%.2f", + $cust_bill_pay_batch->amount - $unapplied )); + $unapplied = 0; + } + $error = $cust_bill_pay_batch->insert; + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + die $error; + } + } + + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; } @@ -2444,6 +2564,7 @@ use Data::Dumper; use MIME::Base64; sub process_re_X { my( $method, $job ) = ( shift, shift ); + warn "process_re_X $method for job $job\n" if $DEBUG; my $param = thaw(decode_base64(shift)); warn Dumper($param) if $DEBUG; @@ -2459,6 +2580,10 @@ sub process_re_X { sub re_X { my($method, $job, %param ) = @_; # [ 'begin', 'end', 'agentnum', 'open', 'days', 'newest_percust' ], + if ( $DEBUG ) { + warn "re_X $method for job $job with param:\n". + join( '', map { " $_ => ". $param{$_}. "\n" } keys %param ); + } #some false laziness w/search/cust_bill.html my $distinct = '';