From eb9d5b215af1fbe867b75c12328126f650f9fb06 Mon Sep 17 00:00:00 2001 From: ivan Date: Sat, 12 Oct 2002 10:15:55 +0000 Subject: [PATCH] ACH support --- FS/FS/Conf.pm | 4 +- FS/FS/cust_bill.pm | 73 +++++++++++++++++++++++--------- FS/FS/cust_main.pm | 20 ++++++--- FS/FS/cust_pay.pm | 7 +-- FS/FS/cust_refund.pm | 7 +-- FS/FS/part_bill_event.pm | 2 +- fs_signup/FS-SignupClient/cgi/signup.cgi | 10 +++-- httemplate/edit/cust_main.cgi | 12 ++++-- httemplate/edit/process/cust_main.cgi | 9 +++- httemplate/view/cust_main.cgi | 10 +++++ 10 files changed, 109 insertions(+), 45 deletions(-) diff --git a/FS/FS/Conf.pm b/FS/FS/Conf.pm index 20e42183b..204d26af3 100644 --- a/FS/FS/Conf.pm +++ b/FS/FS/Conf.pm @@ -870,7 +870,7 @@ httemplate/docs/config.html 'section' => '', 'description' => 'Acceptable payment types for the signup server', 'type' => 'selectmultiple', - 'select_enum' => [ qw(CARD PREPAY BILL COMP) ], + 'select_enum' => [ qw(CARD CHEK PREPAY BILL COMP) ], }, { @@ -957,7 +957,7 @@ httemplate/docs/config.html 'section' => 'UI', 'description' => 'Default payment type. HIDE disables display of billing information and sets customers to BILL.', 'type' => 'select', - 'select_enum' => [ '', 'CARD', 'BILL', 'COMP', 'HIDE' ], + 'select_enum' => [ '', qw(CARD CHEK BILL COMP HIDE) ], }, { diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 296c8b6a6..e875f5229 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -583,32 +583,48 @@ sub comp { =item realtime_card -Attempts to pay this invoice with a Business::OnlinePayment realtime gateway. -See http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment -for supproted processors. +Attempts to pay this invoice with a credit card payment via a +Business::OnlinePayment realtime gateway. See +http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment +for supported processors. =cut sub realtime_card { my $self = shift; + $self->realtime_bop('CC', @_); +} + +=item realtime_ach + +Attempts to pay this invoice with an electronic check (ACH) payment via a +Business::OnlinePayment realtime gateway. See +http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment +for supported processors. + +=cut + +sub realtime_ach { + my $self = shift; + $self->realtime_bop('ECHECK', @_); +} + +sub realtime_bop { + my $self = shift; + my $method = shift; my $cust_main = $self->cust_main; my $amount = $self->owed; unless ( $processor =~ /^Business::OnlinePayment::(.*)$/ ) { - return "Real-time card processing not enabled (processor $processor)"; + return "Real-time card/ACH processing not enabled (processor $processor)"; } my $bop_processor = $1; #hmm? my $address = $cust_main->address1; $address .= ", ". $cust_main->address2 if $cust_main->address2; - #fix exp. date - #$cust_main->paydate =~ /^(\d+)\/\d*(\d{2})$/; - $cust_main->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; - my $exp = "$2/$1"; - my($payname, $payfirst, $paylast); - if ( $cust_main->payname ) { + if ( $cust_main->payname && $method ne 'ECHECK' ) { $payname = $cust_main->payname; $payname =~ /^\s*([\w \,\.\-\']*)?\s+([\w\,\.\-\']+)\s*$/ or do { @@ -646,11 +662,24 @@ sub realtime_card { $description = eval qq("$dtempl"); } + + my %content; + if ( $method eq 'CC' ) { + $content{card_number} = $cust_main->payinfo; + $cust_main->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; + $content{expiration} = "$2/$1"; + } elsif ( $method eq 'ECHECK' ) { + my($account_number,$routing_code) = $cust_main->payinfo + ( $content{account_number}, $content{routing_code} ) = + split('@', $cust_main->payinfo); + $content{bank_name} = $cust_main->payname; + } my $transaction = new Business::OnlinePayment( $bop_processor, @bop_options ); $transaction->content( - 'type' => 'CC', + %content, + 'type' => $method, 'login' => $bop_login, 'password' => $bop_password, 'action' => $action1, @@ -666,8 +695,6 @@ sub realtime_card { 'state' => $cust_main->state, 'zip' => $cust_main->zip, 'country' => $cust_main->country, - 'card_number' => $cust_main->payinfo, - 'expiration' => $exp, 'referer' => 'http://cleanwhisker.420.am/', 'email' => $email, 'phone' => $cust_main->daytime || $cust_main->night, @@ -686,7 +713,8 @@ sub realtime_card { new Business::OnlinePayment( $bop_processor, @bop_options ); my %capture = ( - type => 'CC', + %content, + type => $method, action => $action2, login => $bop_login, password => $bop_password, @@ -694,8 +722,6 @@ sub realtime_card { amount => $amount, authorization => $auth, description => $description, - card_number => $cust_main->payinfo, - expiration => $exp, ); foreach my $field (qw( authorization_source_code returned_ACI transaction_identifier validation_code @@ -720,18 +746,23 @@ sub realtime_card { if ( $transaction->is_success() ) { + my %method2payby = ( + 'CC' => 'CARD', + 'ECHECK' => 'CHEK', + ); + my $cust_pay = new FS::cust_pay ( { 'invnum' => $self->invnum, 'paid' => $amount, '_date' => '', - 'payby' => 'CARD', + 'payby' => method2payby{$method}, 'payinfo' => $cust_main->payinfo, 'paybatch' => "$processor:". $transaction->authorization, } ); my $error = $cust_pay->insert; if ( $error ) { # gah, even with transactions. - my $e = 'WARNING: Card debited but database not updated - '. + my $e = 'WARNING: Card/ACH debited but database not updated - '. 'error applying payment, invnum #' . $self->invnum. " ($processor): $error"; warn $e; @@ -766,7 +797,7 @@ sub realtime_card { "Sender: $invoice_from", "Reply-To: $invoice_from", "Date: ". time2str("%a, %d %b %Y %X %z", time), - "Subject: Your credit card could not be processed", + "Subject: Your payment could not be processed", ] ); my $message = new Mail::Internet ( 'Header' => $header, @@ -838,7 +869,7 @@ sub print_text { # my $invnum = $self->invnum; my $cust_main = qsearchs('cust_main', { 'custnum', $self->custnum } ); $cust_main->payname( $cust_main->first. ' '. $cust_main->getfield('last') ) - unless $cust_main->payname; + unless $cust_main->payname && $cust_main->payby ne 'CHEK'; my( $pr_total, @pr_cust_bill ) = $self->previous; #previous balance # my( $cr_total, @cr_cust_credit ) = $self->cust_credit; #credits @@ -1043,7 +1074,7 @@ sub print_text { =head1 VERSION -$Id: cust_bill.pm,v 1.47 2002-10-04 12:09:21 ivan Exp $ +$Id: cust_bill.pm,v 1.48 2002-10-12 10:15:55 ivan Exp $ =head1 BUGS diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 2701ac35d..d6e4bc1e3 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -158,7 +158,7 @@ FS::Record. The following fields are currently supported: =item ship_fax - phone (optional) -=item payby - `CARD' (credit cards), `BILL' (billing), `COMP' (free), or `PREPAY' (special billing type: applies a credit - see L and sets billing type to BILL) +=item payby - `CARD' (credit cards), `CHEK' (electronic check), `BILL' (billing), `COMP' (free), or `PREPAY' (special billing type: applies a credit - see L and sets billing type to BILL) =item payinfo - card number, P.O., comp issuer (4-8 lowercase alphanumerics; think username) or prepayment identifier (see L) @@ -482,9 +482,9 @@ sub replace { $self->invoicing_list( $invoicing_list ); } - if ( $self->payby eq 'CARD' && + if ( $self->payby =~ /^(CARD|CHEK)$/ && grep { $self->get($_) ne $old->get($_) } qw(payinfo paydate payname) ) { - # card info has changed, want to retry realtime_card invoice events + # card/check info has changed, want to retry realtime_card invoice events #false laziness w/collect foreach my $cust_bill_event ( grep { @@ -664,7 +664,7 @@ sub check { } } - $self->payby =~ /^(CARD|BILL|COMP|PREPAY)$/ + $self->payby =~ /^(CARD|CHEK|BILL|COMP|PREPAY)$/ or return "Illegal payby: ". $self->payby; $self->payby($1); @@ -681,6 +681,14 @@ sub check { return gettext('unknown_card_type') if cardtype($self->payinfo) eq "Unknown"; + } elsif ( $self->payby eq 'CHEK' ) { + + my $payinfo = $self->payinfo; + $payinfo =~ s/[\D\@]//g; + $payinfo =~ /^(\d+)\@(\d{9})$/ or return 'invalid echeck account@aba'; + $payinfo = "$1\@$2"; + $self->payinfo($payinfo); + } elsif ( $self->payby eq 'BILL' ) { $error = $self->ut_textn('payinfo'); @@ -705,7 +713,7 @@ sub check { if ( $self->paydate eq '' || $self->paydate eq '-' ) { return "Expriation date required" - unless $self->payby eq 'BILL' || $self->payby eq 'PREPAY'; + unless $self->payby =~ /^(BILL|PREPAY|CHEK)$/; $self->paydate(''); } else { $self->paydate =~ /^(\d{1,2})[\/\-](\d{2}(\d{2})?)$/ @@ -717,7 +725,7 @@ sub check { if !$import && ( $y<$nowy || ( $y==$nowy && $1<$nowm ) ); } - if ( $self->payname eq '' && + if ( $self->payname eq '' && $self->payby ne 'CHEK' && ( ! $conf->exists('require_cardname') || $self->payby ne 'CARD' ) ) { $self->payname( $self->first. " ". $self->getfield('last') ); } else { diff --git a/FS/FS/cust_pay.pm b/FS/FS/cust_pay.pm index 98eba704b..222691408 100644 --- a/FS/FS/cust_pay.pm +++ b/FS/FS/cust_pay.pm @@ -60,7 +60,8 @@ currently supported: =item _date - specified as a UNIX timestamp; see L. Also see L and L for conversion functions. -=item payby - `CARD' (credit cards), `BILL' (billing), or `COMP' (free) +=item payby - `CARD' (credit cards), `CHEK' (electronic check/ACH), +`BILL' (billing), or `COMP' (free) =item payinfo - card number, check #, or comp issuer (4-8 lowercase alphanumerics; think username), respectively @@ -346,7 +347,7 @@ sub check { $self->_date(time) unless $self->_date; - $self->payby =~ /^(CARD|BILL|COMP)$/ or return "Illegal payby"; + $self->payby =~ /^(CARD|CHEK|BILL|COMP)$/ or return "Illegal payby"; $self->payby($1); #false laziness with cust_refund::check @@ -405,7 +406,7 @@ sub unapplied { =head1 VERSION -$Id: cust_pay.pm,v 1.21 2002-06-04 14:35:52 ivan Exp $ +$Id: cust_pay.pm,v 1.22 2002-10-12 10:15:55 ivan Exp $ =head1 BUGS diff --git a/FS/FS/cust_refund.pm b/FS/FS/cust_refund.pm index 8fe6876d3..aac320e61 100644 --- a/FS/FS/cust_refund.pm +++ b/FS/FS/cust_refund.pm @@ -47,7 +47,8 @@ inherits from FS::Record. The following fields are currently supported: =item _date - specified as a UNIX timestamp; see L. Also see L and L for conversion functions. -=item payby - `CARD' (credit cards), `BILL' (billing), or `COMP' (free) +=item payby - `CARD' (credit cards), `CHEK' (electronic check/ACH), +`BILL' (billing), or `COMP' (free) =item payinfo - card number, P.O.#, or comp issuer (4-8 lowercase alphanumerics; think username) @@ -234,7 +235,7 @@ sub check { unless $self->crednum || qsearchs( 'cust_main', { 'custnum' => $self->custnum } ); - $self->payby =~ /^(CARD|BILL|COMP)$/ or return "Illegal payby"; + $self->payby =~ /^(CARD|CHEK|BILL|COMP)$/ or return "Illegal payby"; $self->payby($1); #false laziness with cust_pay::check @@ -266,7 +267,7 @@ sub check { =head1 VERSION -$Id: cust_refund.pm,v 1.18 2002-02-19 03:22:39 jeff Exp $ +$Id: cust_refund.pm,v 1.19 2002-10-12 10:15:55 ivan Exp $ =head1 BUGS diff --git a/FS/FS/part_bill_event.pm b/FS/FS/part_bill_event.pm index a31b09b36..991616bb8 100644 --- a/FS/FS/part_bill_event.pm +++ b/FS/FS/part_bill_event.pm @@ -124,7 +124,7 @@ sub check { $c =~ /^\s*\$cust_main\->(suspend|cancel|invoicing_list_addpost|bill|collect)\(\);\s*("";)?\s*$/ - or $c =~ /^\s*\$cust_bill\->(comp|realtime_card|realtime_card_cybercash|batch_card|send)\(\);\s*$/ + or $c =~ /^\s*\$cust_bill\->(comp|realtime_card|realtime_ach|realtime_card_cybercash|batch_card|send)\(\);\s*$/ or $c =~ /^\s*\$cust_bill\->send\(\'\w+\'\);\s*$/ diff --git a/fs_signup/FS-SignupClient/cgi/signup.cgi b/fs_signup/FS-SignupClient/cgi/signup.cgi index 816b8213b..333a88cf8 100755 --- a/fs_signup/FS-SignupClient/cgi/signup.cgi +++ b/fs_signup/FS-SignupClient/cgi/signup.cgi @@ -1,6 +1,6 @@ #!/usr/bin/perl -Tw # -# $Id: signup.cgi,v 1.30 2002-08-26 19:07:10 khoff Exp $ +# $Id: signup.cgi,v 1.31 2002-10-12 10:15:55 ivan Exp $ use strict; use vars qw( @payby $cgi $locales $packages $pops $init_data $error @@ -611,14 +611,18 @@ Contact Information my %payby = ( 'CARD' => qq!Credit card
*$cardselect
*Exp !. expselect("CARD"). qq!
*Name on card
!, - 'BILL' => qq!Billing
P.O.
*Exp !. expselect("BILL", "12-2037"). qq!
*Attention
!, + 'CHEK' => qq!Electronic check
${r}Account number
${r}ABA/Routing code
${r}Bank name !, + 'BILL' => qq!Billing
P.O.
Attention
!, 'COMP' => qq!Complimentary
*Approved by
*Exp !. expselect("COMP"), 'PREPAY' => qq!Prepaid card
*!, ); + my( $account, $aba ) = split('@', $payinfo); + my %paybychecked = ( 'CARD' => qq!Credit card
*$cardselect
*Exp !. expselect("CARD", $paydate). qq!
*Name on card
!, - 'BILL' => qq!Billing
P.O.
*Exp !. expselect("BILL", $paydate). qq!
*Attention
!, + 'CHEK' => qq!Electronic check
${r}Account number
${r}ABA/Routing code
${r}Bank name !, + 'BILL' => qq!Billing
P.O.
Attention
!, 'COMP' => qq!Complimentary
*Approved by
*Exp !. expselect("COMP", $paydate), 'PREPAY' => qq!Prepaid card
*!, ); diff --git a/httemplate/edit/cust_main.cgi b/httemplate/edit/cust_main.cgi index 0921cb373..9e62b00ef 100755 --- a/httemplate/edit/cust_main.cgi +++ b/httemplate/edit/cust_main.cgi @@ -350,7 +350,7 @@ if ( $payby_default eq 'HIDE' ) { print qq!'; - foreach my $payby (qw( CARD BILL COMP )) { + foreach my $payby (qw( CARD CHEK BILL COMP )) { foreach my $field (qw( payinfo payname )) { print qq!'; @@ -399,18 +399,22 @@ if ( $payby_default eq 'HIDE' ) { my %payby = ( 'CARD' => qq!Credit card
${r}
${r}Exp !. expselect("CARD"). qq!
${r}Name on card
!, - 'BILL' => qq!Billing
P.O.
${r}Exp !. expselect("BILL", "12-2037"). qq!
Attention
!, + 'CHEK' => qq!Electronic check
${r}Account number
${r}ABA/Routing code
${r}Bank name !, + 'BILL' => qq!Billing
P.O.
Attention
!, 'COMP' => qq!Complimentary
${r}Approved by
${r}Exp !. expselect("COMP"), ); + my( $account, $aba ) = split('@', $payinfo); + my %paybychecked = ( 'CARD' => qq!Credit card
${r}
${r}Exp !. expselect("CARD", $cust_main->paydate). qq!
${r}Name on card
!, - 'BILL' => qq!Billing
P.O.
${r}Exp !. expselect("BILL", $cust_main->paydate). qq!
Attention
!, + 'CHEK' => qq!Electronic check
${r}Account number
${r}ABA/Routing code
${r}Bank name !, + 'BILL' => qq!Billing
P.O.
Attention
!, 'COMP' => qq!Complimentary
${r}Approved by
${r}Exp !. expselect("COMP", $cust_main->paydate), ); $cust_main->payby($payby_default) unless $cust_main->payby; - for (qw(CARD BILL COMP)) { + for (qw(CARD CHEK BILL COMP)) { print qq!payby eq "$_") { print qq! CHECKED> $paybychecked{$_}!; diff --git a/httemplate/edit/process/cust_main.cgi b/httemplate/edit/process/cust_main.cgi index 6ce60d14a..c15ea0321 100755 --- a/httemplate/edit/process/cust_main.cgi +++ b/httemplate/edit/process/cust_main.cgi @@ -10,9 +10,14 @@ $cgi->param('refnum', (split(/:/, ($cgi->param('refnum'))[0] ))[0] ); my $payby = $cgi->param('payby'); if ( $payby ) { - $cgi->param('payinfo', $cgi->param( $payby. '_payinfo' ) ); + if ( $payby eq 'CHEK' ) { + $cgi->param('payinfo', + $cgi->param('CHEK_payinfo1'). '@'. $cgi->param('CHEK_payinfo2') ); + } else { + $cgi->param('payinfo', $cgi->param( $payby. '_payinfo' ) ); + } $cgi->param('paydate', - $cgi->param( $payby. '_month' ). '-'. $cgi->param( $payby. '_year' ) ); + $cgi->param( $payby. '_month' ). '-'. $cgi->param( $payby. '_year' ) ); $cgi->param('payname', $cgi->param( $payby. '_payname' ) ); } diff --git a/httemplate/view/cust_main.cgi b/httemplate/view/cust_main.cgi index 25260fa3c..f7906cfa3 100755 --- a/httemplate/view/cust_main.cgi +++ b/httemplate/view/cust_main.cgi @@ -217,6 +217,16 @@ if ( $conf->config('payby-default') ne 'HIDE' ) { 'Name on card', $cust_main->payname, '' ; + } elsif ( $cust_main->payby eq 'CHEK' ) { + my( $account, $aba ) = split('@', $cust_main->payinfo ); + print 'Electronic check', + 'Account number', + $account, '', + 'ABA/Routing code', + $aba, '', + 'Bank name', + $cust_main->payname, '' + ; } elsif ( $cust_main->payby eq 'BILL' ) { print 'Billing'; print 'P.O. ', -- 2.11.0