You are here

function commerce_authnet_cim_cardonfile_create in Commerce Authorize.Net 7

Commerce Card on File create callback.

Parameters

array $form: The card on file create form.

array $form_state: The card on file create form state.

array $payment_method: The payment method for the card on file request.

object $card_data: The commerce_cardonfile entity.

Return value

object|bool A new commerce_cardonfile entity or FALSE if there was an error.

1 string reference to 'commerce_authnet_cim_cardonfile_create'
commerce_authnet_commerce_payment_method_info in ./commerce_authnet.module
Implements hook_commerce_payment_method_info().

File

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

Code

function commerce_authnet_cim_cardonfile_create($form, &$form_state, $payment_method, $card_data) {
  $account = user_load($card_data->uid);

  // Submit the profile to the field attach handlers.
  $profile = $form_state['commerce_customer_profile'];
  field_attach_submit('commerce_customer_profile', $profile, $form['commerce_customer_profile'], $form_state);
  commerce_customer_profile_save($profile);

  // Format the address into the Auth.net schema.
  $profile_wrapper = entity_metadata_wrapper('commerce_customer_profile', $profile);
  $billto = commerce_authnet_cim_billto_array(NULL, $profile_wrapper->commerce_customer_address
    ->value());

  // Build the card data to submit to Auth.net.
  $number = $form_state['values']['credit_card']['number'];
  $card_data->card_exp_month = $form_state['values']['credit_card']['exp_month'];
  $card_data->card_exp_year = $form_state['values']['credit_card']['exp_year'];
  $card_expire = $card_data->card_exp_year . '-' . $card_data->card_exp_month;
  $card_code = $form_state['values']['credit_card']['code'];
  $card_type = $form_state['values']['credit_card']['type'];

  // Attempt to load and existing profile id from the customers card data.
  $existing_cards = commerce_cardonfile_load_multiple_by_uid($account->uid, $payment_method['instance_id']);

  // Check for a remote ID.
  $remote_id = NULL;
  if (!empty($existing_cards)) {
    $existing_card = reset($existing_cards);
    $remote_id = $existing_card->remote_id;
  }
  if ($remote_id) {

    // Extract the profile id from the remote id.
    list($cim_customer_profile_id, $cim_customer_payment_id) = explode('|', $remote_id);

    // Build a request to add a new payment method to an existing profile.
    $api_request_data = array(
      'customerProfileId' => $cim_customer_profile_id,
      'paymentProfile' => array(
        'billTo' => $billto,
        'payment' => array(
          'creditCard' => array(
            'cardNumber' => $number,
            'expirationDate' => $card_expire,
            'cardCode' => $card_code,
          ),
        ),
      ),
    );
    $xml_response = commerce_authnet_cim_request($payment_method, 'createCustomerPaymentProfileRequest', $api_request_data);
  }
  else {

    // There isn't a profile ID to extract.
    $cim_customer_profile_id = NULL;

    // Build a request to create a profile and add payment method to it.
    $api_request_data = array(
      'profile' => array(
        'merchantCustomerId' => $account->uid,
        'description' => $billto['firstName'] . ' ' . $billto['lastName'],
        'email' => $account->mail,
        'paymentProfiles' => array(
          'billTo' => $billto,
          'payment' => array(
            'creditCard' => array(
              'cardNumber' => $number,
              'expirationDate' => $card_expire,
              'cardCode' => $card_code,
            ),
          ),
        ),
      ),
    );
    $xml_response = commerce_authnet_cim_request($payment_method, 'createCustomerProfileRequest', $api_request_data);
  }
  if ((string) $xml_response->messages->resultCode == 'Ok') {

    // Build a remote ID that includes the Customer Profile ID and the
    // Payment Profile ID.
    if ($cim_customer_profile_id) {
      $remote_id = $cim_customer_profile_id . '|' . (string) $xml_response->customerPaymentProfileId;
    }
    else {
      $remote_id = (string) $xml_response->customerProfileId . '|' . (string) $xml_response->customerPaymentProfileIdList->numericString;
    }
    $card_data_wrapper = entity_metadata_wrapper('commerce_cardonfile', $card_data);
    $card_data->uid = $account->uid;
    $card_data->remote_id = $remote_id;
    $card_data->card_type = $card_type;
    $card_data->card_name = $billto['firstName'] . ' ' . $billto['lastName'];
    $card_data->card_number = substr($number, -4);
    $card_data->status = 1;
    $card_data_wrapper->commerce_cardonfile_profile = $profile;
    return $card_data;
  }
  elseif ((string) $xml_response->messages->message->code == 'E00039') {

    // But if a Customer Profile already existed for this user, attempt
    // instead to add this card as a new Payment Profile to it.
    $result = array_filter(explode(' ', (string) $xml_response->messages->message->text), 'is_numeric');
    $add_to_profile = reset($result);

    // Build a request to add a new payment method to an existing profile.
    $api_request_data = array(
      'customerProfileId' => $add_to_profile,
      'paymentProfile' => array(
        'billTo' => $billto,
        'payment' => array(
          'creditCard' => array(
            'cardNumber' => $number,
            'expirationDate' => $card_expire,
            'cardCode' => $card_code,
          ),
        ),
      ),
    );
    $xml_response = commerce_authnet_cim_request($payment_method, 'createCustomerPaymentProfileRequest', $api_request_data);
    if ((string) $xml_response->messages->resultCode == 'Ok' || (string) $xml_response->messages->message->code == 'E00039') {

      // If we got a duplicate code, then the payment profile already exists
      // at Authorize.Net and needs to be represented locally.
      if ((string) $xml_response->messages->message->code == 'E00039') {
        $cim_profile_response = commerce_authnet_cim_get_customer_profile_request($payment_method, $add_to_profile);
        if ((string) $cim_profile_response->messages->resultCode == 'Ok') {

          // Inspect the returned payment profiles to find the one that
          // generated the duplicate error code.
          $cim_payment_profiles = $cim_profile_response->profile->paymentProfiles;
          if (!is_array($cim_payment_profiles)) {
            $cim_payment_profiles = array(
              $cim_payment_profiles,
            );
          }
          foreach ($cim_payment_profiles as $key => $payment_profile) {

            // We match the submitted values against the existing payment
            // profiles using the last 4 digits of the card number. This could
            // potentially create a conflict if the same customer has two
            // different cards that end in the same four digits, but that is
            // highly unlikely.
            if (substr($number, -4) == substr($payment_profile->payment->creditCard->cardNumber, -4)) {
              $payment_profile_id = (string) $payment_profile->customerPaymentProfileId;
              break;
            }
          }
        }
      }
      else {
        $payment_profile_id = (string) $xml_response->customerPaymentProfileId;
      }

      // Build a remote ID that includes the customer profile ID and the new
      // or existing payment profile ID. We don't do any check here to ensure
      // we found a payment profile ID, as we shouldn't have got a duplicate
      // error if it didn't actually exist.
      $remote_id = $add_to_profile . '|' . $payment_profile_id;
      $card_data_wrapper = entity_metadata_wrapper('commerce_cardonfile', $card_data);
      $card_data->uid = $account->uid;
      $card_data->remote_id = $remote_id;
      $card_data->card_type = $card_type;
      $card_data->card_name = $billto['firstName'] . ' ' . $billto['lastName'];
      $card_data->card_number = substr($number, -4);
      $card_data->status = 1;
      $card_data_wrapper->commerce_cardonfile_profile = $profile;
      return $card_data;
    }
    else {

      // Provide the user with information on the failure if it exists.
      if (!empty($xml_response->messages->message->text)) {
        drupal_set_message(t('Error: @error', array(
          '@error' => (string) $xml_response->messages->message->text,
        )), 'error');
      }
    }
  }
  return FALSE;
}