Make sure expiration date has a leading zero
[Business-OnlinePayment-TransactionCentral.git] / lib / Business / OnlinePayment / TransactionCentral.pm
1 package Business::OnlinePayment::TransactionCentral;
2
3 use 5.005;
4 use strict;
5 use Carp;
6 use Business::OnlinePayment 3;
7 use Business::OnlinePayment::HTTPS 0.02;
8 use vars qw($VERSION @ISA $DEBUG);
9
10 @ISA = qw(Business::OnlinePayment::HTTPS);
11 $VERSION = '0.02';
12 $DEBUG = 0;
13
14 sub set_defaults {
15     my $self = shift;
16
17     $self->server('webservices.primerchants.com');
18     $self->port('443');
19     $self->path('/billing/TransactionCentral/');
20
21     $self->build_subs(qw( order_number avs_code cvv2_response
22                           response_page response_code response_headers
23                      ));
24 }
25
26 sub submit {
27   my($self) = @_;
28
29   $self->revmap_fields(
30     'MerchantID'    => 'login',
31     'RegKey'        => 'password',
32     'Amount'        => 'amount',
33 #    'CreditAmount'  => 'amount',
34     'AccountNo'     => 'card_number',
35     'NameonAccount' => 'name',
36     'AVSADDR'       => 'address',
37     'AVSZIP'        => 'zip',
38     'CCRURL'        => \'',
39     'CVV2'          => 'cvv2',
40     'TransID'       => 'order_number',
41     'TRANSROUTE'    => 'routing_code',
42   );
43
44   #XXX also set required fields here...
45
46   my @required_fields = qw(login password);
47   my %content = $self->content();
48   my $action = $content{'action'};
49   my $url = $self->path;
50   if (
51     $content{'type'} =~ /^(cc|visa|mastercard|american express|discover)$/i
52   ) {
53
54     if ( $action =~ /^\s*normal\s*authorization\s*$/i ) {
55       $url .= 'processCC.asp';
56
57       #REFID
58       $content{'REFID'} = int(rand(2**31));
59
60       #CCMonth & CCYear
61       $content{'expiration'} =~ /^(\d+)\D+\d*(\d{2})$/
62         or croak "unparsable expiration ". $content{'expiration'};
63       my( $month, $year ) = ( $1, $2 );
64       $month = '0'. $month if $month =~ /^\d$/;
65       $content{'CCMonth'} = $month;
66       $content{'CCYear'} = $year;
67
68       #push @required_fields, qw( amount card_numb
69     } elsif ( $action =~ /^\s*authorization\s*only\s*$/i ) {
70       croak "Authorizaiton Only is not supported by Transaction Central";
71     } elsif ( $action =~ /^\s*post\s*authorization\s*$/i ) {
72       croak "Post Authorizaiton is not supported by Transaction Central";
73     } elsif ( $action =~ /^\s*(void|credit)\s*$/i ) {
74       $url .= 'voidcreditcconline.asp';
75
76       $content{'CreditAmount'} = delete $content{'Amount'};
77
78     } else {
79       croak "Unknown action $action";
80     }
81
82   } elsif ( $content{'type'} =~ /^check$/i ) {
83
84     if ( $action =~ /^\s*normal\s*authorization\s*$/i ) {
85       $url .= 'processcheck.asp';
86       $content{'AccountNo'} = $content{'account_number'};
87       $content{'TRANSTYPE'} = $content{'account_type'} =~ /^s/i ? 'SA' : 'CK';
88
89     } elsif ( $action =~ /^\s*authorization\s*only\s*$/i ) {
90       croak "Authorizaiton Only is not supported by Transaction Central";
91     } elsif ( $action =~ /^\s*post\s*authorization\s*$/i ) {
92       croak "Post Authorizaiton is not supported by Transaction Central";
93     } elsif ( $action =~ /^\s*(void|credit)\s*$/i ) {
94       $url .= 'addckcreditupdtonline.asp';
95     } else {
96       croak "Unknown action $action";
97     }
98
99   } else {
100     croak 'Unknown type: '. $content{'type'};
101   }
102   $self->path($url);
103   $self->content(%content);
104
105   my @fields = qw(
106     MerchantID RegKey Amount REFID AccountNo CCMonth CCYear NameonAccount
107     AVSADDR AVSZIP CCRURL CVV2 USER1 USER2 USER3 USER4 TrackData
108     TransID CreditAmount
109     DESCRIPTION DESCDATE TRANSTYPE TRANSROUTE
110   );
111
112   my( $page, $response, %reply_headers ) =
113     $self->https_post( $self->get_fields( @fields ) );
114
115   $self->response_code( $response );
116   $self->response_page( $page );
117   $self->response_headers( \%reply_headers );
118
119   warn "\n" if $DEBUG > 1;
120   if ( $DEBUG > 2 ) {
121     warn "response: $response\n";
122    # warn "reply headers: ".
123    #      join(', ', map "$_ => $reply_headers{$_}", keys %reply_headers ). "\n";
124   }
125   warn "raw response: $page\n" if $DEBUG > 1;
126
127   my %return = map { /^(\w+)=(.*)$/ ? ( $1 => $2 ) : () } split(/&/, $page);
128
129   if ( $DEBUG ) { warn "$_ => $return{$_}\n" foreach keys %return; }
130
131   #$self->result_code(   $return{'AVSCode'} );
132   $self->avs_code(      $return{'AVSCode'} );
133   $self->cvv2_response( $return{'CVV2ResponseMsg'} );
134
135   if ( $return{'Auth'} =~ /^(\d+)$/ ) {
136
137     $self->is_success(1);
138     $self->authorization( $return{'Auth'}   );
139     $self->order_number(  $return{'TransID'} );
140
141   } else {
142
143     $self->is_success(0);
144     $self->error_message( $return{'Notes'} );
145
146   }
147
148 }
149
150 sub revmap_fields {
151     my($self, %map) = @_;
152     my %content = $self->content();
153     foreach(keys %map) {
154 #    warn "$_ = ". ( ref($map{$_})
155 #                         ? ${ $map{$_} }
156 #                         : $content{$map{$_}} ). "\n";
157         $content{$_} = ref($map{$_})
158                          ? ${ $map{$_} }
159                          : $content{$map{$_}};
160     }
161     $self->content(%content);
162 }
163
164 1;
165
166 __END__
167
168 =head1 NAME
169
170 Business::OnlinePayment::TransactionCentral - Transaction Central backend module for Business::OnlinePayment
171
172 =head1 SYNOPSIS
173
174   use Business::OnlinePayment::TransactionCentral;
175   blah blah blah
176
177 =head1 DESCRIPTION
178
179   use Business::OnlinePayment;
180
181   ####
182   # One step transaction, the simple case.
183   ####
184
185   my $tx = new Business::OnlinePayment("TransactionCentral");
186   $tx->content(
187       type           => 'CC',
188       login          => '10011', #MerchantID
189       password       => 'KK48NPYEJHMAH6DK', #Regkey
190       action         => 'Normal Authorization',
191       description    => 'Business::OnlinePayment test',
192       amount         => '49.95',
193       name           => 'Tofu Beast',
194       address        => '123 Anystreet',
195       city           => 'Anywhere',
196       state          => 'UT',
197       zip            => '84058',
198       phone          => '420-867-5309',
199       email          => 'tofu.beast@example.com',
200       card_number    => '4012000000001',
201       expiration     => '08/06',
202       cvv2           => '1234', #optional
203   );
204   $tx->submit();
205
206   if($tx->is_success()) {
207       print "Card processed successfully: ".$tx->authorization."\n";
208   } else {
209       print "Card was rejected: ".$tx->error_message."\n";
210   }
211
212 =head1 SUPPORTED TRANSACTION TYPES
213
214 =head2 CC, Visa, MasterCard, American Express, Discover
215
216 Content required: type, login, password, action, amount, card_number, expiration.
217
218 =head1 PREREQUISITES
219
220   URI::Escape
221   #Tie::IxHash
222
223   Net::SSLeay _or_ ( Crypt::SSLeay and LWP )
224
225 =head1 DESCRIPTION
226
227 For detailed information see L<Business::OnlinePayment>.
228
229 =head1 NOTE
230
231 =head1 AUTHOR
232
233 Ivan Kohler <ivan-transactioncentral@420.am>
234
235 =head1 COPYRIGHT AND LICENSE
236
237 Copyright (C) 2006 by Ivan Kohler
238
239 This library is free software; you can redistribute it and/or modify
240 it under the same terms as Perl itself.
241
242 =head1 SEE ALSO
243
244 perl(1). L<Business::OnlinePayment>.
245
246 =cut