'Payment received', 'page callback' => 'uc_cybersource_hop_post', 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); // Callback functions for Website Payments Standard. $items['cybersource/hop-complete/%uc_order'] = array( 'title' => 'CyberSource payment complete', 'page callback' => 'uc_cybersource_hop_complete', 'page arguments' => array(2), 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); $items['admin/store/orders/%uc_order/cs_tax'] = array( 'title' => 'Order Taxes', 'page callback' => 'uc_cybersource_tax_test', 'page arguments' => array(3), 'access arguments' => array('administer store'), 'type' => MENU_CALLBACK, ); return $items; } /** * Implements hook_page_alter(). */ function uc_cybersource_page_alter(&$page) { $block = block_load('system', 'main'); // Add to the review page hidden form fields with data to post to // CyberSource HOP. if (isset($page[$block->region]['system_main']['#theme']) && $page[$block->region]['system_main']['#theme'] == 'uc_cart_checkout_review' && ($order_id = intval($_SESSION['cart_order'])) > 0) { $order = uc_order_load($order_id); if ($order->payment_method == 'cybersource_hop') { $page[$block->region]['system_main']['#form'] = drupal_get_form('uc_cybersource_hop_form', $order); } } } /** * Implements hook_form_FORM_ID_alter() for uc_payment_method_settings_form(). */ function uc_cybersource_form_uc_payment_method_settings_form_alter(&$form, &$form_state) { if ($form_state['build_info']['args'][0] == 'credit') { $form['#submit'][] = 'uc_cybersource_payment_gateway_settings_submit'; } } /** * Submit handler for payment gateway settings form to encrypt fields. */ function uc_cybersource_payment_gateway_settings_submit($form, &$form_state) { // If CC encryption has been configured properly. if ($key = uc_credit_encryption_key()) { // Setup our encryption object. $crypt = new UbercartEncryption(); // Encrypt the Merchant ID and Transaction key. if (!empty($form_state['values']['uc_cybersource_soap_merchant_id'])) { variable_set('uc_cybersource_soap_merchant_id', $crypt->encrypt($key, $form_state['values']['uc_cybersource_soap_merchant_id'])); } if (!empty($form_state['values']['uc_cybersource_soap_transaction_key'])) { variable_set('uc_cybersource_soap_transaction_key', $crypt->encrypt($key, $form_state['values']['uc_cybersource_soap_transaction_key'])); } // Store any errors. uc_store_encryption_errors($crypt, 'uc_cybersource'); } } /******************************************************************************* * Hook Functions (Ubercart) ******************************************************************************/ /** * Implements hook_uc_payment_gateway(). */ function uc_cybersource_uc_payment_gateway() { // CyberSource APIs other than HOP require uc_credit to be enabled. if (!module_exists('uc_credit')) { return; } $gateways['cybersource'] = array( 'title' => t('CyberSource Silent Order POST'), 'description' => t('Process credit card payments using the Silent Order POST service of CyberSource.'), 'settings' => 'uc_cybersource_settings_form', 'credit' => 'uc_cybersource_charge', 'credit_txn_types' => array(UC_CREDIT_AUTH_ONLY, UC_CREDIT_PRIOR_AUTH_CAPTURE, UC_CREDIT_AUTH_CAPTURE, UC_CREDIT_REFERENCE_TXN), ); return $gateways; } /** * Processes a payment POST from the CyberSource Hosted Order Page API. */ function uc_cybersource_hop_post() { if (!uc_cybersource_hop_include()) { watchdog('uc_cybersource_hop', 'Unable to receive HOP POST due to missing or unreadable HOP.php file.', array(), 'error'); drupal_add_http_header('Status', '503 Service unavailable'); drupal_set_title(t('Unable to receive HOP POST.')); print t('The site was unable to receive a HOP post because of a missing or unreadble HOP.php'); exit(); } $verify = VerifyTransactionSignature($_POST); watchdog('uc_cybersource_hop', 'Receiving payment notification at URL for order @orderNumber', array('@orderNumber' => $_POST['orderNumber'] )); if (!isset($_POST['orderNumber'])) { watchdog('uc_cybersource_hop', 'CS HOP attempted with invalid order number.', array(), WATCHDOG_ERROR); return; } if (!$verify) { watchdog('uc_cybersource_hop', 'Receiving invalid payment notification at URL for order @orderNumber.
@debug
', array('@orderNumber' => $_POST['orderNumber'], '@debug' => print_r($_POST, TRUE) )); return; } // Assign posted variables to local variables. $decision = check_plain($_POST['decision']); $reason_code = check_plain($_POST['reasonCode']); $reason = _parse_cs_reason_code($reason_code); $payment_amount = check_plain($_POST['orderAmount']); $payment_currency = check_plain($_POST['paymentCurrency']); $request_id = check_plain($_POST['requestID']); $request_token = check_plain($_POST['orderPage_requestToken']); $reconciliation_id = check_plain($_POST['reconciliationID']); $order_id = check_plain($_POST['orderNumber']); $payer_email = check_plain($_POST['billTo_email']); $order = uc_order_load($_POST['orderNumber']); switch ($decision) { case 'ACCEPT': watchdog('uc_cybersource_hop', 'CyberSource verified successful payment.'); $duplicate = (bool) db_query_range('SELECT 1 FROM {uc_payment_cybersource_hop_post} WHERE order_id = :order_id AND decision = :decision', 0, 1, array(':order_id' => $order_id, ':decision' => 'ACCEPT'))->fetchField(); if ($duplicate) { watchdog('uc_cybersource_hop', 'CS HOP transaction for order @order-id has been processed before.', array('@order_id' => $order_id), WATCHDOG_NOTICE); return; } db_insert('uc_payment_cybersource_hop_post') ->fields(array( 'order_id' => $order_id, 'request_id' => $request_id, 'request_token' => $request_token, 'reconciliation_id' => $reconciliation_id, 'gross' => $payment_amount, 'decision' => $decision, 'reason_code' => $reason_code, 'payer_email' => $payer_email, 'received' => REQUEST_TIME, )) ->execute(); $comment = t('CyberSource request ID: @txn_id', array('@txn_id' => $request_id)); uc_payment_enter($order_id, 'cybersource_hop', $payment_amount, $order->uid, NULL, $comment); uc_cart_complete_sale($order); uc_order_comment_save($order_id, 0, t('Payment of @amount @currency submitted through CyberSource with request ID @rid.', array('@amount' => $payment_amount, '@currency' => $payment_currency, '@rid' => $request_id)), 'order', 'payment_received'); break; case 'ERROR': uc_order_comment_save($order_id, 0, t("Payment error:@reason with request ID @rid", array('@reason' => $reason, '@rid' => '@request_id')), 'admin'); break; case 'REJECT': uc_order_comment_save($order_id, 0, t("Payment is rejected:@reason with request ID @rid", array('@reason' => $reason, '@rid' => '@request_id')), 'admin'); break; case 'REVIEW': uc_order_update_status($order_id, 'review'); uc_order_comment_save($order_id, 0, t('Payment is in review & not complete: @reason. Request ID @rid', array('@reason' => $reason, '@rid' => '@request_id')), 'admin'); break; } } /** * Checks for HOP.php and includes it or returns FALSE if it cannot be found. */ function uc_cybersource_hop_include() { $hop_paths[0] = 'sites/all/libraries/uc_cybersource/HOP.php'; $hop_paths[1] = drupal_get_path('module', 'uc_cybersource') . '/HOP.php'; // Loop through possible paths, include and return TRUE when HOP.php is // located. foreach ($hop_paths as $key => $path) { if (file_exists($path)) { require_once($path); return TRUE; } } // We didn't find HOP.php in any of the possible paths. return FALSE; } /** * Adds the CyberSource fields to the payment gateway settings form. */ function uc_cybersource_settings_form($form, &$form_state) { // Check for the HOP.php for Silent Order POST. if (variable_get('uc_cybersource_method', 'post') == 'post' && !uc_cybersource_hop_include()) { drupal_set_message(t('You must download the security script from your CyberSource account (found in Tools & Settings > Hosted Order Page > Security) and place it in the ubercart/payment/uc_cybersource directory to use the Silent Order POST. Remember to open it and replace instances of L( with csL(.'), 'error'); } $form['uc_cybersource_server'] = array( '#type' => 'select', '#title' => t('Payment server'), '#description' => t('CyberSource server used when processing payments.'), '#options' => array( 'production' => t('Production'), 'test' => t('Test'), ), '#default_value' => variable_get('uc_cybersource_server', 'test'), ); $form['uc_cybersource_method'] = array( '#type' => 'radios', '#title' => t('Payment method'), '#description' => t('You must ensure your CyberSource account and web server are able to use the service you select.
Silent Order POST requires cURL support and a modified HOP.php.
The SOAP Toolkit API requires the SOAP and DOM extensions for PHP.', array('!url' => url('http://www.ubercart.org/contrib/139', array('absolute' => TRUE)))), '#options' => array( 'post' => t('Silent Order POST'), // 'api' => t('Simple Order API'), 'soap' => t('SOAP Toolkit API'), ), '#default_value' => variable_get('uc_cybersource_method', 'post'), ); $form['uc_cybersource_avs'] = array( '#type' => 'radios', '#title' => t('Ensure address verification'), '#options' => array( 'true' => t('Process transaction only if address passes verification.'), 'false' => t('Process transaction regardless of the result of address verification.'), ), '#default_value' => variable_get('uc_cybersource_avs', 'true'), ); $login = _uc_cybersource_soap_login_data(); $form['soap'] = array( '#type' => 'fieldset', '#title' => t('SOAP Toolkit API settings'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['soap']['uc_cybersource_soap_merchant_id'] = array( '#type' => 'textfield', '#title' => t('Merchant ID'), '#default_value' => $login['merchant_id'], ); $form['soap']['uc_cybersource_soap_transaction_key'] = array( '#type' => 'textarea', '#title' => t('Transaction key'), '#default_value' => $login['transaction_key'], ); $form['soap']['uc_cybersource_soap_create_profile'] = array( '#type' => 'checkbox', '#title' => t('Create a CyberSource Basic Profile for every new credit card order processed.'), '#default_value' => variable_get('uc_cybersource_soap_create_profile', FALSE), ); $form['soap']['uc_cybersource_soap_tax_calculate'] = array( '#type' => 'checkbox', '#title' => t('Enable calculation of taxes through the CyberSource tax service.'), '#default_value' => variable_get('uc_cybersource_soap_tax_calculate', FALSE), ); $form['soap']['ship_from'] = array( '#type' => 'fieldset', '#title' => t('Tax calculation "Ship from" address'), '#description' => t('This address will be used when calculating taxes with CyberSource tax service.'), ); $form['soap']['ship_from']['cs_ship_from_first_name'] = array( '#type' => 'textfield', '#title' => t('First name'), '#default_value' => variable_get('cs_ship_from_first_name', ''), ); $form['soap']['ship_from']['cs_ship_from_last_name'] = array( '#type' => 'textfield', '#title' => t('Last name'), '#default_value' => variable_get('cs_ship_from_last_name', ''), ); $form['soap']['ship_from']['cs_ship_from_street1'] = array( '#type' => 'textfield', '#title' => t('Street address'), '#default_value' => variable_get('cs_ship_from_street1', ''), ); $form['soap']['ship_from']['cs_ship_from_city'] = array( '#type' => 'textfield', '#title' => t('City'), '#default_value' => variable_get('cs_ship_from_city', ''), ); $form['soap']['ship_from']['cs_ship_from_zone'] = array( '#type' => 'textfield', '#title' => t('State/Province'), '#description' => t('Enter the 2 letter abbreviation of your state or province.'), '#default_value' => variable_get('cs_ship_from_zone', ''), '#maxlength' => 2, ); $form['soap']['ship_from']['cs_ship_from_postal_code'] = array( '#type' => 'textfield', '#title' => t('ZIP/Postal code'), '#default_value' => variable_get('cs_ship_from_postal_code', ''), ); $form['soap']['ship_from']['cs_ship_from_country'] = array( '#type' => 'textfield', '#title' => t('Country code'), '#description' => t("Enter the 2 letter ISO 3166-1 code; consult Wikipedia if you don't know yours."), '#default_value' => variable_get('cs_ship_from_country', ''), '#maxlength' => 2, ); $form['soap']['ship_from']['cs_ship_from_email'] = array( '#type' => 'textfield', '#title' => t('E-mail address'), '#default_value' => variable_get('cs_ship_from_email', ''), ); return $form; } /** * Defines payment method properties. * * @return * An array with property and value pairs of CyberSource payment method. */ function uc_cybersource_payment_method() { $methods[] = array( 'id' => 'cybersource_hop', 'name' => t('CyberSource Hosted Order Page'), 'title' => "Credit/Debit card payment processed by CyberSource", 'review' => t('Credit/Debit card payment processed by CyberSource'), 'desc' => t('Payment with CyberSource HOP Service.'), 'callback' => 'uc_payment_method_cybersource_hop', 'weight' => 1, 'checkout' => FALSE, 'no_gateway' => TRUE, ); return $methods; } /** * Payment method callback. */ function uc_payment_method_cybersource_hop($op, &$order) { if ($op == 'settings') { $form['uc_cybersource_hop_server'] = array( '#type' => 'select', '#title' => t('CyberSource HOP server'), '#description' => t('Select between production/live or test mode.'), '#options' => array( 'https://orderpagetest.ic3.com/hop/orderform.jsp' => t('Test Center'), 'https://orderpage.ic3.com/hop/orderform.jsp' => t('Production/Live')), '#default_value' => variable_get('uc_cybersource_hop_server', 'https://orderpagetest.ic3.com/hop/orderform.jsp'), ); $form['uc_cybersource_hop_transaction_type'] = array( '#type' => 'radios', '#title' => t('CyberSource transaction type'), '#description' => t('Authorize and settle, or authorize only for capture on CyberSource.com'), '#options' => array( 'authorization' => t('Authorize only'), 'sale' => t('Authorize and capture'), ), '#default_value' => variable_get('uc_cybersource_hop_transaction_type', 'sale'), ); $form['uc_cybersource_cs_hop_button_text'] = array( '#type' => 'textfield', '#title' => t('CyberSource "Buy button" text'), '#description' => t('This text appears on the button users press to process their payment on the Hosted Order Page.'), '#default_value' => variable_get('uc_cybersource_cs_hop_button_text', t('Process payment')), ); return $form; } } /** * Finalizes CyberSource transaction. */ function uc_cybersource_hop_complete($order) { // If the order ID specified in the return URL is not the same as the one in // the user's session, we need to assume this is either a spoof or that the // user tried to adjust the order on this side while at PayPal. If it was a // legitimate checkout, the CyberSource POST will still register, so the // gets processed correctly. We'll leave an ambiguous message just in case. if (intval($_SESSION['cart_order']) != $order->order_id) { drupal_set_message(t('Thank you for your order! We will be notified by CyberSource that we have received your payment.')); drupal_goto('cart'); } // This lets us know it's a legitimate access of the complete page. $_SESSION['uc_checkout'][$_SESSION['cart_order']]['do_complete'] = TRUE; drupal_goto('cart/checkout/complete'); } /** * Defines values to be posted to CyberSource. * * @return * Transaction data arrays are returned as hidden form values. */ function uc_cybersource_hop_form($form, $form_state, $order) { if (!uc_cybersource_hop_include()) { drupal_set_message(t('Hosted Order Page requires the HOP.php provided by CyberSource.')); // TODO - Does returning false here make sense? return array('success' => FALSE); } $billing_country = uc_get_country_data(array('country_id' => $order->billing_country)); $delivery_country = uc_get_country_data(array('country_id' => $order->delivery_country)); $data = array( 'billTo_firstName' => $order->billing_first_name, 'billTo_lastName' => $order->billing_last_name, 'billTo_street1' => $order->billing_street1, 'billTo_city' => $order->billing_city, 'billTo_country' => $billing_country[0]['country_iso_code_2'], 'billTo_state' => uc_get_zone_code($order->billing_zone), 'billTo_postalCode' => $order->billing_postal_code, 'billTo_email' => $order->primary_email, 'billTo_phoneNumber' => $order->billing_phone, ); if (uc_order_is_shippable($order)) { $data += array( 'shipTo_firstName' => $order->delivery_first_name, 'shipTo_lastName' => $order->delivery_last_name, 'shipTo_street1' => $order->delivery_street1, 'shipTo_street2' => $order->delivery_street2, 'shipTo_city' => $order->delivery_city, 'shipTo_country' => $delivery_country[0]['country_iso_code_2'], 'shipTo_state' => uc_get_zone_code($order->delivery_zone), 'shipTo_postalCode' => $order->delivery_postal_code, ); } $shipping = 0; foreach ($order->line_items as $item) { if ($item['type'] == 'shipping') { $shipping += $item['amount']; } } $tax = 0; if (module_exists('uc_taxes')) { foreach (uc_taxes_calculate($order) as $tax_item) { $tax += $tax_item->amount; } } $amount = $order->order_total - $shipping - $tax; $currency = variable_get('uc_cybersource_hop_currency', 'USD'); $merchantID = getMerchantID(); $timestamp = getmicrotime(); $datax = $merchantID . $amount . $currency . $timestamp; $pub = function_exists('getSharedSecret') ? getSharedSecret() : getPublicKey(); $serialNumber = getSerialNumber(); $pub_digest = hopHash($datax, $pub); $data['amount'] = $amount; $data['currency'] = $currency; $data['merchantID'] = $merchantID; $data['orderNumber'] = $order->order_id; $data['orderPage_timestamp'] = $timestamp; $data['orderPage_ignoreAVS'] = variable_get('uc_cybersource_hop_avs', 'true') == 'true' ? 'false' : 'true'; $data['orderPage_signaturePublic'] = $pub_digest; $data['orderPage_version'] = '4'; $data['orderPage_serialNumber'] = $serialNumber; $data['orderPage_transactionType'] = variable_get('uc_cybersource_hop_transaction_type', 'sale'); $data['orderPage_sendMerchantReceiptEmail'] = variable_get('uc_cybersource_hop_merchant_receipt_email', 'true'); $data['orderPage_sendMerchantURLPost'] = 'true'; // CyberSource posts payment confirmation to this URL. $data['orderPage_merchantURLPostAddress'] = url('cybersource/hop-post', array('absolute' => TRUE)); $data['orderPage_buyButtonText'] = t('Checkout'); $receipt_url = url('cybersource/hop-complete/' . $order->order_id, array('absolute' => TRUE)); $data['orderPage_receiptResponseURL'] = $receipt_url; $data['orderPage_buyButtonText'] = variable_get('uc_cybersource_cs_hop_button_text', t('Process payment')); $comments = t('Order @order-id at @store-name', array('@order-id' => $order->order_id, '@store-name' => uc_store_name())); $alter_data['order'] = $order; $alter_data['comments'] = $comments; $alter_data['merchant_fields'] = array(); // Allow other modules to alter the comment & merchant field data stored // with CyberSource. drupal_alter('uc_cybersource_data', $alter_data); $data['comments'] = $alter_data['comments']; if (!empty($alter_data['merchant_fields'])) { foreach ($alter_data['merchant_fields'] as $key => $value) { $data[$key] = $value; } } foreach ($data as $name => $value) { if (!empty($value)) { $form[$name] = array('#type' => 'hidden', '#value' => $value); } } $form['#action'] = variable_get('uc_cybersource_hop_server', 'https://orderpagetest.ic3.com/hop/orderform.jsp'); $form['submit'] = array( '#type' => 'submit', '#value' => t('Submit order'), ); return $form; } /** * Charges card. */ function uc_cybersource_charge($order_id, $amount, $data) { global $user; $order = uc_order_load($order_id); $amount = uc_currency_format($amount, FALSE, FALSE, '.'); $cc_type = NULL; if (isset($order->payment_details['cc_type'])) { switch (strtolower($order->payment_details['cc_type'])) { case 'amex': case 'american express': $cc_type = '003'; break; case 'visa': $cc_type = '001'; break; case 'mastercard': case 'master card': $cc_type = '002'; break; case 'discover': $cc_type = '004'; break; } } if (is_null($cc_type)) { $cc_type = _uc_cybersource_card_type($order->payment_details['cc_number']); if ($cc_type === FALSE && in_array($data['txn_type'], array(UC_CREDIT_AUTH_ONLY, UC_CREDIT_AUTH_CAPTURE))) { drupal_set_message(t('The credit card type did not pass validation.'), 'error'); watchdog('uc_cybersource', 'Could not figure out cc type: @number / @type', array('@number' => $order->payment_details['cc_number'], '@type' => $order->payment_details['cc_type']), WATCHDOG_ERROR); return array('success' => FALSE); } } $country = uc_get_country_data(array('country_id' => $order->billing_country)); if ($country === FALSE) { $country = array(0 => array('country_iso_code_2' => 'US')); } // Process the charge differently depending on the CyberSource method. switch (variable_get('uc_cybersource_method', 'post')) { // Support for the Silent Order POST. case 'post': return _uc_cybersource_post_charge($order, $amount, $data, $cc_type, $country); // Support for the SOAP Toolkit API. case 'soap': // TODO: Refactor to use separate function for each API type. // - i.e. _uc_cybersource_charge_request_soap($order, $amount, $data); // require_once(drupal_get_path('module', 'uc_cybersource') . '/SOAP.php'); return _uc_cybersource_soap_charge($order, $amount, $data, $cc_type, $country); case 'api': $config = cybs_load_config('cybs.ini'); if (variable_get('uc_cybersource_server', 'test') == 'test') { $config['sendToProduction'] = 'false'; } $request['ccAuthService_run'] = 'true'; if (variable_get('uc_cybersource_hop_transaction_type', 'sale') == 'sale') { $request['ccCaptureService_run'] = 'true'; } $request['merchantReferenceCode'] = $order_id; $request['purchaseTotals_currency'] = 'USD'; $request['purchaseTotals_grandTotalAmount'] = $amount; drupal_set_message('
' . print_r($config, TRUE) . '
'); drupal_set_message('
' . print_r($request, TRUE) . '
'); break; } } /** * POSTs transaction to CyberSource. */ function _uc_cybersource_post_charge($order, $amount, $data, $cc_type, $country) { // Include the HOP.php per the module instructions. if (!uc_cybersource_hop_include()) { drupal_set_message(t('Silent Order POST requires the HOP.php provided by CyberSource.')); return array('success' => FALSE); } $request = array( 'billTo_firstName' => $order->billing_first_name, 'billTo_lastName' => $order->billing_last_name, 'billTo_street1' => $order->billing_street1, 'billTo_city' => $order->billing_city, 'billTo_country' => $country[0]['country_iso_code_2'], 'billTo_state' => uc_get_zone_code($order->billing_zone), 'billTo_postalCode' => $order->billing_postal_code, 'billTo_email' => $order->primary_email, 'card_accountNumber' => $order->payment_details['cc_number'], 'card_cardType' => $cc_type, 'card_expirationMonth' => $order->payment_details['cc_exp_month'], 'card_expirationYear' => $order->payment_details['cc_exp_year'], ); if (variable_get('uc_credit_cvv_enabled', TRUE)) { $request['card_cvNumber'] = $order->payment_details['cc_cvv']; } $currency = variable_get('uc_cybersource_currency', 'usd'); $merchantID = getMerchantID(); $timestamp = getmicrotime(); $data = $merchantID . $amount . $currency . $timestamp; $pub = function_exists('getSharedSecret') ? getSharedSecret() : getPublicKey(); $serialNumber = getSerialNumber(); $pub_digest = hopHash($data, $pub); $request['amount'] = $amount; $request['currency'] = $currency; $request['merchantID'] = $merchantID; $request['orderNumber'] = $order->order_id; $request['orderPage_timestamp'] = $timestamp; $request['orderPage_ignoreAVS'] = variable_get('uc_cybersource_avs', 'true') == 'true' ? 'false' : 'true'; $request['orderPage_signaturePublic'] = $pub_digest; $request['orderPage_version'] = '4'; $request['orderPage_serialNumber'] = $serialNumber; $request['orderPage_transactionType'] = variable_get('uc_cybersource_hop_transaction_type', 'sale'); $data = ''; while (list($key, $value) = each($request)) { $data .= $key . '=' . urlencode(str_replace(',', '', $value)) . '&'; } $data = substr($data, 0, -1); if (variable_get('uc_cybersource_server', 'test') == 'test') { $url = 'https://orderpagetest.ic3.com/hop/ProcessOrder.do'; } else { $url = 'https://orderpage.ic3.com/hop/ProcessOrder.do'; } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_VERBOSE, 0); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); curl_setopt($ch, CURLOPT_NOPROGRESS, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0); $response = curl_exec($ch); if ($error = curl_error($ch)) { watchdog('uc_cybersource', '@error', array('@error' => $error), WATCHDOG_ERROR); } curl_close($ch); if (preg_match_all('`name=".+" value=".+"`', $response, $pairs) > 0) { for ($i = 0; $i < count($pairs[0]); $i++) { list($name, $value) = explode('" value="', substr($pairs[0][$i], 6, strlen($pairs[0][$i]) - 7)); $nvp[$name] = $value; } // Create the order and payment ledger comments. $o_comment = t('Credit card !type: !amount
Decision: @decision
Reason: !reason', array('!type' => variable_get('uc_cybersource_hop_transaction_type', 'sale'), '!amount' => uc_currency_format($nvp['orderAmount']), '@decision' => $nvp['decision'], '!reason' => _uc_cybersource_parse_reason_code($nvp['reasonCode']))); $p_comment = t('!id
!decision, Reason: !reason', array('!id' => $nvp['orderPage_serialNumber'], '!decision' => $nvp['decision'], '!reason' => $nvp['reasonCode'])); if (!empty($nvp['ccAuthReply_avsCode'])) { $o_comment .= t('
AVS: !avs', array('!avs' => _uc_cybersource_parse_avs_code($nvp['ccAuthReply_avsCode']))); $p_comment .= t(', AVS: @avs', array('@avs' => $nvp['ccAuthReply_avsCode'])); } if (!empty($nvp['ccAuthReply_cvCode'])) { $o_comment .= t('
CVV: !cvv', array('!cvv' => _uc_cybersource_parse_cvv_code($nvp['ccAuthReply_cvCode']))); $p_comment .= t(', CVV: @cvv', array('@cvv' => $nvp['ccAuthReply_cvCode'])); } uc_order_comment_save($order->order_id, $user->uid, $o_comment, 'admin'); if ($nvp['decision'] == 'ACCEPT') { $result = array( 'success' => TRUE, 'comment' => $p_comment, 'message' => $o_comment, 'uid' => $user->uid, ); } else { $result = array( 'success' => FALSE, 'comment' => $p_comment, 'message' => $o_comment, 'uid' => $user->uid, ); } } else { $result = array( 'success' => FALSE, 'message' => t('No response returned from CyberSource.'), ); } return $result; } /** * Handles the SOAP charge request and Ubercart order save. */ function _uc_cybersource_soap_charge($order, $amount, $data, $cc_type, $country) { // Include the SOAP helper file. module_load_include('inc', 'uc_cybersource', 'uc_cybersource.soap'); global $user; // Set the URL for the CyberSource SOAP Toolkit API WSDL. if (variable_get('uc_cybersource_server', 'test') == 'test') { $url = 'https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.38.wsdl'; } else { $url = 'https://ics2ws.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.38.wsdl'; } // Variable currency... not used at the moment. $currency = variable_get('uc_cybersource_currency', 'usd'); $billing_country = uc_get_country_data(array('country_id' => $order->billing_country)); $delivery_country = uc_get_country_data(array('country_id' => $order->delivery_country)); try { $soapClient = new CyberSourceSoapClient($url, array()); // To see the functions and types that the SOAP extension can automatically // generate from the WSDL file, uncomment this section and check the logs. // $functions = $soapClient->__getFunctions(); // watchdog('uc_cybersource', '
' . print_r($functions, TRUE) . '
'); // $types = $soapClient->__getTypes(); // watchdog('uc_cybersource', '
' . print_r($types, TRUE) . '
'); $login = _uc_cybersource_soap_login_data(); // Create the request with some meta data. $request = new stdClass(); $request->merchantID = $login['merchant_id']; $request->merchantReferenceCode = $order->order_id; $request->clientLibrary = 'PHP'; $request->clientLibraryVersion = phpversion(); $request->clientEnvironment = php_uname(); // Add the credit card authorization service. if (in_array($data['txn_type'], array(UC_CREDIT_AUTH_ONLY, UC_CREDIT_AUTH_CAPTURE, UC_CREDIT_REFERENCE_TXN))) { $ccAuthService = new stdClass(); $ccAuthService->run = 'true'; $request->ccAuthService = $ccAuthService; } // Add the credit card capture service. if (in_array($data['txn_type'], array(UC_CREDIT_PRIOR_AUTH_CAPTURE, UC_CREDIT_AUTH_CAPTURE, UC_CREDIT_REFERENCE_TXN))) { $ccCaptureService = new stdClass(); $ccCaptureService->run = 'true'; // Add the values for prior authorization capture. if ($data['txn_type'] == UC_CREDIT_PRIOR_AUTH_CAPTURE) { $ccCaptureService->authRequestID = $data['auth_id']; $ccCaptureService->authRequestToken = $order->data['cybersource'][$data['auth_id']]; } $request->ccCaptureService = $ccCaptureService; // Add the subscription ID for a reference transaction. if ($data['txn_type'] == UC_CREDIT_REFERENCE_TXN) { $recurringSubscriptionInfo = new stdClass(); $recurringSubscriptionInfo->subscriptionID = $data['ref_id']; $request->recurringSubscriptionInfo = $recurringSubscriptionInfo; $request->merchantReferenceCode .= ' (COF)'; } } // If enabled, create a subscription profile for this transaction. if (variable_get('uc_cybersource_soap_create_profile', FALSE) && in_array($data['txn_type'], array(UC_CREDIT_AUTH_ONLY, UC_CREDIT_AUTH_CAPTURE))) { // Skip if a profile already exists for this order. if (!isset($order->data['uc_cybersource']['soap']['subscription_id'])) { $recurringSubscriptionInfo = new stdClass(); $recurringSubscriptionInfo->amount = 0; $recurringSubscriptionInfo->frequency = 'on-demand'; $request->recurringSubscriptionInfo = $recurringSubscriptionInfo; $paySubscriptionCreateService = new stdClass(); $paySubscriptionCreateService->run = 'true'; $request->paySubscriptionCreateService = $paySubscriptionCreateService; } } // Add the billing information. $billTo = new stdClass(); $billTo->firstName = $order->billing_first_name; $billTo->lastName = $order->billing_last_name; $billTo->street1 = $order->billing_street1; if ($order->billing_street2) { $billTo->street2 = $order->billing_street2; } $billTo->city = $order->billing_city; $billTo->state = uc_get_zone_code($order->billing_zone); $billTo->postalCode = $order->billing_postal_code; $billTo->country = $billing_country[0]['country_iso_code_2']; if ($order->billing_phone) { $billTo->phoneNumber = $order->billing_phone; } $billTo->email = $order->primary_email; $billTo->customerID = $order->uid; $request->billTo = $billTo; // Add the credit card details if needed. if (in_array($data['txn_type'], array(UC_CREDIT_AUTH_ONLY, UC_CREDIT_AUTH_CAPTURE))) { $card = new stdClass(); $card->accountNumber = $order->payment_details['cc_number']; $card->expirationMonth = $order->payment_details['cc_exp_month']; $card->expirationYear = $order->payment_details['cc_exp_year']; $card->cardType = $cc_type; if (variable_get('uc_credit_cvv_enabled', TRUE)) { $card->cvNumber = $order->payment_details['cc_cvv']; } $request->card = $card; } // Add the order total information. $purchaseTotals = new stdClass(); $purchaseTotals->currency = $currency; $purchaseTotals->grandTotalAmount = $amount; $request->purchaseTotals = $purchaseTotals; // Separately add products and line item into the request items object if // we're charging the full order total. if (round($amount, 2) == round($order->order_total, 2)) { $request->item = array(); $counter = 0; // Add the products to the item array. foreach ($order->products as $product) { $obj = $request->item[] = new stdClass(); $obj->productName = $product->title; $obj->unitPrice = $product->price; $obj->quantity = $product->qty; $obj->productSKU = $product->model; $obj->productCode = 'default'; $obj->id = $counter; $counter++; } // Add the line items to the item array. $discount_amount = 0; foreach ((array) $order->line_items as $line_item) { // Handle negative line items. if ($line_item['amount'] < 0) { $discount_amount += -$line_item['amount']; } // Skip subtotal line items. elseif (strpos($line_item['type'], 'subtotal') === FALSE) { $obj = $request->item[] = new stdClass(); $obj->productName = $line_item['title']; $obj->unitPrice = $line_item['amount']; $obj->quantity = 1; $obj->productSKU = $line_item['type'] . '_' . $line_item['line_item_id']; $obj->id = $counter; $counter++; } } } // Add the total order discount into the request. if ($discount_amount != 0) { $request->purchaseTotals->discountAmount = $discount_amount; } // Add business rules. $business = new stdClass(); $business->ignoreAVSResult = variable_get('uc_cybersource_avs', 'true') == 'true' ? 'false' : 'true'; $request->businessRules = $business; // Send the request to CyberSource and get the reply. $reply = $soapClient->runTransaction($request); } catch (SoapFault $exception) { // Log and display errors if Ubercart is unable to connect via SOAP. watchdog('uc_cybersource', 'Unable to connect to CyberSource via SOAP.', array(), WATCHDOG_ERROR); drupal_set_message(t('We apologize for the delay, but we are unable to process your credit card at this time. Please contact sales to complete your order.', array('@url' => url('contact'))), 'error'); } // Process a reply from CyberSource. if (isset($reply)) { $types = uc_credit_transaction_types(); // Create the order and payment ledger comments. $o_comment = t('@type: @amount
Decision: @decision
Reason: !reason', array('@type' => $types[$data['txn_type']], '@amount' => uc_currency_format($amount), '@decision' => $reply->decision, '!reason' => _uc_cybersource_parse_reason_code($reply->reasonCode))); $p_comment = t('@type:
@id
@decision, Reason: !reason', array('@type' => $types[$data['txn_type']], '@id' => $reply->requestID, '@decision' => $reply->decision, '!reason' => $reply->reasonCode)); if (!empty($reply->ccAuthReply->avsCode)) { $o_comment .= '
' . t('AVS: @avs', array('@avs' => _uc_cybersource_parse_avs_code($reply->ccAuthReply->avsCode))); $p_comment .= t(', AVS: @avs', array('@avs' => $reply->ccAuthReply->avsCode)); } if (!empty($reply->ccAuthReply->cvCode)) { $o_comment .= '
' . t('CVV: @cvv', array('@cvv' => _uc_cybersource_parse_cvv_code($reply->ccAuthReply->cvCode))); $p_comment .= t(', CVV: @cvv', array('@cvv' => $reply->ccAuthReply->cvCode)); } uc_order_comment_save($order->order_id, $user->uid, $o_comment, 'admin'); // Store the subscription ID if one was created. if (isset($reply->paySubscriptionCreateReply)) { // If the create request was successful... if ($reply->paySubscriptionCreateReply->reasonCode == '100') { $id = $reply->paySubscriptionCreateReply->subscriptionID; // Save the subscription ID to the order's data array. $order->data = uc_credit_log_reference($order->order_id, $id, $order->payment_details['cc_number']); uc_order_comment_save($order->order_id, 0, t('CyberSource profile created.
Subscription ID: @id', array('@id' => $id)), 'admin'); } else { uc_order_comment_save($order->order_id, 0, t('Attempt to create CyberSource profile failed.
Reason: @code', array('@code' => $reply->paySubscriptionCreateReply->reasonCode)), 'admin'); } } if ($reply->decision == 'ACCEPT') { $result = array( 'success' => TRUE, 'comment' => $p_comment, 'message' => $o_comment, 'uid' => $user->uid, 'data' => array('module' => 'uc_cybersource', 'txn_type' => $data['txn_type'], 'request_id' => $reply->requestID), ); // If this was an authorization only transaction... if ($data['txn_type'] == UC_CREDIT_AUTH_ONLY) { // Log the authorization to the order. $order->data = uc_credit_log_authorization($order->order_id, $reply->requestID, $amount); // Add the request token associated with the request ID. $order->data['cybersource'][$reply->requestID] = $reply->requestToken; // Save the updated data array to the database. db_update('uc_orders') ->fields(array('data' => serialize($order->data))) ->condition('order_id', $order->order_id) ->execute(); } elseif ($data['txn_type'] == UC_CREDIT_PRIOR_AUTH_CAPTURE) { uc_credit_log_prior_auth_capture($order->order_id, $data['auth_id']); } } else { $result = array( 'success' => FALSE, 'comment' => $p_comment, 'message' => $o_comment, 'uid' => $user->uid, ); } } else { $result = array( 'success' => FALSE, 'message' => t('No response returned from CyberSource.'), ); } // Don't log this as a payment if money wasn't actually captured. if (in_array($data['txn_type'], array(UC_CREDIT_AUTH_ONLY))) { $result['log_payment'] = FALSE; } return $result; } /** * Displays the taxes for an order. */ function uc_cybersource_tax_test($order) { // Fetch the taxes for the order. $data = uc_cybersource_uc_calculate_tax($order); // Build an item list for the taxes. $items = array(); foreach ($data as $tax) { $items[] = t('@tax: @amount', array('@tax' => $tax['name'], '@amount' => uc_currency_format($tax['amount']))); } // Display a message if there are no taxes. if (empty($items)) { $items[] = t('No taxes returned for this order.'); } return array( '#theme' => 'item_list', '#items' => $items, ); } /** * Implements hook_uc_calculate_tax(). * * Calculates taxes for an order using CyberSource's tax service. * * @param $order * An order object with address and product information. * * @return * An array of tax line item objects with the fields 'id', 'name', and * 'amount', keyed by id. */ function uc_cybersource_uc_calculate_tax($order) { // Kick out if the tax service is not enabled. if (!variable_set('uc_cybersource_soap_tax_calculate', FALSE)) { return array(); } if (!is_object($order)) { return array(); } // Include the SOAP helper file. module_load_include('inc', 'uc_cybersource', 'uc_cybersource.soap'); global $user; // Set the URL for the CyberSource SOAP Toolkit API WSDL. if (variable_get('uc_cybersource_server', 'test') == 'test') { $url = 'https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.38.wsdl'; } else { $url = 'https://ics2ws.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.38.wsdl'; } // Variable currency... not used at the moment. $currency = variable_get('uc_cybersource_currency', 'usd'); $billing_country = uc_get_country_data(array('country_id' => $order->billing_country)); $delivery_country = uc_get_country_data(array('country_id' => $order->delivery_country)); try { $soapClient = new CyberSourceSoapClient($url, array()); $login = _uc_cybersource_soap_login_data(); // Create the request with some meta data. $request = new stdClass(); $request->merchantID = $login['merchant_id']; $request->merchantReferenceCode = $order->order_id; $request->clientLibrary = 'PHP'; $request->clientLibraryVersion = phpversion(); $request->clientEnvironment = php_uname(); // Add the billing information. $billTo = new stdClass(); $billTo->firstName = $order->billing_first_name; $billTo->lastName = $order->billing_last_name; $billTo->street1 = $order->billing_street1; if ($order->billing_street2) { $billTo->street2 = $order->billing_street2; } $billTo->city = $order->billing_city; $billTo->state = uc_get_zone_code($order->billing_zone); $billTo->postalCode = $order->billing_postal_code; $billTo->country = $billing_country[0]['country_iso_code_2']; if ($order->billing_phone) { $billTo->phoneNumber = $order->billing_phone; } $billTo->email = $order->primary_email; $billTo->customerID = $order->uid; $request->billTo = $billTo; // Add the shipping information. $shipTo = new stdClass(); $shipTo->firstName = $order->delivery_first_name; $shipTo->lastName = $order->delivery_last_name; $shipTo->street1 = $order->delivery_street1; if ($order->billing_street2) { $shipTo->street2 = $order->delivery_street2; } $shipTo->city = $order->delivery_city; $shipTo->state = uc_get_zone_code($order->delivery_zone); $shipTo->postalCode = $order->delivery_postal_code; $shipTo->country = $delivery_country[0]['country_iso_code_2']; $shipTo->email = $order->primary_email; $request->shipTo = $shipTo; // Add the company's ship from information. $shipFrom = new stdClass(); $shipFrom->firstName = variable_get('cs_ship_from_first_name', ''); $shipFrom->lastName = variable_get('cs_ship_from_last_name', ''); $shipFrom->street1 = variable_get('cs_ship_from_street1', ''); $shipFrom->city = variable_get('cs_ship_from_city', ''); $shipFrom->state = variable_get('cs_ship_from_zone', ''); $shipFrom->postalCode = variable_get('cs_ship_from_postal_code', ''); $shipFrom->country = variable_get('cs_ship_from_country', ''); $shipFrom->email = variable_get('cs_ship_from_email', ''); $request->shipFrom = $shipFrom; // TaxService // US product codes: // 70.280: Software Training Services // 81112201.121: Business Use Services and Upgrades via Elect Dnld // TODO: product code, international product code // TODO: invoiceHeader->invoiceDate: to get correct refund amounts // TODO: VAT $taxService = new stdClass(); $taxService->nexus = 'MA CA'; $taxService->orderOriginCity = $taxService->orderAcceptanceCity = $shipFrom->city; $taxService->orderOriginCountry = $taxService->orderAcceptanceCountry = $shipFrom->country; $taxService->orderOriginState = $taxService->orderAcceptanceState = $shipFrom->state; $taxService->orderOriginPostalCode = $taxService->orderAcceptancePostalCode = $shipFrom->postalCode; $taxService->sellerRegistration = 'XXX TODO'; $taxService->run = 'true'; $request->taxService = $taxService; // Add the order total information. $purchaseTotals = new stdClass(); $purchaseTotals->currency = $currency; // Add the products to the request. $request->item = array(); $counter = 0; // Add the products to the item array. foreach ($order->products as $product) { $obj = $request->item[] = new stdClass(); $obj->productName = $product->title; $obj->unitPrice = $product->price; $obj->quantity = $product->qty; $obj->productSKU = $product->model; $obj->productCode = 'default'; $obj->id = $counter; $counter++; } // drupal_set_message('
Request: ' . print_r($request, TRUE) . '
'); // Send the request to CyberSource and get the reply. $reply = $soapClient->runTransaction($request); // drupal_set_message('
Reply: ' . print_r($reply, TRUE) . '
'); } catch (SoapFault $exception) { // Log and display errors if Ubercart is unable to connect via SOAP. watchdog('uc_cybersource', 'Unable to connect to CyberSource via SOAP.', array(), WATCHDOG_ERROR); drupal_set_message(t('We apologize for the delay, but we are unable to process your credit card at this time. Please contact sales to complete your order.', array('@url' => url('contact'))), 'error'); } // Process a reply from CyberSource. if (isset($reply)) { $result = array(); if ($reply->reasonCode == '100') { // Add a city tax if applicable. if (floatval($reply->taxReply->totalCityTaxAmount) > 0) { $result['city'] = (object) array( 'id' => 'city', 'name' => t('@city city tax', array('@city' => floatval($reply->taxReply->city))), 'amount' => floatval($reply->taxReply->totalCityTaxAmount), ); } // Add a county tax if applicable. if (floatval($reply->taxReply->totalCountyTaxAmount) > 0) { $result['county'] = (object) array( 'id' => 'county', 'name' => t('County tax'), 'amount' => floatval($reply->taxReply->totalCountryTaxAmount), ); } // Add a district tax if applicable. if (floatval($reply->taxReply->totalDistrictTaxAmount) > 0) { $result['district'] = (object) array( 'id' => 'district', 'name' => t('District tax'), 'amount' => floatval($reply->taxReply->totalDistrictTaxAmount), ); } // Add a state tax if applicable. if (floatval($reply->taxReply->totalStateTaxAmount) > 0) { $result['state'] = (object) array( 'id' => 'state', 'name' => t('@state state tax', array('@state' => $reply->taxReply->state)), 'amount' => floatval($reply->taxReply->totalStateTaxAmount), ); } // Verify that the component taxes equal the total. $total = 0; foreach ($result as $tax) { $total += $tax['amount']; } // If it doesn't, log an error message and simply return the total. if ($total != floatval($reply->taxReply->totalTaxAmount)) { watchdog('uc_cybersource', 'Tax calculation produced uneven results. Expected a total of @total, received the following: @dump', array('@total' => uc_currency_format($reply->taxReply->totalTaxAmount), '@dump' => '
' . print_r($result, TRUE) . '
'), WATCHDOG_ERROR); $result = array( 'total' => (object) array( 'id' => 'total', 'name' => t('Tax'), 'amount' => floatval($reply->taxReply->totalTaxAmount), ), ); } } else { watchdog('uc_cybersource', 'Attempted to calculate taxes failed for order @order_id - reason @code', array('@order_id' => $order->order_id, '@code' => $reply->reasonCode), WATCHDOG_ERROR); } } else { watchdog('uc_cybersource', 'Attempted to calculate taxes failed for order @order_id. No response returned from CyberSource.', array('@order_id' => $order->order_id), WATCHDOG_ERROR); $result = array(); } /** * Code for the Simple Order API that was never completed. * * else { * $config = cybs_load_config('cybs.ini'); * if (variable_get('uc_cybersource_server', 'test') == 'test') { * $config['sendToProduction'] = 'false'; * } * * $request['ccAuthService_run'] = 'true'; * if (variable_get('uc_cybersource_hop_transaction_type', 'sale') == 'sale') { * $request['ccCaptureService_run'] = 'true'; * } * $request['merchantReferenceCode'] = $order_id; * $request['purchaseTotals_currency'] = 'USD'; * $request['purchaseTotals_grandTotalAmount'] = $amount; * * drupal_set_message('
' . print_r($config, TRUE) . '
'); * drupal_set_message('
' . print_r($request, TRUE) . '
'); * } */ return $result; } /** * Returns an array with the SOAP Merchant ID and Transaction key. */ function _uc_cybersource_soap_login_data() { static $data; if (!empty($data)) { return $data; } $merchant_id = variable_get('uc_cybersource_soap_merchant_id', ''); $transaction_key = variable_get('uc_cybersource_soap_transaction_key', ''); // If CC encryption has been configured properly. if ($key = uc_credit_encryption_key()) { // Setup our encryption object. $crypt = new UbercartEncryption(); // Decrypt the Merchant ID and Transaction key. if (!empty($merchant_id)) { $merchant_id = $crypt->decrypt($key, $merchant_id); } if (!empty($transaction_key)) { $transaction_key = $crypt->decrypt($key, $transaction_key); } // Store any errors. uc_store_encryption_errors($crypt, 'uc_cybersource'); } $data = array( 'merchant_id' => $merchant_id, 'transaction_key' => $transaction_key, ); return $data; } /** * Returns the code for the credit card type. */ function _uc_cybersource_card_type($cc_number) { switch (substr(strval($cc_number), 0, 1)) { case '3': if (strlen($cc_number) == 14) { return '005'; // Diners Club } elseif (strlen($cc_number) == 15) { return '003'; // AmEx } else { return '007'; // JCB } case '4': return '001'; // Visa case '5': return '002'; // MasterCard case '6': return '004'; // Discover } return FALSE; } /** * Returns the meaning of the reason code given by CyberSource. */ function _uc_cybersource_parse_reason_code($code) { switch ($code) { case '100': return t('Successful transaction.'); case '102': return t('One or more fields in the request are missing or invalid.
Possible action: Resend the request with the correct information.'); case '150': return t('Error: General system failure.
Possible action: Wait a few minutes and resend the request.'); case '151': return t('Error: The request was received, but a server time-out occurred. This error does not include time-outs between the client and the server.
Possible action: To avoid duplicating the order, do not resend the request until you have reviewed the order status in the Business Center.'); case '152': return t('Error: The request was received, but a service did not finish running in time.
Possible action: To avoid duplicating the order, do not resend the request until you have reviewed the order status in the Business Center.'); case '200': return t('The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the Address Verification Service (AVS) check.
Possible action: You can capture the authorization, but consider reviewing the order for the possibility of fraud.'); case '202': return t('Expired card.
Possible action: Request a different card or other form of payment.'); case '203': return t('General decline of the card. No other information provided by the issuing bank.
Possible action: Request a different card or other form of payment.'); case '204': return t('Insufficient funds in the account.
Possible action: Request a different card or other form of payment.'); case '205': return t("Stolen or lost card.
Possible action: Review the customer's information and determine if you want to request a different card from the customer."); case '207': return t('Issuing bank unavailable.
Possible action: Wait a few minutes and resend the request.'); case '208': return t('Inactive card or card not authorized for card-not-present transactions.
Possible action: Request a different card or other form of payment.'); case '210': return t('The card has reached the credit limit.
Possible action: Request a different card or other form of payment.'); case '211': return t('The card verification number is invalid.
Possible action: Request a different card or other form of payment.'); case '220': return t("The processor declined the request based on a general issue with the customer's account.
Possible action: Request a different form of payment."); case '221': return t('The customer matched an entry on the processor’s negative file.
Possible action: Review the order and contact the payment processor.'); case '222': return t("The customer's bank account is frozen.
Possible action: Review the order or request a different form of payment."); case '230': return t('The authorization request was approved by the issuing bank but declined by CyberSource because it did not pass the card verification number check.
Possible action: You can capture the authorization, but consider reviewing the order for the possibility of fraud.'); case '231': return t('Invalid account number.
Possible action: Request a different card or other form of payment.'); case '232': return t('The card type is not accepted by the payment processor.
Possible action: Request a different card or other form of payment. Also, check with CyberSource Customer Support to make sure that your account is configured correctly.'); case '233': return t('The processor declined the request based on an issue with the request itself.
Possible action: Request a different form of payment.'); case '234': return t('There is a problem with your CyberSource merchant configuration.
Possible action: Do not resend the request. Contact Customer Support to correct the configuration problem.'); case '236': return t('Processor failure.
Possible action: Possible action: Wait a few minutes and resend the request.'); case '240': return t('The card type sent is invalid or does not correlate with the credit card number.
Possible action: Ask your customer to verify that the card is really the type indicated in your Web store, then resend the request.'); case '250': return t('Error: The request was received, but a time-out occurred with the payment processor.
Possible action: To avoid duplicating the transaction, do not resend the request until you have reviewed the transaction status in the Business Center.'); case '475': return t('The customer is enrolled in payer authentication.
Possible action: Authenticate the cardholder before continuing with the transaction.'); case '476': return t("The customer cannot be authenticated.
Possible action: Review the customer's order."); case '520': return t('The authorization request was approved by the issuing bank but declined by CyberSource based on your Smart Authorization settings.
Possible action: Do not capture the authorization without further review. Review the avsCode, cvResult, and factorCode fields to determine why CyberSource rejected the request.'); } } /** * Returns the meaning of the code for Address Verification. */ function _uc_cybersource_parse_avs_code($code) { switch ($code) { case 'A': return t('Street address matches, but 5- and 9-digit postal codes do not match.'); case 'B': return t('Street address matches, but postal code not verified. Returned only for non U.S.-issued Visa cards.'); case 'C': return t('Street address and postal code do not match. Returned only for non U.S.-issued Visa cards.'); case 'D': return t('Street address and postal code match. Returned only for non U.S.-issued Visa cards.'); case 'E': return t('AVS data is invalid, or AVS is not allowed for this card type.'); case 'F': return t("Card member's name does not match, but postal code matches. Returned only for the American Express card type."); case 'G': return t('Non-U.S. issuing bank does not support AVS.'); case 'H': return t("Card member's name does not match. Street address and postal code match. Returned only for the American Express card type."); case 'I': return t('Address not verified. Returned only for non U.S.-issued Visa cards.'); case 'K': return t("Card member's name matches but billing address and billing postal code do not match. Returned only for the American Express card type."); case 'L': return t("Card member's name and billing postal code match, but billing address does not match. Returned only for the American Express card type"); case 'N': return t("Street address and postal code do not match. - or - Card member's name, street address and postal code do not match. Returned only for the American Express card type."); case 'O': return t("Card member's name and billing address match, but billing postal code does not match. Returned only for the American Express card type."); case 'P': return t('Postal code matches, but street address not verified. Returned only for non-U.S.-issued Visa cards.'); case 'R': return t('System unavailable.'); case 'S': return t('U.S.-issuing bank does not support AVS.'); case 'T': return t("Card member's name does not match, but street address matches. Returned only for the American Express card type."); case 'U': return t('Address information unavailable. Returned if non-U.S. AVS is not available or if the AVS in a U.S. bank is not functioning properly.'); case 'W': return t('Street address does not match, but 9-digit postal code matches.'); case 'X': return t('Exact match. Street address and 9-digit postal code match.'); case 'Y': return t('Exact match. Street address and 5-digit postal code match.'); case 'Z': return t('Street address does not match, but 5-digit postal code matches.'); case '1': return t('AVS is not supported for this processor or card type.'); case '2': return t('The processor returned an unrecognized value for the AVS response.'); } } /** * Returns the meaning of the code sent back for CVV verification. */ function _uc_cybersource_parse_cvv_code($code) { switch ($code) { case 'D': return t('Transaction determined suspicious by issuing bank.'); case 'I': return t("Card verification number failed processor's data validation check."); case 'M': return t('Card verification number matched.'); case 'N': return t('Card verification number not matched.'); case 'P': return t('Card verification number not processed by processor for unspecified reason.'); case 'S': return t('Card verification number is on the card but was not included in the request.'); case 'U': return t('Card verification is not supported by the issuing bank.'); case 'X': return t('Card verification is not supported by the card association.'); case '1': return t('Card verification is not supported for this processor or card type.'); case '2': return t('Unrecognized result code returned by processor for card verification response.'); case '3': return t('No result code returned by processor.'); } }