e99ab37ed47541a9ed9d951c71bdbcc5998dc6bb
[Business-OnlinePayment-eWay.git] / eWay.pm
1 package Business::OnlinePayment::eWay;
2
3 use strict;
4 use Carp;
5 use Business::OnlinePayment;
6 use Business::CreditCard;
7 use Net::SSLeay qw( post_https );
8 use XML::Simple;
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 = 1;
19
20 my $default_path = '/gateway/xmlpayment.asp';
21 my $default_cvn_path = '/gateway_cvn/xmlpayment.asp';
22 my $default_test_path = '/gateway/xmltest/testpage.asp';
23 my $default_cvn_test_path = '/gateway_cvn/xmltest/testpage.asp';
24
25 sub set_defaults {
26     my $self = shift;
27     $self->server('www.eway.com.au');
28     $self->port('443');
29     $self->path($default_path);
30 }
31
32 sub revmap_fields {
33     my($self,%map) = @_;
34     my %content = $self->content();
35     foreach(keys %map) {
36         $content{$_} = ref($map{$_})
37                          ? ${ $map{$_} }
38                          : (exists($content{$map{$_}})
39                              ? $content{$map{$_}}
40                              : '' 
41                            );
42     }
43     $self->content(%content);
44 }
45
46 sub get_fields {
47     my($self,@fields) = @_;
48
49     my %content = $self->content();
50     my %new = ();
51     foreach( grep defined $content{$_}, @fields) { $new{$_} = $content{$_}; }
52     return %new;
53 }
54
55 sub submit {
56     my($self) = @_;
57     my %content = $self->content;
58
59     my $action = lc($content{'action'});
60     die 'eSec only supports "Normal Authorization" transactions'
61       unless $action eq 'normal authorization';
62
63     $content{'expiration'} =~ /^(\d+)\D+(\d+)$/
64       or croak "unparsable expiration $content{expiration}";
65     my ($month, $year) = ( $1, $2 );
66     $month += 0;
67     $year %= 100; #not y2.1k safe
68
69     $content{'amount'} =~ /^(\d+\.+\d{0,2})$/
70       or croak "unparsable amount $content{amount}";
71     my $amount = $1*100;
72
73     my $address = $content{'address'} if exists $content{'address'};
74     $address .=   $content{'city'}    if exists $content{'city'};
75     $address .=   $content{'state'}   if exists $content{'state'};
76     $address .=   '';
77
78     $self->revmap_fields(
79       ewayCustomerID                 => 'login',
80       ewayTotalAmount                => \$amount,
81       ewayCustomerFirstName          => 'first_name',
82       ewayCustomerLastName           => 'last_name',
83       ewayCustomerEmail              => 'email',
84       ewayCustomerAddress            => \$address,
85       ewayCustomerPostcode           => 'zip',
86       ewayCustomerInvoiceDescription => 'description',
87       ewayCustomerInvoiceRef         => 'invoice_number',
88       ewayCardHoldersName            => 'name',
89       ewayCardNumber                 => 'card_number',
90       ewayCardExpiryMonth            => \$month,
91       ewayCardExpiryYear             => \$year,
92       ewayTrxnNumber                 => 'transaction_number',
93       ewayOption1                    => 'option1',
94       ewayOption2                    => 'option1',
95       ewayOption3                    => 'option1',
96       ewayCVN                        => 'cvv2',
97     );
98     %content = $self->content;
99     if ( $DEBUG ) {
100       warn "content:$_ => $content{$_}\n" foreach keys %content;
101     }
102
103     if ($self->transaction_type() eq 'CC' ) {
104       $self->required_fields(qw/action login amount name card_number expiration/);
105     } else {
106       croak("eWay can't handle transaction type: ".
107             $self->transaction_type());
108     }
109
110     my %post_data = $self->get_fields( map "$_", qw(
111       ewayCustomerID ewayTotalAmount ewayCustomerFirstName ewayCustomerLastName
112       ewayCustomerEmail ewayCustomerAddress ewayCustomerPostcode 
113       ewayCustomerInvoiceDescription ewayCustomerInvoiceRef ewayCardHoldersName
114       ewayCardNumber ewayCardExpiryMonth ewayCardExpiryYear ewayTrxnNumber
115       ewayOption1 ewayOption2 ewayOption3 ewayCVN
116     ) );
117     if ( $DEBUG ) {
118       warn "post_data:$_ => $post_data{$_}\n" foreach keys %post_data;
119     }
120
121     my $pd = XMLout({%post_data}, 'NoAttr' => 1, 'RootName' => 'ewaygateway');
122     if ( $DEBUG ) {
123       warn $pd,"\n";
124     }
125     my $server = $self->server();
126     my $port = $self->port();
127     my $path = $self->path();
128     if ($post_data{ewayCVN} && $path eq $default_path){
129       $path = $default_cvn_path;
130     }
131     if ($self->test_transaction) {
132       if ($path eq $default_path) {
133         $path = $default_test_path;
134       }elsif ($path eq $default_cvn_path){
135         $path = $default_cvn_test_path;
136       }else{
137         croak "Test mode not supported for path: $path\n";
138       }
139     }
140
141     my($page,$server_response) =
142       post_https($server,$port,$path,'',$pd);
143     if ( $DEBUG ) {
144       warn $page,"\n";
145     }
146
147     my $response;
148     if ($server_response =~ /HTTP\/1\.1 200 OK/){
149       $response = XMLin($page);
150     }else{
151       $response->{ewayTrxnError} = $server_response;
152     }
153
154     if ( $response->{ewayTrxnStatus} =~ /^True/ ) {
155       $self->is_success(1);
156       $self->authorization($response->{ewayAuthCode});
157     } else {
158       $self->is_success(0);
159     }
160     $self->error_message($response->{ewayTrxnError});
161     $self->server_response($response);
162 }
163
164 1;
165 __END__
166
167 =head1 NAME
168
169 Business::OnlinePayment::eWay - eWay backend for Business::OnlinePayment
170
171 =head1 SYNOPSIS
172
173   use Business::OnlinePayment;
174
175   my $tx = new Business::OnlinePayment("eWay");
176   $tx->content(
177       login          => '87654321', #ewayCustomerID
178       action         => 'Normal Authorization',
179       description    => 'Business::OnlinePayment test',
180       amount         => '49.95',
181       invoice_number => '100100',
182       name           => 'Tofu Beast',
183       card_number    => '46464646464646',
184       expiration     => '11/08',
185   );
186   $tx->submit();
187
188   if($tx->is_success()) {
189       print "Card processed successfully: ".$tx->authorization."\n";
190   } else {
191       print "Card was rejected: ".$tx->error_message."\n";
192   }
193
194 =head1 DESCRIPTION
195
196 For detailed information see L<Business::OnlinePayment>.
197
198 =head1 NOTE
199
200 =head1 COMPATIBILITY
201
202 This module implements eWay's XML API.  See
203 http://www.eway.com.au/support/xml.aspx for details.
204
205 =head1 AUTHOR
206
207 Jeff Finucane <jeff@cmh.net>
208
209 =head1 SEE ALSO
210
211 perl(1). L<Business::OnlinePayment>.
212
213 =cut
214