1 package Business::OnlinePayment::AuthorizeNet::ARB;
5 use Business::OnlinePayment::AuthorizeNet;
6 use Business::OnlinePayment::HTTPS;
10 use vars qw($VERSION $DEBUG @ISA $me);
12 @ISA = qw(Business::OnlinePayment::AuthorizeNet Business::OnlinePayment::HTTPS);
15 $me='Business::OnlinePayment::AuthorizeNet::ARB';
20 $self->server('api.authorize.net') unless $self->server;
21 $self->port('443') unless $self->port;
22 $self->path('/xml/v1/request.api') unless $self->path;
24 $self->build_subs(qw( order_number md5 avs_code cvv2_response
32 my %content = $self->content();
35 my %actions = ('recurring authorization'
36 => 'ARBCreateSubscriptionRequest',
37 'modify recurring authorization'
38 => 'ARBUpdateSubscriptionRequest',
39 'cancel recurring authorization'
40 => 'ARBCancelSubscriptionRequest',
42 $content{'action'} = $actions{lc($content{'action'})} || $content{'action'};
45 my %types = ('visa' => 'CC',
47 'american express' => 'CC',
51 $content{'type'} = $types{lc($content{'type'})} || $content{'type'};
52 $self->transaction_type($content{'type'});
55 my %account_types = ('personal checking' => 'checking',
56 'personal savings' => 'savings',
57 'business checking' => 'businessChecking',
58 'business savings' => 'savings',
60 $content{'account_type'} = $account_types{lc($content{'account_type'})}
61 || $content{'account_type'};
64 $content{'expdate_yyyymm'} = $self->expdate_yyyymm($content{'expiration'});
66 # stuff it back into %content
67 $self->content(%content);
73 tie my(%map), 'Tie::IxHash', @_;
74 my %content = $self->content();
77 if ( ref( $map{$_} ) eq 'HASH' ) {
78 $value = $map{$_} if ( keys %{ $map{$_} } );
79 }elsif( exists( $content{ $map{$_} } ) ) {
80 $value = $content{ $map{$_} };
83 if (defined($value)) {
93 my $expiration = shift;
95 if ( defined($expiration) and $expiration =~ /^(\d{1,2})\D+(\d{2})$/ ) {
96 my ( $month, $year ) = ( $1, $2 );
97 $expdate_yyyymm = sprintf( "20%02d-%02d", $year, $month );
99 return defined($expdate_yyyymm) ? $expdate_yyyymm : $expiration;
103 my ($self, $writer, $item, $value) = @_;
104 $writer->startTag($item);
105 if ( ref( $value ) eq 'HASH' ) {
106 foreach ( keys ( %$value ) ) {
107 $self->_xmlwrite($writer, $_, $value->{$_});
110 $writer->characters($value);
112 $writer->endTag($item);
120 my @required_fields = qw(action login password);
122 if ( $self->{_content}->{action} eq 'ARBCreateSubscriptionRequest' ) {
123 push @required_fields,
124 qw( type interval start periods amount first_name last_name );
126 if ($self->transaction_type() eq "ECHECK") {
127 push @required_fields,
128 qw( amount routing_code account_number account_type account_name
131 } elsif ($self->transaction_type() eq 'CC' ) {
132 push @required_fields, qw( card_number expiration );
134 }elsif ( $self->{_content}->{action} eq 'ARBUpdateSubscriptionRequest' ) {
135 push @required_fields, qw( subscription );
136 }elsif ( $self->{_content}->{action} eq 'ARBCancelSubscriptionRequest' ) {
137 push @required_fields, qw( subscription );
139 croak "$me can't handle transaction type: ".
140 $self->{_content}->{action}. " for ".
141 $self->transaction_type();
144 $self->required_fields(@required_fields);
146 tie my %merchant, 'Tie::IxHash',
147 $self->revmap_fields(
149 transactionKey => 'password',
153 ($self->{_content}->{interval} or '') =~ /^\s*(\d+)\s+(day|month)s?\s*$/;
154 tie my %interval, 'Tie::IxHash', (
155 ($length ? (length => $length) : () ),
156 ($unit ? (unit => $unit.'s') : () ),
159 tie my %schedule, 'Tie::IxHash',
160 $self->revmap_fields(
161 interval => \%interval,
162 startDate => 'start',
163 totalOccurrences => 'periods',
164 trialOccurrences => 'trialperiods',
167 tie my %account, 'Tie::IxHash', (
168 ( defined($self->transaction_type())
169 && $self->transaction_type() eq 'CC'
170 ) ? $self->revmap_fields(
171 cardNumber => 'card_number',
172 expirationDate => 'expdate_yyyymm',
174 : $self->revmap_fields(
175 accountType => 'account_type',
176 routingNumber => 'routing_code',
177 accountNumber => 'account_number',
178 nameOnAccount => 'account_name',
179 echeckType => 'check_type',
180 bankName => 'bank_name',
184 tie my %payment, 'Tie::IxHash',
185 $self->revmap_fields(
186 ( ( defined($self->transaction_type()) && # require?
187 $self->transaction_type() eq 'CC'
193 tie my %order, 'Tie::IxHash',
194 $self->revmap_fields(
195 invoiceNumber => 'invoice_number',
196 description => 'description',
199 tie my %drivers, 'Tie::IxHash',
200 $self->revmap_fields(
201 number => 'license_num',
202 state => 'license_state',
203 dateOfBirth => 'license_dob',
206 tie my %billto, 'Tie::IxHash',
207 $self->revmap_fields(
208 firstName => 'first_name',
209 lastName => 'last_name',
210 company => 'company',
211 address => 'address',
215 country => 'country',
218 tie my %shipto, 'Tie::IxHash',
219 $self->revmap_fields(
220 firstName => 'ship_first_name',
221 lastName => 'ship_last_name',
222 company => 'ship_company',
223 address => 'ship_address',
225 state => 'ship_state',
227 country => 'ship_country',
230 tie my %customer, 'Tie::IxHash',
231 $self->revmap_fields(
232 type => 'customer_org',
235 phoneNumber => 'phone',
237 driversLicense => \%drivers,
238 taxid => 'customer_ssn',
241 tie my %sub, 'Tie::IxHash',
242 $self->revmap_fields(
243 name => 'subscription_name',
244 paymentSchedule => \%schedule,
246 trialAmount => 'trialamount',
247 payment => \%payment,
249 customer => \%customer,
255 tie my %req, 'Tie::IxHash',
256 $self->revmap_fields (
257 merchantAuthentication => \%merchant,
258 subscriptionId => 'subscription',
259 subscription => \%sub,
262 my $ns = "AnetApi/xml/v1/schema/AnetApiSchema.xsd";
264 my $writer = new XML::Writer( OUTPUT => \$post_data,
270 $writer->startTag($self->{_content}->{action}, 'xmlns', $ns);
271 foreach ( keys ( %req ) ) {
272 $self->_xmlwrite($writer, $_, $req{$_});
274 $writer->endTag($self->{_content}->{action});
277 if ($self->test_transaction()) {
278 $self->server('apitest.authorize.net');
281 warn $post_data if $DEBUG;
282 my($page,$server_response,%headers) =
283 $self->https_post( { 'Content-Type' => 'text/xml' }, $post_data);
285 #trim leading (4?) characters of unknown origin not in spec
286 $page =~ s/^(.*?)</</;
288 warn "Trimmed $garbage from response page.\n" if $DEBUG;
290 warn $page if $DEBUG;
294 if ($server_response =~ /200/){
295 $response = XMLin($page);
296 if (ref($response->{messages}->{message}) eq 'ARRAY') {
297 $message = $response->{messages}->{message}->[0];
299 $message = $response->{messages}->{message};
302 $response->{messages}->{resultCode} = "Server Failed";
303 $message->{code} = $server_response;
306 $self->server_response($page);
307 $self->order_number($response->{subscriptionId});
308 $self->result_code($message->{code});
309 $self->error_message($message->{text});
311 if($response->{messages}->{resultCode} eq "Ok" ) {
312 $self->is_success(1);
314 $self->is_success(0);
315 unless ( $self->error_message() ) { #additional logging information
316 $self->error_message(
317 "(HTTPS response: $server_response) ".
319 join(", ", map { "$_ => ". $headers{$_} } keys %headers ). ") ".
320 "(Raw HTTPS content: $page)"
331 Business::OnlinePayment::AuthorizeNet::ARB - AuthorizeNet ARB backend for Business::OnlinePayment
335 Jeff Finucane, authorizenetarb@weasellips.com
339 perl(1). L<Business::OnlinePayment>.