package Business::OnlinePayment::Jety;
use strict;
-use Carp;
+use Carp 'croak';
use Business::OnlinePayment 3;
use Business::OnlinePayment::HTTPS;
use vars qw($VERSION @ISA $me $DEBUG);
use Tie::IxHash;
@ISA = qw(Business::OnlinePayment::HTTPS);
-$VERSION = '0.02';
+$VERSION = '0.09';
$me = 'Business::OnlinePayment::Jety';
$DEBUG = 0;
-my @fields = (qw(
- username
+my %trans_type = (
+ 'normal authorization' => 'echeck',
+ 'void' => 'ereturn',
+ 'credit' => 'ereturn',
+ );
+
+my %map = (
+# 'function' will always be prepended
+'normal authorization' => [ # note array-ness
+ 'username' => 'login',
+ 'password' => 'password',
+ 'firstname' => 'first_name',
+ 'lastname' => 'last_name',
+ 'address1' => 'address',
+ 'address2' => 'address2',
+ 'city' => 'city',
+ 'state' => 'state',
+ 'zip' => 'zip',
+ 'email' => 'email',
+ 'phone' => 'phone',
+ 'programdesc' => 'description',
+ 'ref' => sub { my %c = @_;
+ $c{'authorization'} ||
+ substr( time2str('%Y%m%d%H%M%S',time). int(rand(10000)), -15 )
+ },
+ 'bankname' => 'bank_name',
+ 'bankcity' => 'bank_city',
+ 'bankstate' => 'bank_state',
+ 'accountaba' => 'routing_code',
+ 'accountdda' => 'account_number',
+ 'amount' => sub { my %c = @_; sprintf("%.02f",$c{'amount'}) },
+],
+'void' => [
+ 'username' => 'login',
+ 'password' => 'password',
+ 'ref' => 'authorization',
+ 'accountdda' => 'account_number',
+ 'amount' => sub { my %c = @_; sprintf("%.02f",$c{'amount'}) },
+],
+);
+$map{'credit'} = $map{'void'};
+
+my %defaults = ( # using the B:OP names
+ 'phone' => '111-111-1111',
+ 'bank_name' => 'unknown',
+ 'bank_city' => 'unknown',
+ 'bank_state' => 'XX',
+ );
+
+my %required = (
+'normal authorization' => [ qw(
+ type
+ action
+ login
password
- function
- firstname
- lastname
- address1
- address2
+ first_name
+ last_name
+ address
city
state
zip
email
- phone
- programdesc
- ref
- bankname
- bankcity
- bankstate
- accountaba
- accountdda
+ account_number
+ routing_code
amount
-));
-
-my %map = (
- login => 'username',
- first_name => 'firstname',
- last_name => 'lastname',
- address => 'address1',
- bank_name => 'bankname',
- bank_city => 'bankcity',
- bank_state => 'bankstate',
- account_number => 'accountdda',
- routing_code => 'accountaba',
+ description
+) ],
+'void' => [ qw(
+ type
+ action
+ login
+ password
+ authorization
+ account_number
+ amount
+) ],
);
-
+$required{'credit'} = $required{'void'};
+
+sub _info {
+ {
+ info_compat => '0.01',
+ gateway_name => 'Jety',
+ gateway_url => 'http://www.jetypay.com',
+ module_version => $VERSION,
+ supported_types => [ 'ECHECK' ],
+ supported_actions => [ 'Normal Authorization', 'Void', 'Credit' ],
+ ECHECK_void_requires_account => 1,
+ }
+}
sub set_defaults {
my $self = shift;
return;
}
-sub map_fields {
- my $self = shift;
- my $content = $self->{_content};
-
- $self->remap_fields(%map);
-
- die "Jety API only supports ECHECK payments.\n"
- if(lc($content->{type}) ne 'echeck');
- die "Jety interface only supports Normal Authorization.\n"
- if(lc($content->{action}) ne 'normal authorization');
-
- $content->{'function'} = 'echeck';
- $content->{'programdesc'} = "415-462-1624 Business::OnlinePayment::Jety v$VERSION";
- $content->{'ref'} = time2str('%Y%m%d',time).'-'.int(rand(1000000));
-
- $content->{'phone'} ||= '111-111-1111';
-
- $content->{'bankname'} ||= 'unknown';
- $content->{'bankcity'} ||= 'unknown';
- $content->{'bankstate'} ||= 'XX';
-
- return;
-}
-
sub submit {
my $self = shift;
$Business::OnlinePayment::HTTPS::DEBUG = $DEBUG;
$self->{_content}->{$_} eq '');
}
- $self->required_fields(qw(
- type
- action
- first_name
- last_name
- address
- city
- state
- zip
- email
- phone
- account_number
- routing_code
- amount
- ) );
- $self->map_fields;
- tie my %request, 'Tie::IxHash', (
- map { $_, $self->{_content}->{$_} } @fields
- );
+ my %content = $self->content();
+ my $action = lc($content{'action'});
+
+ croak "Jety only supports ECHECK payments.\n"
+ if( lc($content{'type'}) ne 'echeck' );
+ croak "Unsupported transaction type: '$action'\n"
+ if( !exists($trans_type{$action}) );
+
+ $self->required_fields(@{ $required{$action} });
+
+ my @fields = @{ $map{$action} } ;
+ tie my %request, 'Tie::IxHash', ( 'function' => $trans_type{$action} );
+ while(@fields) {
+ my ($key, $value) = (shift (@fields), shift (@fields));
+ if( ref($value) eq 'CODE' ) {
+ $request{$key} = $value->(%content);
+ }
+ elsif (defined($content{$value}) and $content{$value} ne '') {
+ $request{$key} = $content{$value};
+ }
+ elsif (exists($defaults{$value})) {
+ $request{$key} = $defaults{$value};
+ } # else do nothing
+ }
$DB::single = $DEBUG;
if($self->test_transaction()) {
return;
}
+sub get_returns {
+# Required parameters:
+# ftp_user, ftp_pass, ftp_host, ftp_path
+# Optional:
+# start, end
+ eval('use Date::Parse q!str2time!; use Net::FTP; use File::Temp q!tempdir!');
+ die $@ if $@;
+
+ my $self = shift;
+# $self->required_fields, for processor options
+ my @missing;
+ my ($user, $pass, $host, $path) = map {
+ if($self->can($_) and $self->$_) {
+ $self->$_ ;
+ } else {
+ push @missing, $_; '';
+ }
+ } qw(ftp_user ftp_pass ftp_host);
+ die "missing gateway option(s): ".join(', ',@missing)."\n" if @missing;
+ my $ftp_path = $self->ftp_path if $self->can('ftp_path');
+
+ my $start = $self->{_content}->{start};
+ $start &&= str2time($start);
+ $start ||= time - 86400;
+ $start = time2str('%Y%m%d',$start);
+
+ my $end = $self->{_content}->{end};
+ $end &&= str2time($end);
+ $end ||= time;
+ $end = time2str('%Y%m%d',$end);
+
+ my $ftp = Net::FTP->new($host)
+ or die "FTP connection to '$host' failed.\n";
+ $ftp->login($user, $pass) or die "FTP login failed: ".$ftp->message."\n";
+ $ftp->cwd($path) or die "can't chdir to $path\n" if $path;
+
+ my $tmp = tempdir(CLEANUP => 1);
+ my @files;
+ foreach my $filename ($ftp->ls) {
+ if($filename =~ /^\w+_RET(\d{8}).csv$/
+ and $1 >= $start
+ and $1 <= $end ) {
+ $ftp->get($filename, "$tmp/$1") or die "Failed to download $filename: ".$ftp->message."\n";
+ push @files, $1;
+ }
+ }
+ $ftp->close;
+
+ my @tids;
+ foreach my $filename (@files) {
+ open IN, '<', "$tmp/$filename";
+ my @fields = split ',',<IN>; #fetch header row
+ my ($i) = grep { $fields[$_] eq 'AccountToID' } 0..(scalar @fields - 1);
+ $i ||= 1;
+ while(<IN>) {
+ my @fields = split ',', $_;
+ push @tids, $fields[$i];
+ }
+ close IN;
+ }
+ return @tids;
+}
+
1;
__END__
use Business::OnlinePayment;
####
- # Electronic check authorization. We only support
- # 'Normal Authorization'.
+ # Electronic check authorization.
####
my $tx = new Business::OnlinePayment("Jety");
login => 'testdrive',
password => 'testpass',
action => 'Normal Authorization',
- description => 'Business::OnlinePayment test',
+ description => '111-111-1111 www.example.com',
amount => '49.95',
invoice_number => '100100',
first_name => 'Jason',
=head2 ECHECK
-Content required: type, login, password, action, amount, first_name, last_name, account_number, routing_code.
+Content required: type, login, password, action, amount, first_name, last_name, account_number, routing_code, description.
+
+description should be set in the form "111-111-1111 www.example.com"
=head1 DESCRIPTION
The following actions are valid:
- normal authorization
+ Normal Authorization
+ Void
+ Credit
=head1 AUTHOR
perl(1). L<Business::OnlinePayment>.
+=head1 ADVERTISEMENT
+
+Need a complete, open-source back-office and customer self-service solution?
+The Freeside software includes support for credit card and electronic check
+processing, integrated trouble ticketing, and customer signup and self-service
+web interfaces.
+
+http://freeside.biz/freeside/
+
=cut