1 package Business::OnlinePayment::WesternACH;
5 use Business::OnlinePayment 3;
6 use Business::OnlinePayment::HTTPS;
8 use vars qw($VERSION @ISA $me $DEBUG);
10 @ISA = qw(Business::OnlinePayment::HTTPS);
12 $me = 'Business::OnlinePayment::WesternACH';
20 tender_type => 'check',
25 my $required = { map { $_ => 1 } ( qw(
39 # Structure of the XML request document
40 # Right sides of the hash entries are Business::OnlinePayment
41 # field names. Those that start with _ are local method names.
44 TransactionRequest => {
47 password => 'password',
52 type => '_payment_type',
54 # effective date: not supported
56 type => 'tender_type',
58 InvoiceNumber => { value => 'invoice_number' },
59 AccountHolder => { value => '_full_name' },
60 Address => { value => 'address' },
61 ClientID => { value => 'customer_id' },
63 routing => 'routing_code',
64 account => 'account_number',
65 check => 'check_number',
66 type => '_check_type',
67 verification => 'check_ver',
69 Authorization => { schedule => 'schedule' },
70 SECCode => { value => 'sec_code' },
79 $self->server('www.webcheckexpress.com');
81 $self->path('/requester.php');
87 $Business::OnlinePayment::HTTPS::DEBUG = $DEBUG;
90 # Return-with-error situations
91 croak "Unsupported transaction type: '" . $self->transaction_type . "'"
92 if(not $self->transaction_type =~ /^e?check$/i);
94 croak "Unsupported action: '" . $self->{_content}->{action} . "'"
95 if(!defined($self->_payment_type));
97 croak 'Test transactions not supported'
98 if($self->test_transaction());
102 $self->is_success(0);
103 $self->error_message($@);
107 my $xml_request = XMLout($self->build($request), KeepRoot => 1);
109 my ($xml_reply, $response, %reply_headers) = $self->https_post({ 'Content-Type' => 'text/xml' }, $xml_request);
111 if(not $response =~ /^200/) {
112 croak "HTTPS error: '$response'";
115 $self->server_response($xml_reply);
116 my $reply = XMLin($xml_reply, KeepRoot => 1)->{TransactionResponse};
118 if(exists($reply->{Response})) {
119 $self->is_success( ( $reply->{Response}->{status} eq 'successful') ? 1 : 0);
120 $self->error_message($reply->{Response}->{ErrorMessage});
122 elsif(exists($reply->{FatalException})) {
123 $self->is_success(0);
124 $self->error_message($reply->{FatalException});
127 $DB::single = 1 if $DEBUG;
134 my $content = { $self->content };
137 if (ref($skel) ne 'HASH') { croak 'Failed to build non-hash' };
138 foreach my $k (keys(%$skel)) {
139 my $val = $skel->{$k};
140 # Rules for building from the skeleton:
141 # 1. If the value is a hashref, build it recursively.
142 if(ref($val) eq 'HASH') {
143 $data->{$k} = $self->build($val);
145 # 2. If the value starts with an underscore, it's treated as a method name.
146 elsif($val =~ /^_/ and $self->can($val)) {
147 $data->{$k} = $self->can($val)->($self);
149 # 3. If the value is undefined, keep it undefined.
150 elsif(!defined($val)) {
153 # 4. If the value is the name of a key in $self->content, look up that value.
154 elsif(exists($content->{$val})) {
155 $data->{$k} = $content->{$val};
157 # 5. If the value is a key in $defaults, use that value.
158 elsif(exists($defaults->{$val})) {
159 $data->{$k} = $defaults->{$val};
161 # 6. If the value is not required, use an empty string.
162 elsif(! $required->{$val}) {
167 croak "Missing request field: '$val'";
174 # For testing build().
176 return XMLout($self->build($request), KeepRoot => 1);
181 my $action = $self->{_content}->{action};
182 if(!defined($action) or $action =~ /^normal authorization$/i) {
185 elsif($action =~ /^credit$/i) {
195 my $type = $self->{_content}->{account_type};
196 return 'checking' if($type =~ /checking/i);
197 return 'savings' if($type =~ /savings/i);
198 croak "Invalid account_type: '$type'";
203 return join(' ',$self->{_content}->{first_name},$self->{_content}->{last_name});
211 Business::OnlinePayment::WesternACH - Western ACH backend for Business::OnlinePayment
215 use Business::OnlinePayment;
218 # Electronic check authorization. We only support
219 # 'Normal Authorization' and 'Credit'.
222 my $tx = new Business::OnlinePayment("AuthorizeNet");
225 login => 'testdrive',
226 password => 'testpass',
227 action => 'Normal Authorization',
228 description => 'Business::OnlinePayment test',
230 invoice_number => '100100',
231 first_name => 'Jason',
232 last_name => 'Kohles',
233 address => '123 Anystreet',
237 account_type => 'personal checking',
238 account_number => '1000468551234',
239 routing_code => '707010024',
240 check_number => '1001', # optional
244 if($tx->is_success()) {
245 print "Check processed successfully: ".$tx->authorization."\n";
247 print "Check was rejected: ".$tx->error_message."\n";
250 =head1 SUPPORTED TRANSACTION TYPES
254 Content required: type, login, password|transaction_key, action, amount, first_name, last_name, account_number, routing_code, account_type.
258 For detailed information see L<Business::OnlinePayment>.
260 =head1 METHODS AND FUNCTIONS
262 See L<Business::OnlinePayment> for the complete list. The following methods either override the methods in L<Business::OnlinePayment> or provide additional functions.
266 Currently returns nothing; these transactions don't seem to have result codes.
270 Returns the response reason text. This can come from several locations in the response document or from certain local errors.
272 =head2 server_response
274 Returns the complete response from the server.
276 =head1 Handling of content(%content) data:
280 The following actions are valid:
287 Mark Wells <mark@freeside.biz> with advice from Ivan Kohler <ivan-westernach@freeside.biz>.
291 perl(1). L<Business::OnlinePayment>.