Forums

Authorize .net failure need to go back to form

aarmstrong 12 Nov, 2008
I have a form that is using the A .net plugin. The form is working as is the plugin. The only issue I have is that when the authorization fails I need the user to be taken back to the form so they can correct the CC info. At the moment it completes the form even if the authorization fails. Is there a way to send the user back to the form and display the error message A .net sends back?

There are 2 places where it makes sense to stop the processing of the form and send the user back to the form submission page. The obvious one is the 'On Submit code - before sending email'. The other place is within the A. net plugin settings, the 'Extra after onsubmit code'. The problem is I am not sure what to add here that will tell the processing to go back to the form submission page.

Any idea?
aarmstrong 12 Nov, 2008
I have been looking into this more closely and here is what I have come up with. I added some code to the plugins 'Extra after onsubmit code' code section that looks like this:

if ($cf_AUTHNET_response_code != 'Approved') {
  showErrorMessage('There was a problem with your credit card: (' . $cf_AUTHNET_response_reason_text . ')' );
  showform($_POST);
  return;
}


The problem with this is this section of code is run from an eval statement that you find on line 983 of the plugin souce code.

                /*********do the after onsubmit code**********/
                if ( !empty($row->extra5) ) {
                        eval( "?>".$row->extra5 );
                }


Unfortunately the way the eval is done it ignores any returns sent back from the code it runs which at the moment I am not returning.

Another thing I found odd about this plugin is that when it parses the response from the A .net gateway it treats a response of approved the same as it does a response of declined or error. I would have expected the default action when the response is error or delined to go back to the form and display the reason for this but the plugin just goes on regardless of the response. I am going to do some testing and see if I can make it go bac k to the form.
Max_admin 12 Nov, 2008
Hi,

try this code at the "on Submit after email" box ?

if ($cf_AUTHNET_response_code != 'Approved') {
  showErrorMessage('There was a problem with your credit card: (' . $cf_AUTHNET_response_reason_text . ')' );
  showform($_POST);
  return;
}


let me know!

Regards
Max
Max
ChronoForms developer...
Did you try ChronoMyAdmin for managing your Joomla database tables ?
aarmstrong 13 Nov, 2008
Thanks for your reply but the On submit after email code does not work for me. If the credit card is declined or has an error connecting to the Authorize .net gateway I do not want an email sent at all. I would imagine that most people would want this as well since the form would generally be used to accept payment for something and if the payment did not complete there would be no need to complete the process. Even if your suggestion works I expect some users would be confused by receiving the email when the card was not accepted.

Another problem with all of the before and after code is the way they are written. They do not allow the code to stop the processing because they are run in an eval statement that does not consider the value returned by the eval'd code.

/*********do the before onsubmit code**********/
if ( !empty($row->extra4) ) {
   eval( "?>".$row->extra4 );
}


Take this code segment. The eval statement runs the code until the end of the code or until the return statement is given. If a value is passed to return statement this value is returned by the eval function. Since this code snippet does not check for the return value no matter what we do in the code it will continue on after the eval with the form submission process.

In order to stop the form submission it would need something like this:

/*********do the before onsubmit code**********/
if ( !empty($row->extra4) ) {
   if (eval( "?>".$row->extra4 ) != NULL) {
   }
}


The before and after code in the Authorize .net plugin is eval'd the same way so no matter what we do in the eval'd code the return statement will only return from the eval code and will not stop the execution of the plugin code. Before this plugin was finished I identified this problem in a post from the beginning of the year.

http://www.chronoengine.com/forums/index.php?option=com_chronoforums&cont=posts&f=2&t=4768

Until this limitation is corrected the before and after code from the main code and the plugin cannot be used to stop the form processing and the same goes from the code in the plugin.

If I had my dream solution the before and after code would provide a mechanism to return an error string. Something like this:

