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 # Structure of the XML request document
26 # Right sides of the hash entries are Business::OnlinePayment
27 # field names. Those that start with _ are local method names.
30 TransactionRequest => {
33 password => 'password',
38 type => '_payment_type',
40 # effective date: not supported
42 type => 'tender_type',
44 InvoiceNumber => { value => 'invoice_number' },
45 AccountHolder => { value => '_full_name' },
46 Address => { value => 'address' },
47 ClientID => { value => 'customer_id' },
49 routing => 'routing_code',
50 account => 'account_number',
51 check => 'check_number',
52 type => '_check_type',
53 verification => 'check_ver',
55 Authorization => { schedule => 'schedule' },
56 SECCode => { value => 'sec_code' },
65 $self->server('www.webcheckexpress.com');
67 $self->path('/requester.php');
73 $Business::OnlinePayment::HTTPS::DEBUG = $DEBUG;
76 # Return-with-error situations
77 croak "Unsupported transaction type: '" . $self->transaction_type . "'"
78 if(not $self->transaction_type =~ /^e?check$/i);
80 croak "Unsupported action: '" . $self->{_content}->{action} . "'"
81 if(!defined($self->_payment_type));
83 croak 'Test transactions not supported'
84 if($self->test_transaction());
89 $self->error_message($@);
93 my $xml_request = XMLout($self->build($request), KeepRoot => 1);
95 my ($xml_reply, $response, %reply_headers) = $self->https_post({ 'Content-Type' => 'text/xml' }, $xml_request);
97 if(not $response =~ /^200/) {
98 croak "HTTPS error: '$response'";
101 $self->server_response($xml_reply);
102 my $reply = XMLin($xml_reply, KeepRoot => 1)->{TransactionResponse};
104 if(exists($reply->{Response})) {
105 $self->is_success( ( $reply->{Response}->{status} eq 'successful') ? 1 : 0);
106 $self->error_message($reply->{Response}->{ErrorMessage});
108 elsif(exists($reply->{FatalException})) {
109 $self->is_success(0);
110 $self->error_message($reply->{FatalException});
113 $DB::single = 1 if $DEBUG;
120 my $content = { $self->content };
123 if (ref($skel) ne 'HASH') { croak 'Failed to build non-hash' };
124 foreach my $k (keys(%$skel)) {
125 my $val = $skel->{$k};
126 # Rules for building from the skeleton:
127 # 1. If the value is a hashref, build it recursively.
128 if(ref($val) eq 'HASH') {
129 $data->{$k} = $self->build($val);
131 # 2. If the value starts with an underscore, it's treated as a method name.
132 elsif($val =~ /^_/ and $self->can($val)) {
133 $data->{$k} = $self->can($val)->($self);
135 # 3. If the value is undefined, keep it undefined.
136 elsif(!defined($val)) {
139 # 4. If the value is the name of a key in $self->content, look up that value.
140 elsif(exists($content->{$val})) {
141 $data->{$k} = $content->{$val};
143 # 5. If the value is a key in $defaults, use that value.
144 elsif(exists($defaults->{$val})) {
145 $data->{$k} = $defaults->{$val};
149 croak "Missing request field: '$val'";
156 # For testing build().
158 return XMLout($self->build($request), KeepRoot => 1);
163 my $action = $self->{_content}->{action};
164 if(!defined($action) or $action =~ /^normal authorization$/i) {
167 elsif($action =~ /^credit$/i) {
177 my $type = $self->{_content}->{account_type};
178 return 'checking' if($type =~ /checking/i);
179 return 'savings' if($type =~ /savings/i);
180 croak "Invalid account_type: '$type'";
185 return join(' ',$self->{_content}->{first_name},$self->{_content}->{last_name});
193 Business::OnlinePayment::WesternACH - Western ACH backend for Business::OnlinePayment
197 use Business::OnlinePayment;
200 # Electronic check authorization. We only support
201 # 'Normal Authorization' and 'Credit'.
204 my $tx = new Business::OnlinePayment("AuthorizeNet");
207 login => 'testdrive',
208 password => 'testpass',
209 action => 'Normal Authorization',
210 description => 'Business::OnlinePayment test',
212 invoice_number => '100100',
213 first_name => 'Jason',
214 last_name => 'Kohles',
215 address => '123 Anystreet',
219 account_type => 'personal checking',
220 account_number => '1000468551234',
221 routing_code => '707010024',
222 check_number => '1001', # optional
226 if($tx->is_success()) {
227 print "Check processed successfully: ".$tx->authorization."\n";
229 print "Check was rejected: ".$tx->error_message."\n";
232 =head1 SUPPORTED TRANSACTION TYPES
236 Content required: type, login, password|transaction_key, action, amount, first_name, last_name, account_number, routing_code, account_type.
240 For detailed information see L<Business::OnlinePayment>.
242 =head1 METHODS AND FUNCTIONS
244 See L<Business::OnlinePayment> for the complete list. The following methods either override the methods in L<Business::OnlinePayment> or provide additional functions.
248 Currently returns nothing; these transactions don't seem to have result codes.
252 Returns the response reason text. This can come from several locations in the response document or from certain local errors.
254 =head2 server_response
256 Returns the complete response from the server.
258 =head1 Handling of content(%content) data:
262 The following actions are valid:
269 Mark Wells <mark@freeside.biz> with advice from Ivan Kohler <ivan@freeside.biz>.
273 perl(1). L<Business::OnlinePayment>.