use vars qw($VERSION $DEBUG @ISA $me);
@ISA = qw(Business::OnlinePayment::HTTPS);
-$VERSION = '2.00';
+$VERSION = '2.01';
$DEBUG = 0;
$me='Business::OnlinePayment::PaymenTech';
'Content-Transfer-Encoding' => 'text',
'Request-Number' => 1,
'Document-Type' => 'Request',
- #'Trace-Number' => 1,
'Interface-Version' => "$me $VERSION",
); # Content-Type has to be passed separately
CurrencyExponent => ':currency_exp',
CardSecValInd => ':cvvind',
CardSecVal => ':cvv2',
-# AVSname => ':name', not needed
AVSzip => ':zip',
AVSaddress1 => ':address',
AVScity => ':city',
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 = (
action
bin
merchant_id
- card_number
- expiration
- currency
- address
- city
- zip
invoice_number
amount
)
$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
+ ));
}
('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
}
$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));
}
$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);
$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;