X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_main%2FBilling_Realtime.pm;h=3e4a438d675b50f01dbaa5ed2619b68cfc3a2bc5;hb=d39978bc228a538071e062329532e33df4a6dc9d;hp=8cac9824a9eec7975fd2360ee03742a099c0b8cb;hpb=5636b1ec4d5acc194b1fd680e4d5301d7ef991db;p=freeside.git diff --git a/FS/FS/cust_main/Billing_Realtime.pm b/FS/FS/cust_main/Billing_Realtime.pm index 8cac9824a..3e4a438d6 100644 --- a/FS/FS/cust_main/Billing_Realtime.pm +++ b/FS/FS/cust_main/Billing_Realtime.pm @@ -5,7 +5,7 @@ use vars qw( $conf $DEBUG $me ); use vars qw( $realtime_bop_decline_quiet ); #ugh use Carp; use Data::Dumper; -use Business::CreditCard 0.28; +use Business::CreditCard 0.35; use FS::UID qw( dbh ); use FS::Record qw( qsearch qsearchs ); use FS::payby; @@ -355,6 +355,35 @@ sub _bop_content { \%content; } +sub _tokenize_card { + my ($self,$transaction,$payinfo,$log) = @_; + + if ( $transaction->can('card_token') + and $transaction->card_token + and $payinfo !~ /^99\d{14}$/ #not already tokenized + ) { + + my @cust_payby = $self->cust_payby('CARD','DCRD'); + @cust_payby = grep { $payinfo == $_->payinfo } @cust_payby; + if (@cust_payby > 1) { + $log->error('Multiple matching card numbers for cust '.$self->custnum.', could not tokenize card'); + } elsif (@cust_payby) { + my $cust_payby = $cust_payby[0]; + $cust_payby->payinfo($transaction->card_token); + my $error = $cust_payby->replace; + if ( $error ) { + $log->error('Error storing token for cust '.$self->custnum.', cust_payby '.$cust_payby->custpaybynum.': '.$error); + } else { + $log->debug('Tokenized card for cust '.$self->custnum.', cust_payby '.$cust_payby->custpaybynum); + } + } else { + $log->debug('No matching card numbers for cust '.$self->custnum.', could not tokenize card'); + } + + } + +} + my %bop_method2payby = ( 'CC' => 'CARD', 'ECHECK' => 'CHEK', @@ -369,6 +398,8 @@ sub realtime_bop { unless $FS::UID::AutoCommit; local($DEBUG) = $FS::cust_main::DEBUG if $FS::cust_main::DEBUG > $DEBUG; + + my $log = FS::Log->new('FS::cust_main::Billing_Realtime::realtime_bop'); my %options = (); if (ref($_[0]) eq 'HASH') { @@ -510,11 +541,8 @@ sub realtime_bop { $paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; $content{expiration} = "$2/$1"; - my $paycvv = exists($options{'paycvv'}) - ? $options{'paycvv'} - : $self->paycvv; - $content{cvv2} = $paycvv - if length($paycvv); + $content{cvv2} = $options{'paycvv'} + if length($options{'paycvv'}); my $paystart_month = exists($options{'paystart_month'}) ? $options{'paystart_month'} @@ -764,10 +792,10 @@ sub realtime_bop { ### # compare to FS::cust_main::save_cust_payby - check both to make sure working correctly - if ( length($self->paycvv) + if ( length($options{'paycvv'}) && ! grep { $_ eq cardtype($options{payinfo}) } $conf->config('cvv-save') ) { - my $error = $self->remove_cvv; + my $error = $self->remove_cvv_from_cust_payby($options{payinfo}); if ( $error ) { warn "WARNING: error removing cvv: $error\n"; } @@ -777,18 +805,7 @@ sub realtime_bop { # Tokenize ### - - if ( $transaction->can('card_token') && $transaction->card_token ) { - - if ( $options{'payinfo'} eq $self->payinfo ) { - $self->payinfo($transaction->card_token); - my $error = $self->replace; - if ( $error ) { - warn "WARNING: error storing token: $error, but proceeding anyway\n"; - } - } - - } + $self->_tokenize_card($transaction,$options{'payinfo'},$log); ### # result handling @@ -1790,11 +1807,8 @@ sub realtime_verify_bop { $paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; $content{expiration} = "$2/$1"; - my $paycvv = exists($options{'paycvv'}) - ? $options{'paycvv'} - : $self->paycvv; - $content{cvv2} = $paycvv - if length($paycvv); + $content{cvv2} = $options{'paycvv'} + if length($options{'paycvv'}); my $paystart_month = exists($options{'paystart_month'}) ? $options{'paystart_month'} @@ -1918,6 +1932,8 @@ sub realtime_verify_bop { } } + my $log = FS::Log->new('FS::cust_main::Billing_Realtime::realtime_verify_bop'); + if ( $transaction->is_success() ) { $cust_pay_pending->status('authorized'); @@ -1954,6 +1970,7 @@ sub realtime_verify_bop { if ( $reverse->is_success ) { $cust_pay_pending->status('done'); + $cust_pay_pending->statustext('reversed'); my $cpp_authorized_err = $cust_pay_pending->replace; return $cpp_authorized_err if $cpp_authorized_err; @@ -1962,6 +1979,7 @@ sub realtime_verify_bop { my $e = "Authorization successful but reversal failed, custnum #". $self->custnum. ': '. $reverse->result_code. ": ". $reverse->error_message; + $log->warning($e); warn $e; return $e; @@ -2000,6 +2018,7 @@ sub realtime_verify_bop { # Neither address nor postal code matches N N N N if (my $avscode = uc($transaction->avs_code)) { + # map codes to accept/warn/reject my $avs = { 'American Express card' => { @@ -2053,13 +2072,18 @@ sub realtime_verify_bop { my $cardtype = cardtype($content{card_number}); if ($avs->{$cardtype}) { my $avsact = $avs->{$cardtype}->{$avscode}; + my $warning = ''; if ($avsact eq 'r') { return "AVS code verification failed, cardtype $cardtype, code $avscode"; } elsif ($avsact eq 'w') { - warn "AVS code verification did not occur, cardtype $cardtype, code $avscode"; + $warning = "AVS did not occur, cardtype $cardtype, code $avscode"; } elsif (!$avsact) { - warn "AVS code verification did not occur, unknown avscode, cardtype $cardtype, code $avscode"; + $warning = "AVS code unknown, cardtype $cardtype, code $avscode"; } # else $avsact eq 'a' + if ($warning) { + $log->warning($warning); + warn $warning; + } } # else $cardtype avs handling not implemented } # else !$transaction->avs_code @@ -2080,17 +2104,7 @@ sub realtime_verify_bop { # Tokenize ### - if ( $transaction->can('card_token') && $transaction->card_token ) { - - if ( $options{'payinfo'} eq $self->payinfo ) { - $self->payinfo($transaction->card_token); - my $error = $self->replace; - if ( $error ) { - warn "WARNING: error storing token: $error, but proceeding anyway\n"; - } - } - - } + $self->_tokenize_card($transaction,$options{'payinfo'},$log); ### # result handling