1 package Business::OnlinePayment::Jettis;
5 use Business::OnlinePayment;
6 #use Business::CreditCard;
7 use Net::SSLeay qw( make_form post_https make_headers );
9 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $DEBUG);
13 @ISA = qw(Exporter AutoLoader Business::OnlinePayment);
23 2 => "Missing CC Number",
24 3 => "Missing First Name",
25 4 => "Missing Last Name",
26 5 => "Missing Zip Code",
27 6 => "Missing Expiration Month",
28 7 => "Missing Expiration Year",
29 8 => "Missing Username",
30 9 => "Missing V Password",
31 10 => "No Agree Terms",
34 13 => "Missing State",
35 14 => "Username Length",
36 15 => "Username Invalid Chars",
37 16 => "Password Length",
38 17 => "Different V Password",
39 18 => "Same V Password",
40 19 => "Invalid Email",
41 20 => "Missing Address",
42 21 => "Invalid Phone Number",
43 22 => "Failed Mod 10",
44 23 => "Invalid Expiration",
45 24 => "Negative Database",
47 26 => "Database Error",
48 27 => "Username Exists",
49 28 => "Invalid Store Params",
53 32 => "Invalid Version",
54 33 => "Invalid Country Code",
56 35 => "High Fraud Country",
57 36 => "Different Country IP",
60 39 => "Password Maintenance",
61 40 => "Password Invalid Chars",
62 41 => "Duplicate Membership",
64 43 => "Too many consecutive errors",
65 44 => "Missing Password",
66 45 => "Zip Code Quotes",
68 47 => "Street Quotes",
69 48 => "Missing Country",
70 49 => "Country Invalid Chars",
71 50 => "Missing Quantity",
72 51 => "Quantity Invalid Chars",
73 52 => "Missing IP Address",
74 53 => "Invalid IP Address",
75 54 => "Merchant Text Area Quotes",
76 55 => "First Name Length",
77 56 => "Last Name Length",
82 61 => "Address Length",
83 62 => "Merch Area Length",
84 63 => "Quantity Limit Per Day Exceeded",
85 64 => "Amount Limit Per Day Exceeded",
86 65 => "Quantity Limit Per Month Exceeded",
87 66 => "Amount Limit Per Month Exceeded",
88 67 => "Credit CC Num Mismatch",
89 68 => "Credit Price Mismatch",
90 69 => "Merch ID Mismatch",
91 70 => "Credit Prod ID Mismatch",
92 71 => "Invalid Bill Item ID",
93 72 => "Invalid Prod ID",
94 73 => "Invalid Merch ID",
95 74 => "Fraud Scrubbing",
96 75 => "Already Credited",
97 76 => "Credit Card BIN Exclusion",
98 77 => "Email Exclusion",
99 78 => "IP not reversible",
100 79 => "Invalid Bill ID",
101 80 => "Auth already settled",
102 81 => "Invalid Account Num",
103 82 => "Mail Zip Code Exclusion",
104 83 => "Missing IP Code",
105 84 => "Username Mismatch",
106 85 => "Password Mismatch",
107 101 => "Bank Timeout",
108 102 => "Invalid Request",
110 104 => "Memory Allocation",
115 111 => "Expiration Date",
120 116 => "Merchant Number",
122 118 => "Merchant Bank Down",
123 119 => "Invalid Transaction Type",
124 120 => "Call Center",
127 123 => "Account Declined",
128 124 => "Fraud Alert",
132 128 => "Card Expired",
133 129 => "Bank Invalid Email",
134 130 => "Batch Unbalanced",
135 131 => "Batch Unopened",
136 140 => "Control Invalid",
137 141 => "Control Readonly",
138 142 => "Control Bad",
139 150 => "Duplicate Address",
140 151 => "Unknown Address",
141 160 => "Duplicate Merchant Number",
142 161 => "Merchant Busy",
143 162 => "Merchant Inhibit",
145 171 => "AVS Unmatched Void",
146 172 => "AVS Void Failure",
147 180 => "Invalid IP code",
148 181 => "Invalid CVV2",
149 182 => "Invalid Original Transaction Date",
150 198 => "Server Timeout",
151 199 => "Unrecognized",
152 300 => "Re-Presented Check",
154 400 => "Failed Routing Mod 10",
155 401 => "Missing Bank Name",
156 402 => "Bank Name Quotes",
157 403 => "Missing Bank Account Number",
158 404 => "Invalid Bank Account Number",
159 405 => "Missing Bank Routing Number",
160 406 => "Invalid Bank Routing Number",
161 407 => "Missing Check Number",
162 408 => "Unsupported Transaction Type",
163 409 => "Invalid Bank Name",
164 410 => "ACH Verification Declined",
165 435 => "Missing Drivers License",
166 436 => "Missing Drivers License State",
167 437 => "Invalid Drivers License",
168 999 => "Unknown Error",
173 $self->server('join.billingservices.com');
175 $self->path('/psys/txnUrl');
176 $self->build_subs(qw( product_id merchant_id order_number ));
180 my($self, %map) = @_;
181 my %content = $self->content();
184 my %actions = ('normal authorization' => 'PURCHASE',
185 'credit' => 'CREDIT',
187 $content{'action'} = $actions{lc($content{'action'})}
188 if exists( $actions{lc($content{'action'})} );
190 if ($content{'customer_ssn'} =~ /^(\d{3})-(\d{2})-(\d{4})$/)
192 $content{'ssn4'} = $3;
196 $content{$_} = ref($map{$_})
198 : $content{$map{$_}};
200 $self->content(%content);
205 my %content = $self->content();
207 my $type = lc($content{'type'});
208 if ( $type =~ /^e?check$/ ) {
210 croak "$type not (yet) supported";
213 my $action = $content{'action'};
214 croak "$action not currently supported"
215 unless $action =~ /^(PURCHASE|CREDIT)$/;
217 $self->revmap_fields(
218 SUCCESS_URL => \'https://secure.suicidegirls.com/',
219 PS_TXN_TYPE => 'action',
220 PRODUCT_ID => \($self->product_id()),
221 MERCHANT_ID => 'login',
224 REMOTE_ADDR => \'10.0.0.1',
227 PAY_METHOD_ID => \'A', # ACH
230 CHECK_NUM => \'1000',
231 BANK_ACCT_NUM => 'account_number',
232 BANK_ROUT_NUM => 'routing_code',
233 BANK_NAME => 'bank_name',
235 FIRST_NAME => 'first_name',
236 LAST_NAME => 'last_name',
238 ADDR_STREET_1 => 'address',
240 ADDR_STATE => 'state',
242 ADDR_COUNTRY => \'840', # US
243 MERCH_TEXT_AREA => 'description',
244 BILL_ITEM_ID => 'order_number',
245 DL_NUM => \'B01111111111', #XXX state_id (license_num?)
246 DL_STATE => 'state', #XXX state_id_state
249 my %post_data = $self->get_fields(qw(
250 SUCCESS_URL PS_TXN_TYPE PRODUCT_ID MERCHANT_ID VERSION SOR REMOTE_ADDR
251 TERMS_AGREE CHECK_AGE PAY_METHOD_ID PRICE QTY CHECK_NUM BANK_ACCT_NUM
252 BANK_ROUT_NUM BANK_NAME EMAIL FIRST_NAME LAST_NAME SSN4 ADDR_STREET_1
253 ADDR_CITY ADDR_STATE ADDR_ZIP ADDR_COUNTRY MERCH_TEXT_AREA BILL_ITEM_ID
257 my $pd = make_form(%post_data);
258 my $s = $self->server();
259 my $p = $self->port();
260 my $t = $self->path();
261 my $headers = make_headers('Referer' => $content{'referer'} );
262 my($page,$server_response,%headers) = post_https($s,$p,$t,$headers,$pd);
264 # warn join('-',%headers);
266 my $uri = new URI $headers{'LOCATION'} or die "no LOCATION: header!";
267 my %response = $uri->query_form or die "no response in LOCATION: header!";
269 if ( $response{'RESULT_MAIN'} eq '0' ) {
270 $self->is_success(1);
271 $self->result_code('0');
272 $self->authorization($response{'AUTHORIZATION_CODE'});
273 $self->order_number($response{'BILL_ITEM_ID'});
275 $self->is_success(0);
276 $self->result_code($response{'RESULT_MAIN'});
277 $self->error_message($error{$response{'RESULT_MAIN'}});
288 Business::OnlinePayment::Jettis - Jettis backend for Business::OnlinePayment
292 use Business::OnlinePayment;
294 my $tx = new Business::OnlinePayment("Jettis");
297 login => 'test', #ClientID
298 action => 'Normal Authorization',
299 description => 'Business::OnlinePayment test',
301 invoice_number => '100100',
302 name => 'Tofu Beast',
303 account_number => '12345',
304 routing_code => '123456789',
305 bank_name => 'First National Test Bank',
309 if($tx->is_success()) {
310 print "Check processed successfully: ".$tx->authorization."\n";
312 print "Check was rejected: ".$tx->error_message."\n";
317 For detailed information see L<Business::OnlinePayment>.
321 This module only implements 'ECHECK' (ACH) functionality at this time. Credit
322 card transactions are not (yet) supported.
326 This module implements an interface to Jettis.com's HTTPS API. Unfortunately,
327 no documentation is publicly available. Jettis won't even send their full
328 manual to their customers - they insist on sending only few-page snippets at a
333 Steve Simitzis <steve@saturn5.com>
334 Ivan Kohler <ivan-jettis@420.am>
338 perl(1). L<Business::OnlinePayment>