Hi,
I have made a payment module that we take customer credit card number on site and make process.
If 3ds is enabled form the admin then payment method send to ASC URL for the verification and then return back to TermURL .
I am a making a XML then calling the curl then upon response code for 116 we are making 3ds verification .
But i getting problem that how i can send to the ASC URL and make TermURL(also called callback URL) to make payment and create order successfully? Please help me.
Here is my current code :
<?php
/**
* IPSP Billing DirectAPI payment module
*
* @package ipsp billing
* @copyright Copyright 2016 IPSP Billing Team
* @license http://www.zen-cart.com/license/2_0.txt GNU Public License V2.0
* @version Author: Mario New in v1.0.0
*/
/**
* IPSP Billing DirectAPI Payment module class
*/
class ipsp_billing_directapi extends base {
/**
* $code determines the internal 'code' name used to designate "this" payment module
*
* @var string
*/
var $code;
/**
* $moduleVersion is the plugin version number
*/
var $moduleVersion = '1.0.0';
/**
* $title is the displayed name for this payment method
*
* @var string
*/
var $title;
/**
* $description is admin-display details for this payment method
*
* @var string
*/
var $description;
/**
* $enabled determines whether this module shows or not... in catalog.
*
* @var boolean
*/
var $enabled;
/**
* $sort_order determines the display-order of this module to customers
*/
var $sort_order;
/**
* $commError and $commErrNo are CURL communication error details for debug purposes
*/
var $commError, $commErrNo;
/**
* transaction vars hold the IDs of the completed payment
*/
var $transaction_id, $transaction_messages, $auth_code, $acs_URL, $responsecode;
/**
* internal vars
*/
private $avs_codes, $cvv_codes;
/**
* Constructor
*/
function __construct() {
global $order;
$this->code = 'ipsp_billing_directapi';
$this->title = MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_TEXT_CATALOG_TITLE; // Payment module title in Catalog
if (IS_ADMIN_FLAG === true) {
$this->title = MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_TEXT_ADMIN_TITLE;
if (MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_AUTH_CODE == 'xxxxxxxxxxxxxxxx')
$this->title .= '<span class="alert"> (not configured; API details needed)</span>';
if (MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ENABLE_3DS == 'Sandbox')
$this->title .= '<span class="alert"> (Sandbox mode)</span>';
$new_version_details = plugin_version_check_for_updates(2050, $this->moduleVersion);
if ($new_version_details !== false) {
$this->title .= '<span class="alert">' . ' - NOTE: A NEW VERSION OF THIS PLUGIN IS AVAILABLE. <a href="' . $new_version_details['link'] . '" target="_blank">[Details]</a>' . '</span>';
}
}
$this->description = MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_TEXT_DESCRIPTION;
$this->enabled = ((MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_STATUS == 'True') ? true : false);
$this->sort_order = MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_SORT_ORDER;
// determine order-status for transactions
if ((int) MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ORDER_STATUS_ID > 0) {
$this->order_status = MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ORDER_STATUS_ID;
}
if ($this->responsecode == '116' && MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ENABLE_3DS == 'Yes') {
$this->form_action_url = $this->acs_URL;
}
$this->_logDir = DIR_FS_LOGS;
}
function update_status() {
}
function javascript_validation() {
return '';
}
function selection() {
global $order;
for ($i = 1; $i < 13; $i++) {
$expires_month[] = array('id' => sprintf('%02d', $i), 'text' => strftime('%B - (%m)', mktime(0, 0, 0, $i, 1, 2000)));
}
$today = getdate();
for ($i = $today['year']; $i < $today['year'] + 15; $i++) {
$expires_year[] = array('id' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)), 'text' => strftime('%Y', mktime(0, 0, 0, 1, 1, $i)));
}
// helper for auto-selecting the radio-button next to this module so the user doesn't have to make that choice
$onFocus = ' onfocus="methodSelect(\'pmt-' . $this->code . '\')"';
$selection = array(
'id' => $this->code,
'module' => MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_TEXT_CATALOG_TITLE,
'fields' => array(
array(
'title' => MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_TEXT_CREDIT_CARD_NUMBER,
'field' => zen_draw_input_field($this->code . '_cc_number', '', 'payeezy-data="cc_number" id="' . $this->code . '_cc-number"' . $onFocus . ' autocomplete="off"'),
'tag' => $this->code . '_cc-number'
),
array(
'title' => MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_TEXT_CREDIT_CARD_EXPIRES,
'field' => zen_draw_pull_down_menu($this->code . '_cc_expires_month', $expires_month, strftime('%m'), 'payeezy-data="exp_month" id="' . $this->code . '_cc-expires-month"' . $onFocus) . ' ' .
zen_draw_pull_down_menu($this->code . '_cc_expires_year', $expires_year, '', 'payeezy-data="exp_year" id="' . $this->code . '_cc-expires-year"' . $onFocus),
'tag' => $this->code . '_cc-expires-month'
),
array(
'title' => MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_TEXT_CVV,
'field' => zen_draw_input_field($this->code . '_cc_cvv', '', 'size="4" maxlength="4"' . 'payeezy-data="cvv_code" id="' . $this->code . '_cc-cvv"' . $onFocus . ' autocomplete="off"'),
'tag' => $this->code . '_cc-cvv'
),
)
);
return $selection;
}
function pre_confirmation_check() {
global $messageStack;
if (!isset($_POST[$this->code . '_cc_number']) || trim($_POST[$this->code . '_cc_number']) == '' || !isset($_POST[$this->code . '_cc_cvv']) || trim($_POST[$this->code . '_cc_cvv']) == '') {
$messageStack->add_session('checkout_payment', MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ERROR_MISSING_FDTOKEN, 'error');
zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, '', 'SSL', true, false));
}
}
function confirmation() {
$confirmation = array('fields' => array(
array('title' => MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_TEXT_CREDIT_CARD_NUMBER,
'field' => zen_output_string_protected($_POST[$this->code . '_cc_number'])),
array('title' => MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_TEXT_CREDIT_CARD_EXPIRES,
'field' => strftime('%B, %Y', mktime(0, 0, 0, $_POST[$this->code . '_cc_expires_month'], 1, $_POST[$this->code . '_cc_expires_year']))),
));
return $confirmation;
}
function process_button() {
$process_button_string = zen_draw_hidden_field('cc_number', zen_output_string_protected($_POST[$this->code . '_cc_number']));
$process_button_string .= zen_draw_hidden_field('cc_expires_month', (int) $_POST[$this->code . '_cc_expires_month']);
$process_button_string .= zen_draw_hidden_field('cc_expires_year', (int) $_POST[$this->code . '_cc_expires_year']);
$process_button_string .= zen_draw_hidden_field('cc_cvv', zen_output_string_protected($_POST[$this->code . '_cc_cvv']));
return $process_button_string;
}
function before_process() {
global $db, $messageStack, $order, $currencies;
// Calculate the next expected order id
$result = $db->Execute("select max(orders_id)+1 as orders_id from " . TABLE_ORDERS . " order by orders_id");
$next_order_id = $result->fields['orders_id'];
// add randomized suffix to order id to produce uniqueness ... since it's unwise to submit the same order-number twice to the gateway, and this order is not yet committed
$next_order_id = (string) $next_order_id . '-' . zen_create_random_value(6, 'chars');
//$customer_ip = $_SERVER["REMOTE_ADDR"];
$xml = '<?xml version="1.0" encoding="utf-8"?>
<Request type="AuthorizeCapture">
<AccountID>' . MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ACC_ID . '</AccountID>
<AccountAuth>' . MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_AUTH_CODE . '</AccountAuth>
<Transaction>
<Reference>' . $next_order_id . '</Reference>
<Amount>' . number_format($order->info['total'], 2) . '</Amount>
<Currency>' . strtoupper($order->info['currency']) . '</Currency>
<Email>' . $order->customer['email_address'] . '</Email>
<IPAddress>' . '175.45.134.67' . '</IPAddress>
<Phone>' . $order->customer['telephone'] . '</Phone>
<FirstName>' . $order->billing['firstname'] . '</FirstName>
<LastName>' . $order->billing['lastname'] . '</LastName>
<Address>' . $order->billing['street_address'] . '</Address>
<City>' . $order->billing['city'] . '</City>
<State>' . $order->billing['state'] . '</State>
<PostCode>' . $order->billing['postcode'] . '</PostCode>
<Country>' . $order->billing['country']['iso_code_2'] . '</Country>
<CardNumber>' . $_POST['cc_number'] . '</CardNumber>
<CardExpMonth>' . $_POST['cc_expires_month'] . '</CardExpMonth>
<CardExpYear>' . $_POST['cc_expires_year'] . '</CardExpYear>
<CardCVV>' . $_POST['cc_cvv'] . '</CardCVV>
</Transaction>
</Request>';
$this->logTransactionData($xml);
$result = $this->send_request(MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_GATEWAY_URL, $xml);
$this->logTransactionData($result);
$response = $this->get_responsestatus($result);
// log the response data
$this->logTransactionData($response);
if ($response === FALSE) {
$messageStack->add_session('checkout_payment', MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ERROR_DECLINED, 'error');
zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, '', 'SSL', true, false));
} else {
if ($response['responsecode'] == '100' || $response['responsecode'] == '110') {
$this->transaction_id = $response['txid'];
$this->transaction_messages = $response['msg'];
return true;
} elseif ($response['responsecode'] == '116' && MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ENABLE_3DS == 'Yes') {
$ACSURL = $response['ACSURL'];
$PaReq = $response['PaReq'];
$MD = $response['MD'];
$html = '<html><head><title>Three DS Verification</title></head><body>';
$html.= '<form action='.$ACSURL.' method="post" id="threeds_direct">'
. '<input type="hidden" name="PaReq" value='.$PaReq.'>'
. '<input type="hidden" name="MD" value='.$MD.'>'
. '<input type="hidden" name="TermUrl" value="http://magento1.chetu.local/index.php?main_page=checkout_payment/">'
. '</form>';
$html.= '<div style="text-align:center;">You will be redirected for 3DS verification. Please do not refresh page!!!<br/><br/>
<img title="Loading next step..." alt="Loading next step..." ></div>';
$html.= '<script type="text/javascript">document.getElementById("threeds_direct").submit();</script></body></html>';
echo $html;
//zen_redirect(zen_href_link($response['ACSURL'], '', 'SSL', true, false));
} else {
$messageStack->add_session('checkout_payment', MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ERROR_PAYMNET_GATEWAY, 'error');
zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, '', 'SSL', true, false));
}
}
}
/**
* Post-process activities. Updates the order-status history data with the auth code from the transaction.
*
* @return boolean
*/
function after_process() {
global $insert_id, $db, $order;
$sql = "insert into " . TABLE_ORDERS_STATUS_HISTORY . " (comments, orders_id, orders_status_id, customer_notified, date_added) values (:orderComments, :orderID, :orderStatus, 1, now() )";
$sql = $db->bindVars($sql, ':orderComments', 'Credit Card payment. TransID: ' . $this->transaction_id . ' - ' . $this->transaction_messages, 'string');
$sql = $db->bindVars($sql, ':orderID', $insert_id, 'integer');
$sql = $db->bindVars($sql, ':orderStatus', $this->order_status, 'integer');
$db->Execute($sql);
return false;
}
function check() {
global $db;
if (!isset($this->_check)) {
$check_query = $db->Execute("select configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_STATUS'");
$this->_check = $check_query->RecordCount();
}
return $this->_check;
}
function install() {
global $db;
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable IPSP Billing DirectAPI Module', 'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_STATUS', 'True', 'Check true to enable this payment method.', '6', '0', 'zen_cfg_select_option(array(\'True\', \'False\'), ', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort order of display.', 'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_SORT_ORDER', '0', 'Sort order of displaying payment options to the customer. Lowest is displayed first.', '6', '0', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Order Status', 'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ORDER_STATUS_ID', '2', 'Set the status of orders made with this payment module to this value', '6', '0', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Account ID', 'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ACC_ID', 'xxxxxxxx', 'This is your 8 digit account ID.', '6', '0', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Authentication Code', 'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_AUTH_CODE', 'xxxxxxxxxxxxxxxx', 'This is your 16 character authentication code.', '6', '0', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Payment gateway URL', 'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_GATEWAY_URL', '', 'The payment gateway URL.', '6', '0', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Notification URL', 'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_NOTIFICATION_URL', '', 'Notification URL for payment status.', '6', '0', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable 3DS', 'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ENABLE_3DS', 'No', 'For 3DS only', '6', '0', 'zen_cfg_select_option(array(\'Yes\', \'No\'), ', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Term URL', 'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_TERM_URL', '', 'For 3DS only.', '6', '0', now())");
$db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable log', 'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_LOGGING', 'True', 'Check true to enable log.', '6', '0', 'zen_cfg_select_option(array(\'True\', \'False\'), ', now())");
}
function remove() {
global $db;
$db->Execute("delete from " . TABLE_CONFIGURATION . " where configuration_key in ('" . implode("', '", $this->keys()) . "')");
}
function keys() {
return array(
'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_STATUS',
'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_SORT_ORDER',
'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ORDER_STATUS_ID',
'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ACC_ID',
'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_AUTH_CODE',
'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_GATEWAY_URL',
'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_NOTIFICATION_URL',
'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_ENABLE_3DS',
'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_TERM_URL',
'MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_LOGGING',
);
}
private function send_request($url, $xml) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type: text/xml"));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
private function get_responsestatus($result) {
$xmlresult = simplexml_load_string($result);
// Simple display of the end result
if (isset($xmlresult->ResponseCode)) {
$status['responsecode'] = $xmlresult->ResponseCode;
}
if (isset($xmlresult->Description)) {
$status['msg'] = $xmlresult->Description;
}
if (isset($xmlresult->Reference)) {
$status['reference'] = $xmlresult->Reference;
}
if (isset($xmlresult->TransactionID)) {
$status['txid'] = $xmlresult->TransactionID;
}
if (isset($xmlresult->ProcessingTime)) {
$status['processingtime'] = $xmlresult->ProcessingTime;
}
if (isset($xmlresult->StatusCode)) {
$status['statuscode'] = $xmlresult->StatusCode;
}
if (isset($xmlresult->StatusDescription)) {
$status['statusdescription'] = $xmlresult->StatusDescription;
}
if (isset($xmlresult->ThreeDS->ACSURL)) {
$status['ACSURL'] = $xmlresult->ThreeDS->ACSURL;
}
if (isset($xmlresult->ThreeDS->PaReq)) {
$status['PaReq'] = $xmlresult->ThreeDS->PaReq;
}
if (isset($xmlresult->ThreeDS->MD)) {
$status['MD'] = $xmlresult->ThreeDS->MD;
}
if (isset($xmlresult->RefTrxID)) {
$status['RefTrxID'] = $xmlresult->RefTrxID;
}
if (isset($status['responsecode'])) {
return $status;
} else {
return FALSE;
}
}
/**
* Log transaction errors if enabled
*/
private function logTransactionData($response) {
global $db;
$logMessage = date('M-d-Y h:i:s') .
"\n=================================\n\n" .
'' . $response . "\n";
if (strstr(MODULE_PAYMENT_IPSP_BILLING_DIRECTAPI_LOGGING, 'True')) {
$todayDate = date('Y-m-d');
$file = $this->_logDir . '/' . 'IPSP_Billing_' . $todayDate . '.log';
if ($fp = @fopen($file, 'a')) {
fwrite($fp, $logMessage);
fclose($fp);
}
}
}
}