/*********do the before onsubmit code**********/
if ( !empty($row->extra4) ) {
   if (eval( "?>".$row->extra4 ) != NULL ) {
      /* do something to stop the code */
      showErrorMessage($cf_AUTHNET_codeb4_errormsg);
      showform($_POST);
      return;
   }
}


Then the following code could be used to stop the for processing. I am testing this later this evening and will report back my results.

if ($cf_AUTHNET_response_code != 'Approved') {
  $cf_AUTHNET_codeb4_errormsg = 'There was a problem with your credit card: (' . $cf_AUTHNET_response_reason_text . ')';
  return 911;
}
aarmstrong 13 Nov, 2008
Closer but not there yet. I modified the cf_Authorize_dotnet.php file with the changes above and I am getting closer but not there yet. With the changes above I am able to display an error message popup however it is currently displaying an empty message. So there is still more work to do there.

The bigger issue is that this modified code section sort of works:

/*********do the before onsubmit code**********/
if ( !empty($row->extra4) ) {
   if (eval( "?>".$row->extra4 ) != NULL ) {
      /* do something to stop the code */
      showErrorMessage($cf_AUTHNET_codeb4_errormsg);
      showform($_POST);
      return;
   }
}


The final return exits the plugin but as with the previous problem with the eval the return does not stop the chronocontact.php from continuing on with the form processing. So it does display the form again but it also goes ahead and sends the email. The segment of code below calls the plugin onsubmit function.


        /* Do Onsubmit before_email plugins*/
        
        $ava_plugins = explode(",",$paramsvalues->plugins);
        $ava_plugins_order = explode(",",$paramsvalues->mplugins_order);
        //$ava_plugins_array = array();
        array_multisort($ava_plugins_order, $ava_plugins);
        foreach($ava_plugins as $ava_plugin){
                $query     = "SELECT * FROM #__chrono_contact_plugins WHERE form_id='".$rows[0]->id."' AND event='ONSUBMIT' AND name='".$ava_plugin."'";
                $database->setQuery( $query );
                $plugins = $database->loadObjectList();
                if(count($plugins)){
                        require_once($mosConfig_absolute_path."/components/com_chronocontact/plugins/".$ava_plugin.".php");
                        ${$ava_plugin} = new $ava_plugin();
                        $params = mosParseParams($plugins[0]->params);
                        if($params->onsubmit == 'before_email'){
                                ${$ava_plugin}->onsubmit( 'com_chronocontact', $params, $plugins[0] );
                        }
                }
        }


The next step is to modify the plugin onsubmit line to check for an error code. This is becoming a lot of work but I need it.
Max_admin 13 Nov, 2008
Hi aarmstrong,

this code works at a joomla 2.3.9 site of some client :

<?php
global $cf_AUTHNET_response_code;
if($cf_AUTHNET_response_code != 'Approved'){
$rows[0]->emailresults = 0;
//write error message
}else{
//transaction went through
}


I think what you need with V3.0 stable and J1.5 should be like this without any hacks or changes :
<?php
global $cf_AUTHNET_response_code;
if($cf_AUTHNET_response_code != 'Approved'){
$emails[0]->enabled = 0;
//write error message
}else{
//transaction went through
}


this code goes in the onsubmit before email box!

Regards
Max
Max
ChronoForms developer...
Did you try ChronoMyAdmin for managing your Joomla database tables ?
aarmstrong 13 Nov, 2008
That is exactly the solution I needed. Thanks a ton and thanks for all your suggestions and help.
Max_admin 13 Nov, 2008
Glad I could help!

Regards
Max
Max
ChronoForms developer...
Did you try ChronoMyAdmin for managing your Joomla database tables ?
aarmstrong 25 Nov, 2008
OK, one more thing to do. I have my form working with the Authorize .net plugin and it send the user back to the form without sending the emails. I now have turned on the option to write the form data to database table. When I submit the form and it fails it still writes the data to the database table I have created. Is there a way to disable this from within my code segments?
aarmstrong 26 Nov, 2008
Found another problem that breaks the fixes above. If I set the Redirect URL for a form it continues on to the redirection page instead of keeping me on the same form. What code can I use to disable the redirection url?
Max_admin 26 Nov, 2008
you can remove any redirection URL and redirect through code with :

