| 1 |
<?php
|
| 2 |
// $Id: uc_protx_vsp_direct.module,v 1.1.2.10 2009/05/11 14:05:55 longwave Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Protx VSP Direct payment gateway module for Ubercart.
|
| 7 |
*
|
| 8 |
* Developed by solarian (http://drupal.org/user/166738).
|
| 9 |
* Incorporating suggestions from hanoii (http://drupal.org/user/23157).
|
| 10 |
* Implementing v2.23 of the VSP Direct Protocol.
|
| 11 |
* http://www.sagepay.com/documents/sagepayDirectProtocolandIntegrationGuideline.pdf
|
| 12 |
*
|
| 13 |
* Note: Originally the Protx interface was called the "Verified Payment System"
|
| 14 |
* and was referred to by the acronym "VPS", but now it's called "Veri-Secure Payment"
|
| 15 |
* and therefore has a different acronym, "VSP".
|
| 16 |
* Data fields and URLs, however, still partly use the "VPS" acronym.
|
| 17 |
*
|
| 18 |
* This software is licenced under the GPLv2.
|
| 19 |
*
|
| 20 |
*/
|
| 21 |
|
| 22 |
define('UC_PROTX_VSP_DIRECT_PROTOCOL_VERSION', '2.23');
|
| 23 |
|
| 24 |
function _uc_protx_vsp_direct_comments_to_protx($order_id) {
|
| 25 |
$comments = uc_order_comments_load($order_id, TRUE);
|
| 26 |
|
| 27 |
if (is_array($comments)) {
|
| 28 |
foreach ( $comments as $comment ) {
|
| 29 |
$subpatterns = array();
|
| 30 |
preg_match('/VendorTxCode: (.*)/', $comment->message, $subpatterns);
|
| 31 |
if ( $subpatterns[1] ) {
|
| 32 |
$protx['vendortxcode'] = $subpatterns[1];
|
| 33 |
}
|
| 34 |
$subpatterns = array();
|
| 35 |
preg_match('/VPSTxId: (.*)/', $comment->message, $subpatterns);
|
| 36 |
if ( $subpatterns[1] ) {
|
| 37 |
$protx['vpstxid'] = $subpatterns[1];
|
| 38 |
}
|
| 39 |
|
| 40 |
$subpatterns = array();
|
| 41 |
preg_match('/SecurityKey: (.*)/', $comment->message, $subpatterns);
|
| 42 |
if ( $subpatterns[1] ) {
|
| 43 |
$protx['securitykey'] = $subpatterns[1];
|
| 44 |
}
|
| 45 |
|
| 46 |
$subpatterns = array();
|
| 47 |
$str = t('Transaction authenticated');
|
| 48 |
preg_match("/$str/", $comment->message, $subpatterns);
|
| 49 |
if ( $subpatterns[0] ) {
|
| 50 |
$protx['authenticated'] = TRUE;
|
| 51 |
}
|
| 52 |
|
| 53 |
$subpatterns = array();
|
| 54 |
$str = t('Transaction authorized');
|
| 55 |
preg_match("/$str/", $comment->message, $subpatterns);
|
| 56 |
if ( $subpatterns[0] ) {
|
| 57 |
$protx['authorized'] = TRUE;
|
| 58 |
}
|
| 59 |
}
|
| 60 |
}
|
| 61 |
|
| 62 |
//print_r($protx);
|
| 63 |
return $protx;
|
| 64 |
}
|
| 65 |
|
| 66 |
/*******************************************************************************
|
| 67 |
* Hook Functions (Drupal)
|
| 68 |
******************************************************************************/
|
| 69 |
|
| 70 |
/**
|
| 71 |
* Implementation of hook_menu().
|
| 72 |
*/
|
| 73 |
function uc_protx_vsp_direct_menu($may_cache) {
|
| 74 |
$items = array();
|
| 75 |
|
| 76 |
// add css
|
| 77 |
if (!$may_cache) {
|
| 78 |
drupal_add_css(drupal_get_path('module', 'uc_protx_vsp_direct') .'/uc_protx_vsp_direct.css', 'module', 'all', FALSE);
|
| 79 |
}
|
| 80 |
|
| 81 |
if ($may_cache) {
|
| 82 |
$items[] = array(
|
| 83 |
'path' => 'uc_protx_vsp_direct/3DSecure',
|
| 84 |
'callback' => 'uc_protx_vsp_direct_3DSecure',
|
| 85 |
'access' => TRUE,
|
| 86 |
'type' => MENU_CALLBACK,
|
| 87 |
);
|
| 88 |
$items[] = array(
|
| 89 |
'path' => 'uc_protx_vsp_direct/3DSecure_callback',
|
| 90 |
'callback' => 'uc_protx_vsp_direct_3DSecure_callback',
|
| 91 |
'access' => TRUE,
|
| 92 |
'type' => MENU_CALLBACK,
|
| 93 |
);
|
| 94 |
$items[] = array(
|
| 95 |
'path' => 'uc_protx_vsp_direct/3DSecure_waitingPage',
|
| 96 |
'callback' => 'uc_protx_vsp_direct_3DSecure_waitingPage',
|
| 97 |
'access' => TRUE,
|
| 98 |
'type' => MENU_CALLBACK,
|
| 99 |
);
|
| 100 |
$items[] = array(
|
| 101 |
'path' => 'uc_protx_vsp_direct/3DSecure_complete',
|
| 102 |
'callback' => 'uc_protx_vsp_direct_3DSecure_complete',
|
| 103 |
'access' => TRUE,
|
| 104 |
'type' => MENU_CALLBACK,
|
| 105 |
);
|
| 106 |
}
|
| 107 |
else {
|
| 108 |
if (is_numeric(arg(3))) {
|
| 109 |
$items[] = array(
|
| 110 |
'path' => 'admin/store/orders/'. arg(3) .'/uc_protx_vsp_direct_auth',
|
| 111 |
'title' => t('Protx authorization terminal: Order @order_id', array('@order_id' => arg(3))),
|
| 112 |
'description' => t('Authorize apayment for order @order_id.', array('@order_id' => arg(3))),
|
| 113 |
'callback' => 'uc_protx_vsp_direct_auth_page',
|
| 114 |
'callback arguments' => array(arg(3)),
|
| 115 |
'access' => user_access('authorize credit cards'),
|
| 116 |
'type' => MENU_CALLBACK
|
| 117 |
);
|
| 118 |
}
|
| 119 |
}
|
| 120 |
|
| 121 |
return $items;
|
| 122 |
}
|
| 123 |
|
| 124 |
|
| 125 |
/**
|
| 126 |
* Implementation of hook_form_alter().
|
| 127 |
*/
|
| 128 |
function uc_protx_vsp_direct_form_alter($form_id, &$form) { // This just adds the Protx logo.
|
| 129 |
if ($form_id == 'uc_payment_gateways_form' && isset($form['uc_pg_protx_vsp_direct']['uc_pg_protx_vsp_direct_enabled']['#title'])) {
|
| 130 |
$form['uc_pg_protx_vsp_direct']['uc_pg_protx_vsp_direct_enabled']['#title'] .= '<img src="'. base_path() . drupal_get_path('module', 'uc_protx_vsp_direct') .'/img/protxtrans150_75.gif" alt="" id="uc_protx_vsp_direct_protx" />';
|
| 131 |
}
|
| 132 |
}
|
| 133 |
|
| 134 |
/*******************************************************************************
|
| 135 |
* Hook Functions (Ubercart)
|
| 136 |
******************************************************************************/
|
| 137 |
|
| 138 |
function uc_protx_vsp_direct_payment_gateway() {
|
| 139 |
|
| 140 |
$gateways[] = array(
|
| 141 |
'id' => 'protx_vsp_direct',
|
| 142 |
'title' => t('Protx VSP Direct'),
|
| 143 |
'description' => t('Process credit card payments using Protx VSP Direct.'),
|
| 144 |
'settings' => 'uc_protx_vsp_direct_settings_form',
|
| 145 |
'credit' => 'uc_protx_vsp_direct_charge',
|
| 146 |
);
|
| 147 |
|
| 148 |
return $gateways;
|
| 149 |
}
|
| 150 |
|
| 151 |
/**
|
| 152 |
* Implementation of hook_store_status().
|
| 153 |
*/
|
| 154 |
function uc_protx_vsp_direct_store_status() {
|
| 155 |
// Throw up an error row if encryption has not been setup yet.
|
| 156 |
$vendor = variable_get('uc_protx_vsp_direct_vendor', '');
|
| 157 |
if ($vendor) {
|
| 158 |
$statuses[] = array(
|
| 159 |
'status' => 'ok',
|
| 160 |
'title' => t('Protx Vendor mame'),
|
| 161 |
'desc' => t('You have properly set a vendor name for protx: %vendor.', array('%vendor' => $vendor)),
|
| 162 |
);
|
| 163 |
}
|
| 164 |
else {
|
| 165 |
$statuses[] = array(
|
| 166 |
'status' => 'error',
|
| 167 |
'title' => t('Protx Vendor mame'),
|
| 168 |
'desc' => t('Protx VSP Direct module has not been configured yet. Please configure its settings from the !settings, under the Protx VPS Direct collapsed box.', array('!settings' => l(t('Payment gateways section of Ubercart'), 'admin/store/settings/payment/edit/gateways'))),
|
| 169 |
);
|
| 170 |
}
|
| 171 |
|
| 172 |
$server = variable_get('uc_protx_vsp_direct_server', 2);
|
| 173 |
if ($server < 2) {
|
| 174 |
$statuses[] = array(
|
| 175 |
'status' => 'warning',
|
| 176 |
'title' => t('Protx Server'),
|
| 177 |
'desc' => t('Protx VSP Direct is not configured to use the Live server. No real transaction will be processed. You can change it in the !settings, under the Protx VPS Direct collapsed box. (Currently set to %server)', array('!settings' => l(t('Payment gateways section of Ubercart'), 'admin/store/settings/payment/edit/gateways'), '%server' => $server == 1 ? t('Test server') : t('VSP Simulator'))),
|
| 178 |
);
|
| 179 |
}
|
| 180 |
else {
|
| 181 |
$statuses[] = array(
|
| 182 |
'status' => 'ok',
|
| 183 |
'title' => t('Protx Server'),
|
| 184 |
'desc' => t('Protx VSP Direct is configured to use the Live server. Transactions will be processed normally.'),
|
| 185 |
);
|
| 186 |
}
|
| 187 |
|
| 188 |
return $statuses;
|
| 189 |
}
|
| 190 |
|
| 191 |
/*******************************************************************************
|
| 192 |
* Callback Functions, Forms, and Tables
|
| 193 |
******************************************************************************/
|
| 194 |
|
| 195 |
/**
|
| 196 |
* Callback for payment gateway settings.
|
| 197 |
*/
|
| 198 |
function uc_protx_vsp_direct_settings_form() {
|
| 199 |
|
| 200 |
if (!extension_loaded('curl')) {
|
| 201 |
drupal_set_message(t('The Protx VSP Direct payment gateway requires the cURL PHP extension to be loaded.'), 'error');
|
| 202 |
}
|
| 203 |
|
| 204 |
if (variable_get('uc_credit_validate_numbers', FALSE)) {
|
| 205 |
drupal_set_message(t('Message from Protx_VSP_Direct module: Credit card number validation is broken in Ubercart 1.0. You are advised to turn it off in "Payment Methods->Credit card settings"'), 'error');
|
| 206 |
}
|
| 207 |
|
| 208 |
$form['uc_protx_vsp_direct_vendor'] = array(
|
| 209 |
'#type' => 'textfield',
|
| 210 |
'#title' => t('Vendor Login Name'),
|
| 211 |
'#default_value' => variable_get('uc_protx_vsp_direct_vendor', ''),
|
| 212 |
'#description' => t(''),
|
| 213 |
'#size' => 15,
|
| 214 |
'#maxlength' => 15,
|
| 215 |
);
|
| 216 |
|
| 217 |
$form['uc_protx_vsp_direct_server'] = array(
|
| 218 |
'#type' => 'radios',
|
| 219 |
'#title' => t('Protx Server'),
|
| 220 |
'#options' => array(t('VSP Simulator'), t('Test Server'), t('Live System')),
|
| 221 |
'#default_value' => variable_get('uc_protx_vsp_direct_server', 2),
|
| 222 |
'#description' => t(''),
|
| 223 |
);
|
| 224 |
|
| 225 |
$options = array();
|
| 226 |
$options['PAYMENT'] = t('PAYMENT');
|
| 227 |
$options['AUTHENTICATE'] = t('AUTHENTICATE');
|
| 228 |
$form['uc_protx_vsp_direct_transaction'] = array(
|
| 229 |
'#type' => 'radios',
|
| 230 |
'#title' => t('Transaction type'),
|
| 231 |
'#options' => $options,
|
| 232 |
'#default_value' => variable_get('uc_protx_vsp_direct_transaction', 'PAYMENT'),
|
| 233 |
'#description' => t('Select what type of transaction type should be used when sending the payment to the protx server. So far just PAYMENT and AUTHENTICATE are supported and DEFERRED is currently missing. In case of choosing AUTHENTICATE, authorization of the card should be done manually using the protx server.'),
|
| 234 |
);
|
| 235 |
|
| 236 |
$form['uc_protx_vsp_direct_iframe'] = array(
|
| 237 |
'#type' => 'checkbox',
|
| 238 |
'#title' => t('Use inline frames for 3D-Secure'),
|
| 239 |
'#default_value' => variable_get('uc_protx_vsp_direct_iframe', 1),
|
| 240 |
'#description' => t("<strong>For 3D-Secure transactions only.</strong> Using an inline frame allows the transaction to appear as if it's all taking place at this store, but it's not W3C standards compliant if you're using the normal (for Drupal) XHTML Strict Document Type Declaration. However, this is not really a problem in practice, or you can change your theme's DTD (e.g., to a Frameset DTD) if you prefer. If this setting is turned off, it will be obvious to the user that he is being redirected to a different server to complete the transaction, rather like Protx VSP Form."),
|
| 241 |
);
|
| 242 |
|
| 243 |
$form['uc_protx_vsp_direct_send_extra'] = array(
|
| 244 |
'#type' => 'checkbox',
|
| 245 |
'#title' => t('Send additional transaction data'),
|
| 246 |
'#default_value' => variable_get('uc_protx_vsp_direct_send_extra', 0),
|
| 247 |
'#description' => t('Protx offer to store extra info such as the customer’s personal info and delivery address, the contents of their order and their IP address. Some of this information is used for fraud screening purposes.'),
|
| 248 |
);
|
| 249 |
|
| 250 |
$form['uc_protx_vsp_direct_info_cards'] = array(
|
| 251 |
'#type' => 'markup',
|
| 252 |
'#value' => theme('uc_protx_vsp_direct_cards'),
|
| 253 |
);
|
| 254 |
|
| 255 |
$form['#validate'] = array('uc_protx_vsp_direct_settings_validate' => Array());
|
| 256 |
return $form;
|
| 257 |
}
|
| 258 |
|
| 259 |
|
| 260 |
function uc_protx_vsp_direct_settings_validate($form_values) {
|
| 261 |
$field = 'uc_protx_vsp_direct_vendor';
|
| 262 |
$vendor = strlen($form_values[$field]['#post'][$field]);
|
| 263 |
if ($vendor==0 || $vendor>15) {
|
| 264 |
form_set_error($field, t('Please enter a valid Vendor Login Name.'));
|
| 265 |
}
|
| 266 |
}
|
| 267 |
|
| 268 |
|
| 269 |
/*******************************************************************************
|
| 270 |
* Module and Helper Functions
|
| 271 |
******************************************************************************/
|
| 272 |
function uc_protx_vsp_direct_charge($order_id, $amount, $data) {
|
| 273 |
|
| 274 |
if (!extension_loaded('curl')) {
|
| 275 |
drupal_set_message(t('The Protx VSP Direct payment gateway requires the cURL PHP extension to be loaded.'), 'error');
|
| 276 |
}
|
| 277 |
|
| 278 |
global $user;
|
| 279 |
$order = uc_order_load($order_id);
|
| 280 |
$result = array(
|
| 281 |
'success' => FALSE,
|
| 282 |
'comment' => '', // For uc_payment_receipts if success == TRUE
|
| 283 |
'message' => '', // For watchdog() if success == FALSE; sent to drupal_set_message() if not default payment gateway
|
| 284 |
'uid' => $user->uid,
|
| 285 |
);
|
| 286 |
$data['Vendor'] = variable_get('uc_protx_vsp_direct_vendor', '');
|
| 287 |
if ($data['Vendor']=='' || strlen($data['Vendor'])>15) {
|
| 288 |
$result['message'] = t('Invalid Vendor Login Name. Authorization Request could not be sent.');
|
| 289 |
return $result;
|
| 290 |
}
|
| 291 |
|
| 292 |
// ----------------------------------------
|
| 293 |
// Set HTTPS URL
|
| 294 |
$url = uc_protx_vsp_direct_url('registration', variable_get('uc_protx_vsp_direct_server', 2));
|
| 295 |
// ----------------------------------------
|
| 296 |
|
| 297 |
// ----------------------------------------
|
| 298 |
// Validate Card Type data from select list.
|
| 299 |
// 'VISA', 'MC', 'DELTA', 'SOLO', 'MAESTRO', 'UKE', 'AMEX', 'DC' or 'JCB'
|
| 300 |
$searches = array(
|
| 301 |
'`.*?delta.*`i' => 'DELTA',// Visa Delta needs to take precedence in this list over ordinary Visa
|
| 302 |
'`.*?electron.*`i' => 'UKE', // Visa Electron needs to take precedence in this list over ordinary Visa
|
| 303 |
'`.*?visa.*`i' => 'VISA',
|
| 304 |
'`.*?master[ ]*card.*`i' => 'MC',
|
| 305 |
'`.*?solo.*`i' => 'SOLO',
|
| 306 |
'`.*?(maestro|switch).*`i' => 'MAESTRO',
|
| 307 |
'`.*?(amex|american[ ]*express).*`i' => 'AMEX',
|
| 308 |
'`.*?diner.*`i' => 'DC',
|
| 309 |
'`.*?jcb.*`i' => 'JCB',
|
| 310 |
);
|
| 311 |
|
| 312 |
$data['CardType'] = '';
|
| 313 |
foreach ($searches as $pattern => $replace) {
|
| 314 |
if (preg_match($pattern, $order->payment_details['cc_type'])) {
|
| 315 |
$data['CardType'] = $replace;
|
| 316 |
break;
|
| 317 |
}
|
| 318 |
}
|
| 319 |
if ($data['CardType'] == '') {
|
| 320 |
$result['message'] = t('Cannot find card type "%CardType".', array('%CardType' => $order->payment_details['cc_type']));
|
| 321 |
return $result;
|
| 322 |
}
|
| 323 |
// ----------------------------------------
|
| 324 |
|
| 325 |
|
| 326 |
// ----------------------------------------
|
| 327 |
// Build the basic set of data for this transaction.
|
| 328 |
$max = 0;
|
| 329 |
foreach ($order->products as $product) { // The 100-character description perhaps ought to consist of the most expensive item.
|
| 330 |
if ( ($product->price * $product->qty) > $max ) {
|
| 331 |
$data['description'] = $product->title;
|
| 332 |
}
|
| 333 |
$max = max($max, $product->price);
|
| 334 |
}
|
| 335 |
if (count($order->products)>1) {
|
| 336 |
$appendix .= ' [etc.] - '. count($order->products) .' products';
|
| 337 |
}
|
| 338 |
$data['description'] = substr($data['description'], 0, 100-strlen($appendix)) . $appendix;
|
| 339 |
|
| 340 |
// We must do a basic sanity check on the card number because Credit Card module might not do any at all (as of Ubercart RC5).
|
| 341 |
if (!ctype_digit($order->payment_details['cc_number'])) {
|
| 342 |
$result['message'] = t('Invalid card number.');
|
| 343 |
return $result;
|
| 344 |
}
|
| 345 |
|
| 346 |
$delivery_country = uc_get_country_data(array('country_id' => $order->delivery_country));
|
| 347 |
$billing_country = uc_get_country_data(array('country_id' => $order->billing_country));
|
| 348 |
|
| 349 |
$transaction = array(
|
| 350 |
'VPSProtocol' => UC_PROTX_VSP_DIRECT_PROTOCOL_VERSION,
|
| 351 |
'TxType' => variable_get('uc_protx_vsp_direct_transaction', 'PAYMENT'),
|
| 352 |
'Vendor' => $data['Vendor'],
|
| 353 |
'VendorTxCode' => md5( time() . $user->uid . $order->order_id . rand() ), // This must be unique to the vendor.
|
| 354 |
'Amount' => sprintf('%01.2f', $amount),
|
| 355 |
'Currency' => variable_get('uc_currency_code', 'GBP'), // This is a UK-based payment gateway, hence GBP default.
|
| 356 |
'Description' => $data['description'],
|
| 357 |
'CardHolder' => substr($order->payment_details['cc_owner'], 0, 50),
|
| 358 |
'CardNumber' => $order->payment_details['cc_number'],
|
| 359 |
'ExpiryDate' => sprintf('%02d', $order->payment_details['cc_exp_month']) . substr($order->payment_details['cc_exp_year'], -2),
|
| 360 |
'CV2' => $order->payment_details['cc_cvv'],
|
| 361 |
'CardType' => $data['CardType'],
|
| 362 |
'BillingSurname' => substr($order->billing_last_name, 0, 20),
|
| 363 |
'BillingFirstnames' => substr($order->billing_first_name, 0, 20),
|
| 364 |
'BillingAddress1' => substr($order->billing_street1, 0, 100),
|
| 365 |
'BillingAddress2' => substr($order->billing_street2, 0, 100),
|
| 366 |
'BillingCity' => substr($order->billing_city, 0, 40),
|
| 367 |
'BillingPostCode' => substr($order->billing_postal_code, 0, 10),
|
| 368 |
'BillingCountry' => $billing_country[0]['country_iso_code_2'],
|
| 369 |
'BillingPhone' => substr($order->billing_phone, 0, 20),
|
| 370 |
'DeliverySurname' => substr($order->delivery_last_name, 0, 20),
|
| 371 |
'DeliveryFirstnames' => substr($order->delivery_first_name, 0, 20),
|
| 372 |
'DeliveryAddress1' => substr($order->delivery_street1, 0, 100),
|
| 373 |
'DeliveryAddress2' => substr($order->delivery_street2, 0, 100),
|
| 374 |
'DeliveryCity' => substr($order->delivery_city, 0, 40),
|
| 375 |
'DeliveryPostCode' => substr($order->delivery_postal_code, 0, 10),
|
| 376 |
'DeliveryCountry' => $delivery_country[0]['country_iso_code_2'],
|
| 377 |
'DeliveryPhone' => substr($order->delivery_phone, 0, 20),
|
| 378 |
'GiftAidPayment' => '0',
|
| 379 |
'ApplyAVSCV2' => '0',
|
| 380 |
'Apply3DSecure' => '0',
|
| 381 |
'AccountType' => 'E',
|
| 382 |
);
|
| 383 |
// ----------------------------------------
|
| 384 |
|
| 385 |
|
| 386 |
// ----------------------------------------
|
| 387 |
// Extra fields which need to be patched into credit card module -- StartDate, IssueNumber.
|
| 388 |
if (isset($order->payment_details['cc_start_month']) && isset($order->payment_details['cc_start_year'])) {
|
| 389 |
$month = $order->payment_details['cc_start_month'];
|
| 390 |
$year = $order->payment_details['cc_start_year'];
|
| 391 |
if (is_numeric($month) && is_numeric($year) && $month>0 && $month<13 && strlen($year)==4) {
|
| 392 |
$transaction = array_merge($transaction, array( 'StartDate' => sprintf('%02d', $month) . substr($year, -2) ));
|
| 393 |
}
|
| 394 |
}
|
| 395 |
|
| 396 |
if (isset($order->payment_details['cc_issue'])) { // N.B. issue number must be stored as string, since '4' is different from '04'.
|
| 397 |
$issue = $order->payment_details['cc_issue'];
|
| 398 |
if (is_numeric($issue) && (strlen($issue)==1 || strlen($issue)==2)) {
|
| 399 |
$transaction = array_merge($transaction, array( 'IssueNumber' => $order->payment_details['cc_issue'] ));
|
| 400 |
}
|
| 401 |
}
|
| 402 |
// ----------------------------------------
|
| 403 |
|
| 404 |
|
| 405 |
|
| 406 |
// ----------------------------------------
|
| 407 |
// Collect extra information for Protx if this option is checked.
|
| 408 |
if (variable_get('uc_protx_vsp_direct_send_extra', 0)) {
|
| 409 |
|
| 410 |
$data['CustomerName'] = rtrim($order->delivery_first_name .' '. $order->delivery_last_name .', '. $order->delivery_company, ', ');
|
| 411 |
if ($data['CustomerName'] == '') {
|
| 412 |
$data['CustomerName'] = rtrim($order->billing_first_name .' '. $order->billing_last_name .', '. $order->billing_company, ', ');
|
| 413 |
}
|
| 414 |
|
| 415 |
// The Basket field is <=7,500 characters.
|
| 416 |
// The first line is just the total of lines in the basket, followed by a colon.
|
| 417 |
// The final line should be shipping, tax, etc., and any items that can't be included in under 7,500 chars.
|
| 418 |
// The final line has no final colon
|
| 419 |
$basket['strlen'] = 0;
|
| 420 |
$basket['subtotal'] = 0;
|
| 421 |
|
| 422 |
// The number of lines of items, inc. the extra one for shipping, tax and any items that don't fit in under 7,500 chars:
|
| 423 |
$basket['lines'] = count($order->products) + 1;
|
| 424 |
|
| 425 |
foreach ($order->products as $x => $product) {
|
| 426 |
$item_total = $product->price * $product->qty;
|
| 427 |
$basket['amounts'][] = $item_total;
|
| 428 |
$basket['items'][] = str_replace(
|
| 429 |
':', ' - ', $product->title)
|
| 430 |
.':'. $product->qty
|
| 431 |
.':' // Net
|
| 432 |
.':' // Tax
|
| 433 |
.':'. sprintf('%01.2f', $product->price) // Gross
|
| 434 |
.':'. sprintf('%01.2f', $item_total)
|
| 435 |
.':'
|
| 436 |
;
|
| 437 |
$basket['strlen'] += strlen(end($basket['items']));
|
| 438 |
$basket['subtotal'] += $item_total;
|
| 439 |
}
|
| 440 |
|
| 441 |
$basket['finalLine']['amount'] = $amount - $basket['subtotal'];// At this stage this will probably just be tax & shipping.
|
| 442 |
$basket['finalLine']['text'] = '[Other items, shipping and taxes]:::::';
|
| 443 |
|
| 444 |
// The final line has no final colon, but we need one to complete the first line.
|
| 445 |
while ( strlen($basket['lines'] .':') + $basket['strlen'] > (7500 - strlen($basket['finalLine']['text'] . $basket['finalLine']['amount'])) ) {
|
| 446 |
$basket['strlen'] -= strlen(array_pop($basket['items']));
|
| 447 |
$basket['lines']--;
|
| 448 |
$basket['finalLine']['amount'] += array_pop($basket['amounts']);
|
| 449 |
}
|
| 450 |
|
| 451 |
$data['Basket'] = $basket['lines'] .':';
|
| 452 |
foreach ($basket['items'] as $item) {
|
| 453 |
$data['Basket'] .= $item;
|
| 454 |
}
|
| 455 |
$data['Basket'] .= $basket['finalLine']['text'] . $basket['finalLine']['amount'];
|
| 456 |
|
| 457 |
|
| 458 |
if (getenv('HTTP_CLIENT_IP')) {
|
| 459 |
$data['ClientIPAddress'] = getenv('HTTP_CLIENT_IP');
|
| 460 |
}
|
| 461 |
elseif (getenv('HTTP_X_FORWARDED_FOR')) {
|
| 462 |
$data['ClientIPAddress'] = getenv('HTTP_X_FORWARDED_FOR');
|
| 463 |
}
|
| 464 |
elseif (getenv('HTTP_X_FORWARDED')) {
|
| 465 |
$data['ClientIPAddress'] = getenv('HTTP_X_FORWARDED');
|
| 466 |
}
|
| 467 |
elseif (getenv('HTTP_FORWARDED_FOR')) {
|
| 468 |
$data['ClientIPAddress'] = getenv('HTTP_FORWARDED_FOR');
|
| 469 |
}
|
| 470 |
elseif (getenv('HTTP_FORWARDED')) {
|
| 471 |
$data['ClientIPAddress'] = getenv('HTTP_FORWARDED');
|
| 472 |
}
|
| 473 |
else {
|
| 474 |
$data['ClientIPAddress'] = $_SERVER['REMOTE_ADDR'];
|
| 475 |
}
|
| 476 |
|
| 477 |
$transaction = array_merge(
|
| 478 |
$transaction,
|
| 479 |
array(
|
| 480 |
'CustomerName' => $data['CustomerName'],
|
| 481 |
'ContactNumber' => $order->billing_phone,
|
| 482 |
//'ContactFax' => $order->, // This value is not available as of Ubercart RC5.
|
| 483 |
'CustomerEMail' => $order->primary_email,
|
| 484 |
'Basket' => $data['Basket'],
|
| 485 |
'ClientIPAddress' => $data['ClientIPAddress'],
|
| 486 |
)
|
| 487 |
);
|
| 488 |
}
|
| 489 |
// ----------------------------------------
|
| 490 |
|
| 491 |
// ----------------------------------------
|
| 492 |
// Put all this data into an HTTPS POST request
|
| 493 |
$post = '';
|
| 494 |
foreach ($transaction as $name => $value) {
|
| 495 |
//$post .= urlencode(iconv('UTF-8', 'ISO-8859-1', $name)) . '=' . urlencode(iconv('UTF-8', 'ISO-8859-1', $value)) . '&';
|
| 496 |
$post .= urlencode($name) .'='. urlencode($value) .'&';
|
| 497 |
}
|
| 498 |
$post = substr($post, 0, -1);
|
| 499 |
|
| 500 |
list($response, $http_response_code, $curl_error) = uc_protx_vsp_direct_curl($url, $post);
|
| 501 |
|
| 502 |
if ($curl_error!='') {
|
| 503 |
$result['message'] = t('Message from PHP cURL: @curlError', array('@curlError' => $curl_error));
|
| 504 |
return $result;
|
| 505 |
}
|
| 506 |
|
| 507 |
if ($http_response_code!=200) {
|
| 508 |
$result['message'] = t('The request met with HTTP response code @code', array('@code' => $http_response_code));
|
| 509 |
return $result;
|
| 510 |
}
|
| 511 |
// ----------------------------------------
|
| 512 |
|
| 513 |
// store a comment with some protx useful data of the transaction being saved
|
| 514 |
$comment = t(
|
| 515 |
'Transaction sent.<br />VendorTxCode: @VendorTxCode',
|
| 516 |
array(
|
| 517 |
'@VendorTxCode' => $transaction['VendorTxCode'],
|
| 518 |
)
|
| 519 |
);
|
| 520 |
uc_order_comment_save($order_id, $user->uid, $comment);
|
| 521 |
|
| 522 |
// ----------------------------------------
|
| 523 |
// Now make sense of the response.
|
| 524 |
|
| 525 |
if ($response['Status']=='3DAUTH') {
|
| 526 |
$_SESSION['3dsecure']['ACSURL'] = $response['ACSURL'];
|
| 527 |
$_SESSION['3dsecure']['MD'] = $response['MD'];
|
| 528 |
$_SESSION['3dsecure']['PAReq'] = $response['PAReq'];
|
| 529 |
drupal_goto('uc_protx_vsp_direct/3DSecure');
|
| 530 |
}
|
| 531 |
else {
|
| 532 |
uc_protx_vsp_direct_response($response, $result);
|
| 533 |
}
|
| 534 |
|
| 535 |
if ($result['success'] == TRUE) {
|
| 536 |
uc_order_comment_save($order_id, $user->uid, $result['comment']);
|
| 537 |
}
|
| 538 |
|
| 539 |
return $result;
|
| 540 |
}
|
| 541 |
|
| 542 |
function uc_protx_vsp_direct_3DSecure() {
|
| 543 |
|
| 544 |
if (empty($_SESSION['3dsecure']) || !isset($_SESSION['cart_order'])) {
|
| 545 |
drupal_set_message(t('Credit card 3D-Secure authorization could not be completed.'), 'error');
|
| 546 |
drupal_goto('cart/checkout');
|
| 547 |
}
|
| 548 |
|
| 549 |
$term_url = url('uc_protx_vsp_direct/3DSecure_callback', NULL, NULL, TRUE);
|
| 550 |
|
| 551 |
// Note the different case of "PaReq" here in the HTML element name:
|
| 552 |
if (variable_get('uc_protx_vsp_direct_iframe', 1)) {
|
| 553 |
drupal_add_js("window.onload = function() { document.forms['uc_protx_vsp_direct_3dsecure'].submit(); }", 'inline');
|
| 554 |
$output =
|
| 555 |
'<form name="uc_protx_vsp_direct_3dsecure" method="post" action="'. $_SESSION['3dsecure']['ACSURL'] .'" target="Secure3D">
|
| 556 |
<p>
|
| 557 |
<input type="hidden" name="MD" value="'. $_SESSION['3dsecure']['MD'] .'" />
|
| 558 |
<input type="hidden" name="PaReq" value="'. $_SESSION['3dsecure']['PAReq'] .'" />
|
| 559 |
<input type="hidden" name="TermUrl" value="'. $term_url .'" />
|
| 560 |
</p>
|
| 561 |
<noscript>
|
| 562 |
<p>
|
| 563 |
<input type="submit" value="Click here to continue" />
|
| 564 |
</p>
|
| 565 |
</noscript>
|
| 566 |
</form>
|
| 567 |
<iframe name="Secure3D" id="Secure3D" src="'. url('uc_protx_vsp_direct/3DSecure_waitingPage') .'">
|
| 568 |
</iframe>'
|
| 569 |
;
|
| 570 |
return $output;
|
| 571 |
}
|
| 572 |
else {
|
| 573 |
$output =
|
| 574 |
'<?xml version="1.0" encoding="utf-8"?>
|
| 575 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
| 576 |
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
| 577 |
<head>
|
| 578 |
<title>3D-Secure</title>
|
| 579 |
<script type="text/javascript">window.onload = function() { document.forms[0].submit(); }</script>
|
| 580 |
</head>
|
| 581 |
<body>
|
| 582 |
<form method="post" action="'. $_SESSION['3dsecure']['ACSURL'] .'">
|
| 583 |
<p>
|
| 584 |
<input type="hidden" name="MD" value="'. $_SESSION['3dsecure']['MD'] .'" />
|
| 585 |
<input type="hidden" name="PaReq" value="'. $_SESSION['3dsecure']['PAReq'] .'" />
|
| 586 |
<input type="hidden" name="TermUrl" value="'. $term_url .'" />
|
| 587 |
</p>
|
| 588 |
<noscript>
|
| 589 |
<p>
|
| 590 |
<input type="submit" value="Click here to continue" />
|
| 591 |
</p>
|
| 592 |
</noscript>
|
| 593 |
</form>
|
| 594 |
</body>
|
| 595 |
</html>'
|
| 596 |
;
|
| 597 |
echo $output;
|
| 598 |
exit;
|
| 599 |
}
|
| 600 |
}
|
| 601 |
|
| 602 |
function uc_protx_vsp_direct_3DSecure_callback() {
|
| 603 |
|
| 604 |
// Note the different case of "PaReq" in the $_POST version:
|
| 605 |
if (!isset($_POST['MD']) || !isset($_POST['PaRes']) || !isset($_SESSION['3dsecure']['MD'])
|
| 606 |
|| !isset($_SESSION['cart_order']) || $_POST['MD'] != $_SESSION['3dsecure']['MD']) {
|
| 607 |
drupal_set_message(t('Credit card 3D-Secure authorization could not be completed.'), 'error');
|
| 608 |
drupal_goto('cart/checkout');
|
| 609 |
}
|
| 610 |
|
| 611 |
$order = uc_order_load($_SESSION['cart_order']);
|
| 612 |
if ($order === FALSE) {
|
| 613 |
drupal_goto('cart/checkout');
|
| 614 |
}
|
| 615 |
$amount = $order->amount;
|
| 616 |
|
| 617 |
$url = uc_protx_vsp_direct_url('3d-secure', variable_get('uc_protx_vsp_direct_server', 2));
|
| 618 |
$post = 'MD='. $_POST['MD'] .'&PARes='. $_POST['PaRes'];
|
| 619 |
list($response, $http_response_code, $curl_error) = uc_protx_vsp_direct_curl($url, $post);
|
| 620 |
|
| 621 |
if ($curl_error!='') {
|
| 622 |
watchdog('uc_protx_vsp_direct', t('Payment failed: Message from PHP cURL: @curlError', array('@curlError' => $curl_error)), WATCHDOG_ERROR);
|
| 623 |
drupal_set_message(t('Credit card 3D-Secure authorization could not be completed.'), 'error');
|
| 624 |
drupal_goto('cart/checkout');
|
| 625 |
}
|
| 626 |
|
| 627 |
if ($http_response_code!=200) {
|
| 628 |
watchdog('uc_protx_vsp_direct', t('Payment failed: The 3D-Secure callback request met with HTTP response code @code', array('@code' => $http_response_code)), WATCHDOG_WARNING);
|
| 629 |
return;
|
| 630 |
}
|
| 631 |
|
| 632 |
$result['success'] = FALSE;
|
| 633 |
uc_protx_vsp_direct_response($response, $result);
|
| 634 |
|
| 635 |
unset($_SESSION['3dsecure']);
|
| 636 |
|
| 637 |
if ($result['success'] == TRUE) {
|
| 638 |
uc_payment_enter($order->order_id, 'credit', $order->order_total, $order->uid, '', $result['comment']);
|
| 639 |
uc_order_comment_save($order->order_id, $order->uid, $result['comment']);
|
| 640 |
$_SESSION['do_complete'] = TRUE;
|
| 641 |
$redirect = 'cart/checkout/complete';
|
| 642 |
}
|
| 643 |
else {
|
| 644 |
watchdog('uc_protx_vsp_direct', t('Payment failed: @message', array('@message' => $result['message'])), WATCHDOG_WARNING);
|
| 645 |
drupal_set_message(variable_get('uc_credit_fail_message', t('We were unable to process your credit card payment. Please verify your card details and try again. If the problem persists, contact us to complete your order.')), 'error');
|
| 646 |
$redirect = 'cart/checkout';
|
| 647 |
}
|
| 648 |
|
| 649 |
if (variable_get('uc_protx_vsp_direct_iframe', 1)) {
|
| 650 |
$output =
|
| 651 |
'<html><head><title></title></head><body onload="document.forms[0].submit();"><form name="uc_protx_vsp_direct_3dsecure" method="post" action="'. url($redirect) .'" target="_top"></body></html>
|
| 652 |
<noscript>
|
| 653 |
<input type="submit" value="Please click here to continue." />
|
| 654 |
</noscript>
|
| 655 |
</form>'
|
| 656 |
;
|
| 657 |
echo $output;
|
| 658 |
exit;
|
| 659 |
}
|
| 660 |
else {
|
| 661 |
drupal_goto($redirect);
|
| 662 |
}
|
| 663 |
}
|
| 664 |
|
| 665 |
function uc_protx_vsp_direct_curl($url, $post) {
|
| 666 |
$ch = curl_init($url);
|
| 667 |
curl_setopt_array(
|
| 668 |
$ch,
|
| 669 |
array(
|
| 670 |
CURLOPT_HEADER => FALSE,
|
| 671 |
// If Protx are sending a redirect this should really be handled manually
|
| 672 |
CURLOPT_FOLLOWLOCATION => FALSE,
|
| 673 |
CURLOPT_FRESH_CONNECT => TRUE,
|
| 674 |
CURLOPT_POST => TRUE,
|
| 675 |
CURLOPT_RETURNTRANSFER => TRUE,
|
| 676 |
CURLOPT_SSL_VERIFYPEER => FALSE,
|
| 677 |
CURLOPT_TRANSFERTEXT => TRUE,
|
| 678 |
CURLOPT_VERBOSE => FALSE,
|
| 679 |
CURLOPT_CONNECTTIMEOUT => 60,
|
| 680 |
CURLOPT_SSL_VERIFYHOST => 2,
|
| 681 |
CURLOPT_POSTFIELDS => $post,
|
| 682 |
)
|
| 683 |
);
|
| 684 |
|
| 685 |
$raw_response = curl_exec($ch);
|
| 686 |
$http_response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
| 687 |
$curl_error = curl_error($ch);
|
| 688 |
|
| 689 |
$response_strings = explode("\r\n", $raw_response);
|
| 690 |
|
| 691 |
foreach ($response_strings as $str) {
|
| 692 |
list($name, $value) = explode('=', $str, 2); // This strange limit method is required because sometimes the '=' character is also part of the data.
|
| 693 |
if ($name!='') $response[$name] = $value;
|
| 694 |
}
|
| 695 |
|
| 696 |
curl_close($ch);
|
| 697 |
return array($response, $http_response_code, $curl_error);
|
| 698 |
}
|
| 699 |
|
| 700 |
function uc_protx_vsp_direct_url($method, $server) {
|
| 701 |
|
| 702 |
$servers = array(
|
| 703 |
// Ordinary method, or for first stage of 3D-Secure method
|
| 704 |
'registration' => array(
|
| 705 |
0 => 'https://test.sagepay.com/Simulator/VSPDirectGateway.asp',
|
| 706 |
1 => 'https://test.sagepay.com/gateway/service/vspdirect-register.vsp',
|
| 707 |
2 => 'https://live.sagepay.com/gateway/service/vspdirect-register.vsp',
|
| 708 |
),
|
| 709 |
'authorize' => array(
|
| 710 |
0 => 'https://test.sagepay.com/Simulator/VSPServerGateway.asp?Service=VendorAuthoriseTx',
|
| 711 |
1 => 'https://test.sagepay.com/gateway/service/authorise.vsp',
|
| 712 |
2 => 'https://live.sagepay.com/gateway/service/authorise.vsp',
|
| 713 |
),
|
| 714 |
// 3D-Secure method, used only when $response['Status']=='3DAUTH'
|
| 715 |
'3d-secure' => array(
|
| 716 |
0 => 'https://test.sagepay.com/Simulator/VSPDirectCallback.asp',
|
| 717 |
1 => 'https://test.sagepay.com/gateway/service/direct3dcallback.vsp',
|
| 718 |
2 => 'https://live.sagepay.com/gateway/service/direct3dcallback.vsp',
|
| 719 |
),
|
| 720 |
);
|
| 721 |
|
| 722 |
return $servers[$method][$server];
|
| 723 |
}
|
| 724 |
|
| 725 |
function uc_protx_vsp_direct_3DSecure_waitingPage() {
|
| 726 |
echo '<html><head><title></title></head><body><p style="font-family: Verdana; color: #AAA; font-weight: bold">Please wait to be redirected to your card issuer for authorization...</p></body></html>';
|
| 727 |
}
|
| 728 |
|
| 729 |
function uc_protx_vsp_direct_response($response, &$result) {
|
| 730 |
|
| 731 |
switch ($response['Status']) {
|
| 732 |
|
| 733 |
case 'AUTHENTICATED':
|
| 734 |
case 'OK':
|
| 735 |
if ( $response['Status'] == 'AUTHENTICATED' ) {
|
| 736 |
$str = t('Transaction authenticated');
|
| 737 |
}
|
| 738 |
else {
|
| 739 |
$str = t('Transaction authorized');
|
| 740 |
}
|
| 741 |
$result['message'] = '';
|
| 742 |
$result['comment'] = t(
|
| 743 |
'@response_str.
|
| 744 |
<br />VPSTxId: @VPSTxId
|
| 745 |
<br />SecurityKey: @SecurityKey
|
| 746 |
<br />TxAuthNo: @TxAuthNo
|
| 747 |
<br />AVSCV2: @AVSCV2
|
| 748 |
<br /><em>(AddressResult: @AddressResult | PostCodeResult: @PostCodeResult | CV2Result: @CV2Result)</em>
|
| 749 |
<br />3D-Secure Status: @3DSecureStatus',
|
| 750 |
array(
|
| 751 |
'@VPSTxId' => $response['VPSTxId'],
|
| 752 |
'@SecurityKey' => $response['SecurityKey'],
|
| 753 |
'@TxAuthNo' => $response['TxAuthNo'],
|
| 754 |
'@AVSCV2' => $response['AVSCV2'],
|
| 755 |
'@AddressResult' => $response['AddressResult'],
|
| 756 |
'@PostCodeResult' => $response['PostCodeResult'],
|
| 757 |
'@CV2Result' => $response['CV2Result'],
|
| 758 |
'@3DSecureStatus' => $response['3DSecureStatus'],
|
| 759 |
'@response_str' => $str,
|
| 760 |
)
|
| 761 |
);
|
| 762 |
|
| 763 |
if ($response['3DSecureStatus']=='OK') {
|
| 764 |
$result['comment'] .= t('<br />CAVV: @CAVV', array('@CAVV' => $response['CAVV']));
|
| 765 |
}
|
| 766 |
|
| 767 |
$result['success'] = TRUE;
|
| 768 |
break;
|
| 769 |
|
| 770 |
case 'NOTAUTHED':
|
| 771 |
$result['message'] = t('The transaction was not authorised by the acquiring bank.');
|
| 772 |
break;
|
| 773 |
|
| 774 |
case 'REJECTED':
|
| 775 |
$result['message'] = t('The VSP System rejected the transaction because of the rules you have set on your Protx account. The message was: %StatusDetail', array('%StatusDetail' => $response['StatusDetail']));
|
| 776 |
break;
|
| 777 |
|
| 778 |
case 'INVALID':
|
| 779 |
case 'MALFORMED':
|
| 780 |
case 'ERROR':
|
| 781 |
$result['message'] = $response['StatusDetail'];
|
| 782 |
break;
|
| 783 |
|
| 784 |
case 'REGISTERED':
|
| 785 |
default:
|
| 786 |
// This should never happen.
|
| 787 |
$result['message'] = t('Protx responded with a status code that indicates acceptance of the request, but which is not implemented by this module: @code @StatusDetail', array('@code' => $response['Status'], '@StatusDetail' => $response['StatusDetail']));
|
| 788 |
break;
|
| 789 |
}
|
| 790 |
|
| 791 |
}
|
| 792 |
|
| 793 |
/**
|
| 794 |
* Implementation of hook_order_pane().
|
| 795 |
*/
|
| 796 |
function uc_protx_vsp_direct_order_pane() {
|
| 797 |
$panes[] = array(
|
| 798 |
'id' => 'uc_protx_vsp_direct',
|
| 799 |
'callback' => 'uc_protx_vsp_direct_order_pane_callback',
|
| 800 |
'title' => t('Protx'),
|
| 801 |
'desc' => t('Display protx authorization button.'),
|
| 802 |
'class' => 'pos-left',
|
| 803 |
'weight' => 5,
|
| 804 |
'show' => array('view'), //'edit', 'customer', 'invoice', 'customer'),
|
| 805 |
);
|
| 806 |
|
| 807 |
return $panes;
|
| 808 |
}
|
| 809 |
|
| 810 |
/**
|
| 811 |
* Handle the Payment order pane.
|
| 812 |
*/
|
| 813 |
function uc_protx_vsp_direct_order_pane_callback($op, $arg1) {
|
| 814 |
switch ($op) {
|
| 815 |
case 'view':
|
| 816 |
$order = $arg1;
|
| 817 |
$protx = _uc_protx_vsp_direct_comments_to_protx($order->order_id);
|
| 818 |
if ( $protx['authenticated'] && !$protx['authorized'] ) {
|
| 819 |
$output = drupal_get_form('uc_protx_vsp_direct_order_pane_view_form', $order);
|
| 820 |
}
|
| 821 |
return $output;
|
| 822 |
}
|
| 823 |
}
|
| 824 |
|
| 825 |
function uc_protx_vsp_direct_order_pane_view_form($order) {
|
| 826 |
$form['order_id'] = array(
|
| 827 |
'#type' => 'hidden',
|
| 828 |
'#value' => $order->order_id,
|
| 829 |
);
|
| 830 |
|
| 831 |
$form['submit'] = array(
|
| 832 |
'#type' => 'submit',
|
| 833 |
'#value' => t('Authorize card'),
|
| 834 |
);
|
| 835 |
|
| 836 |
return $form;
|
| 837 |
}
|
| 838 |
|
| 839 |
function uc_protx_vsp_direct_order_pane_view_form_submit($form_id, $form_values) {
|
| 840 |
return 'admin/store/orders/'. $form_values['order_id'] .'/uc_protx_vsp_direct_auth';
|
| 841 |
}
|
| 842 |
|
| 843 |
function uc_protx_vsp_direct_perm() {
|
| 844 |
return array(
|
| 845 |
'authorize credit cards',
|
| 846 |
);
|
| 847 |
}
|
| 848 |
|
| 849 |
function uc_protx_vsp_direct_auth_page($order_id) {
|
| 850 |
$comments = uc_order_comments_load($order_id, TRUE);
|
| 851 |
$output .= tapir_get_table('op_admin_comments_view_table', $comments);
|
| 852 |
$output .= drupal_get_form('uc_protx_vsp_direct_auth_form', $order_id);
|
| 853 |
|
| 854 |
return $output;
|
| 855 |
}
|
| 856 |
|
| 857 |
function uc_protx_vsp_direct_auth_form($order_id) {
|
| 858 |
$form['order_id'] = array(
|
| 859 |
'#type' => 'value',
|
| 860 |
'#value' => $order_id,
|
| 861 |
);
|
| 862 |
|
| 863 |
$form['submit'] = array(
|
| 864 |
'#type' => 'submit',
|
| 865 |
'#value' => t('Authorize card'),
|
| 866 |
);
|
| 867 |
|
| 868 |
return $form;
|
| 869 |
}
|
| 870 |
|
| 871 |
function uc_protx_vsp_direct_auth_form_submit($form_id, $form_values) {
|
| 872 |
global $user;
|
| 873 |
|
| 874 |
$order_id = $form_values['order_id'];
|
| 875 |
$order = uc_order_load($order_id);
|
| 876 |
$protx = _uc_protx_vsp_direct_comments_to_protx($order_id);
|
| 877 |
|
| 878 |
$transaction = array(
|
| 879 |
'VPSProtocol' => UC_PROTX_VSP_DIRECT_PROTOCOL_VERSION,
|
| 880 |
'TxType' => 'AUTHORISE',
|
| 881 |
'Vendor' => variable_get('uc_protx_vsp_direct_vendor', ''),
|
| 882 |
'VendorTxCode' => md5( time() . $user->uid . $order->order_id . rand() ), // This must be unique to the vendor.
|
| 883 |
'Amount' => sprintf('%01.2f', $order->order_total),
|
| 884 |
'Currency' => variable_get('uc_currency_code', 'GBP'), // This is a UK-based payment gateway, hence GBP default.
|
| 885 |
'Description' => t('Authorizing order @orderid.', array('@orderid' => $order_id)),
|
| 886 |
// VPSTxId of the authenticate transaction against which the authorisation is required.
|
| 887 |
'RelatedVPSTxId' => $protx['vpstxid'],
|
| 888 |
// VendorTxCode of the authenticate transaction against which the authorisation is require
|
| 889 |
'RelatedVendorTxCode' => $protx['vendortxcode'],
|
| 890 |
// The SecurityKey of the authenticate transaction sent back by the VSP System when the transaction was registered.
|
| 891 |
'RelatedSecurityKey' => $protx['securitykey'],
|
| 892 |
// (optional) Using this flag you can fine tune the AVS/CV2 checks and rule set you’ve defined at a transaction level. This is useful in circumstances where direct and trusted customer contact has been established and you wish to override the default security checks.
|
| 893 |
'ApplyAVSCV2' => '0',
|
| 894 |
);
|
| 895 |
|
| 896 |
// Put all this data into an HTTPS POST request
|
| 897 |
$post = '';
|
| 898 |
foreach ($transaction as $name => $value) {
|
| 899 |
//$post .= urlencode(iconv('UTF-8', 'ISO-8859-1', $name)) . '=' . urlencode(iconv('UTF-8', 'ISO-8859-1', $value)) . '&';
|
| 900 |
$post .= urlencode($name) .'='. urlencode($value) .'&';
|
| 901 |
}
|
| 902 |
$post = substr($post, 0, -1);
|
| 903 |
|
| 904 |
$url = uc_protx_vsp_direct_url('authorize', variable_get('uc_protx_vsp_direct_server', 2));
|
| 905 |
list($response, $http_response_code, $curl_error) = uc_protx_vsp_direct_curl($url, $post);
|
| 906 |
|
| 907 |
if ($curl_error!='') {
|
| 908 |
watchdog('uc_protx_vsp_direct', t('Message from PHP cURL: @curlError', array('@curlError' => $curl_error)), WATCHDOG_ERROR);
|
| 909 |
drupal_set_message(t('Credit card authorization could not be completed.'), 'error');
|
| 910 |
return 'admin/store/orders/'. $order_id .'/uc_protx_vsp_direct_auth';
|
| 911 |
}
|
| 912 |
|
| 913 |
if ($http_response_code!=200) {
|
| 914 |
watchdog('uc_protx_vsp_direct', t('The request met with HTTP response code @code', array('@code' => $http_response_code)), WATCHDOG_ERROR);
|
| 915 |
drupal_set_message(t('Credit card authorization could not be completed.'), 'error');
|
| 916 |
return 'admin/store/orders/'. $order_id .'/uc_protx_vsp_direct_auth';
|
| 917 |
}
|
| 918 |
|
| 919 |
uc_protx_vsp_direct_response($response, $result);
|
| 920 |
|
| 921 |
if ( $result['success'] ) {
|
| 922 |
drupal_set_message(t('The transaction was succesfully authorised by the acquiring bank.'));
|
| 923 |
uc_order_comment_save($order_id, $user->uid, $result['message']);
|
| 924 |
}
|
| 925 |
else {
|
| 926 |
drupal_set_message($result['message'], 'error');
|
| 927 |
}
|
| 928 |
|
| 929 |
return 'admin/store/orders/'. $order_id .'/uc_protx_vsp_direct_auth';
|
| 930 |
}
|
| 931 |
|
| 932 |
/**
|
| 933 |
* Outputs the cards used in the configuration fieldset
|
| 934 |
* @return <string>
|
| 935 |
*/
|
| 936 |
function theme_uc_protx_vsp_direct_cards() {
|
| 937 |
$img_path = base_path() . drupal_get_path('module', 'uc_protx_vsp_direct') .'/img';
|
| 938 |
$img_path_cards = base_path() . drupal_get_path('module', 'uc_protx_vsp_direct') .'/img/protx_cards';
|
| 939 |
|
| 940 |
$output = <<<CARDS
|
| 941 |
<div class="uc_protx_vsp_direct_cards">
|
| 942 |
<img src="$img_path_cards/mastercard normal.gif" alt="Mastercard" />
|
| 943 |
<img src="$img_path_cards/visa.gif" alt="Visa" />
|
| 944 |
<img src="$img_path_cards/delta.gif" alt="Visa Debit" />
|
| 945 |
<img src="$img_path_cards/electron.gif" alt="Electron" />
|
| 946 |
<img src="$img_path_cards/amexsmall.gif" alt="American Express" />
|
| 947 |
</div>
|
| 948 |
<div class="uc_protx_vsp_direct_cards">
|
| 949 |
<img src="$img_path_cards/maestro.gif" alt="Maestro" />
|
| 950 |
<img src="$img_path_cards/solo.gif" alt="Solo" />
|
| 951 |
<img src="$img_path_cards/dinersclublogo125_26.gif" alt="Diners" />
|
| 952 |
<img src="$img_path_cards/jcb.gif" alt="JCB" />
|
| 953 |
</div>
|
| 954 |
<div class="uc_protx_vsp_direct_cards">
|
| 955 |
<p>This gateway supports 3D-Secure:</p>
|
| 956 |
<img src="$img_path/vbv_logo24.gif" alt="Verified by Visa" />
|
| 957 |
<img src="$img_path/msc_logo24.gif" alt="Mastercard SecureCode" />
|
| 958 |
</div>
|
| 959 |
CARDS;
|
| 960 |
|
| 961 |
return $output;
|
| 962 |
}
|