1 package Business::OnlinePayment::IATSPayments;
2 use base qw( Business::OnlinePayment );
7 use Business::CreditCard;
9 #SOAP::Lite->import(+trace=>'debug');
11 our $VERSION = '0.02';
12 $VERSION = eval $VERSION; # modperlstyle: convert the string into a number
16 'info_compat' => '0.01',
17 'gateway_name' => 'IATS Payments',
18 'gateway_url' => 'http://home.iatspayments.com/',
19 'module_version' => $VERSION,
20 'supported_types' => [ 'CC', 'ECHECK' ],
21 #'token_support' => 1,
22 'test_transaction' => 1,
24 'supported_actions' => [ 'Normal Authorization',
34 #$self->build_subs(qw( order_number avs_code cvv2_response
35 # response_page response_code response_headers
38 $self->build_subs(qw( avs_code ));
45 my %content = $self->content();
48 my %types = ( 'visa' => 'CC',
50 'american express' => 'CC',
54 $content{'type'} = $types{lc($content{'type'})} || $content{'type'};
55 $self->transaction_type($content{'type'});
58 my $action = lc($content{'action'});
60 ( 'normal authorization' => 'ProcessCreditCardV1',
61 'credit' => 'ProcessCreditCardRefundWithTransactionIdV1',
64 ( 'normal authorization' => 'ProcessACHEFTV1',
65 'credit' => 'ProcessACHEFTRefundWithTransactionIdV1',
68 if ($self->transaction_type eq 'CC') {
69 $content{'action'} = $actions{$action} || $action;
70 } elsif ($self->transaction_type eq 'ECHECK') {
72 $content{'action'} = $check_actions{$action} || $action;
75 my %account_types = ('personal checking' => 'CHECKING',
76 'personal savings' => 'SAVINGS',
77 'business checking' => 'CHECKING',
78 'business savings' => 'SAVINGS',
79 #not technically B:OP valid i guess?
80 'checking' => 'CHECKING',
81 'savings' => 'SAVINGS',
83 $content{'account_type'} = $account_types{lc($content{'account_type'})}
84 || $content{'account_type'};
87 # stuff it back into %content
88 $self->content(%content);
95 my %content = $self->content();
97 $content{$map{$_}} = $content{$_};
99 $self->content(%content);
102 # NA: VISA, MC, AMX, DSC
103 # UK: VISA, MC, AMX, MAESTR
105 'VISA card' => 'VISA',
106 'MasterCard' => 'MC',
107 'Discover card' => 'DSC',
108 'American Express card' => 'AMEX',
109 'Switch' => 'MAESTR',
113 #https://www.iatspayments.com/english/help/rejects.html
115 '1' => 'Agent code has not been set up on the authorization system. Please call iATS at 1-888-955-5455.',
116 '2' => 'Unable to process transaction. Verify and re-enter credit card information.',
117 '3' => 'Invalid Customer Code.',
118 '4' => 'Incorrect expiration date.',
119 '5' => 'Invalid transaction. Verify and re-enter credit card information.',
120 '6' => 'Please have cardholder call the number on the back of the card.',
121 '7' => 'Lost or stolen card.',
122 '8' => 'Invalid card status.',
123 '9' => 'Restricted card status. Usually on corporate cards restricted to specific sales.',
124 '10' => 'Error. Please verify and re-enter credit card information.',
125 '11' => 'General decline code. Please have client call the number on the back of credit card',
126 '12' => 'Incorrect CVV2 or Expiry date',
127 '14' => 'The card is over the limit.',
128 '15' => 'General decline code. Please have client call the number on the back of credit card',
129 '16' => 'Invalid charge card number. Verify and re-enter credit card information.',
130 '17' => 'Unable to authorize transaction. Authorizer needs more information for approval.',
131 '18' => 'Card not supported by institution.',
132 '19' => 'Incorrect CVV2 security code',
133 '22' => 'Bank timeout. Bank lines may be down or busy. Re-try transaction later.',
134 '23' => 'System error. Re-try transaction later.',
135 '24' => 'Charge card expired.',
136 '25' => 'Capture card. Reported lost or stolen.',
137 '26' => 'Invalid transaction, invalid expiry date. Please confirm and retry transaction.',
138 '27' => 'Please have cardholder call the number on the back of the card.',
139 '32' => 'Invalid charge card number.',
140 '39' => 'Contact IATS 1-888-955-5455.',
141 '40' => 'Invalid card number. Card not supported by IATS.',
142 '41' => 'Invalid Expiry date.',
143 '42' => 'CVV2 required.',
144 '43' => 'Incorrect AVS.',
145 '45' => 'Credit card name blocked. Call iATS at 1-888-955-5455.',
146 '46' => 'Card tumbling. Call iATS at 1-888-955-5455.',
147 '47' => 'Name tumbling. Call iATS at 1-888-955-5455.',
148 '48' => 'IP blocked. Call iATS at 1-888-955-5455.',
149 '49' => 'Velocity 1 – IP block. Call iATS at 1-888-955-5455.',
150 '50' => 'Velocity 2 – IP block. Call iATS at 1-888-955-5455.',
151 '51' => 'Velocity 3 – IP block. Call iATS at 1-888-955-5455.',
152 '52' => 'Credit card BIN country blocked. Call iATS at 1-888-955-5455.',
153 '100' => 'DO NOT REPROCESS. Call iATS at 1-888-955-5455.',
154 #Timeout The system has not responded in the time allotted. Call iATS at 1-888-955-5455.
157 our %failure_status = (
164 '45' => 'blacklisted',
165 '48' => 'blacklisted',
166 '49' => 'blacklisted',
167 '50' => 'blacklisted',
168 '51' => 'blacklisted',
169 '52' => 'blacklisted',
170 #'100' => # it sounds serious. but why? it says nothing specific
179 login => 'agentCode',
180 password => 'password',
182 description => 'comment',
184 invoice_number => 'invoiceNum',
185 customer_ip => 'customerIPAddress',
187 last_name => 'lastName',
188 first_name => 'firstName',
189 address => 'address',
193 #country => 'x_Country',
195 card_number => 'creditCardNum',
196 expiration => 'creditCardExpiry',
199 authorization => 'transactionId',
201 account_type => 'accountType',
205 my %content = $self->content();
207 $content{'mop'} = $mop{ cardtype($content{creditCardNum}) }
208 if $content{'type'} eq 'CC';
210 if ( $self->test_transaction ) {
211 $content{agentCode} = 'TEST88';
212 $content{password} = 'TEST88';
216 ( ! $content{currency} || $content{currency} =~ /^(USD|CAD)$/i )
217 ? 'https://www.iatspayments.com/NetGate/'
218 : 'https://www.uk.iatspayments.com/NetGate/';
220 my $action = $content{action};
222 my $uri = $base_uri. "ProcessLink.asmx?op=$action";
224 my %data = map { $_ => $content{$_} } (qw(
232 if ( $action =~ /RefundWithTransacdtionIdV[\d\.]+$/ ) {
234 $data{ $_ } = $content{$_} for qw(
240 $data{ $_ } = $content{$_} for qw(
250 if ( $content{'type'} eq 'CC' ) {
252 $data{$_} = $content{$_}
253 for qw( creditCardNum creditCardExpiry cvv2 mop );
255 } elsif ( $content{'type'} eq 'ECHECK' ) {
257 $data{'accountNum'}= $content{'routing_code'}. $content{'account_number'};
259 $data{$_} = $content{$_}
260 for qw( accountType );
266 my @opts = map { SOAP::Data->name($_)->value( $data{$_} ) }
269 my $result = SOAP::Lite
271 ->default_ns($base_uri)
272 #->on_action( sub { join '/', @_ } )
273 ->on_action( sub { join '', @_ } )
280 my $iatsresponse = $result->{IATSRESPONSE};
282 if ( $iatsresponse->{STATUS} eq 'Failure' && $iatsresponse->{ERRORS} ) {
283 die 'iATS Payments error: '. $iatsresponse->{ERRORS}. "\n";
284 } elsif ( $iatsresponse->{STATUS} ne 'Success' ) {
285 die "Couldn't parse iATS Payments response: ". Dumper($result);
288 my $processresult = $iatsresponse->{PROCESSRESULT};
290 if ( defined( $processresult->{TRANSACTIONID} ) ) {
291 $processresult->{TRANSACTIONID} =~ s/^\s+//;
292 $processresult->{TRANSACTIONID} =~ s/\s+$//;
294 $self->authorization($processresult->{TRANSACTIONID} || '');
296 if ( $processresult->{AUTHORIZATIONRESULT} =~ /^\s*OK(:\s*\d+:)?(\w)?\s*$/i ) {
297 $self->is_success(1);
298 $self->avs_code($2); #avs_code? sure looks like one
300 } elsif ( $processresult->{AUTHORIZATIONRESULT} =~ /^\s*Timeout\s*$/i ) {
301 $self->is_success(0);
302 $self->error_message('The system has not responded in the time allotted. '.
303 'Call iATS at 1-888-955-5455.');
305 } elsif ( $processresult->{AUTHORIZATIONRESULT}
306 =~ /^\s*REJ(ECT)?:\s*(\d+)\s*$/i
309 $self->is_success(0);
310 $self->result_code($2);
311 $self->error_message( $reject{$2} || $processresult->{AUTHORIZATIONRESULT});
312 $self->failure_status( $failure_status{$2} || 'decline' );
315 die "No/Unknown AUTHORIZATIONRESULT iATS Payments response: ".
316 Dumper($processresult);
327 Business::OnlinePayment::IATSPayments - IATS Payments backend for Business::OnlinePayment
331 use Business::OnlinePayment;
334 new Business::OnlinePayment( 'IATSPayments' );
337 login => 'TEST88', # agentCode
338 password => 'TEST88', #password
341 action => 'Normal Authorization',
344 first_name => 'Tofu',
345 last_name => 'Beast',
346 address => '123 Anystreet',
351 card_number => '4111111111111111',
352 expiration => '09/20',
356 description => 'Business::OnlinePayment test',
357 customer_ip => '1.2.3.4',
362 if($tx->is_success()) {
363 print "Card processed successfully: ".$tx->authorization."\n";
365 print "Card was rejected: ".$tx->error_message."\n";
368 =head1 SUPPORTED TRANSACTION TYPES
370 =head2 CC, Visa, MasterCard, American Express, Discover
372 Content required: type, login, action, amount, card_number, expiration.
376 Content required: type, login, action, amount, name, account_number, routing_code.
380 For detailed information see L<Business::OnlinePayment>.
382 =head1 METHODS AND FUNCTIONS
384 See L<Business::OnlinePayment> for the complete list. The following methods either override the methods in L<Business::OnlinePayment> or provide additional functions.
388 Returns the response error code.
392 Returns the response error number.
396 The following actions are valid
403 Business::OnlinePayment::IATSPayments uses iATS WebServices ProcessLink 4.0
404 and (for tokenization support) iATS WebServices CustomerLink 4.0.
408 Ivan Kohler <ivan-iatspayments@freeside.biz>
412 perl(1). L<Business::OnlinePayment>.