You are here

function commerce_authnet_aim_submit_form_submit in Commerce Authorize.Net 7

Payment method callback: checkout form submission.

File

./commerce_authnet.module, line 381
Implements Authorize.Net payment services for use in Drupal Commerce.

Code

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

  // If Card on File is enabled and active for this payment method, then we need
  // to figure out what to do.
  if (module_exists('commerce_cardonfile') && $payment_method['settings']['cardonfile'] && !empty($pane_values['cardonfile'])) {
    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_cim_submit_new_card_form_submit($payment_method, $pane_form, $pane_values, $order, $charge);
      }
    }
  }

  // Determine the credit card type if possible for use in later code.
  if (!empty($pane_values['credit_card']['number'])) {
    module_load_include('inc', 'commerce_payment', 'includes/commerce_payment.credit_card');
    $card_type = commerce_payment_validate_credit_card_type($pane_values['credit_card']['number'], array_keys(commerce_payment_credit_card_types()));
  }

  // If the charge amount is 0...
  if ($charge['amount'] == 0) {

    // Prevent the transaction except under limited circumstances.
    $prevent_transaction = TRUE;

    // Allow 0 amount authorizations on Visa cards.
    if ($payment_method['settings']['txn_type'] == COMMERCE_CREDIT_AUTH_ONLY && $card_type == 'visa') {
      $prevent_transaction = FALSE;
    }

    // If the transaction should still be prevented...
    if ($prevent_transaction) {

      // Create a transaction to log the skipped transaction and display a
      // helpful message to the customer.
      $transaction = commerce_payment_transaction_new('authnet_aim', $order->order_id);
      $transaction->amount = $charge['amount'];
      $transaction->currency_code = $charge['currency_code'];
      $transaction->status = COMMERCE_PAYMENT_STATUS_FAILURE;
      $transaction->message = t('Invalid @amount transaction not attempted.', array(
        '@amount' => commerce_currency_format($charge['amount'], $charge['currency_code']),
      ));
      commerce_payment_transaction_save($transaction);
      drupal_set_message(t('We encountered an error processing your transaction. Please contact us to resolve the issue.'), 'error');
      return FALSE;
    }
  }
  $order_wrapper = entity_metadata_wrapper('commerce_order', $order);

  // Get the default transaction type from the payment method settings.
  $txn_type = $payment_method['settings']['txn_type'];

  // 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'])) {
    $txn_type = $pane_values['txn_type'];
  }

  // Build a name-value pair array for this transaction.
  $nvp = array(
    'x_type' => commerce_authnet_txn_type($txn_type),
    'x_method' => 'CC',
    'x_amount' => number_format(commerce_currency_amount_to_decimal($charge['amount'], $charge['currency_code']), 2, '.', ''),
    'x_currency_code' => $charge['currency_code'],
    'x_card_num' => $pane_values['credit_card']['number'],
    'x_exp_date' => $pane_values['credit_card']['exp_month'] . $pane_values['credit_card']['exp_year'],
  );
  if (isset($pane_values['credit_card']['code'])) {
    $nvp['x_card_code'] = $pane_values['credit_card']['code'];
  }

  // Build a description for the order.
  $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();
      }
    }
  }

  // Add additional transaction invormation to the request array.
  $nvp += array(
    // Order Information.
    'x_invoice_num' => $order->order_number,
    'x_description' => substr(implode(', ', $description), 0, 255),
    // Customer Information.
    'x_email' => substr($order->mail, 0, 255),
    'x_cust_id' => substr($order->uid, 0, 20),
    'x_customer_ip' => substr(ip_address(), 0, 15),
  );

  // Prepare the billing address for use in the request.
  if (isset($order->commerce_customer_billing) && $order_wrapper->commerce_customer_billing
    ->value()) {
    $billing_address = $order_wrapper->commerce_customer_billing->commerce_customer_address
      ->value();
    if (empty($billing_address['first_name'])) {
      $name_parts = explode(' ', $billing_address['name_line']);
      $billing_address['first_name'] = array_shift($name_parts);
      $billing_address['last_name'] = implode(' ', $name_parts);
    }
    $nvp += array(
      // Customer Billing Address
      'x_first_name' => substr($billing_address['first_name'], 0, 50),
      'x_last_name' => substr($billing_address['last_name'], 0, 50),
      'x_company' => substr($billing_address['organisation_name'], 0, 50),
      'x_address' => substr($billing_address['thoroughfare'], 0, 60),
      'x_city' => substr($billing_address['locality'], 0, 40),
      'x_state' => substr($billing_address['administrative_area'], 0, 40),
      'x_zip' => substr($billing_address['postal_code'], 0, 20),
      'x_country' => $billing_address['country'],
    );
  }

  // Prepare the shipping address for use in the request.
  if (isset($order->commerce_customer_shipping) && $order_wrapper->commerce_customer_shipping
    ->value()) {
    $shipping_address = $order_wrapper->commerce_customer_shipping->commerce_customer_address
      ->value();
    if (empty($shipping_address['first_name'])) {
      $name_parts = explode(' ', $shipping_address['name_line']);
      $shipping_address['first_name'] = array_shift($name_parts);
      $shipping_address['last_name'] = implode(' ', $name_parts);
    }
    $nvp += array(
      // Customer shipping Address
      'x_ship_to_first_name' => substr($shipping_address['first_name'], 0, 50),
      'x_ship_to_last_name' => substr($shipping_address['last_name'], 0, 50),
      'x_ship_to_company' => substr($shipping_address['organisation_name'], 0, 50),
      'x_ship_to_address' => substr($shipping_address['thoroughfare'], 0, 60),
      'x_ship_to_city' => substr($shipping_address['locality'], 0, 40),
      'x_ship_to_state' => substr($shipping_address['administrative_area'], 0, 40),
      'x_ship_to_zip' => substr($shipping_address['postal_code'], 0, 20),
      'x_ship_to_country' => $shipping_address['country'],
    );
  }

  // Submit the request to Authorize.Net.
  $response = commerce_authnet_aim_request($payment_method, $nvp);

  // Prepare a transaction object to log the API response.
  $transaction = commerce_payment_transaction_new('authnet_aim', $order->order_id);
  $transaction->instance_id = $payment_method['instance_id'];
  $transaction->remote_id = $response[6];
  $transaction->amount = $charge['amount'];
  $transaction->currency_code = $charge['currency_code'];
  $transaction->payload[REQUEST_TIME] = $response;

  // If we didn't get an approval response code...
  if ($response[0] != '1') {

    // Create a failed transaction with the error message.
    $transaction->status = COMMERCE_PAYMENT_STATUS_FAILURE;
  }
  else {

    // Set the transaction status based on the type of transaction this was.
    switch ($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;
    }
  }

  // Store the type of transaction in the remote status.
  $transaction->remote_status = $response[11];

  // Build a meaningful response message.
  $message = array(
    '<b>' . commerce_authnet_reverse_txn_type($response[11]) . '</b>',
    '<b>' . ($response[0] != '1' ? t('REJECTED') : t('ACCEPTED')) . ':</b> ' . check_plain($response[3]),
    t('AVS response: @avs', array(
      '@avs' => commerce_authnet_avs_response($response[5]),
    )),
  );

  // Add the CVV response if enabled.
  if (isset($nvp['x_card_code'])) {
    $message[] = t('CVV match: @cvv', array(
      '@cvv' => commerce_authnet_cvv_response($response[38]),
    ));
  }
  $transaction->message = implode('<br />', $message);

  // Save the transaction information.
  commerce_payment_transaction_save($transaction);

  // If the payment failed, display an error and rebuild the form.
  if ($response[0] != '1') {
    drupal_set_message(t('We received the following error processing your card. Please enter your information again or try a different card.'), 'error');
    drupal_set_message(check_plain($response[3]), 'error');
    return FALSE;
  }
}