$mainframe->redirect('redirect_url_here');
Max
ChronoForms developer...
Did you try ChronoMyAdmin for managing your Joomla database tables ?
sjellum 04 Jun, 2009
I have been trying to get this to work on a site that has Joomla 1.0, ChronoForms 2.3.9

The code I am using in On Submit before email is:
<?php
global $cf_AUTHNET_response_code;

if($cf_AUTHNET_response_code != 'Approved'){
$emails[0]->enabled = 0;
$mainframe->redirect('http://www.colvinrunpto.org/index.php?option=com_chronocontact&chronoformname=BA
SA_Spring09_test');
//write error message
}else{
//transaction went through
}

On an authorization failure, this produces the error message:
Fatal error: Call to a member function redirect() on a non-object in
/home/crptou/public_html/components/com_chronocontact/chronocontact.php(401) : eval()'d code on line 6

I tried to add in:
global $mainframe;

and now get the error:

Fatal error: Call to undefined method mosMainFrame::redirect() in
/home/crptou/public_html/components/com_chronocontact/chronocontact.php(401) : eval()'d code on line 7

Any help would be appreciated!
Max_admin 23 Jun, 2009
Hi, to redirect in the J1.0 use :
mosRedirect('url here');
Max
ChronoForms developer...
Did you try ChronoMyAdmin for managing your Joomla database tables ?
aarmstrong 13 Aug, 2009

Hi, to redirect in the J1.0 use :

mosRedirect('url here');



Hi, me again. Client has approved update to Joomla 1.5 so I need to get this working in 1.5 now. Will the same command work or is there a different one I need to use? Thanks again, your product has served me well and your support has been excellent.

On a completely unrelated note is there any plans to add functionality to the Plugin to stop the processing and take the user back to the form when the CC has an error or is not approved. I don't really undterstand why this would not be the default functionality but I suppose there could be a need to go on regardless of the CC processing outcome. Maybe an option in the plugin that lets you decide to go on or to stop processing and return to the form so the user can correct the card info.
GreyHead 16 Aug, 2009
Hi aarmstrong,

The equivalent command in Joomla 1.5 is
<?php
gloabal $mainframe;
$mainframe->redirect('url', 'message', 'message_type');
?>
The 'message' and 'message_type' are optional parameters that will show a Joomla system message after the redirect if they are included. The 'message_type' affects the styling of the message - I don't recall the full list 'alert', 'info', 'error', maybe one or two others.

Bob

NB There's a slightly arcane ChronoForms bug that sometimes causes problems saving forms that include $mainframe->redirect :-(
aarmstrong 28 Aug, 2009
I noticed in the latest auth.net plugin the global variables have changed from the

$cf_AUTHNET_response_code


to

$MyPlugins->cf_Authorize_dotnet['response_code']


Does this mean that in my code sections all I need to do is this in order to access the values returned from the plugin?

<?php

global $MyPlugins;

if ($MyPlugins->cf_Authorize_dotnet['response_code'] != 'Approved') {
  /* do somthing */
}

?>


I have code sections that look like this now and I need to update them to the new format.

<?php
global $mainframe;
global $cf_AUTHNET_response_code;
global $cf_AUTHNET_response_subcode;
global $cf_AUTHNET_response_reason_code;
global $cf_AUTHNET_response_reason_text;
global $cf_AUTHNET_approval_code;
global $cf_AUTHNET_avs_result_code;
global $cf_AUTHNET_transaction_id;


if($cf_AUTHNET_response_code != 'Approved'){
  /* do something */
}
?>
GreyHead 29 Aug, 2009
Hi aarmstrong,

Looks like it , I didn't know that the plugin had been updated.

Bob
aarmstrong 29 Aug, 2009
Not sure what all has changed but all my old code is no longer working since I upgraded to the latest version of chronoforms and the auth.net plugin. Is there any new documentation on how this should work or any examples? I have a form where I need to take credit card info and process it and only submit the form and send email if the credit card is approved. If the card fails I want to cancel the email and send the user back to the populated form showing an error/warning with the failure reason. In the past I used code similar to this in the before email code.

<?php
global $cf_AUTHNET_response_code, $cf_AUTHNET_response_reason_text, $cf_AUTHNET_approval_code, $cf_AUTHNET_transaction_id;
if($cf_AUTHNET_response_code != 'Approved'){
  $emails[0]->enabled = 0;
  $rows[0]->autogenerated = "";
  //write error message
  showErrorMessage("Credit Card Error: (" . $cf_AUTHNET_response_reason_text . ")");
  showform($_POST);
}else{
  //transaction went through
}
?>


Seems the showErrorMessage function no longer exists and the showform function expects 2 parameters. It also does not seem like the $emails[0]->enabled = 0 is disabling the email any more either.

In addition to this auth.net global variables seem to have changed to something like this:

$MyPlugins->cf_Authorize_dotnet['response_reason_text']



Any help to get this working again is greatly appreciated.
GreyHead 30 Aug, 2009
Hi aarmstrong,

Practically, the best answer to this is for you to contact Max directly through the Contact Us form here. It will be much easier for him to tell you what he's changed than for me to try to work it out.

Bob
leeburstroghm 30 Aug, 2009
Well guys.

I was able to set up authorize. to send out a request, and check the responses. though, the response returned does not match the API manual for response codes. probably a mistake in the plugins part.

I have this added to the BEFORE email. As This is the only way to STOP the email from being sent to the customer and the client, if the authorize.net returns error.

this is what I have in the on submit events form code. before email. modified from the paypal registration tutorial.
<?php
$MyPlugins =& CFPlugins::getInstance($MyForm->formrow->id);
$MyPlugins->runPlugin('after_email', array('ONSUBMIT', 'ONLOADONSUBMIT'), 'cf_Authorize_dotnet');
if($MyPlugins->cf_Authorize_dotnet['response_code'] == '1'){
    echo  "Thank you for your purchase. You will be receiving a confirmation email shortly";
    $MyFormEmails =& CFEMails::getInstance($MyForm->formrow->id);
    $MyFormEmails->setEmailData(1, 'enabled', '1');
    $MyFormEmails->sendEmails($MyForm, $MyFormEmails->emails);
  }else{
    $MyForm->addErrorMsg( 'An error occured with the Credit Card Processing:<br />'.$MyPlugins->cf_Authorize_dotnet['response_code'].': '.$MyPlugins->cf_Authorize_dotnet['response_reason_text'] );
    $MyForm->haltFunction["autogenerated_after_email"] = true;
  }
?>


The $MyPlugins->cf_Authorize_dotnet['response_code'] outputs "ERROR" instead of the Numerical 2. or 3. I am checking for a '1' for success, but when ever I do get success, I will get the result code and change it then, so no problem

I had a developer account, and notice a debug and test in the authorize.net plugin. I do not see a url setting and I dont know what url the post is sending to. I keep getting a transaction key or account not active error. Not sure if its the plugin or the info I have, I put my developer info in and I get the same error! a Developer selection to use the developer url for testing would be GREATE!!
Transaction POST URL:
https://test.authorize.net/gateway/transact.dll
Maybe I will make that change in the code myself.. ??!!

Hope this helps.

By the way. WHERE do I purchase the Authorize.net plugin??!! I find no refrence to how or where to go to buy this guy. if it works, I would purchase right away!!
aarmstrong 31 Aug, 2009
I ended up dropping the Authorize.net plugin completely and decided to use the server validation custom code section instead and write my own interface to Authorize.net using curl. This ends up working better for me in the long run due to all the other stuff I had to do in custom code sections to get the form to work the way I wanted it to. With this code I can let chronoforms handle the client side validation as usual, I can validate using my custom code below, and chronoforms can handle the emails and redirect. Before I had to disable to the email and redirection in code due to the way the plugin handled (or rather lack of) failures.

Hope this code helps anybody who had the same problems as I did. Remember to update this to turn off test mode before taking the form live.


<?PHP

// By default, this sample code is designed to post to our test server for
// developer accounts: https://test.authorize.net/gateway/transact.dll
// for real accounts (even in test mode), please make sure that you are
// posting to: https://secure.authorize.net/gateway/transact.dll
//$post_url = "https://test.authorize.net/gateway/transact.dll";
$post_url = "https://secure.authorize.net/gateway/transact.dll";

/* test numbers
good:
370000000000002 American Express
6011000000000012 Discover
5424000000000015 MasterCard
4007000000027 Visa

bad: 4222222222222222
amount determines error returned
*/

$post_values = array(
	
	// the API Login ID and Transaction Key must be replaced with valid values
	"x_login"		=> "your_login",
	"x_tran_key"		=> "your_key",
	"x_test_request"	=> "T",

	"x_version"		=> "3.1",
	"x_delim_data"		=> "TRUE",
	"x_delim_char"		=> "|",
	"x_relay_response"	=> "FALSE",

	"x_type"		=> "AUTH_CAPTURE",
	"x_method"		=> "CC",
	
	"x_card_num"		=> $_POST['cardNumber'],
	"x_exp_date"		=> $_POST['cardMonth'] . '-' .  $_POST['cardYear'],

	"x_amount"		=> $_POST['amount'],
	"x_description"		=> $_POST['description'],

	"x_first_name"		=> $_POST['cardFirstName'],
	"x_last_name"		=> $_POST['cardLastName'],
	"x_address"		=> $_POST['cardAddress'],
	"x_city"                => $_POST['cardCity'],
	"x_state"		=> $_POST['cardST'],
	"x_zip"			=> $_POST['cardZIP']
	// Additional fields can be added here as outlined in the AIM integration
	// guide at: http://developer.authorize.net
);

// This section takes the input fields and converts them to the proper format
// for an http post.  For example: "x_login=username&x_tran_key=a1B2c3D4"
$post_string = "";
foreach( $post_values as $key => $value )
	{ $post_string .= "$key=" . urlencode( $value ) . "&"; }
$post_string = rtrim( $post_string, "& " );

// This sample code uses the CURL library for php to establish a connection,
// submit the post, and record the response.
// If you receive an error, you may want to ensure that you have the curl
// library enabled in your php configuration
$request = curl_init($post_url); // initiate curl object
	curl_setopt($request, CURLOPT_HEADER, 0); // set to 0 to eliminate header info from response
	curl_setopt($request, CURLOPT_RETURNTRANSFER, 1); // Returns response data instead of TRUE(1)
	curl_setopt($request, CURLOPT_POSTFIELDS, $post_string); // use HTTP POST to send form data
	curl_setopt($request, CURLOPT_SSL_VERIFYPEER, FALSE); // uncomment this line if you get no gateway response.
	$post_response = curl_exec($request); // execute curl post and store results in $post_response
	// additional options may be required depending upon your server configuration
	// you can find documentation on curl options at http://www.php.net/curl_setopt
curl_close ($request); // close curl object

// This line takes the response and breaks it into an array using the specified delimiting character
$response_array = explode($post_values["x_delim_char"],$post_response);

$response_code = $response_array[0];
$response_reason = $response_array[3];

// individual elements of the array could be accessed to read certain response
// fields.  For example, response_array[0] would return the Response Code,
// response_array[2] would return the Response Reason Code.
// for a list of response fields, please review the AIM Implementation Guide

if ($response_code != 1){
	return "Credit Card Error: $response_reason";
}
?>

This topic is locked and no more replies can be posted.