## Business::OnlinePayment::Skipjack
##
## Original Skipjack.pm developed by New York Connect Net (http://nyct.net)
## Michael Bacarella <mbac@nyct.net>
##
## Modified for GetCareer.com by Slipstream.com
## Troy Davis <troy@slipstream.com>
##
## 'Adapted' (completely rewritten) for Business::OnlinePayment 
## by Fire2Wire Internet Services (http://www.fire2wire.com)
## Mark Wells <mark@pc-intouch.com>
## Kristian Hoffmann <khoff@pc-intouch.com>
## James Switzer <jamess@fire2wire.com>

## Required packages:
## Net::SSLeay
## Text::CSV
## Business::OnlinePayment


package Business::OnlinePayment::Skipjack;

use strict;
use Business::OnlinePayment;
use Net::SSLeay qw(post_https make_form);
use Text::CSV;
use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);

$VERSION="0.1.1";

require Exporter;

@ISA = qw(Exporter AutoLoader Business::OnlinePayment);
# Items to export into callers namespace by default. Note: do not export
# names by default without a very good reason. Use EXPORT_OK instead.
# Do not simply export all your public functions/methods/constants.
@EXPORT = qw();
@EXPORT_OK = qw();

my %CC_ERRORS = (
        '-1'    =>      'Invalid length (-1)',
        '-35'   =>      'Invalid credit card number (-35)',
        '-37'   =>      'Failed communication (-37)',
        '-39'   =>      'Serial number is too short (-39)',
        '-51'   =>      'The zip code is invalid',
        '-52'   =>      'The shipto zip code is invalid',
        '-53'   =>      'Length of expiration date (-53)',
        '-54'   =>      'Length of account number date (-54)',
        '-55'   =>      'Length of street address (-55)',
        '-56'   =>      'Length of shipto street address (-56)',
        '-57'   =>      'Length of transaction amount (-57)',
        '-58'   =>      'Length of name (-58)',
        '-59'   =>      'Length of location (-59)',
        '-60'   =>      'Length of state (-60)',
        '-61'   =>      'Length of shipto state (-61)',
        '-62'   =>      'Length of order string (-62)',
        '-64'   =>      'Invalid phone number (-64)',
        '-65'	=>		'Empty name (-65)', 
        '-66'   =>      'Empty email (-66)',
        '-67'   =>      'Empty street address (-66)',
        '-68'   =>      'Empty city (-68)',
        '-69'   =>      'Empty state (-69)',
        '-70'   =>      'Empty zip code (-70)',
        '-71'   =>      'Empty order number (-71)',
        '-72'   =>      'Empty account number (-72)',
        '-73'   =>      'Empty expiration month (-73)',
        '-74'   =>      'Empty expiration year (-74)',
        '-75'   =>      'Empty serial number (-75)',
        '-76'   =>      'Empty transaction amount (-76)',
        '-79'   =>      'Length of customer name (-79)',
        '-80'   =>      'Length of shipto customer name (-80)',
        '-81'   =>      'Length of customer location (-81)',
        '-82'   =>      'Length of customer state (-82)',
        '-83'   =>      'Length of shipto phone (-83)',
        '-84'   =>      'Pos Error duplicate ordernumber (-84)',
        '-91'   =>      'Pos Error CVV2 (-91)',
        '-92'   =>      'Pos Error Approval Code (-92)',
        '-93'   =>      'Pos Error Blind Credits Not Allowed (-93)',
        '-94'   =>      'Pos Error Blind Credits Failed (-94)',
        '-95'   =>      'Pos Error Voice Authorizations Not Allowed (-95)',
        );

my %AVS_CODES = (
	'X' => 'Exact match, 9 digit zip', 
	'Y' => 'Exact match, 5 digit zip', 
	'A' => 'Address match only', 
	'W' => '9 digit match only', 
	'Z' => '5 digit match only', 
	'N' => 'No address or zip match', 
	'U' => 'Address unavailable', 
	'R' => 'Issuer system unavailable', 
	'E' => 'Not a mail/phone order', 
	'S' => 'Service not supported' 
	);

my %FIELDS = (
	name	=> 'sjname',
	email	=> 'Email',
	address	=> 'Streetaddress',
	city	=> 'City',
	state	=> 'State',
	zip	=> 'Zipcode',
	invoice_number	=> 'Ordernumber',
	card_number	=> 'Accountnumber',
	exp_month	=> 'Month',
	exp_year	=> 'Year',
	amount	=> 'Transactionamount',
	orderstring	=> 'Orderstring',
	phone	=> 'Shiptophone',
	login	=> 'Serialnumber',
	);


sub _gen_ordernum { return int(rand(4000000000)); }

sub set_defaults
{
  my $self = shift;

  # For production
  $self->server('www.skipjackic.com');
  $self->path('/scripts/evolvcc.dll?AuthorizeAPI');

  # For auth testing
  #$self->server('developer.skipjackic.com'); # test mode
  #$self->path('/scripts/evolvcc.dll?AuthorizeAPI');

  # For comms testing
  #$self->server('www.skipjackic.com');
  #$self->path('/secure/echo.asp');

  $self->port(443);

  return;
}


sub submit
{
  my $self = shift;
  my %c = $self->content;
  my (%input, %output);
  my ($page, $response, %reply_headers);

#  if($c{type} and $c{type} ne 'normal authorization') {
  if($c{type} eq 'credit') {
    warn 'Business::OnlinePayment::Skipjack does not support "' . 
        $c{type}. '"transactions';
    return;
  }

  # FIXME!
  # This should be set from %processor_info.

  # Or, if we want, from $c{login}.

  $c{expiration} =~ /(\d\d?)\D*(\d\d?)/; # Slightly less crude way to extract the exp date.
  $c{exp_month} = sprintf('%02d',$1);
  $c{exp_year} = sprintf('%02d',$2);

  $c{invoice_number} = _gen_ordernum unless $c{invoice_number};

  $c{orderstring} = '0~'.$c{description}.'~'.$c{amount}.'~1~N~||'
      unless $c{orderstring};

  %input = map { ($FIELDS{$_} || $_), $c{$_} } keys(%c);

  ($page, $response, %reply_headers) = 
      post_https($self->server,
                 $self->port,
                 $self->path,
                 '',
                 make_form(%input));


  %output = parse_Authorize_API($page);

  $self->{_result} = \%output;
  $self->authorization($output{'AUTHCODE'});
  return;
}

sub is_success
{
  my $self = shift;

  return ($self->{_result}->{'szIsApproved'} == 1);
}

sub error_message
{
  my $self = shift;
  my $r;

  if($self->is_success) { return ''; }
  if(($r = $self->{_result}->{'szReturnCode'}) < 0) { return $CC_ERRORS{$r}; }
  if($r = $self->{_result}->{'szAVSResponseMessage'}) { return $r; }
  if($r = $self->{_result}->{'szAuthorizationDeclinedMessage'}) { return $r; }
}

sub parse_Authorize_API
{

  my $page = shift;
  my %output;
  my $csv_keys = new Text::CSV;
  my $csv_values = new Text::CSV;

  my ($keystring, $valuestring) = split(/\r\n/, $page);
  $csv_keys->parse($keystring);
  $csv_values->parse($valuestring);
  @output{$csv_keys->fields()} = $csv_values->fields();

  return %output;

}

__END__

1;

