From 0ddbeb00fa8c2d777d8344ee690054bb7d382c6c Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 23 Apr 2007 03:41:31 +0000 Subject: [PATCH] add to ACH batch feature from customer view page --- FS/FS/Conf.pm | 7 ++ FS/FS/cust_bill.pm | 102 +--------------------------- FS/FS/cust_main.pm | 129 ++++++++++++++++++++++++++++++++++++ FS/FS/pay_batch.pm | 27 +++++++- httemplate/misc/download-batch.cgi | 2 +- httemplate/misc/payment.cgi | 10 +++ httemplate/misc/process/payment.cgi | 40 +++++++---- 7 files changed, 201 insertions(+), 116 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 8bff460fe..93ecf30c7 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -1227,6 +1227,13 @@ httemplate/docs/config.html }, { + 'key' => 'paymentforcedtobatch', + 'section' => 'UI', + 'description' => 'Causes per customer payment entry to be forced to a batch processor rather than performed realtime.', + 'type' => 'checkbox', + }, + + { 'key' => 'svc_acct-notes', 'section' => 'UI', 'description' => 'Extra HTML to be displayed on the Account View screen.', diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index d39e6ddc1..877d364e8 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -1434,107 +1434,9 @@ sub batch_card { 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; + $options{invnum} = $self->invnum; - 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; - - $dbh->do("LOCK TABLE pay_batch IN SHARE ROW EXCLUSIVE MODE") - or return "Cannot lock pay_batch: " . $dbh->errstr; - - my %pay_batch = ( - 'status' => 'O', - 'payby' => FS::payby->payby2payment($cust_main->payby), - ); - - my $pay_batch = qsearchs( 'pay_batch', \%pay_batch ); - - unless ( $pay_batch ) { - $pay_batch = new FS::pay_batch \%pay_batch; - 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->batchnum, - 'custnum' => $cust_main->custnum, - } ); - - my $cust_pay_batch = new FS::cust_pay_batch ( { - 'batchnum' => $pay_batch->batchnum, - 'invnum' => $self->getfield('invnum'), # is there a better value? - # this field should be - # removed... - # cust_bill_pay_batch now - 'custnum' => $cust_main->custnum, - 'last' => $cust_main->getfield('last'), - 'first' => $cust_main->getfield('first'), - 'address1' => $cust_main->address1, - 'address2' => $cust_main->address2, - 'city' => $cust_main->city, - 'state' => $cust_main->state, - 'zip' => $cust_main->zip, - 'country' => $cust_main->country, - 'payby' => $cust_main->payby, - 'payinfo' => $cust_main->payinfo, - 'exp' => $cust_main->paydate, - 'payname' => $cust_main->payname, - 'amount' => $amount, # consolidating - } ); - - $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; - ''; + $cust_main->batch_card(%options); } sub _agent_template { diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 1224c88da..708f014a8 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -3177,6 +3177,132 @@ sub realtime_refund_bop { } +=item batch_card OPTION => VALUE... + +Adds a payment for this invoice to the pending credit card batch (see +L), or, if the B option is set to a true value, +runs the payment using a realtime gateway. + +=cut + +sub batch_card { + my ($self, %options) = @_; + + my $amount; + if (exists($options{amount})) { + $amount = $options{amount}; + }else{ + $amount = sprintf("%.2f", $self->balance - $self->in_transit_payments); + } + return '' unless $amount > 0; + + my $invnum = delete $options{invnum}; + my $payby = $options{invnum} || $self->payby; #dubious + + if ($options{'realtime'}) { + return $self->realtime_bop( FS::payby->payby2bop($self->payby), + $amount, + %options, + ); + } + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + my $dbh = dbh; + + $dbh->do("LOCK TABLE pay_batch IN SHARE ROW EXCLUSIVE MODE") + or return "Cannot lock pay_batch: " . $dbh->errstr; + + my %pay_batch = ( + 'status' => 'O', + 'payby' => FS::payby->payby2payment($payby), + ); + + my $pay_batch = qsearchs( 'pay_batch', \%pay_batch ); + + unless ( $pay_batch ) { + $pay_batch = new FS::pay_batch \%pay_batch; + 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->batchnum, + 'custnum' => $self->custnum, + } ); + + foreach (qw( address1 address2 city state zip country payby payinfo paydate + payname )) { + $options{$_} = '' unless exists($options{$_}); + } + + my $cust_pay_batch = new FS::cust_pay_batch ( { + 'batchnum' => $pay_batch->batchnum, + 'invnum' => $invnum || 0, # is there a better value? + # this field should be + # removed... + # cust_bill_pay_batch now + 'custnum' => $self->custnum, + 'last' => $self->getfield('last'), + 'first' => $self->getfield('first'), + 'address1' => $options{address1} || $self->address1, + 'address2' => $options{address2} || $self->address2, + 'city' => $options{city} || $self->city, + 'state' => $options{state} || $self->state, + 'zip' => $options{zip} || $self->zip, + 'country' => $options{country} || $self->country, + 'payby' => $options{payby} || $self->payby, + 'payinfo' => $options{payinfo} || $self->payinfo, + 'exp' => $options{paydate} || $self->paydate, + 'payname' => $options{payname} || $self->payname, + 'amount' => $amount, # consolidating + } ); + + $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 = $self->total_credited + $self->total_unapplied_payments + $self->in_transit_payments; + foreach my $cust_bill ($self->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; + ''; +} + =item total_owed Returns the total owed for this customer on all invoices @@ -4882,6 +5008,9 @@ payinfo_masked false laziness with cust_pay.pm and cust_refund.pm Birthdates rely on negative epoch values. +The payby for card/check batches is broken. With mixed batching, bad +things will happen. + =head1 SEE ALSO L, L, L, L diff --git a/FS/FS/pay_batch.pm b/FS/FS/pay_batch.pm index 5a06ba603..c09753449 100644 --- a/FS/FS/pay_batch.pm +++ b/FS/FS/pay_batch.pm @@ -138,7 +138,7 @@ sub set_status { $self->replace(); } -=item import results OPTION => VALUE, ... +=item import_results OPTION => VALUE, ... Import batch results. @@ -162,6 +162,7 @@ sub import_results { my $formatre; # for Fixed.+ my @values; my $begin_condition; + my $pre_hook; my $end_condition; my $end_hook; my $hook; @@ -340,7 +341,7 @@ sub import_results { @fields = ( '', # Name - 'paybatchnum', # ID: Invoice number of the transaction + 'custnum' , # ID: Customer number of the transaction 'aba', # ABA Number for the transaction 'payinfo', # Bank Account Number for the transaction '', # Transaction Type: 27 - debit @@ -354,6 +355,20 @@ sub import_results { ''; }; + $pre_hook = sub { + my $hash = shift; + my @cust_pay_batch = # this is dodgy, it works due to autoposting + qsearch('cust_pay_batch', { 'custnum' => $hash->{'custnum'}+0, + 'status' => '' + } ); + if ( scalar(@cust_pay_batch) == 1 ) { + $hash->{'paybatchnum'} = $cust_pay_batch[0]->paybatchnum; + }else{ + return "can't find batch payment for customer number " .$hash->{custnum}; + } + ''; + }; + $hook = sub { my $hash = shift; $hash->{'_date'} = time; # got a better one? @@ -429,6 +444,14 @@ sub import_results { $hash{$field} = $value; } + if ( defined($pre_hook) ) { + my $error = &{$pre_hook}(\%hash); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + if ( &{$end_condition}(\%hash) ) { my $error = &{$end_hook}(\%hash, $total); if ( $error ) { diff --git a/httemplate/misc/download-batch.cgi b/httemplate/misc/download-batch.cgi index da975376b..26c385ebc 100644 --- a/httemplate/misc/download-batch.cgi +++ b/httemplate/misc/download-batch.cgi @@ -99,7 +99,7 @@ % % my( $account, $aba ) = split( '@', $cust_pay_batch->payinfo ); % my $payname=$cust_pay_batch->payname; $payname =~ tr/",/ /; #payinfo too? -% my $batchline = qq!"$payname","!.$cust_pay_batch->paybatchnum. +% my $batchline = qq!"$payname","!.$cust_pay_batch->custnum. #dodgy, works for autoapply % qq!","$aba","$account","27","!.$cust_pay_batch->amount. % qq!","27","0.00"!; % push @batchlines, $batchline; diff --git a/httemplate/misc/payment.cgi b/httemplate/misc/payment.cgi index 1008a216b..ac102826a 100644 --- a/httemplate/misc/payment.cgi +++ b/httemplate/misc/payment.cgi @@ -225,6 +225,16 @@ function OLiframeContent(src, width, height, name) { Remember this information +% if ($conf->exists("batch-enable")) { + + exists("paymentforcedtobatch") && $payby eq 'CHEK' ) ? 'CHECKED DISABLED' : '' %> NAME="batch" VALUE="1"> + Add to current batch +% if ($conf->exists("paymentforcedtobatch") && $payby eq 'CHEK' ) { + +% } + + +% } payby ne 'DCRD' ) || ( $payby eq 'CHEK' && $cust_main->payby eq 'CHEK' ) ) ? ' CHECKED' : '' %> NAME="auto" VALUE="1" onClick="if (this.checked) { document.OneTrueForm.save.checked=true; }"> Charge future payments to this <% $type{$payby} %> automatically diff --git a/httemplate/misc/process/payment.cgi b/httemplate/misc/process/payment.cgi index 8878f5255..9ac5d5d9e 100644 --- a/httemplate/misc/process/payment.cgi +++ b/httemplate/misc/process/payment.cgi @@ -89,19 +89,33 @@ % die "unknown payby $payby"; %} % -%my $error = $cust_main->realtime_bop( $FS::payby::payby2bop{$payby}, $amount, -% 'quiet' => 1, -% 'manual' => 1, -% 'payinfo' => $payinfo, -% 'paydate' => "$year-$month-01", -% 'payname' => $payname, -% 'paybatch' => $paybatch, -% 'paycvv' => $paycvv, -% map { $_ => $cgi->param($_) } @{$payby2fields{$payby}} -%); -%eidiot($error) if $error; -% -%$cust_main->apply_payments; +%my $error = ''; +%if ($cgi->param('batch')) { +% $error = $cust_main->batch_card( +% 'payby' => $payby, +% 'amount' => $amount, +% 'payinfo' => $payinfo, +% 'paydate' => "$year-$month-01", +% 'payname' => $payname, +% map { $_ => $cgi->param($_) } +% @{$payby2fields{$payby}} +% ); +% eidiot($error) if $error; +%}else{ +% $error = $cust_main->realtime_bop( $FS::payby::payby2bop{$payby}, $amount, +% 'quiet' => 1, +% 'manual' => 1, +% 'payinfo' => $payinfo, +% 'paydate' => "$year-$month-01", +% 'payname' => $payname, +% 'paybatch' => $paybatch, +% 'paycvv' => $paycvv, +% map { $_ => $cgi->param($_) } @{$payby2fields{$payby}} +% ); +% eidiot($error) if $error; +% +% $cust_main->apply_payments; +%} % %if ( $cgi->param('save') ) { % my $new = new FS::cust_main { $cust_main->hash }; -- 2.11.0