function commerce_sagepay_server_handle_callback in Drupal Commerce SagePay Integration 7
Process the callback that is sent by SagePay Server.
Parameters
string $order_id: The order id.
string $key: The security key.
1 string reference to 'commerce_sagepay_server_handle_callback'
- commerce_sagepay_menu in ./
commerce_sagepay.module - Implements hook_menu().
File
- includes/
commerce_sagepay_server.inc, line 234
Code
function commerce_sagepay_server_handle_callback($order_id, $key, $debug_vps = array()) {
$notification = array();
$order = commerce_order_load($order_id);
$payment_key = $order->data['payment_redirect_key'];
// Check key against supplied value.
if (!$payment_key === $key) {
$notification['status'] = 'INVALID';
$notification['message'] = t('Payment Redirect key did not match.');
}
// The function gives us the ability to load in a fake POST dataset for
// testing purposes. If this is not present, use the $_POST values.
if (empty($debug_vps)) {
$vps_data = $_POST;
}
if (empty($vps_data)) {
$notification['status'] = 'ERROR';
$notification['message'] = t('No Payload returned in the notification POST.');
watchdog('commerce_sagepay', 'VPS Callback URL accessed with no POST data
submitted.', array(), WATCHDOG_WARNING);
}
if (empty($notification)) {
// Load transactions with a matching order id, remote transaction id
// and the status "Started".
// We need to load the original transaction to identify the charge total.
$conditions = array(
'order_id' => $order_id,
'remote_id' => $vps_data['VPSTxId'],
'remote_status' => 'STARTED',
);
$transactions = commerce_payment_transaction_load_multiple(array(), $conditions);
// We expect a transaction to be found, so fail if there isn't one.
if (empty($transactions)) {
$notification['status'] = 'INVALID';
$notification['message'] = t('No matching transaction found');
watchdog('commerce_sagepay', 'No Matching transaction found in Sage
Pay Server VPS Callback for order %order_id', array(
'%order_id' => $order_id,
), WATCHDOG_ERROR);
}
// We expect only ONE transaction to be found, so fail if there are more.
if (count($transactions) > 1) {
$notification['status'] = 'INVALID';
$notification['message'] = t('Multiple matching transaction found');
watchdog('commerce_sagepay', 'Multiple matching transaction found in
Sage Pay Server VPS Callback for order %order_id', array(
'%order_id' => $order_id,
), WATCHDOG_ERROR);
}
// Verify the transaction.
$transaction_values = array_values($transactions);
$transaction = $transaction_values[0];
// Check we have the correct transaction.
$payment_method = $transaction->payment_method;
if ($transaction->payload['VendorTxCode'] == $vps_data["VendorTxCode"]) {
// Get the total and currency from the original transaction.
$charge = array(
'amount' => $transaction->amount,
'currency_code' => $transaction->currency_code,
);
// get the vendor ID
$vendor_name = variable_get(SAGEPAY_SETTING_VENDOR_NAME);
if (isset($order->data['sagepay_overrides']['Vendor'])) {
$vendor_name = $order->data['sagepay_overrides']['Vendor'];
}
// Vendor name always needs to be lowercase.
$vendor_name = drupal_strtolower($vendor_name);
// Check for tampering.
$md5_check = array();
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["VPSTxId"]) ? $_REQUEST["VPSTxId"] : '', "Text");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["VendorTxCode"]) ? $_REQUEST["VendorTxCode"] : '', "VendorTxCode");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["Status"]) ? $_REQUEST["Status"] : '', "Text");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["TxAuthNo"]) ? $_REQUEST["TxAuthNo"] : '', "Number");
$md5_check[] = $vendor_name;
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["AVSCV2"]) ? $_REQUEST["AVSCV2"] : '', "Text");
$md5_check[] = $transaction->payload['SecurityKey'];
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["AddressResult"]) ? $_REQUEST["AddressResult"] : '', "Text");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["PostCodeResult"]) ? $_REQUEST["PostCodeResult"] : '', "Text");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["CV2Result"]) ? $_REQUEST["CV2Result"] : '', "Text");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["GiftAid"]) ? $_REQUEST["GiftAid"] : '', "Number");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["3DSecureStatus"]) ? $_REQUEST["3DSecureStatus"] : '', "Text");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["CAVV"]) ? $_REQUEST["CAVV"] : '', "Text");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["AddressStatus"]) ? $_REQUEST["AddressStatus"] : '', "Text");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["PayerStatus"]) ? $_REQUEST['PayerStatus'] : '', "Text");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["CardType"]) ? $_REQUEST["CardType"] : '', "Text");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["Last4Digits"]) ? $_REQUEST["Last4Digits"] : '', "Text");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["DeclineCode"]) ? $_REQUEST["DeclineCode"] : '', "Text");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["ExpiryDate"]) ? $_REQUEST["ExpiryDate"] : '', "Text");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["FraudResponse"]) ? $_REQUEST["FraudResponse"] : '', "Text");
$md5_check[] = _commerce_sagepay_clean_input(isset($_REQUEST["BankAuthCode"]) ? $_REQUEST["BankAuthCode"] : '', "Text");
$str_vpssignature = _commerce_sagepay_clean_input(check_plain($_REQUEST["VPSSignature"]), "Text");
$str_message = implode('', $md5_check);
$str_mysignature = strtoupper(md5($str_message));
if ($str_mysignature == $str_vpssignature) {
$transaction->payload['vps_status'] = $vps_data['Status'];
switch ($vps_data['Status']) {
case 'OK':
watchdog('commerce_sagepay', 'OK Payment callback received from
SagePay for order %order_id with status code %status', array(
'%order_id' => $order_id,
'%status' => $transaction->payload['Status'],
));
commerce_sagepay_transaction($payment_method, $order, $charge, $vps_data, COMMERCE_PAYMENT_STATUS_SUCCESS, $vps_data['TxType'], $transaction);
$notification['status'] = 'OK';
$notification['message'] = t('Transaction notification received.');
break;
case 'NOTAUTHED':
watchdog('commerce_sagepay', 'NOTAUTHED error from SagePay for order %order_id with message %msg', array(
'%order_id' => $order_id,
'%msg' => $transaction->payload['StatusDetail'],
), WATCHDOG_ALERT);
commerce_sagepay_transaction($payment_method, $order, $charge, $vps_data, COMMERCE_PAYMENT_STATUS_FAILURE, SAGEPAY_REMOTE_STATUS_FAIL, $transaction);
$notification['status'] = 'OK';
$notification['message'] = $transaction->payload['StatusDetail'];
$notification['cancel'] = TRUE;
break;
case 'REJECTED':
watchdog('commerce_sagepay', 'REJECTED error from SagePay for order %order_id with message %msg', array(
'%order_id' => $order_id,
'%msg' => $transaction->payload['StatusDetail'],
), WATCHDOG_ALERT);
commerce_sagepay_transaction($payment_method, $order, $charge, $vps_data, COMMERCE_PAYMENT_STATUS_FAILURE, SAGEPAY_REMOTE_STATUS_FAIL, $transaction);
$notification['status'] = 'OK';
$notification['message'] = $transaction->payload['StatusDetail'];
$notification['cancel'] = TRUE;
break;
case 'ABORT':
watchdog('commerce_sagepay', 'ABORT error from SagePay for order %order_id with message %msg', array(
'%order_id' => $order_id,
'%msg' => $transaction->payload['StatusDetail'],
), WATCHDOG_ALERT);
commerce_sagepay_transaction($payment_method, $order, $charge, $vps_data, COMMERCE_PAYMENT_STATUS_FAILURE, SAGEPAY_REMOTE_STATUS_FAIL, $transaction);
$notification['status'] = 'OK';
$notification['message'] = $transaction->payload['StatusDetail'];
$notification['cancel'] = TRUE;
break;
case 'FAIL':
watchdog('commerce_sagepay', 'FAIL error from SagePay for order %order_id with message %msg', array(
'%order_id' => $order_id,
'%msg' => $transaction->payload['StatusDetail'],
), WATCHDOG_ERROR);
commerce_sagepay_transaction($payment_method, $order, $charge, $vps_data, COMMERCE_PAYMENT_STATUS_FAILURE, SAGEPAY_REMOTE_STATUS_FAIL, $transaction);
$notification['status'] = 'OK';
$notification['message'] = $transaction->payload['StatusDetail'];
$notification['cancel'] = TRUE;
break;
default:
watchdog('commerce_sagepay', 'Unknown error from SagePay for order
%order_id with message %msg', array(
'%order_id' => $order_id,
'%msg' => $transaction->payload['StatusDetail'],
), WATCHDOG_ERROR);
commerce_sagepay_transaction($payment_method, $order, $charge, $vps_data, COMMERCE_PAYMENT_STATUS_FAILURE, SAGEPAY_REMOTE_STATUS_FAIL, $transaction);
$notification['status'] = 'OK';
$notification['message'] = 'Unexpected Status code received: ' . $vps_data['Status'];
$notification['cancel'] = TRUE;
}
}
else {
$payload = $transaction->payload;
$payload['vps_status'] = 'TAMPER';
commerce_sagepay_transaction($payment_method, $order, array(), $payload, COMMERCE_PAYMENT_STATUS_FAILURE, SAGEPAY_REMOTE_STATUS_FAIL, $transaction);
$notification['status'] = 'INVALID';
$notification['message'] = t('MD5 did not match - signs of tampering
.');
}
}
else {
$payload = $transaction->payload;
$payload['vps_status'] = 'TAMPER';
commerce_sagepay_transaction($payment_method, $order, array(), $payload, COMMERCE_PAYMENT_STATUS_FAILURE, SAGEPAY_REMOTE_STATUS_FAIL, $transaction);
$notification['status'] = 'INVALID';
$notification['message'] = t('Vendor TX code did not match - signs of
tampering
.');
}
}
// Send response back to SagePay to indicate we have received and processed.
$eoln = chr(13) . chr(10);
if (array_key_exists('cancel', $notification)) {
$notification['redirect'] = url('checkout/' . $order_id . '/payment/back/' . $payment_key, array(
'absolute' => TRUE,
));
}
else {
$notification['redirect'] = url('checkout/' . $order_id . '/payment/return/' . $payment_key, array(
'absolute' => TRUE,
));
}
$return_notification = 'Status=' . $notification['status'] . $eoln . 'RedirectURL=' . $notification['redirect'] . $eoln . 'StatusDetail=' . $notification['message'] . $eoln;
echo $return_notification;
exit;
}