X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=lib%2FBusiness%2FOnlinePayment%2FFirstDataGlobalGateway.pm;h=92984da3162f4f114cc1f9fa8411c140d904ed54;hb=094794d04a28d126f72f89359284d75750798409;hp=081100d284be1fa12117805ce632f33045dd7b20;hpb=f6660ccc1cf3719650dc179aa7b1fd117b07ed0b;p=Business-OnlinePayment-FirstDataGlobalGateway.git diff --git a/lib/Business/OnlinePayment/FirstDataGlobalGateway.pm b/lib/Business/OnlinePayment/FirstDataGlobalGateway.pm index 081100d..92984da 100644 --- a/lib/Business/OnlinePayment/FirstDataGlobalGateway.pm +++ b/lib/Business/OnlinePayment/FirstDataGlobalGateway.pm @@ -5,7 +5,7 @@ use warnings; use strict; use Data::Dumper; use Business::CreditCard; -use SOAP::Lite +trace => 'all'; +use SOAP::Lite; #+trace => 'all'; #SOAP::Lite->import(+trace=>'debug'); our $VERSION = '0.01'; @@ -13,6 +13,23 @@ $VERSION = eval $VERSION; # modperlstyle: convert the string into a number our @alpha = ( 'a'..'z', 'A'..'Z', '0'..'9' ); +our %failure_status = ( + 302 => 'nsf', + 501 => 'pickup', + 502 => 'stolen', + 503 => 'stolen', # "Fraud/Security violation" + 504 => 'blacklisted', + 509 => 'nsf', + 510 => 'nsf', + 519 => 'blacklisted', + 521 => 'nsf', + 522 => 'expired', + 530 => 'blacklisted', + 534 => 'blacklisted', + # others are all "declined" +); + + sub _info { { 'info_compat' => '0.01', @@ -20,11 +37,14 @@ sub _info { 'gateway_url' => 'https://www.firstdata.com/en_us/products/merchants/ecommerce/online-payment-processing.html', 'module_version' => $VERSION, 'supported_types' => [ 'CC' ], #, 'ECHECK' ], - #'token_support' => 1, - #'test_transaction' => 1, + #'token_support' => 1, # "Transarmor" is this, but not implemented yet + 'test_transaction' => 1, 'supported_actions' => [ 'Normal Authorization', - #'Credit', + 'Authorization Only', + 'Post Authorization', + 'Credit', + 'Void', ], }; } @@ -33,12 +53,9 @@ sub set_defaults { my $self = shift; #my %opts = @_; - #$self->build_subs(qw( order_number avs_code cvv2_response - # response_page response_code response_headers - # )); - - $self->build_subs(qw( avs_code )); - + $self->build_subs(qw( order_number avs_code cvv2_response + authorization failure_status result_code + )); } sub map_fields { @@ -81,6 +98,9 @@ sub map_fields { $content{'action'} = $actions{$action} || $action; + # make sure there's a combined name + $content{name} ||= $content{first_name} . ' ' . $content{last_name}; + # stuff it back into %content $self->content(%content); @@ -105,7 +125,7 @@ sub submit { 'login' => 'ExactID', 'password' => 'Password', - 'action' => 'TransactionType', + 'action' => 'Transaction_Type', 'amount' => 'DollarAmount', 'currency' => 'Currency', @@ -131,14 +151,6 @@ sub submit { my %content = $self->content(); - #$content{'mop'} = $mop{ cardtype($content{creditCardNum}) } - # if $content{'type'} eq 'CC'; - - #if ( $self->test_transaction ) { - # $content{agentCode} = 'TEST88'; - # $content{password} = 'TEST88'; - #} - $content{Expiry_Date} =~ s/\///; $content{country} ||= 'US'; @@ -170,55 +182,63 @@ sub submit { } my $proxy = "$base_uri/v11"; - my $uri = "$base_uri/rpc-enc"; - my %transaction = map { $_ => $content{$_} } (qw( + my @transaction = map { SOAP::Data->name($_)->value( $content{$_} ) } + grep { defined($content{$_}) } + (qw( ExactID Password Transaction_Type DollarAmount Card_Number Transaction_Tag Track1 Track2 Authorization_Num Expiry_Date CardHoldersName VerificationStr1 VerificationStr2 CVD_Presence_Ind Reference_No ZipCode Tax1Amount Tax1Number Tax2Amount Tax2Number Customer_Ref Reference_3 - Language Client_IP Client_Email user_name Currency PartialRedemption + Language Client_IP Client_Email User_Name Currency PartialRedemption CAVV XID Ecommerce_Flag )); #TransarmorToken CardType EAN VirtualCard CardCost FraudSuspected #CheckNumber CheckType BankAccountNumber BankRoutingNumber CustomerName #CustomerIDType CustomerID - #my @opts = map { SOAP::Data->name($_)->value( $data{$_} ) } - # keys %data; - - my $result = SOAP::Lite - ->proxy($proxy) - - ->default_ns($base_uri) - ->uri($uri) - - ->on_action( sub { join '/', @_ } ) - #->on_action( sub { join '', @_ } ) - #->on_action(sub { qq("$_[0]") }) #? https://firstdata.zendesk.com/entries/407569-First-Data-Global-Gateway-e4-Web-Service-API-Sample-Code-Perl - ->autotype(0) - - ->readable(1) - - ->ns($uri,'q1') - ->SendAndCommit( SOAP::Data->name('Transaction')->value( \%transaction ) ) - - ->result(); - - die Dumper($result); - - die Dumper($result->result) if $result->fault; - #die $result->fault->faultstring if $result->fault; - - die Dumper($result); - - #$self->is_success - #$self->authorization - #$self->avs_code - #$self->error_message - #$self->result_code - ##$self->failure_status + my $wsdl = "$proxy/wsdl"; + my $client = SOAP::Lite->service($wsdl)->proxy($proxy)->readable(1); + my $action_prefix = 'http://secure2.e-xact.com/vplug-in/transaction/rpc-enc'; + my $type_prefix = $action_prefix . '/encodedTypes'; + $client->on_action( sub { $action_prefix . '/' . $_[1] } ); + my $source = SOAP::Data->name('SendAndCommitSource') + ->value(\@transaction) + ->type("$type_prefix:Transaction"); + local $@; + my $som = eval { $client->call('SendAndCommit', $source) }; + die $@ if $@; + if ($som->fault) { # indicates a protocol error + die $som->faultstring; + } + $DB::single = 1; + $som->match('/Envelope/Body/SendAndCommitResponse/SendAndCommitResult'); + my $result = $som->valueof; # hashref of the result properties + $self->is_success( $result->{Transaction_Approved} ); + $self->authorization( $result->{Authorization_Num} ); + $self->order_number( $result->{SequenceNo} ); + $self->avs_code( $result->{AVS} ); + $self->cvv2_response( $result->{CVV2} ); + + if (!$self->is_success) { + # note spelling of "EXact_Resp_Code" + if ($result->{EXact_Resp_Code} ne '00') { + # then there's something wrong with the transaction inputs + # (invalid card number, malformed amount, attempt to refund a + # transaction that didn't happen, etc.) + $self->error_message($result->{EXact_Message}); + $self->result_code($result->{EXact_Resp_Code}); + $self->failure_status(''); + # not a decline, as the transaction was never really detected + } else { + $self->error_message($result->{Bank_Message}); + $self->result_code($result->{Bank_Resp_Code}); + $self->failure_status( + $failure_status{$result->{Bank_Resp_Code}} || 'declined' + ); + } + } } 1;