package Business::OnlinePayment::eWay;

use strict;
use Carp;
use Business::OnlinePayment;
use Business::CreditCard;
use Net::SSLeay qw( post_https );
use XML::Simple;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $DEBUG);

require Exporter;

@ISA = qw(Exporter AutoLoader Business::OnlinePayment);
@EXPORT = qw();
@EXPORT_OK = qw();
$VERSION = '0.01';

$DEBUG = 1;

my $default_path = '/gateway/xmlpayment.asp';
my $default_cvn_path = '/gateway_cvn/xmlpayment.asp';
my $default_test_path = '/gateway/xmltest/testpage.asp';
my $default_cvn_test_path = '/gateway_cvn/xmltest/testpage.asp';

sub set_defaults {
    my $self = shift;
    $self->server('www.eway.com.au');
    $self->port('443');
    $self->path($default_path);
}

sub revmap_fields {
    my($self,%map) = @_;
    my %content = $self->content();
    foreach(keys %map) {
        $content{$_} = ref($map{$_})
                         ? ${ $map{$_} }
                         : (exists($content{$map{$_}})
                             ? $content{$map{$_}}
			     : '' 
			   );
    }
    $self->content(%content);
}

sub get_fields {
    my($self,@fields) = @_;

    my %content = $self->content();
    my %new = ();
    foreach( grep defined $content{$_}, @fields) { $new{$_} = $content{$_}; }
    return %new;
}

sub submit {
    my($self) = @_;
    my %content = $self->content;

    my $action = lc($content{'action'});
    die 'eSec only supports "Normal Authorization" transactions'
      unless $action eq 'normal authorization';

    $content{'expiration'} =~ /^(\d+)\D+(\d+)$/
      or croak "unparsable expiration $content{expiration}";
    my ($month, $year) = ( $1, $2 );
    $month += 0;
    $year %= 100; #not y2.1k safe

    $content{'amount'} =~ /^(\d+\.+\d{0,2})$/
      or croak "unparsable amount $content{amount}";
    my $amount = $1*100;

    my $address = $content{'address'} if exists $content{'address'};
    $address .=   $content{'city'}    if exists $content{'city'};
    $address .=   $content{'state'}   if exists $content{'state'};
    $address .=   '';

    $self->revmap_fields(
      ewayCustomerID                 => 'login',
      ewayTotalAmount                => \$amount,
      ewayCustomerFirstName          => 'first_name',
      ewayCustomerLastName           => 'last_name',
      ewayCustomerEmail              => 'email',
      ewayCustomerAddress            => \$address,
      ewayCustomerPostcode           => 'zip',
      ewayCustomerInvoiceDescription => 'description',
      ewayCustomerInvoiceRef         => 'invoice_number',
      ewayCardHoldersName            => 'name',
      ewayCardNumber                 => 'card_number',
      ewayCardExpiryMonth            => \$month,
      ewayCardExpiryYear             => \$year,
      ewayTrxnNumber                 => 'transaction_number',
      ewayOption1                    => 'option1',
      ewayOption2                    => 'option1',
      ewayOption3                    => 'option1',
      ewayCVN                        => 'cvv2',
    );
    %content = $self->content;
    if ( $DEBUG ) {
      warn "content:$_ => $content{$_}\n" foreach keys %content;
    }

    if ($self->transaction_type() eq 'CC' ) {
      $self->required_fields(qw/action login amount name card_number expiration/);
    } else {
      croak("eWay can't handle transaction type: ".
            $self->transaction_type());
    }

    my %post_data = $self->get_fields( map "$_", qw(
      ewayCustomerID ewayTotalAmount ewayCustomerFirstName ewayCustomerLastName
      ewayCustomerEmail ewayCustomerAddress ewayCustomerPostcode 
      ewayCustomerInvoiceDescription ewayCustomerInvoiceRef ewayCardHoldersName
      ewayCardNumber ewayCardExpiryMonth ewayCardExpiryYear ewayTrxnNumber
      ewayOption1 ewayOption2 ewayOption3 ewayCVN
    ) );
    if ( $DEBUG ) {
      warn "post_data:$_ => $post_data{$_}\n" foreach keys %post_data;
    }

    my $pd = XMLout({%post_data}, 'NoAttr' => 1, 'RootName' => 'ewaygateway');
    if ( $DEBUG ) {
      warn $pd,"\n";
    }
    my $server = $self->server();
    my $port = $self->port();
    my $path = $self->path();
    if ($post_data{ewayCVN} && $path eq $default_path){
      $path = $default_cvn_path;
    }
    if ($self->test_transaction) {
      if ($path eq $default_path) {
        $path = $default_test_path;
      }elsif ($path eq $default_cvn_path){
        $path = $default_cvn_test_path;
      }else{
        croak "Test mode not supported for path: $path\n";
      }
    }

    my($page,$server_response) =
      post_https($server,$port,$path,'',$pd);
    if ( $DEBUG ) {
      warn $page,"\n";
    }

    my $response;
    if ($server_response =~ /HTTP\/1\.1 200 OK/){
      $response = XMLin($page);
    }else{
      $response->{ewayTrxnError} = $server_response;
    }

    if ( $response->{ewayTrxnStatus} =~ /^True/ ) {
      $self->is_success(1);
      $self->authorization($response->{ewayAuthCode});
    } else {
      $self->is_success(0);
    }
    $self->error_message($response->{ewayTrxnError});
    $self->server_response($response);
}

1;
__END__

=head1 NAME

Business::OnlinePayment::eWay - eWay backend for Business::OnlinePayment

=head1 SYNOPSIS

  use Business::OnlinePayment;

  my $tx = new Business::OnlinePayment("eWay");
  $tx->content(
      login          => '87654321', #ewayCustomerID
      action         => 'Normal Authorization',
      description    => 'Business::OnlinePayment test',
      amount         => '49.95',
      invoice_number => '100100',
      name           => 'Tofu Beast',
      card_number    => '46464646464646',
      expiration     => '11/08',
  );
  $tx->submit();

  if($tx->is_success()) {
      print "Card processed successfully: ".$tx->authorization."\n";
  } else {
      print "Card was rejected: ".$tx->error_message."\n";
  }

=head1 DESCRIPTION

For detailed information see L<Business::OnlinePayment>.

=head1 NOTE

=head1 COMPATIBILITY

This module implements eWay's XML API.  See
http://www.eway.com.au/support/xml.aspx for details.

=head1 AUTHOR

Jeff Finucane <jeff@cmh.net>

=head1 SEE ALSO

perl(1). L<Business::OnlinePayment>.

=cut

