c765ecd2e040f23a1897152d9514b838bf4d10ac
[Business-OnlinePayment-Exact.git] / lib / Business / OnlinePayment / Exact.pm
1 package Business::OnlinePayment::Exact;
2
3 use 5.006001;
4 use strict;
5 use warnings;
6 use SOAP::Lite;
7 use Business::OnlinePayment;
8
9 our @ISA = qw(Business::OnlinePayment);
10 our @EXPORT_OK = ();
11 our @EXPORT = qw();
12
13 our $VERSION = '0.01';
14
15 sub set_defaults {
16     my $self = shift;
17     $self->build_subs(qw(proxy on_action uri tns types process encodingstyle
18         order_number));
19     $self->proxy('https://secure2.e-xact.com/vpos/process/vpos.asmx');
20     $self->on_action('http://secure2.e-xact.com/vpos/process/Process');
21     $self->uri('http://secure2.e-xact.com/vpos/process/');
22     $self->tns('http://secure2.e-xact.com/vpos/process/');
23     $self->types('http://secure2.e-xact.com/vpos/process/encodedTypes');
24     $self->process('http://secure2.e-xact.com/vpos/process/Request');
25     $self->encodingstyle('http://schemas.xmlsoap.org/soap/encoding/');
26 }
27
28 sub map_fields {
29     my $self = shift;
30     my %content = $self->content();
31     my %actions = ('normal authorization' => '00',
32                    'authorization only' => '01',
33                    'credit' => '04',
34                    'post authorization' => '02',
35                    'void' => '13',
36     );
37     $content{'action'} = $actions{lc($content{'action'})};
38     $content{'name'} = $content{'first_name'}.' '.$content{'last_name'} ||
39         $content{'name'} if $content{'first_name'} and $content{'last_name'};
40     $content{'expiration'} =~ /(\d\d)\D*(\d\d)/ if $content{'expiration'};
41     $content{'expiration_month'} = $1 || $content{'expiration_month'};
42     $content{'expiration_year'} = $2 || $content{'expiration_year'};
43     $content{'expiration'} = $content{'expiration_month'}.
44         $content{'expiration_year'} || $content{'expiration'};
45     $self->content(%content);
46 }
47
48 sub remap_fields {
49     my($self,%map) = @_;
50
51     my %content = $self->content();
52     foreach(keys %map) {
53         $content{$map{$_}} = $content{$_};
54     }
55     $self->content(%content);
56 }
57
58 sub test_transaction {
59     my( $self, $enabled ) = @_;
60     die if $enabled;
61 }
62
63 sub submit {
64     my $self = shift;
65     $self->map_fields;
66     $self->remap_fields(
67         login => 'ExactID',
68         password => 'Password',
69         action => 'Transaction_Type',
70         amount => 'DollarAmount',
71         customer_ip => 'Client_IP',
72         order_number => 'Reference_No',
73         name => 'CardHoldersName',
74         address => 'VerificationStr1',
75         email => 'Client_Email',
76         card_number => 'Card_Number',
77         expiration => 'Expiry_Date',
78         referer => 'Customer_Ref', 
79     );
80     my %content = $self->content();
81     #make data here
82     my @data;
83     foreach (keys %content) {
84         push @data, SOAP::Data->name($_ => $content{$_})->type('string');
85     }
86
87     my $data = 
88     SOAP::Data->attr({'xsi:type' => 'types:Transaction'})
89         ->name('Transaction')->value(\SOAP::Data->value(@data));
90     #figure out action
91     #make request
92
93     my $s = SOAP::Lite
94     ->proxy($self->proxy)
95     ->on_action(sub{return $self->on_action})
96     ->uri($self->uri)
97     ->readable(1);
98
99     $s->serializer->register_ns($self->tns => 'tns');
100     $s->serializer->register_ns($self->types => 'types');
101
102     my $m = SOAP::Data->name('q1:Process')
103         ->attr({'xmlns:q1' => $self->process,
104         'soap:encodingStyle' => $self->encodingstyle});
105
106     my $result = $s->call($m => $data);
107     #get result
108     if ($result->fault) {
109         $self->is_success(0);
110         $self->error_message($result->faultstring);
111     }
112     else {
113         if ($result->valueof('//TransactionResult/Transaction_Approved') 
114         eq '1' and $result->valueof('//TransactionResult/EXact_Resp_Code') 
115         eq '00' and $result->valueof('//TransactionResult/Transaction_Error') 
116         eq '0') {
117             $self->is_success(1);
118             $self->error_message(
119                 $result->valueof('//TransactionResult/EXact_Message'));
120             $self->authorization(
121                 $result->valueof('//TransactionResult/Authorization_Num'));
122             $self->order_number(
123                 $result->valueof('//TransactionResult/SequenceNo'));
124             }
125         else {
126             $self->is_success(0);
127             $self->error_message(
128                 $result->valueof('//TransactionResult/EXact_Message'));
129         }
130
131     }
132 }
133
134
135 1;
136 __END__
137 =head1 NAME
138
139 Business::OnlinePayment::Exact - Perl extension for doing credit card 
140 processing through the E-xact v7 Web Services API payment gateway.
141
142 =head1 SYNOPSIS
143
144   use Business::OnlinePayment;
145   my $tx = new Business::OnlinePayment('Exact');
146   $tx->content(
147     amount => '19.00',
148     card_number => '4200000000000000',
149     expiration => '0110',
150     name => 'Some Guy',
151     action => 'authorization only',
152     login => 'A000XX-XX'
153     password => 'password'
154   );
155   $tx->submit;
156   if ($tx->is_success()) {
157     my $ordernum = $tx->order_number;
158     print "Got the cash";
159   }
160   else {
161     print $tx->error_message;
162   }
163
164 =head1 ABSTRACT
165
166     This is a Business::OnlinePayment module for E-xact loosely based on
167     Business::OnlinePayment::AuthorizeNet.  I've only used it for normal
168     authorization so it may require some work to do pre auth, etc.
169
170
171 =head1 DESCRIPTION
172
173     See synopsis.  It works like any other Business::OnlinePayment module.
174     The following content keys are usefull:
175     login
176     password
177     amount
178     card_number
179     expiration
180     name
181     referer
182     email
183     address
184     order_number
185     customer_ip
186     action
187
188     The following content keys are also available (but not really usefull):
189     'first_name' and 'last_name' will combine to override 'name'
190     'expiration_month' and 'expiration_year' will combine to override 
191     'expiration'
192
193     The 'authorization' method will return the bank authorization code, and the
194     'order_number' method will contain the sequence number from E-xact.
195     The content key 'referer' can be used to store any string data (20 bytes)
196     and used to search for those transactions from the web interface.
197
198 =head2 EXPORT
199
200 None by default.
201
202 =head1 SEE ALSO
203
204 Business::OnlinePayment
205 SOAP::Lite
206 "Exact Payment WebService Plug-In Programming Reference Guide v7"
207 (which can be found on www.e-xact.com with enough digging)
208
209 =head1 AUTHOR
210
211 mock, E<lt>mock@obscurity.orgE<gt>
212
213 =head1 COPYRIGHT AND LICENSE
214
215 Copyright (C) 2005 by mock
216
217 This library is free software; you can redistribute it and/or modify
218 it under the same terms as Perl itself, either Perl version 5.8.1 or,
219 at your option, any later version of Perl 5 you may have available.
220
221 =cut