You are here

function commerce_authnet_acceptjs_submit_form_submit in Commerce Authorize.Net 7

Payment method callback: checkout form submission.

File

includes/commerce_authnet.acceptjs.inc, line 146
Includes the Accept.js payment method callbacks.

Code

function commerce_authnet_acceptjs_submit_form_submit($payment_method, $pane_form, $pane_values, $order, $charge) {

  // If txn_type has been specified in the pane values array, such as through
  // the special select element we alter onto the payment terminal form, use
  // that instead.
  if (!empty($pane_values['txn_type'])) {
    $payment_method['settings']['txn_type'] = $pane_values['txn_type'];
  }
  if (module_exists('commerce_cardonfile') && $payment_method['settings']['cardonfile'] && !empty($pane_values['cardonfile'])) {

    // @TODO SUPPORT COF!
    if (!empty($pane_values['cardonfile']) && $pane_values['cardonfile'] !== 'new') {

      // We're using a stored payment profile. Pass it along to CIM.
      return commerce_authnet_cim_submit_form_submit($payment_method, $pane_form, $pane_values, $order, $charge);
    }
    else {
      if (!empty($pane_values['credit_card']['cardonfile_store']) && $pane_values['credit_card']['cardonfile_store']) {

        // We've got a request to store a new card.
        return commerce_authnet_acceptjs_submit_new_card_form_submit($payment_method, $pane_form, $pane_values, $order, $charge);
      }
    }
  }
  $values = $pane_values['credit_card']['cc'];
  $data_descriptor = $values['data_descriptor'];
  $data_value = $values['data_value'];

  // https://developer.authorize.net/api/reference/#payment-transactions-create-an-accept-payment-transaction
  $request = array(
    'createTransactionRequest' => array(
      'merchantAuthentication' => array(
        'name' => $payment_method['settings']['login'],
        'transactionKey' => $payment_method['settings']['tran_key'],
      ),
      'clientId' => 'CG-PHP-SDK',
      'refId' => 'ref' . time(),
      'transactionRequest' => array(
        'transactionType' => $payment_method['settings']['txn_type'] == COMMERCE_CREDIT_AUTH_CAPTURE ? 'authCaptureTransaction' : 'authOnlyTransaction',
        'amount' => number_format(commerce_currency_amount_to_decimal($charge['amount'], $charge['currency_code']), 2, '.', ''),
        'payment' => array(
          'opaqueData' => array(
            'dataDescriptor' => $data_descriptor,
            'dataValue' => $data_value,
          ),
        ),
        'solution' => array(
          'id' => 'A1000009',
        ),
      ),
    ),
  );
  if (!empty($order)) {
    $order_wrapper = entity_metadata_wrapper('commerce_order', $order);
    $request['createTransactionRequest']['transactionRequest']['order']['invoiceNumber'] = $order->order_number;
    $description = array();

    // Descriptions come from products, though not all environments have them.
    // So check first.
    if (function_exists('commerce_product_line_item_types')) {
      foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {
        if (in_array($line_item_wrapper->type
          ->value(), commerce_product_line_item_types())) {
          $description[] = round($line_item_wrapper->quantity
            ->value(), 2) . 'x ' . $line_item_wrapper->line_item_label
            ->value();
          $request['createTransactionRequest']['transactionRequest']['lineItems']['lineItem'][] = array(
            'itemId' => drupal_substr($line_item_wrapper->line_item_label
              ->value(), 0, 31),
            'name' => drupal_substr($line_item_wrapper->commerce_product->title
              ->value(), 0, 31),
            'quantity' => round($line_item_wrapper->quantity
              ->value(), 2),
            'unitPrice' => commerce_currency_amount_to_decimal($line_item_wrapper->commerce_unit_price->amount
              ->value(), $line_item_wrapper->commerce_unit_price->currency_code
              ->value()),
          );
        }
      }
    }
    $request['createTransactionRequest']['transactionRequest']['order']['description'] = substr(implode(', ', $description), 0, 255);
    $request['createTransactionRequest']['transactionRequest']['customer'] = array(
      'id' => substr($order->uid, 0, 20),
      'email' => substr($order->mail, 0, 255),
    );
    if (isset($order->commerce_customer_billing)) {
      $request['createTransactionRequest']['transactionRequest']['billTo'] = commerce_authnet_cim_billto_array($order);
    }
    if (isset($order->commerce_customer_shipping)) {
      $request['createTransactionRequest']['transactionRequest']['shipTo'] = commerce_authnet_cim_shipto_array($order);
    }
    $request['createTransactionRequest']['transactionRequest']['customerIP'] = substr(ip_address(), 0, 15);
  }
  $request_json = drupal_json_encode($request);
  if ($payment_method['settings']['txn_mode'] == AUTHNET_TXN_MODE_DEVELOPER) {
    $api_url = 'https://apitest.authorize.net/xml/v1/request.api';
  }
  else {
    $api_url = 'https://api.authorize.net/xml/v1/request.api';
  }

  // Setup the cURL request.
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $api_url);
  curl_setopt($ch, CURLOPT_VERBOSE, 0);
  curl_setopt($ch, CURLOPT_POST, 1);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $request_json);
  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);
  curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json',
    'Content-Length: ' . strlen($request_json),
  ));
  $result_json = curl_exec($ch);

  // Log any errors to the watchdog.
  if ($error = curl_error($ch)) {
    watchdog('commerce_authnet', 'cURL error: @error', array(
      '@error' => $error,
    ), WATCHDOG_ERROR);
    curl_close($ch);
    return FALSE;
  }
  curl_close($ch);

  // The API returns hidden Byte Order Mark characters, causing the
  // JSON decoding to fail.
  $result_json = preg_replace('/[\\x00-\\x1F\\x80-\\xFF]/', '', $result_json);
  $result = drupal_json_decode($result_json);

  // Prepare a transaction object to log the API response.
  $transaction = commerce_payment_transaction_new('authnet_acceptjs', $order->order_id);
  $transaction->instance_id = $payment_method['instance_id'];
  $transaction->remote_id = $result['transactionResponse']['transId'];
  $transaction->amount = $charge['amount'];
  $transaction->currency_code = $charge['currency_code'];
  $transaction->payload[REQUEST_TIME] = $result_json;
  if (empty($result['messages']['resultCode']) || $result['messages']['resultCode'] != 'Ok') {
    $transaction->status = COMMERCE_PAYMENT_STATUS_FAILURE;
    $transaction_message = array();
    foreach ($result['messages']['message'] as $message) {
      $transaction_message[] = t('Authorize.net error: @code - @error', array(
        '@code' => $message['code'],
        '@error' => $message['text'],
      ));
      watchdog('commerce_authnet', 'Authorize.net error: @code - @error', array(
        '@code' => $message['code'],
        '@error' => $message['text'],
      ), WATCHDOG_ERROR);
      $transaction->message = implode('<br />', $transaction_message);
    }
    commerce_payment_transaction_save($transaction);
    return FALSE;
  }
  elseif (!empty($result['transactionResponse']['errors'])) {
    $transaction->status = COMMERCE_PAYMENT_STATUS_FAILURE;
    $transaction_message = array();
    foreach ($result['transactionResponse']['errors'] as $message) {
      $transaction_message[] = t('Authorize.net error: @code - @error', array(
        '@code' => $message['errorCode'],
        '@error' => $message['errorText'],
      ));
      watchdog('commerce_authnet', 'Authorize.net error: @code - @error', array(
        '@code' => $message['errorCode'],
        '@error' => $message['errorText'],
      ), WATCHDOG_ERROR);
      $transaction->message = implode('<br />', $transaction_message);
      drupal_set_message(check_plain($message['errorText']), 'error');
    }
    commerce_payment_transaction_save($transaction);
    return FALSE;
  }

  // Set the transaction status based on the type of transaction this was.
  switch ($payment_method['settings']['txn_type']) {
    case COMMERCE_CREDIT_AUTH_ONLY:
      $transaction->status = COMMERCE_PAYMENT_STATUS_PENDING;
      break;
    case COMMERCE_CREDIT_AUTH_CAPTURE:
      $transaction->status = COMMERCE_PAYMENT_STATUS_SUCCESS;
      break;
    case COMMERCE_CREDIT_CAPTURE_ONLY:
      $transaction->status = COMMERCE_PAYMENT_STATUS_SUCCESS;
      break;
  }
  $transaction->remote_status = commerce_authnet_txn_type($payment_method['settings']['txn_type']);

  // Build a meaningful response message.
  $message = array(
    '<b>' . commerce_authnet_reverse_txn_type($transaction->remote_status) . '</b>',
    '<b>' . ($result['transactionResponse']['messages'][0]['code'] != '1' ? t('REJECTED') : t('ACCEPTED')) . ':</b> ' . check_plain($result['transactionResponse']['messages'][0]['description']),
    t('AVS response: @avs', array(
      '@avs' => commerce_authnet_avs_response($result['transactionResponse']['avsResultCode']),
    )),
  );

  // Add the CVV response if enabled.
  if (isset($result['transactionResponse']['cvvResultCode'])) {
    $message[] = t('CVV match: @cvv', array(
      '@cvv' => commerce_authnet_cvv_response($result['transactionResponse']['cvvResultCode']),
    ));
  }
  $transaction->message = implode('<br />', $message);
  commerce_payment_transaction_save($transaction);
  return TRUE;
}