X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;f=FS%2FFS%2Fcust_main%2FBilling_Realtime.pm;h=c676607da8245ed01d5d9ba8628738f34f4c8c89;hb=af3030ce8b5be0c280f39eb7ffb8bebcb7953f56;hp=b892e97c2b89060d46e6590134fae01e1aaafd01;hpb=d860f85d2a4823a040996f9b1055e2d4054b864e;p=freeside.git diff --git a/FS/FS/cust_main/Billing_Realtime.pm b/FS/FS/cust_main/Billing_Realtime.pm index b892e97c2..c676607da 100644 --- a/FS/FS/cust_main/Billing_Realtime.pm +++ b/FS/FS/cust_main/Billing_Realtime.pm @@ -556,6 +556,8 @@ sub realtime_bop { ? uc($options{'paytype'}) : uc($self->getfield('paytype')) || 'PERSONAL CHECKING'; + $content{company} = $self->company if $self->company; + if ( $content{account_type} =~ /BUSINESS/i && $self->company ) { $content{account_name} = $self->company; } else { @@ -1916,6 +1918,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'); @@ -1932,8 +1936,10 @@ sub realtime_verify_bop { ); $reverse->content( 'action' => 'Reverse Authorization', + $self->_bop_auth(\%options), # B:OP + 'amount' => '1.00', 'authorization' => $transaction->authorization, 'order_number' => $ordernum, @@ -1958,11 +1964,125 @@ 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; } + ### Address Verification ### + # + # Single-letter codes vary by cardtype. + # + # Erring on the side of accepting cards if avs is not available, + # only rejecting if avs occurred and there's been an explicit mismatch + # + # Charts below taken from vSecure documentation, + # shows codes for Amex/Dscv/MC/Visa + # + # ACCEPTABLE AVS RESPONSES: + # Both Address and 5-digit postal code match Y A Y Y + # Both address and 9-digit postal code match Y A X Y + # United Kingdom – Address and postal code match _ _ _ F + # International transaction – Address and postal code match _ _ _ D/M + # + # ACCEPTABLE, BUT ISSUE A WARNING: + # Ineligible transaction; or message contains a content error _ _ _ E + # System unavailable; retry R U R R + # Information unavailable U W U U + # Issuer does not support AVS S U S S + # AVS is not applicable _ _ _ S + # Incompatible formats – Not verified _ _ _ C + # Incompatible formats – Address not verified; postal code matches _ _ _ P + # International transaction – address not verified _ G _ G/I + # + # UNACCEPTABLE AVS RESPONSES: + # Only Address matches A Y A A + # Only 5-digit postal code matches Z Z Z Z + # Only 9-digit postal code matches Z Z W W + # 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' => { + 'A' => 'r', + 'N' => 'r', + 'R' => 'w', + 'S' => 'w', + 'U' => 'w', + 'Y' => 'a', + 'Z' => 'r', + }, + 'Discover card' => { + 'A' => 'a', + 'G' => 'w', + 'N' => 'r', + 'U' => 'w', + 'W' => 'w', + 'Y' => 'r', + 'Z' => 'r', + }, + 'MasterCard' => { + 'A' => 'r', + 'N' => 'r', + 'R' => 'w', + 'S' => 'w', + 'U' => 'w', + 'W' => 'r', + 'X' => 'a', + 'Y' => 'a', + 'Z' => 'r', + }, + 'VISA card' => { + 'A' => 'r', + 'C' => 'w', + 'D' => 'a', + 'E' => 'w', + 'F' => 'a', + 'G' => 'w', + 'I' => 'w', + 'M' => 'a', + 'N' => 'r', + 'P' => 'w', + 'R' => 'w', + 'S' => 'w', + 'U' => 'w', + 'W' => 'r', + 'Y' => 'a', + 'Z' => 'r', + }, + }; + 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') { + $warning = "AVS did not occur, cardtype $cardtype, code $avscode"; + } elsif (!$avsact) { + $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 + + } else { # is not success + + # status is 'done' not 'declined', as in _realtime_bop_result + $cust_pay_pending->status('done'); + $cust_pay_pending->statustext( $transaction->error_message || 'Unknown error' ); + # could also record failure_status here, + # but it's not supported by B::OP::vSecureProcessing... + # need a B::OP module with (reverse) auth only to test it with + my $cpp_declined_err = $cust_pay_pending->replace; + return $cpp_declined_err if $cpp_declined_err; + } ### @@ -1975,7 +2095,9 @@ sub realtime_verify_bop { $self->payinfo($transaction->card_token); my $error = $self->replace; if ( $error ) { - warn "WARNING: error storing token: $error, but proceeding anyway\n"; + my $warning = "WARNING: error storing token: $error, but proceeding anyway\n"; + $log->warning($warning); + warn $warning; } }