From 5c47ecbab800bca7daaab03436951396aa98804f Mon Sep 17 00:00:00 2001 From: mark Date: Sun, 29 Nov 2009 21:02:06 +0000 Subject: [PATCH] Added support for MarkForCapture and Reversal transactions. --- Changes | 2 + lib/Business/OnlinePayment/PaymenTech.pm | 109 ++++++++++++++++++++++--------- 2 files changed, 81 insertions(+), 30 deletions(-) diff --git a/Changes b/Changes index a616435..acb3016 100644 --- a/Changes +++ b/Changes @@ -2,3 +2,5 @@ Revision history for Business-OnlinePayment-PaymenTech 2.00 Wed Oct 7 09:25:34 PDT 2009 Complete rewrite to use the XML interface directly. +2.01 Sun Nov 29 12:59:44 PST 2009 + Added support for MarkForCapture and Reversal transactions. diff --git a/lib/Business/OnlinePayment/PaymenTech.pm b/lib/Business/OnlinePayment/PaymenTech.pm index bbbae48..0f23ee7 100644 --- a/lib/Business/OnlinePayment/PaymenTech.pm +++ b/lib/Business/OnlinePayment/PaymenTech.pm @@ -8,7 +8,7 @@ use Tie::IxHash; use vars qw($VERSION $DEBUG @ISA $me); @ISA = qw(Business::OnlinePayment::HTTPS); -$VERSION = '2.00'; +$VERSION = '2.01'; $DEBUG = 0; $me='Business::OnlinePayment::PaymenTech'; @@ -17,7 +17,6 @@ my %request_header = ( 'Content-Transfer-Encoding' => 'text', 'Request-Number' => 1, 'Document-Type' => 'Request', - #'Trace-Number' => 1, 'Interface-Version' => "$me $VERSION", ); # Content-Type has to be passed separately @@ -36,7 +35,6 @@ tie my %new_order, 'Tie::IxHash', ( CurrencyExponent => ':currency_exp', CardSecValInd => ':cvvind', CardSecVal => ':cvv2', -# AVSname => ':name', not needed AVSzip => ':zip', AVSaddress1 => ':address', AVScity => ':city', @@ -44,6 +42,31 @@ tie my %new_order, 'Tie::IxHash', ( OrderID => ':invoice_number', Amount => ':amount', Comments => ':email', # as per B:OP:WesternACH + TxRefNum => ':order_number', # used only for Refund +); + +tie my %mark_for_capture, 'Tie::IxHash', ( + OrbitalConnectionUsername => ':login', + OrbitalConnectionPassword => ':password', + OrderID => ':invoice_number', + Amount => ':amount', + BIN => ':bin', + MerchantID => ':merchant_id', + TerminalID => ':terminal_id', + TxRefNum => ':order_number', +); + +tie my %reversal, 'Tie::IxHash', ( + OrbitalConnectionUsername => ':login', + OrbitalConnectionPassword => ':password', + TxRefNum => ':order_number', + TxRefIdx => 0, + OrderID => ':invoice_number', + BIN => ':bin', + MerchantID => ':merchant_id', + TerminalID => ':terminal_id', +# Always attempt to reverse authorization. + OnlineReversalInd => 'Y', ); my %defaults = ( @@ -58,12 +81,6 @@ my @required = ( qw( action bin merchant_id - card_number - expiration - currency - address - city - zip invoice_number amount ) @@ -83,7 +100,17 @@ sub set_defaults { $self->port('443') unless $self->port; $self->path('/authorize') unless $self->path; - $self->build_subs(qw( TxRefNum ProcStatus ApprovalStatus StatusMsg Response )); + $self->build_subs(qw( + order_number + ProcStatus + ApprovalStatus + StatusMsg + Response + RespCode + AuthCode + AVSRespCode + CVV2RespCode + )); } @@ -120,19 +147,15 @@ sub map_fields { ('normal authorization' => 'AC', 'authorization only' => 'A', 'credit' => 'R', + 'void' => 'V', 'post authorization' => 'MFC', # for our use, doesn't go in the request ); $content{'message_type'} = $message_type{lc($content{'action'})} or die "unsupported action: '".$content{'action'}."'"; - if($content{'message_type'} eq 'MFC') { - die 'MarkForCapture not implemented'; - # for later implementation - } foreach (keys(%defaults) ) { $content{$_} = $defaults{$_} if !defined($content{$_}); } - $DB::single=1; if(length($content{merchant_id}) == 12) { $content{bin} = '000002' # PNS } @@ -158,12 +181,8 @@ sub map_fields { $content{name} = $content{first_name} . ' ' . $content{last_name}; # According to the spec, the first 8 characters of this have to be unique. # The test server doesn't enforce this, but we comply anyway to the extent possible. - if($content{invoice_number}) { - # Mark it so that it's obvious that this is an invoice number - $content{invoice_number} = 'INV '.$content{invoice_number}; - } - else { - # Otherwise, make something up! + if(! $content{invoice_number}) { + # Choose one arbitrarily $content{invoice_number} ||= sprintf("%04x%04x",time % 2**16,int(rand() * 2**16)); } @@ -178,14 +197,31 @@ sub submit { $DB::single = $DEBUG; $self->map_fields(); + my %content = $self->content; - # This will change when we add e-check support my @required_fields = @required; - $self->required_fields(@required_fields); + my $request; + if( $content{'message_type'} eq 'MFC' ) { + $request = { MarkForCapture => $self->build(\%mark_for_capture) }; + push @required_fields, 'order_number'; + } + elsif( $content{'message_type'} eq 'V' ) { + $request = { Reversal => $self->build(\%reversal) }; + } + else { + $request = { NewOrder => $self->build(\%new_order) }; + push @required_fields, qw( + card_number + expiration + currency + address + city + zip + ); + } - # This will change when we add mark-for-capture support - my $request = { NewOrder => $self->build(\%new_order) }; + $self->required_fields(@required_fields); my $post_data = XMLout({ Request => $request }, KeepRoot => 1, NoAttr => 1, NoSort => 1); @@ -208,23 +244,36 @@ sub submit { $response = XMLin($page, KeepRoot => 0); $self->Response($response); my ($r) = values(%$response); + foreach(qw(ProcStatus RespCode AuthCode AVSRespCode CVV2RespCode)) { + if(exists($r->{$_}) and + !ref($r->{$_})) { + $self->$_($r->{$_}); + } + } if(!exists($r->{'ProcStatus'})) { $error = "Malformed response: '$page'"; + $self->is_success(0); } - elsif($r->{'ProcStatus'} != 0 || $r->{'ApprovalStatus'} != 1) { + elsif( $r->{'ProcStatus'} != 0 or + # NewOrders get ApprovalStatus, Reversals don't. + ( exists($r->{'ApprovalStatus'}) ? + $r->{'ApprovalStatus'} != 1 : + $r->{'StatusMsg'} ne 'Approved' ) + ) { $error = "Transaction error: '". ($r->{'ProcStatusMsg'} || $r->{'StatusMsg'}) . "'"; + $self->is_success(0); } else { # success! $self->is_success(1); - $self->authorization($r->{'TxRefNum'}); + # For credits, AuthCode is empty and gets converted to a hashref. + $self->authorization($r->{'AuthCode'}) if !ref($r->{'AuthCode'}); + $self->order_number($r->{'TxRefNum'}); } - }else{ + } else { $error = "Server error: '$server_response'"; } $self->error_message($error); - $self->is_success(0) if $error; - } 1; -- 2.11.0