X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_bill.pm;h=8a05fcf3197969ac6eb65279bf74bbaf8e776685;hb=aaad08cae3a0d46d012de5b78360101cda836c30;hp=f353ea84c95f98a4aee5fc29b3b01e3ed64d6649;hpb=172c50ae6b9bef1e72c9f454d0c3621aabe210fb;p=freeside.git diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index f353ea84c..8a05fcf31 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -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; @@ -121,8 +121,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 +148,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 @@ -236,6 +248,25 @@ sub cust_main { qsearchs( 'cust_main', { 'custnum' => $self->custnum } ); } +=item cust_suspend_if_balance_over AMOUNT + +Suspends the customer associated with this invoice if the total amount owed on +this invoice and all older invoices is greater than the specified amount. + +Returns a list: an empty list on success or a list of errors. + +=cut + +sub cust_suspend_if_balance_over { + my( $self, $amount ) = ( shift, shift ); + my $cust_main = $self->cust_main; + if ( $cust_main->total_owed_date($self->_date) < $amount ) { + return (); + } else { + $cust_main->suspend; + } +} + =item cust_credit Depreciated. See the cust_credited method. @@ -739,16 +770,9 @@ server username password dir -format - 'default' or 'billco' -#??? -If I is not specified or "default", the file will be named -"N-YYYYMMDDHHMMSS.csv" where N is the invoice number and YYMMDDHHMMSS is a -timestamp. - -#??? -If I is "billco", two files will be created and uploaded. They will be named "N-YYYYMMDDHHMMSS-header.csv" and "N-YYYYMMDDHHMMSS-detail.csv" where N -is the invoice number and YYMMDDHHMMSS is a timestamp(???). +The file will be named "N-YYYYMMDDHHMMSS.csv" where N is the invoice number +and YYMMDDHHMMSS is a timestamp. See L for a description of the output format. @@ -763,27 +787,13 @@ sub send_csv { mkdir $spooldir, 0700 unless -d $spooldir; my $tracctnum = $self->invnum. time2str('-%Y%m%d%H%M%S', time); - my $file = "$spooldir/$tracctnum"; - if ( lc($opt{'format'}) eq 'billco' ) { - $file .= '-header.csv'; - } else { - #$file = $spooldir. '/'. $self->invnum. time2str('-%Y%m%d%H%M%S.csv', time); - $file .= '.csv'; - } + my $file = "$spooldir/$tracctnum.csv"; my ( $header, $detail ) = $self->print_csv(%opt, 'tracctnum' => $tracctnum ); open(CSV, ">$file") or die "can't open $file: $!"; print CSV $header; - my $oldfile = ''; - if ( lc($opt{'format'}) eq 'billco' ) { - close CSV; - $oldfile = $file; - $file = "$spooldir/$tracctnum-detail.csv"; - open(CSV,">$file") or die "can't open $file: $!"; - } - print CSV $detail; close CSV; @@ -804,14 +814,10 @@ sub send_csv { $net->cwd($opt{dir}) or die "can't cwd to $opt{dir}"; - if ( $oldfile) { - $net->put($oldfile) or die "can't put $oldfile: $!"; - } $net->put($file) or die "can't put $file: $!"; $net->quit; - unlink $oldfile if $oldfile; unlink $file; } @@ -822,26 +828,47 @@ Spools CSV invoice data. Options are: -format - 'default' or 'billco' +=over 4 + +=item format - 'default' or 'billco' + +=item dest - if set (to POST, EMAIL or FAX), only sends spools invoices if the customer has the corresponding invoice destinations set (see L). + +=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 sub spool_csv { my($self, %opt) = @_; - #create file(s) + my $cust_main = $self->cust_main; + + if ( $opt{'dest'} ) { + my %invoicing_list = map { /^(POST|FAX)$/ or 'EMAIL' =~ /^(.*)$/; $1 => 1 } + $cust_main->invoicing_list; + return 'N/A' unless $invoicing_list{$opt{'dest'}} + || ! 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; my $tracctnum = $self->invnum. time2str('-%Y%m%d%H%M%S', time); - my $file = "$spooldir/spool"; - if ( lc($opt{'format'}) eq 'billco' ) { - $file .= '-header.csv'; - } else { - #$file = $spooldir. '/'. $self->invnum. time2str('-%Y%m%d%H%M%S.csv', time); - $file .= '.csv'; - } + + my $file = + "$spooldir/". + ( $opt{'agent_spools'} ? 'agentnum'.$cust_main->agentnum : 'spool' ). + ( lc($opt{'format'}) eq 'billco' ? '-header' : '' ) . + '.csv'; my ( $header, $detail ) = $self->print_csv(%opt, 'tracctnum' => $tracctnum ); @@ -851,14 +878,15 @@ sub spool_csv { print CSV $header; - my $oldfile = ''; if ( lc($opt{'format'}) eq 'billco' ) { flock(CSV, LOCK_UN); close CSV; - $oldfile = $file; - $file = "$spooldir/spool-detail.csv"; + $file = + "$spooldir/". + ( $opt{'agent_spools'} ? 'agentnum'.$cust_main->agentnum : 'spool' ). + '-detail.csv'; open(CSV,">>$file") or die "can't open $file: $!"; flock(CSV, LOCK_EX); @@ -870,6 +898,8 @@ sub spool_csv { flock(CSV, LOCK_UN); close CSV; + return ''; + } =item print_csv OPTION => VALUE, ... @@ -1010,7 +1040,8 @@ sub print_csv { $taxtotal += $_->{'amount'} foreach $self->_items_tax; my $duedate = ''; - if ( $conf->config('invoice_default_terms') =~ /^\s*Net\s*(\d+)\s*$/ ) { + 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) ); } @@ -1251,8 +1282,23 @@ L). sub batch_card { my $self = shift; my $cust_main = $self->cust_main; + 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 ) { + die "error creating new batch: $error\n"; + } + } my $cust_pay_batch = new FS::cust_pay_batch ( { + 'batchnum' => $pay_batch->getfield('batchnum'), 'invnum' => $self->getfield('invnum'), 'custnum' => $cust_main->getfield('custnum'), 'last' => $cust_main->getfield('last'), @@ -1263,7 +1309,7 @@ sub batch_card { 'state' => $cust_main->getfield('state'), 'zip' => $cust_main->getfield('zip'), 'country' => $cust_main->getfield('country'), - 'cardnum' => $cust_main->payinfo, + 'payinfo' => $cust_main->payinfo, 'exp' => $cust_main->getfield('paydate'), 'payname' => $cust_main->getfield('payname'), 'amount' => $self->owed, @@ -1271,6 +1317,8 @@ sub batch_card { my $error = $cust_pay_batch->insert; die $error if $error; + $dbh->commit or die $dbh->errstr if $oldAutoCommit; + ''; } @@ -2396,6 +2444,7 @@ sub _items_payments { } + =back =head1 SUBROUTINES @@ -2431,6 +2480,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; @@ -2446,6 +2496,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 = '';