1package Business::OnlinePayment::PaymentsGateway; 2 3use strict; 4use Carp; 5use Business::OnlinePayment; 6use Net::SSLeay qw(sslcat); 7use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $DEBUG); 8 9@ISA = qw( Business::OnlinePayment ); 10$VERSION = '0.02'; 11 12$DEBUG = 0; 13 14my %pg_response_code = ( 15 'A01' => 'Transaction approved/completed', 16 'U01' => 'Merchant not allowed to access customer account', 17 'U02' => 'Customer account is in the ACH Direct "known bad" list', 18 'U03' => 'Merchant daily limit exceeded', 19 'U04' => 'Merchant monthly limit exceeded', 20 'U05' => 'AVS state/zipcode check failed', 21 'U06' => 'AVS state/area code check failed', 22 'U07' => 'AVS anonymous email check failed', 23 'U08' => 'Account has more transactions than the merchant\'s daily velocity'. 24 ' limit allows for', 25 'U09' => 'Account has more transactions than the merchant\'s velocity'. 26 ' window allows for', 27 'U10' => 'Transaction has the same attributes as another transaction'. 28 ' within the time set by the merchant', 29 'U11' => '(RECUR TRANS NOT FOUND) Transaction types 40-42 only', 30 'U12' => 'Original transaction not voidable or capture-able', 31 'U13' => 'Transaction to be voided or captured was not found', 32 'U14' => 'void/capture and original transaction types do not agree (CC/EFT)', 33 'U18' => 'Void or Capture failed', 34 #'U19' => 'Account ABA number if invalid', 35 'U19' => 'Account ABA number is invalid', 36 'U20' => 'Credit card number is invalid', 37 'U21' => 'Date is malformed', 38 'U22' => 'Swipe data is malformed', 39 'U23' => 'Malformed expiration date', 40 'U51' => 'Merchant is not "live"', 41 'U52' => 'Merchant not approved for transaction type (CC or EFT)', 42 'U53' => 'Transaction amount exceeds merchant\'s per transaction limit', 43 'U54' => 'Merchant\'s configuration requires updating - call customer'. 44 ' support', 45 'U80' => 'Transaction was declined due to preauthorization (ATM Verify)'. 46 ' result', 47 'U84' => 'Preauthorizer not responding', 48 'U85' => 'Preauthorizer error', 49 'U83' => 'Transaction was declined due to authorizer declination', 50 'U84' => 'Authorizer not responding', 51 'U85' => 'Authorizer error', 52 'U86' => 'Authorizer AVS check failed', 53 'F01' => 'Required field is missing', 54 'F03' => 'Name is not recognized', 55 'F04' => 'Value is not allowed', 56 'F05' => 'Field is repeated in message', 57 'F07' => 'Fields cannot both be present', 58 #'E10' => 'Merchant id or password in incorrect', 59 'E10' => 'Merchant id or password is incorrect', 60 'E20' => 'Transaction message not received (I/O flush required?)', 61 'E90' => 'Originating IP not on merchant\'s approved IP list', 62 'E99' => 'An unspecified error has occurred', 63); 64 65sub set_defaults { 66 my $self = shift; 67 $self->server('paymentsgateway.net'); 68 $self->port( 5050 ); 69} 70 71sub map_fields { 72 my $self = shift; 73 my %content = $self->content(); 74 75 #ACTION MAP 76 my %actions = ( 77 'normal authorization' => 0, 78 'authorization only' => 1, 79 'post authorization' => 2, 80 'credit' => 3, 81 ); 82 83 my %types = ( 84 'visa' => 10, 85 'mastercard' => 10, 86 'american express' => 10, 87 'discover' => 10, 88 'cc' => 10, 89 'check' => 20, 90 'echeck' => 20, 91 ); 92 93 #pg_type/action = action + type 94 95 $self->transaction_type( $actions{ lc($content{'action'}) } 96 + $types{ lc($content{'type' }) } ); 97 98 #$self->content(%content); 99} 100 101sub revmap_fields { 102 my($self, %map) = @_; 103 my %content = $self->content(); 104 foreach(keys %map) { 105 $content{$_} = ref($map{$_}) 106 ? ${ $map{$_} } 107 : $content{$map{$_}}; 108 } 109 $self->content(%content); 110} 111 112sub submit { 113 my $self = shift; 114 $self->map_fields(); 115 116 #my %content = $self->content(); 117 118 $self->revmap_fields( 119 'PG_MERCHANT_ID' => 'login', 120 'pg_password' => 'password', 121 'pg_transaction_type' => \($self->transaction_type()), 122 #'pg_merchant_data_1' 123 #... 124 #'pg_merchant_data_9' 125 'pg_total_amount' => 'amount', 126 #'pg_sales_tax_amount' 127 'pg_consumer_id' => 'customer_id', 128 'ecom_consumerorderid' => 'invoice_number', #??? 129 #'ecom_walletid' => 130 'pg_billto_postal_name_company' => 'company', #???? 131 'ecom_billto_postal_name_first' => 'first_name', #???? 132 'ecom_billto_postal_name_last' => 'last_name', # ???? 133 'ecom_billto_postal_street_line1' => 'address', 134 #'ecom_billto_postal_street_line2' 135 'ecom_billto_postal_city' => 'city', 136 'ecom_billto_postal_stateprov' => 'state', 137 'ecom_billto_postal_postalcode' => 'zip', 138 'ecom_billto_postal_countrycode' => 'country', 139 'ecom_billto_telecom_phone_number' => 'phone', 140 'ecom_billto_online_email' => 'email', 141 #'pg_billto_ssn' 142 #'pg_billto_dl_number' 143 #'pg_billto_dl_state' 144 'ecom_payment_check_trn' => 'routing_code', 145 'ecom_payment_check_account' => 'account_number', 146 'ecom_payment_check_account_type' => \'C', #checking 147 #'ecom_payment_check_checkno' => 148 ); 149 my %content = $self->content(); 150 151 # name (first_name & last_name ) ? 152 # fax 153 154 # card_number exp_date 155 156 #account_number routing_code bank_name 157 158 my @fields = ( 159 qw( PG_MERCHANT_ID pg_password pg_transaction_type ), 160 ( map { "pg_merchant_$_" } ( 1 .. 9 ) ), 161 qw( pg_total_amount pg_sales_tax_amount pg_consumer_id 162 ecom_consumerorderid ecom_walletid 163 pg_billto_postal_name_company 164 ecom_billto_postal_name_first ecom_billto_postal_name_last 165 ecom_billto_postal_street_line1 166 ecom_billto_postal_street_line2 167 ecom_billto_postal_city ecom_billto_postal_stateprov 168 ecom_billto_postal_postalcode ecom_billto_postal_countrycode 169 ecom_billto_telecom_phone_number ecom_billto_online_email 170 pg_billto_ssn pg_billto_dl_number pg_billto_dl_state 171 ) 172 ); 173 174 if ( $content{'type'} =~ /^e?check$/i ) { 175 push @fields, qw( ecom_payment_check_trn 176 ecom_payment_check_account 177 ecom_payment_check_account_type ); 178 } else { 179 croak $content{'type'}. ' not (yet) supported'; 180 } 181 182 my $request = join("\n", map { "$_=". $content{$_} } 183 grep { defined($content{$_}) && $content{$_} ne '' } 184 @fields ). 185 "\nendofdata\n"; 186 187 warn $request if $DEBUG; 188 189 warn "TEST: ". $self->test_transaction(). "\n" if $DEBUG; 190 191 $self->port( $self->port() + 1000 ) if $self->test_transaction(); 192 193 warn "SERVER ". $self->server(). "\n" if $DEBUG; 194 warn "PORT ". $self->port(). "\n" if $DEBUG; 195 196 my $reply = sslcat( $self->server(), $self->port(), $request ); 197 die "no reply from server" unless $reply; 198 199 warn "reply from server: $reply\n" if $DEBUG; 200 201 my %response = map { /^(\w+)=(.*)$/ or /^(endofdata)()$/ 202 or warn "can't parse response line: $_"; 203 ($1, $2); 204 } split(/\n/, $reply); 205 206 if ( $response{'pg_response_type'} eq 'A' ) { 207 $self->is_success(1); 208 $self->result_code($response{'pg_response_code'}); 209 $self->authorization($response{'pg_authorization_code'}); 210 } else { 211 $self->is_success(0); 212 $self->result_code($response{'pg_response_code'}); 213 $self->error_message( $pg_response_code{$response{'pg_response_code'}}. 214 ': '. $response{'pg_response_description'} ); 215 } 216} 217 2181; 219 220__END__ 221 222=head1 NAME 223 224Business::OnlinePayment::PaymentsGateway - PaymentsGateway.Net backend for Business::OnlinePayment 225 226=head1 SYNOPSIS 227 228 use Business::OnlinePayment; 229 230 my $tx = new Business::OnlinePayment("PaymentsGateway"); 231 $tx->content( 232 type => 'CHECK', 233 login => 'test', 234 password => 'test', 235 action => 'Normal Authorization', 236 description => 'Business::OnlinePayment test', 237 amount => '49.95', 238 invoice_number => '100100', 239 name => 'Tofu Beast', 240 account_number => '12345', 241 routing_code => '123456789', 242 bank_name => 'First National Test Bank', 243 ); 244 $tx->submit(); 245 246 if($tx->is_success()) { 247 print "Card processed successfully: ".$tx->authorization."\n"; 248 } else { 249 print "Card was rejected: ".$tx->error_message."\n"; 250 } 251 252=head1 DESCRIPTION 253 254For detailed information see L<Business::OnlinePayment>. 255 256=head1 NOTE 257 258This module only implements 'ECHECK' (ACH) transactions at this time. Credit 259card transactions are not (yet) supported. 260 261=head1 COMPATIBILITY 262 263This module implements the interface documented in the 264"PaymentsGateway.net Integration Guide, Version 2.1, September 2002" 265 266=head1 AUTHOR 267 268Ivan Kohler <ivan-paymentsgateway@420.am> 269 270=head1 SEE ALSO 271 272perl(1). L<Business::OnlinePayment> 273 274=cut 275 276