1 package Business::OnlinePayment::Jety;
5 use Business::OnlinePayment 3;
6 use Business::OnlinePayment::HTTPS;
7 use vars qw($VERSION @ISA $me $DEBUG);
12 @ISA = qw(Business::OnlinePayment::HTTPS);
14 $me = 'Business::OnlinePayment::Jety';
19 'normal authorization' => 'echeck',
24 # 'function' will always be prepended
25 'normal authorization' => [ # note array-ness
26 'username' => 'login',
27 'password' => 'password',
28 'firstname' => 'first_name',
29 'lastname' => 'last_name',
30 'address1' => 'address',
31 'address2' => 'address2',
37 'programdesc' => 'description',
38 'ref' => sub { my %c = @_;
39 $c{'authorization'} ||
40 substr( time2str('%Y%m%d%H%M%S',time). int(rand(10000)), -15 )
42 'bankname' => 'bank_name',
43 'bankcity' => 'bank_city',
44 'bankstate' => 'bank_state',
45 'accountaba' => 'routing_code',
46 'accountdda' => 'account_number',
47 'amount' => sub { my %c = @_; sprintf("%.02f",$c{'amount'}) },
50 'username' => 'login',
51 'password' => 'password',
52 'ref' => 'authorization',
53 'accountdda' => 'account_number',
54 'amount' => sub { my %c = @_; sprintf("%.02f",$c{'amount'}) },
58 my %defaults = ( # using the B:OP names
59 'phone' => '111-111-1111',
60 'bank_name' => 'unknown',
61 'bank_city' => 'unknown',
66 'normal authorization' => [ qw(
96 info_compat => '0.01',
97 gateway_name => 'Jety',
98 gateway_url => 'http://www.jetypay.com',
99 module_version => $VERSION,
100 supported_types => [ 'ECHECK' ],
101 supported_actions => [ 'Normal Authorization', 'Void' ],
102 ECHECK_void_requires_account => 1,
108 $self->server('api.cardservicesportal.com');
110 $self->path('/servlet/drafts.echeck');
116 $Business::OnlinePayment::HTTPS::DEBUG = $DEBUG;
117 $DB::single = $DEBUG;
119 # strip existent but empty fields so that required_fields works right
120 foreach(keys(%{$self->{_content}})) {
121 delete $self->{_content}->{$_}
122 if (!defined($self->{_content}->{$_} ) or
123 $self->{_content}->{$_} eq '');
126 my %content = $self->content();
127 my $action = lc($content{'action'});
129 croak "Jety only supports ECHECK payments.\n"
130 if( lc($content{'type'}) ne 'echeck' );
131 croak "Unsupported transaction type: '$action'\n"
132 if( !exists($trans_type{$action}) );
134 $self->required_fields(@{ $required{$action} });
136 my @fields = @{ $map{$action} } ;
137 tie my %request, 'Tie::IxHash', ( 'function' => $trans_type{$action} );
139 my ($key, $value) = (shift (@fields), shift (@fields));
140 if( ref($value) eq 'CODE' ) {
141 $request{$key} = $value->(%content);
143 elsif (defined($content{$value}) and $content{$value} ne '') {
144 $request{$key} = $content{$value};
146 elsif (exists($defaults{$value})) {
147 $request{$key} = $defaults{$value};
151 $DB::single = $DEBUG;
152 if($self->test_transaction()) {
153 print "https://".$self->server.$self->path."\n";
154 print "$_\t".$request{$_}."\n" foreach keys(%request);
155 $self->error_message('test mode not supported');
156 $self->is_success(0);
159 my ($reply, $response, %reply_headers) = $self->https_post(\%request);
161 if(not $response =~ /^200/) {
162 croak "HTTPS error: '$response'";
165 # string looks like this:
166 # P1=1234&P2=General Status&P3=Specific Status
167 # P3 is not always there, though.
168 if($reply =~ /^P1=(\d+)&P2=([\w ]*)(&P3=(\S+))?/) {
170 $self->is_success(1);
171 $self->authorization($4);
174 $self->is_success(0);
175 $self->error_message($2.($4 ? "($4)" : ''));
179 croak "Malformed server response: '$reply'";
186 # Required parameters:
187 # ftp_user, ftp_pass, ftp_host, ftp_path
190 eval('use Date::Parse q!str2time!; use Net::FTP; use File::Temp q!tempdir!');
194 # $self->required_fields, for processor options
196 my ($user, $pass, $host, $path) = map {
197 if($self->can($_) and $self->$_) {
200 push @missing, $_; '';
202 } qw(ftp_user ftp_pass ftp_host);
203 die "missing gateway option(s): ".join(', ',@missing)."\n" if @missing;
204 my $ftp_path = $self->ftp_path if $self->can('ftp_path');
206 my $start = $self->{_content}->{start};
207 $start &&= str2time($start);
208 $start ||= time - 86400;
209 $start = time2str('%Y%m%d',$start);
211 my $end = $self->{_content}->{end};
212 $end &&= str2time($end);
214 $end = time2str('%Y%m%d',$end);
216 my $ftp = Net::FTP->new($host)
217 or die "FTP connection to '$host' failed.\n";
218 $ftp->login($user, $pass) or die "FTP login failed: ".$ftp->message."\n";
219 $ftp->cwd($path) or die "can't chdir to $path\n" if $path;
221 my $tmp = tempdir(CLEANUP => 1);
223 foreach my $filename ($ftp->ls) {
224 if($filename =~ /^\w+_RET(\d{8}).csv$/
227 $ftp->get($filename, "$tmp/$1") or die "Failed to download $filename: ".$ftp->message."\n";
234 foreach my $filename (@files) {
235 open IN, '<', "$tmp/$filename";
236 my @fields = split ',',<IN>; #fetch header row
237 my ($i) = grep { $fields[$_] eq 'AccountToID' } 0..(scalar @fields - 1);
240 my @fields = split ',', $_;
241 push @tids, $fields[$i];
253 Business::OnlinePayment::Jety - Jety Payments ACH backend for Business::OnlinePayment
257 use Business::OnlinePayment;
260 # Electronic check authorization. We only support
261 # 'Normal Authorization'.
264 my $tx = new Business::OnlinePayment("Jety");
267 login => 'testdrive',
268 password => 'testpass',
269 action => 'Normal Authorization',
270 description => '111-111-1111 www.example.com',
272 invoice_number => '100100',
273 first_name => 'Jason',
274 last_name => 'Kohles',
275 address => '123 Anystreet',
279 account_type => 'personal checking',
280 account_number => '1000468551234',
281 routing_code => '707010024',
282 check_number => '1001', # optional
286 if($tx->is_success()) {
287 print "Check processed successfully: ".$tx->authorization."\n";
289 print "Check was rejected: ".$tx->error_message."\n";
292 =head1 SUPPORTED TRANSACTION TYPES
296 Content required: type, login, password, action, amount, first_name, last_name, account_number, routing_code, description.
298 description should be set in the form "111-111-1111 www.example.com"
302 For detailed information see L<Business::OnlinePayment>.
304 =head1 METHODS AND FUNCTIONS
306 See L<Business::OnlinePayment> for the complete list. The following methods either override the methods in L<Business::OnlinePayment> or provide additional functions.
310 Returns the four-digit result code.
314 Returns a useful error message.
316 =head1 Handling of content(%content) data:
320 The following actions are valid:
326 Mark Wells <mark@freeside.biz>
330 perl(1). L<Business::OnlinePayment>.