You are here

function uc_payment_method_credit in Ubercart 6.2

Same name and namespace in other branches
  1. 5 payment/uc_credit/uc_credit.module \uc_payment_method_credit()
  2. 7.3 payment/uc_credit/uc_credit.module \uc_payment_method_credit()

Callback function for the Credit Card payment method.

1 call to uc_payment_method_credit()
uc_credit_form_alter in payment/uc_credit/uc_credit.module
Implements hook_form_alter().
1 string reference to 'uc_payment_method_credit'
uc_credit_payment_method in payment/uc_credit/uc_credit.module
Implements hook_payment_method().

File

payment/uc_credit/uc_credit.module, line 426
Defines the credit card payment method and hooks in payment gateways.

Code

function uc_payment_method_credit($op, &$arg1, $silent = FALSE) {
  switch ($op) {
    case 'cart-details':
      $details = drupal_get_form('uc_payment_method_credit_form', $arg1);
      return uc_strip_form($details);
    case 'cart-process':

      // Fetch the CC details from the $_POST directly.
      $cc_data = array(
        'cc_type' => isset($_POST['cc_type']) ? $_POST['cc_type'] : '',
        'cc_owner' => isset($_POST['cc_owner']) ? $_POST['cc_owner'] : '',
        'cc_number' => str_replace(' ', '', $_POST['cc_number']),
        'cc_start_month' => isset($_POST['cc_start_month']) ? $_POST['cc_start_month'] : '',
        'cc_start_year' => isset($_POST['cc_start_year']) ? $_POST['cc_start_year'] : '',
        'cc_exp_month' => $_POST['cc_exp_month'],
        'cc_exp_year' => $_POST['cc_exp_year'],
        'cc_issue' => isset($_POST['cc_issue']) ? $_POST['cc_issue'] : '',
        'cc_cvv' => $_POST['cc_cvv'],
        'cc_bank' => isset($_POST['cc_bank']) ? $_POST['cc_bank'] : '',
      );

      // Recover cached CC data in $_POST if it exists.
      if (isset($_POST['payment_details_data'])) {
        $cache = uc_credit_cache('save', $_POST['payment_details_data']);
      }

      // Account for partial CC numbers when masked by the system.
      if (substr($cc_data['cc_number'], 0, strlen(t('(Last4)'))) == t('(Last4)')) {

        // Recover the number from the encrypted data in $_POST if truncated.
        if (isset($cache['cc_number'])) {
          $cc_data['cc_number'] = $cache['cc_number'];
        }
        else {
          $cc_data['cc_number'] = '';
        }
      }

      // Account for masked CVV numbers.
      if (!empty($cc_data['cc_cvv']) && $cc_data['cc_cvv'] == str_repeat('-', strlen($cc_data['cc_cvv']))) {

        // Recover the number from the encrypted data in $_POST if truncated.
        if (isset($cache['cc_cvv'])) {
          $cc_data['cc_cvv'] = $cache['cc_cvv'];
        }
        else {
          $cc_data['cc_cvv'] = '';
        }
      }

      // Go ahead and put the CC data in the payment details array.
      $arg1->payment_details = $cc_data;

      // Default our value for validation.
      $return = TRUE;

      // Make sure an owner value was entered.
      if (variable_get('uc_credit_owner_enabled', FALSE) && empty($cc_data['cc_owner'])) {
        if (!$silent) {
          drupal_set_message(t('Enter the owner name as it appears on the card.'), 'error');
        }
        $return = FALSE;
      }

      // Validate the CC number if that's turned on/check for non-digits.
      if (variable_get('uc_credit_validate_numbers', TRUE) && !_valid_card_number($cc_data['cc_number']) || !ctype_digit($cc_data['cc_number'])) {
        if (!$silent) {
          drupal_set_message(t('You have entered an invalid credit card number.'), 'error');
        }
        $return = FALSE;
      }

      // Validate the start date (if entered).
      if (variable_get('uc_credit_start_enabled', FALSE) && !_valid_card_start($cc_data['cc_start_month'], $cc_data['cc_start_year'])) {
        if (!$silent) {
          drupal_set_message(t('The start date you entered is invalid.'), 'error');
        }
        $return = FALSE;
      }

      // Validate the card expiration date.
      if (!_valid_card_expiration($cc_data['cc_exp_month'], $cc_data['cc_exp_year'])) {
        if (!$silent) {
          drupal_set_message(t('The credit card you entered has expired.'), 'error');
        }
        $return = FALSE;
      }

      // Validate the issue number (if entered).  With issue numbers, '01' is
      // different from '1', but is_numeric() is still appropriate.
      if (variable_get('uc_credit_issue_enabled', FALSE) && !_valid_card_issue($cc_data['cc_issue'])) {
        if (!$silent) {
          drupal_set_message(t('The issue number you entered is invalid.'), 'error');
        }
        $return = FALSE;
      }

      // Validate the CVV number if enabled.
      if (variable_get('uc_credit_cvv_enabled', TRUE) && !_valid_cvv($cc_data['cc_cvv'])) {
        if (!$silent) {
          drupal_set_message(t('You have entered an invalid CVV number.'), 'error');
        }
        $return = FALSE;
      }

      // Validate the bank name if enabled.
      if (variable_get('uc_credit_bank_enabled', FALSE) && empty($cc_data['cc_bank'])) {
        if (!$silent) {
          drupal_set_message(t('You must enter the issuing bank for that card.'), 'error');
        }
        $return = FALSE;
      }

      // Initialize the encryption key and class.
      $key = uc_credit_encryption_key();
      $crypt = new uc_encryption_class();

      // Store the encrypted details in the session for the next pageload.
      // We are using base64_encode() because the encrypt function works with a
      // limited set of characters, not supporting the full Unicode character
      // set or even extended ASCII characters that may be present.
      // base64_encode() converts everything to a subset of ASCII, ensuring that
      // the encryption algorithm does not mangle names.
      $_SESSION['sescrd'] = $crypt
        ->encrypt($key, base64_encode(serialize($arg1->payment_details)));

      // Log any errors to the watchdog.
      uc_store_encryption_errors($crypt, 'uc_credit');

      // If we're going to the review screen, set a variable that lets us know
      // we're paying by CC.
      if ($return) {
        $_SESSION['cc_pay'] = TRUE;
      }
      return $return;
    case 'cart-review':
      if (variable_get('uc_credit_type_enabled', FALSE)) {
        $review[] = array(
          'title' => t('Card Type'),
          'data' => check_plain($arg1->payment_details['cc_type']),
        );
      }
      if (variable_get('uc_credit_owner_enabled', FALSE)) {
        $review[] = array(
          'title' => t('Card Owner'),
          'data' => check_plain($arg1->payment_details['cc_owner']),
        );
      }
      $review[] = array(
        'title' => t('Card Number'),
        'data' => uc_credit_display_number($arg1->payment_details['cc_number']),
      );
      if (variable_get('uc_credit_start_enabled', FALSE)) {
        $start = check_plain($arg1->payment_details['cc_start_month'] . '/' . $arg1->payment_details['cc_start_year']);
        $review[] = array(
          'title' => t('Start Date'),
          'data' => strlen($start) > 1 ? $start : '',
        );
      }
      $review[] = array(
        'title' => t('Expiration'),
        'data' => check_plain($arg1->payment_details['cc_exp_month'] . '/' . $arg1->payment_details['cc_exp_year']),
      );
      if (variable_get('uc_credit_issue_enabled', FALSE)) {
        $review[] = array(
          'title' => t('Issue Number'),
          'data' => user_access('view cc numbers') ? check_plain($arg1->payment_details['cc_issue']) : str_repeat('-', strlen($arg1->payment_details['cc_issue'])),
        );
      }
      if (variable_get('uc_credit_cvv_enabled', TRUE)) {
        $review[] = array(
          'title' => t('CVV'),
          'data' => user_access('view cc numbers') ? check_plain($arg1->payment_details['cc_cvv']) : str_repeat('-', strlen($arg1->payment_details['cc_cvv'])),
        );
      }
      if (variable_get('uc_credit_bank_enabled', FALSE)) {
        $review[] = array(
          'title' => t('Issuing Bank'),
          'data' => check_plain($arg1->payment_details['cc_bank']),
        );
      }
      return $review;
    case 'order-view':
      $output = '';

      // Add the hidden span for the CC details if possible.
      if (user_access('view cc details')) {
        drupal_add_js(drupal_get_path('module', 'uc_credit') . '/uc_credit.js');
        $output .= '<span onclick="toggle_card_details();" style="cursor: pointer;">' . '<a id="cc_details_title" href="" onclick="return false;" style="display: none;">' . t('View card details.') . '</a>';
        $output .= '<span id="cc_details"><table style="width: auto;">';
        if (variable_get('uc_credit_type_enabled', TRUE)) {
          $type = check_plain($arg1->payment_details['cc_type']);
          if (strlen($type) > 0) {
            $output .= '<tr><td>' . t('Card Type:') . ' </td><td>' . $type . '</td></tr>';
          }
        }
        if (variable_get('uc_credit_owner_enabled', FALSE) && isset($arg1->payment_details['cc_owner'])) {
          $owner = check_plain($arg1->payment_details['cc_owner']);
          if (strlen($owner) > 0) {
            $output .= '<tr><td>' . t('Card Owner:') . ' </td><td>' . $owner . '</td></tr>';
          }
        }
        $output .= '<tr><td>' . t('Card Number:') . ' </td><td>' . uc_credit_display_number($arg1->payment_details['cc_number']) . '</td></tr>';
        $exp = check_plain($arg1->payment_details['cc_exp_month'] . '/' . $arg1->payment_details['cc_exp_year']);
        if (strlen($exp) > 1) {
          $output .= '<tr><td>' . t('Expiration:') . ' </td><td>' . $exp . '</td></tr>';
        }
        if (variable_get('uc_credit_debug', FALSE)) {
          if (variable_get('uc_credit_start_enabled', FALSE) && isset($arg1->payment_details['cc_start_month']) && isset($arg1->payment_details['cc_start_year'])) {
            $start = check_plain($arg1->payment_details['cc_start_month'] . '/' . $arg1->payment_details['cc_start_year']);
            if (strlen($start) > 1) {
              $output .= '<tr><td>' . t('Start Date:') . ' </td><td>' . $start . '</td></tr>';
            }
          }
          if (variable_get('uc_credit_issue_enabled', FALSE) && isset($arg1->payment_details['cc_issue'])) {
            $issue = check_plain($arg1->payment_details['cc_issue']);
            if (strlen($issue) > 0) {
              $output .= '<tr><td>' . t('Issue Number:') . ' </td><td>' . $issue . '</td></tr>';
            }
          }
          if (variable_get('uc_credit_cvv_enabled', TRUE) && isset($arg1->payment_details['cc_cvv'])) {
            $cvv = user_access('view cc numbers') ? check_plain($arg1->payment_details['cc_cvv']) : str_repeat('-', strlen($arg1->payment_details['cc_cvv']));
            if (strlen($cvv) > 0) {
              $output .= '<tr><td>' . t('CVV:') . ' </td><td>' . $cvv . '</td></tr>';
            }
          }
          if (variable_get('uc_credit_bank_enabled', TRUE) && isset($arg1->payment_details['cc_bank'])) {
            $bank = check_plain($arg1->payment_details['cc_bank']);
            if (strlen($bank) > 0) {
              $output .= '<tr><td>' . t('Issuing Bank:') . ' </td><td>' . $bank . '</td></tr>';
            }
          }
        }
        $output .= '</table></span></span>';

        // Add the form to process the card if applicable.
        if (user_access('process credit cards')) {
          $output .= drupal_get_form('uc_credit_order_view_form', $arg1->order_id);
        }
      }
      return $output;
    case 'customer-view':
      $output = t('Card Number:') . '<br />' . uc_credit_display_number($arg1->payment_details['cc_number'], TRUE);
      return $output;
    case 'order-details':
      if (variable_get('uc_credit_debug', FALSE)) {
        $details = drupal_get_form('uc_payment_method_credit_form', $arg1);
        return uc_strip_form($details);
      }
      else {
        return t('Use the terminal available through the<br />%button button on the View tab to<br />process credit card payments.', array(
          '%button' => t('Process card'),
        ));
      }
    case 'edit-process':
      if (!variable_get('uc_credit_debug', FALSE)) {
        return;
      }
      $cache = uc_credit_cache('load');
      $changes['payment_details']['cc_type'] = $_POST['cc_type'];
      $changes['payment_details']['cc_owner'] = $_POST['cc_owner'];
      if (strpos($_POST['cc_number'], t('(Last 4) ')) !== 0) {
        $changes['payment_details']['cc_number'] = $_POST['cc_number'];
      }
      else {
        $changes['payment_details']['cc_number'] = $cache['cc_number'];
      }
      $changes['payment_details']['cc_exp_month'] = $_POST['cc_exp_month'];
      $changes['payment_details']['cc_exp_year'] = $_POST['cc_exp_year'];
      if ($_POST['cc_cvv'] !== str_repeat('-', strlen($_POST['cc_cvv']))) {
        $changes['payment_details']['cc_cvv'] = $_POST['cc_cvv'];
      }
      else {
        $changes['payment_details']['cc_cvv'] = isset($cache['cc_cvv']) ? $cache['cc_cvv'] : '';
      }
      $changes['payment_details']['cc_bank'] = $_POST['cc_bank'];
      return $changes;
    case 'settings':
      if (!user_access('administer credit cards')) {
        $form['notice'] = array(
          '#value' => '<div>' . t('You must have access to <b>administer credit cards</b> to adjust these settings.') . '</div>',
        );
        return $form;
      }

      // Form elements that deal specifically with card number security.
      $form['cc_security'] = array(
        '#type' => 'fieldset',
        '#title' => t('Credit card data security'),
        '#description' => t('You are responsible for the security of your website, including the protection of credit card numbers.  Please be aware that choosing some settings in this section may decrease the security of credit card data on your website and increase your liability for damages in the case of fraud.'),
        '#collapsible' => FALSE,
      );
      $form['cc_security']['uc_credit_encryption_path'] = array(
        '#type' => 'textfield',
        '#title' => t('Encryption key directory'),
        '#description' => t('The card type, expiration date and last four digits of the card number are encrypted and stored temporarily while the customer is in the process of checking out.<br /><b>You must enable encryption</b> by following the <a href="!url">encryption instructions</a> in order to accept credit card payments.<br />In short, you must enter the path of a directory outside of your document root where the encryption key may be stored.<br />Relative paths will be resolved relative to the Drupal installation directory.<br />Once this directory is set, you should not change it.', array(
          '!url' => 'http://drupal.org/node/1309226',
        )),
        '#default_value' => uc_credit_encryption_key() ? variable_get('uc_credit_encryption_path', t('Not configured.')) : t('Not configured.'),
      );
      $form['cc_security']['uc_credit_debug'] = array(
        '#type' => 'checkbox',
        '#title' => t('Operate in credit card debug mode.'),
        '#description' => t('In debug mode, the full credit card number is stored which may be in violation of PCI security standards.<br />Debug mode is only recommended for testing transactions with fake credit card details.'),
        '#default_value' => variable_get('uc_credit_debug', FALSE),
      );

      // Form elements that deal with the credit card workflow during checkout.
      $form['cc_workflow'] = array(
        '#type' => 'fieldset',
        '#title' => t('Checkout workflow'),
        '#description' => t('These settings alter the way credit card data is collected and used during checkout.'),
        '#collapsible' => FALSE,
      );
      $form['cc_workflow']['uc_credit_validate_numbers'] = array(
        '#type' => 'checkbox',
        '#title' => t('Validate credit card numbers at checkout.'),
        '#description' => t('Invalid card numbers will show an error message to the user so they can correct it.<br />This feature is recommended unless you are in debug mode.'),
        '#default_value' => variable_get('uc_credit_validate_numbers', TRUE),
      );
      $form['cc_workflow']['uc_credit_checkout_process'] = array(
        '#type' => 'checkbox',
        '#title' => t('Attempt to process credit card payments at checkout.'),
        '#description' => t('Failed attempts will prevent checkout completion and display the error message from above.<br />This box must be checked to process customer credit cards if you are not in debug mode.'),
        '#default_value' => variable_get('uc_credit_checkout_process', TRUE),
      );

      // Form elements to handle the automatic clearing of card data.
      $form['cc_clear'] = array(
        '#type' => 'fieldset',
        '#title' => t('Debug mode data clearing'),
        '#description' => t('Specify below the status and age of orders whose credit card details will be removed.  This setting only applies when operating in debug mode. <strong>Cron must be running for this feature to work.</strong>', array(
          '!url' => url('admin/store/settings/cart/edit'),
        )),
        '#collapsible' => FALSE,
      );
      foreach (uc_order_status_list() as $status) {
        $options[$status['id']] = $status['title'];
      }
      $form['cc_clear']['uc_credit_clear_status'] = array(
        '#type' => 'select',
        '#title' => t('Order status'),
        '#options' => $options,
        '#default_value' => variable_get('uc_credit_clear_status', uc_order_state_default('completed')),
        '#prefix' => '<div style="float: left; margin-right: 1em;">',
        '#suffix' => '</div>',
      );
      $form['cc_clear']['uc_credit_number_duration'] = array(
        '#type' => 'select',
        '#title' => t('Age'),
        '#options' => drupal_map_assoc(range(1, 24)),
        '#default_value' => variable_get('uc_credit_number_duration', '3'),
        '#prefix' => '<div style="float: left; margin-right: 1em;">',
        '#suffix' => '</div>',
      );
      $form['cc_clear']['uc_credit_number_unit'] = array(
        '#type' => 'select',
        '#title' => t('Unit of time'),
        '#options' => array(
          'hours' => t('hour(s)'),
          'days' => t('day(s)'),
          'weeks' => t('week(s)'),
          'years' => t('year(s)'),
        ),
        '#default_value' => variable_get('uc_credit_number_unit', 'days'),
        '#prefix' => '<div style="float: left;">',
        '#suffix' => '</div>',
      );

      // Form elements that deal with the type of data requested at checkout.
      $form['cc_fields'] = array(
        '#type' => 'fieldset',
        '#title' => t('Credit card fields'),
        '#description' => t('Specify what information to collect from customers in addition to the card number.'),
        '#collapsible' => FALSE,
      );
      $form['cc_fields']['uc_credit_cvv_enabled'] = array(
        '#type' => 'checkbox',
        '#title' => t('Enable CVV text field on checkout form.'),
        '#description' => t('The CVV is an added security measure on credit cards. On Visa, Mastercard, and Discover cards it is a three digit number, and on AmEx cards it is a four digit number. If your credit card processor or payment gateway requires this information, you should enable this feature here.'),
        '#default_value' => variable_get('uc_credit_cvv_enabled', TRUE),
      );
      $form['cc_fields']['uc_credit_owner_enabled'] = array(
        '#type' => 'checkbox',
        '#title' => t('Enable card owner text field on checkout form.'),
        '#default_value' => variable_get('uc_credit_owner_enabled', FALSE),
      );
      $form['cc_fields']['uc_credit_start_enabled'] = array(
        '#type' => 'checkbox',
        '#title' => t('Enable card start date on checkout form.'),
        '#default_value' => variable_get('uc_credit_start_enabled', FALSE),
      );
      $form['cc_fields']['uc_credit_issue_enabled'] = array(
        '#type' => 'checkbox',
        '#title' => t('Enable card issue number text field on checkout form.'),
        '#default_value' => variable_get('uc_credit_issue_enabled', FALSE),
      );
      $form['cc_fields']['uc_credit_bank_enabled'] = array(
        '#type' => 'checkbox',
        '#title' => t('Enable issuing bank text field on checkout form.'),
        '#default_value' => variable_get('uc_credit_bank_enabled', FALSE),
      );
      $form['cc_fields']['uc_credit_type_enabled'] = array(
        '#type' => 'checkbox',
        '#title' => t('Enable card type selection on checkout form.'),
        '#description' => t('If enabled, specify in the textarea below which card options to populate the select box with.'),
        '#default_value' => variable_get('uc_credit_type_enabled', FALSE),
      );
      $form['cc_fields']['uc_credit_accepted_types'] = array(
        '#type' => 'textarea',
        '#title' => t('Card type select box options'),
        '#description' => t('Enter one card type per line. These fields will populate the card type select box if it is enabled.'),
        '#default_value' => variable_get('uc_credit_accepted_types', implode("\r\n", array(
          t('Visa'),
          t('Mastercard'),
          t('Discover'),
          t('American Express'),
        ))),
        '#wysiwyg' => FALSE,
      );

      // From elements that deal with card types accepted.
      $form['cc_types'] = array(
        '#type' => 'fieldset',
        '#title' => t('Accepted card types (for validation)'),
        '#description' => t('Use the checkboxes to specify which card types you accept for payment. Selected card types will show their icons in the payment method selection list and be used for card number validation.'),
      );
      $form['cc_types']['uc_credit_visa'] = array(
        '#type' => 'checkbox',
        '#title' => t('Visa'),
        '#default_value' => variable_get('uc_credit_visa', TRUE),
      );
      $form['cc_types']['uc_credit_mastercard'] = array(
        '#type' => 'checkbox',
        '#title' => t('Mastercard'),
        '#default_value' => variable_get('uc_credit_mastercard', TRUE),
      );
      $form['cc_types']['uc_credit_discover'] = array(
        '#type' => 'checkbox',
        '#title' => t('Discover'),
        '#default_value' => variable_get('uc_credit_discover', TRUE),
      );
      $form['cc_types']['uc_credit_amex'] = array(
        '#type' => 'checkbox',
        '#title' => t('American Express'),
        '#default_value' => variable_get('uc_credit_amex', TRUE),
      );

      // Form elements that deal with credit card messages to customers.
      $form['cc_messages'] = array(
        '#type' => 'fieldset',
        '#title' => t('Customer messages'),
        '#description' => t('Here you can alter messages displayed to customers using credit cards.'),
        '#collapsible' => FALSE,
      );
      $form['cc_messages']['uc_credit_policy'] = array(
        '#type' => 'textarea',
        '#title' => t('Credit card payment policy'),
        '#description' => t('Instructions for customers on the checkout page above the credit card fields.'),
        '#default_value' => variable_get('uc_credit_policy', t('Your billing information must match the billing address for the credit card entered below or we will be unable to process your payment.')),
        '#rows' => 3,
      );
      $form['cc_messages']['uc_credit_fail_message'] = array(
        '#type' => 'textarea',
        '#title' => t('Card processing failure message'),
        '#description' => t('Error message displayed to customers when an attempted payment fails at checkout.'),
        '#default_value' => variable_get('uc_credit_fail_message', t('We were unable to process your credit card payment. Please verify your details and try again.  If the problem persists, contact us to complete your order.')),
      );
      return $form;
  }
}