initial import
[Business-OnlinePayment-Network1Financial.git] / Network1Financial.pm
1 package Business::OnlinePayment::Network1Financial;
2
3 use strict;
4 use Carp;
5 use Business::OnlinePayment;
6 #use Business::CreditCard;
7 use Net::SSLeay qw( make_form post_https make_headers );
8 use URI;
9 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $DEBUG);
10
11 require Exporter;
12
13 @ISA = qw(Exporter AutoLoader Business::OnlinePayment);
14 @EXPORT = qw();
15 @EXPORT_OK = qw();
16 $VERSION = '0.01';
17
18 $DEBUG = 0;
19
20 #my %error = (
21 #  000000 => 'INTERNAL SERVER ERROR',
22 #  000001 => 'INTERNAL SERVER ERROR',
23 #  000002 => 'INTERNAL SERVER ERROR',
24 #  900000 => 'INVALID T_ORDERNUM',
25 #  900001 => 'INVALID C_NAME',
26 #  900002 => 'INVALID C_ADDRESS',
27 #  900003 => 'INVALID C_CITY',
28 #  900004 => 'INVALID C_STATE',
29 #  900005 => 'INVALID C_ZIP',
30 #  900006 => 'INVALID C_COUNTRY',
31 #  900007 => 'INVALID C_TELEPHONE',
32 #  900008 => 'INVALID C_FAX',
33 #  900009 => 'INVALID C_EMAIL',
34 #  900010 => 'INVALID C_SHIP_NAME',
35 #  900011 => 'INVALID C_SHIP_ADDRESS',
36 #  900012 => 'INVALID C_SHIP_CITY',
37 #  900013 => 'INVALID C_SHIP_STATE',
38 #  900014 => 'INVALID C_SHIP_ZIP',
39 #  900015 => 'INVALID C_SHIP_COUNTRY',
40 #  900016 => 'INVALID C_CARDNUMBER',
41 #  900017 => 'INVALID C_EXP',
42 #  900018 => 'INVALID C_CVV',
43 #  900019 => 'INVALID T_AMT',
44 #  900020 => 'INVALID T_CODE',
45 #  900021 => 'INVALID T_AUTH',
46 #  900022 => 'INVALID T_REFERENCE',
47 #  900023 => 'INVALID T_TRACKDATA',
48 #  900024 => 'INVALID T_TRACKING_NUMBER',
49 #  900025 => 'INVALID T_CUSTOMER_NUMBER',
50 #  910000 => 'SERVICE NOT ALLOWED',
51 #  910001 => 'VISA NOT ALLOWED',
52 #  910002 => 'MASTERCARD NOT ALLOWED',
53 #  910003 => 'AMEX NOT ALLOWED',
54 #  910004 => 'DISCOVER NOT ALLOWED',
55 #  910005 => 'CARD TYPE NOT ALLOWED',
56 #  911911 => 'SECURITY VIOLATION',
57 #  920000 => 'ITEM NOT FOUND',
58 #  920001 => 'CREDIT VOL EXCEEDED',
59 #  920002 => 'AVS FAILURE',
60 #  999999 => 'INTERNAL SERVER ERROR',
61 #);
62
63 sub set_defaults {
64     my $self = shift;
65     $self->server('va.eftsecure.net');
66     $self->port('443');
67     #$self->path('/cgi-bin/eftBankcard.dll?transaction');
68     #$self->build_subs(qw( product_id merchant_id ));
69 }
70
71 sub map_fields {
72     my $self = shift;
73     my %content = $self->content();
74
75     # ACTION MAP
76     my %actions = ( 'normal authorization' => '01',
77                     'authorization only'   => '02',
78                     'credit'               => '06',
79                     'post authorization'   => '03',
80                   );
81     $content{'action'} = $actions{lc($content{'action'})} || $content{'action'};
82
83     # TYPE MAP
84     my %types = ('visa'               => 'BankCard',
85                  'mastercard'         => 'BankCard',
86                  'american express'   => 'BankCard',
87                  'discover'           => 'BankCard',
88                  'cc'                 => 'BankCard',
89                  'check'              => 'VirtualCheck',
90                 );
91     $content{'type'} = $types{lc($content{'type'})} || $content{'type'};
92     $self->transaction_type($content{'type'});
93
94     # stuff it back into %content
95     $self->content(%content);
96 }
97
98 sub revmap_fields {
99     my($self, %map) = @_;
100     my %content = $self->content();
101     foreach(keys %map) {
102         $content{$_} = ref($map{$_})
103                          ? ${ $map{$_} }
104                          : $content{$map{$_}};
105     }
106     $self->content(%content);
107 }
108
109 sub submit {
110     my $self = shift;
111     $self->map_fields();
112     my %content = $self->content();
113
114     my $action = lc($content{'action'});
115     if ( $action eq '01' ) {
116     } else {
117       croak "$action not (yet) supported";
118     }
119     
120     my $type = $content{'type'};
121     if ( $type eq 'BankCard' ) {
122     } else {
123       croak "$type not (yet) supported";
124     }
125
126     ( my $exp = $content{'expiration'} ) =~ s/\///;
127
128     $self->revmap_fields(
129         'M_id'              => 'login',
130         'M_key'             => 'password',
131         'C_name'            => 'name',
132         'C_address'         => 'address',
133         'C_city'            => 'city',
134         'C_state'           => 'state',
135         'C_zip'             => 'zip',
136         'C_country'         => 'country',
137         'C_email'           => 'email',
138         'C_cardnumber'      => 'card_number',
139         'C_exp'             => \$exp,
140         'T_amount'          => 'amount',
141         'T_code'            => 'action',
142         #'T_ordernum'        => 'invoice_number', #probably not unique...
143         #'T_auth'            =>
144         #'T_trackdata'       =>
145         'C_cvv'             => 'cvv',
146         'T_customer_number' => 'customer_id',
147         #'T_tax'             =>
148         #'T_shipping'        =>
149         #'C_ship_name'       =>
150         #'C_ship_address'    =>
151         #'C_ship_city'       =>
152         #'C_ship_state'      =>
153         #'C_ship_zip'        =>
154         #'C_ship_country'    =>
155         'C_telephone'       => 'phone',
156         #'C_fax'             => 'fax',
157     );
158
159     my %post_data = $self->get_fields(qw(
160         M_id M_key C_name C_address C_city C_state C_zip C_country C_email
161         C_cardnumber C_exp T_amt T_code
162         C_cvv T_customer_number
163         C_telephone
164     ));
165         #T_ordernum T_auth T_trackdata
166         #T_tax T_shipping C_ship_name C_ship_address C_ship_city C_ship_state
167         #C_ship_zip C_ship_country
168         #C_fax
169
170     my $pd = make_form(%post_data);
171     my $s = $self->server();
172     my $p = $self->port();
173     my $t = "/cgi-bin/eft$type.dll?transaction";
174     my($page,$server_response,%headers) = post_https($s,$p,$t,'',$pd);
175
176     my $approved = substr($page,1, 1); #A is approved E is declined/error.
177     my $result_code = substr($page, 2, 6);
178     my $error_message = substr($page, 8, 32);
179     #print "Front-End Indicator: " . substr($page, 40, 2);
180     #print "CVV Indicator: " . substr($page, 42, 1);
181     #print "AVS Indicator: " . substr($page, 43, 1);
182     #print "Risk Indicator: " . substr($page, 44, 2);
183     my $reference = substr($page, 46, 10);
184     #print "Order Number: " . substr($page, index($page, chr(28)) + 1,
185     #                      rindex($page, chr(28)) - index($page, chr(28)) - 1);
186
187     if ( $approved eq 'A' ) {
188       $self->is_success(1);
189       $self->result_code($result_code);
190       $self->error_message($error_message);
191       $self->authorization($reference);
192     } else {
193       $self->is_success(0);
194       $self->result_code($result_code);
195       $self->error_message($error_message);
196     }
197
198 }
199
200 1;
201 __END__
202
203 =head1 NAME
204
205 Business::OnlinePayment::Network1Financial - Network1 Financial backend for Business::OnlinePayment
206
207 =head1 SYNOPSIS
208
209   use Business::OnlinePayment;
210
211   my $tx = new Business::OnlinePayment("Network1Financial");
212   $tx->content(
213       type           => 'CC',
214       login          => 'test', #12 Digit ID Number
215       password       => 'test', #12 Digit Security Key
216       action         => 'Normal Authorization',
217       description    => 'Business::OnlinePayment test',
218       amount         => '49.95',
219       invoice_number => '100100',
220       name           => 'Tofu Beast',
221       card_number    => '4007000000027',
222       expiration     => '09/02',
223   );
224   $tx->submit();
225
226   if($tx->is_success()) {
227       print "Card processed successfully: ".$tx->authorization."\n";
228   } else {
229       print "Card was rejected: ".$tx->error_message."\n";
230   }
231
232 =head1 DESCRIPTION
233
234 For detailed information see L<Business::OnlinePayment>.
235
236 =head1 NOTE
237
238 This module only implements credit card trasactions at this time.  Electronic
239 check (ACH) transactions are not (yet) supported.
240
241 =head1 COMPATIBILITY
242
243 This module implements the interface documented at
244 https://va.eftsecure.net/VirtualTerminal/Documentation/
245
246 =head1 AUTHOR
247
248 Ivan Kohler <ivan-network1financial@420.am>
249
250 =head1 SEE ALSO
251
252 perl(1). L<Business::OnlinePayment>
253
254 =cut
255