# Connection routine for AuthorizeNet version 3 using the 'ADC Direct Response'
# method. 
# by mark@summersault.com with code reused and inspired by  
#	Mike Heins <mike@minivend.com> 
#	webmaster@nameastar.net 
#   Jeff Nappi <brage@cyberhighway.net> 
#   Paul Delys <paul@gi.alaska.edu> 
#  Edited by Ray Desjardins <ray@dfwmicrotech.com>

# Edited only for references to Minivend, changed to Interchange
# by Mike Heins. Thanks, guys!

# Patches for AUTH_CAPTURE and VOID support contributed by
# nferrari@ccsc.com (Nelson H Ferrari)
 
Variable AUTHORIZENET_HELP <<EOV
 
 1. Modify interchange.cfg to use this file. 
  
	#include globalsub/authorizenet 
 
 2. Modify catalog.cfg to set the server and your Authorize.Net account info 
 
	 
 # Username and password 
 Variable MV_PAYMENT_ID      YourAuthorizeNetID 
 Variable MV_PAYMENT_SECRET  YourAuthorizeNetPassword 
 Variable MV_PAYMENT_MODE    custom authorizenet 
 Variable MV_PAYMENT_REFERER A valid referering url (match this with your setting on secure.authorize.net 

 # If planning to do AUTH_ONLY or other with special admin page
 Variable MV_PAYMENT_REMAP order_id=mv_order_id auth_code=mv_auth_code
  
 3. Make sure CreditCardAuto is off (default in Interchange demos) 
 
 4. Restart Interchange. 
 
EOV

GlobalSub <<EOS
sub authorizenet { 
	my ($user, $secret, $amount) = @_; 
	  
	my (%actual) = Vend::Order::map_actual(); 
	  
	if (! $user ) { 
		$user    =  $::Variable->{MV_PAYMENT_ID} || 
                    $::Variable->{CYBER_ID} 
                    or return undef; 
	} 
	 
	if(! $secret) { 
        $secret  =  $::Variable->{MV_PAYMENT_SECRET} || 
                    $::Variable->{CYBER_SECRET} 
                    or return undef; 
    } 
     
    my $server  =   $::Variable->{MV_PAYMENT_SERVER} || 
                    $::Variable->{CYBER_SERVER} || 
                    'secure.authorize.net'; 
                     
    my $script 	=   $::Variable->{MV_PAYMENT_SCRIPT} || 
                    $::Variable->{CYBER_SCRIPT} || 
                    '/gateway/transact.dll'; 
                     
    my $port    =   $::Variable->{MV_PAYMENT_PORT} || 
                    $::Variable->{CYBER_PORT} || 
                    443; 
                     
	my $precision = $::Variable->{MV_PAYMENT_PRECISION} || 
                    $::Variable->{CYBER_PRECISION} || 
                    2; 
	my $referer   = $::Variable->{MV_PAYMENT_REFERER};                     
                                         
	$actual{mv_credit_card_exp_month} =~ s/\D//g; 
    $actual{mv_credit_card_exp_month} =~ s/^0+//; 
    $actual{mv_credit_card_exp_year} =~ s/\D//g; 
    $actual{mv_credit_card_exp_year} =~ s/\d\d(\d\d)/$1/; 
 
    $actual{mv_credit_card_number} =~ s/\D//g; 
 
    my $exp = sprintf '%02d%02d', 
                        $actual{mv_credit_card_exp_month}, 
                        $actual{mv_credit_card_exp_year};                     
                         
	# Using mv_payment_mode for compatibility with older versions, probably not
	# necessary.
	$actual{cyber_mode} = $actual{mv_payment_mode} || 'AUTH_CAPTURE'
        unless $actual{cyber_mode}; 

	my %type_map = ( 
		mauth_capture 			=>	'AUTH_CAPTURE', 
		mauthonly				=>	'AUTH_ONLY', 
		CAPTURE_ONLY			=>  'CAPTURE_ONLY', 
		CREDIT					=>	'CREDIT', 
		VOID					=>	'VOID', 
		AUTH_ONLY				=>	'AUTH_ONLY',
		PRIOR_AUTH_CAPTURE		=>	'PRIOR_AUTH_CAPTURE', 
 
	);                        
	 
	if (defined $type_map{$actual{cyber_mode}}) { 
        $actual{cyber_mode} = $type_map{$actual{cyber_mode}}; 
    } 
    else { 
        $actual{cyber_mode} = 'AUTH_CAPTURE'; 
    } 
 
    if(! $amount) { 
        $amount = Vend::Interpolate::total_cost(); 
        $amount = sprintf("%.${precision}f", $amount); 
    }  
     
    my($orderID); 
    my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time()); 
 
    # We'll make an order ID based on date, time, and MiniVend session 
 
    # $mon is the month index where Jan=0 and Dec=11, so we use 
    # $mon+1 to get the more familiar Jan=1 and Dec=12 
    $orderID = sprintf("%04d%02d%02d%02d%02d%05d%s", 
            $year + 1900,$mon + 1,$mday,$hour,$min,$$,$Vend::SessionName); 
             
    my %query = ( 
#                    x_Test_Request	=> $::Variable->{MV_PAYMENT_TEST},
                    x_Card_Num		=> $actual{mv_credit_card_number}, 
                    x_First_Name    => $actual{b_fname}, 
                    x_Last_Name     => $actual{b_lname},
                    x_Address       => $actual{address}, 
                    x_City          => $actual{b_city}, 
                    x_State         => $actual{b_state}, 
                    x_Zip			=> $actual{zip},
					x_Type			=> $actual{cyber_mode},
                    x_Amount    	=> $amount, 
                    x_Exp_Date  	=> $exp,
                    x_Method    	=> 'CC',
					x_Trans_ID		=> $actual{order_id},
					x_Auth_Code		=> $actual{auth_code},
                    x_Invoice_Num   => $actual{mv_order_number},
#                    x_Company      => $actual{company},
#                    x_Phone        => $actaul{day_phone},  
                    x_Password  	=> $secret, 
                    x_Login     	=> $user, 
                    x_Version   	=> '3.0', 
                    x_ADC_URL   	=> 'FALSE', 
                    x_ADC_Delim_Data	=> 'TRUE', 
 
 
    ); 
     
    my @query; 
 
    for (keys %query) { 
        my $key = $_; 
        my $val = $query{$key}; 
        $val =~ s/["\$\n\r]//g; 
        $val =~ s/\$//g; 
        my $len = length($val); 
        if($val =~ /[&=]/) { 
            $key .= "[$len]"; 
        } 
        push @query, "$key=$val"; 
    } 
    my $string = join '&', @query; 
     
    use Net::SSLeay qw(post_https make_form make_headers); 
     
    my ($page, $response, %reply_headers) 
                = post_https($server, $port, $script,  
                	   make_headers( Referer => $referer),  
                       make_form( 
                               %query 
                       )); 
	 
    # Minivend names are on the  left, Authorize.Net on the right 
    my %result_map = ( qw/ 
            MStatus               x_response_code 
            pop.status            x_response_code 
            MErrMsg               x_response_reason_text 
            pop.error-message     x_response_reason_text 
            order-id              x_trans_id 
            pop.order-id          x_trans_id 
            pop.auth-code         x_auth_code 
            pop.avs_code          x_avs_code 
            pop.avs_zip           x_zip 
            pop.avs_addr          x_address 
    / 
    );           
     
 
#::logError(qq{\nauthorizenet page: $page response: $response\n});  
 
    my ($response_code, 
    	$response_subcode, 
    	$response_reason_code, 
    	$response_reason_text, 
    	$auth_code, 
    	$avs_code, 
    	$trans_id) = split (/,/,$page); 
    	 
::logError(qq{authorizenet response_reason_text=$response_reason_text response_code: $response_code});    	 
 
    my %result; 
    if ($response_code == 1) { 
    	$result{MStatus} = 'success'; 
    	# order-id and auth_code are set to 0 if Authorize.net in test mode.
		# Order.pm interprets order-id == 0 as authorization error.
		$result{'order-id'} = $trans_id || 1;
		$result{'auth_code'} = $auth_code;
    } else { 
    	$result{MStatus} = 'failure'; 
    	$Vend::Session->{MStatus} = 'failure'; 
 
		# NOTE: A lot more AVS codes could be checked for here.  
    	if ($avs_code eq 'N') { 
    		$result{MErrMsg} = "You must enter the correct billing address of your credit card. The bank returned the following error: " . $response_reason_text; 
    	} else { 
    		$result{MErrMsg} = "$response_reason_text" ;
			my $msg = errmsg("Authorizenet error: %s. Please call in your order or try again.",
					$response_reason_text,
					);
    	} 
		$Vend::Session->{payment_error} = $result{MErrMsg};
    } 
     
    return (%result); 
 
} 
EOS


