You are here

function uc_recurring_hosted_paypal_wpp_process in UC Recurring Payments and Subscriptions 7.2

Same name and namespace in other branches
  1. 6.2 modules/uc_recurring_hosted/uc_recurring_hosted.module \uc_recurring_hosted_paypal_wpp_process()

PayPal website payments pro process.

1 call to uc_recurring_hosted_paypal_wpp_process()
uc_recurring_hosted_paypal_wpp_profile_creation_form_submit in modules/uc_recurring_hosted/uc_recurring_hosted.module
@todo Please document this function.
1 string reference to 'uc_recurring_hosted_paypal_wpp_process'
uc_recurring_hosted_recurring_info in modules/uc_recurring_hosted/uc_recurring_hosted.module
Implements hook_recurring_info().

File

modules/uc_recurring_hosted/uc_recurring_hosted.module, line 669
Provides hosted gateway specific code for recurring payments, specifically Authorize.net ARB and Paypal WPS

Code

function uc_recurring_hosted_paypal_wpp_process($order, &$fee) {
  global $user;

  // Setup variables for the payment schedule.
  list($length, $unit) = explode(' ', $fee->regular_interval);
  list($trial_length, $trial_unit) = explode(' ', $fee->initial_charge);

  // Make sure we have valid values.
  if ($length <= 0 || $unit == 'days' && $length > 365 || $unit == 'months' && $length > 12 || $unit == 'semimonths' && $length > 24 || $unit == 'weeks' && $length > 52 || $unit == 'years' && $length > 1) {

    // Get a default SKU if none was supplied.
    if (empty($fee->model)) {
      $fee->model = db_query("SELECT model FROM {uc_products} WHERE nid = :nid", array(
        ':nid' => $fee->nid,
      ))
        ->fetchField();
    }
    watchdog('uc_recurring', 'Product @sku has invalid interval settings for PayPal - @length @unit', array(
      '@sku' => $fee->model,
      '@length' => $length,
      '@unit' => $unit,
    ), WATCHDOG_ERROR);
    return FALSE;
  }

  // 'weeks' => 'Week', etc. PayPal API allows billing period to be one of
  // Day, Week, SemiMonth, or Year.
  if ($unit == 'semimonth') {
    $unit = 'SemiMonth';
  }
  else {
    $unit = ucfirst(substr($unit, 0, -1));
  }
  if ($trial_unit == 'semimonth') {
    $trial_unit = 'SemiMonth';
  }
  else {
    $trial_unit = ucfirst(substr($trial_unit, 0, -1));
  }
  if ($fee->initial_charge) {
    $start_date = date(DATE_ATOM, strtotime('+ ' . $fee->initial_charge));
  }
  else {

    //the same as date(DATE_ATOM,$fee->next_charge)
    $start_date = date(DATE_ATOM, strtotime('+ ' . $fee->regular_interval));
  }
  $cc_type = '';
  if (isset($order->payment_details['cc_type'])) {
    switch (strtolower($order->payment_details['cc_type'])) {
      case 'amex':
      case 'american express':
        $cc_type = 'Amex';
        break;
      case 'visa':
        $cc_type = 'Visa';
        break;
      case 'mastercard':
      case 'master card':
        $cc_type = 'MasterCard';
        break;
      case 'discover':
        $cc_type = 'Discover';
        break;
    }
  }
  if (empty($cc_type)) {
    $cc_type = _uc_paypal_card_type($order->payment_details['cc_number']);
    if ($cc_type === FALSE) {
      drupal_set_message(t('The credit card type did not pass validation.'), 'error');
      watchdog('uc_recurring', 'Could not figure out credit card type @type', array(
        '@type' => $order->payment_details['cc_type'],
      ), WATCHDOG_ERROR);
      return FALSE;
    }
  }

  // Build an NVP request.
  // @link https://cms.paypal.com/us/cgi-bin/?&cmd=_render-content&content_ID=developer/e_howto_api_WPRecurringPayments @endlink
  $nvp_request = array(
    // Set the version required for recurring payments.
    'VERSION' => UC_PAYPAL_RECURRING_API,
    'METHOD' => 'CreateRecurringPaymentsProfile',
    'DESC' => 'Order ' . $order->order_id . ' at ' . check_plain(variable_get('uc_store_name', 'Ubercart')),
    'PROFILESTARTDATE' => $start_date,
    'PROFILEREFERENCE' => $order->order_id,
    'CREDITCARDTYPE' => $cc_type,
    'ACCT' => $order->payment_details['cc_number'],
    'EXPDATE' => date('mY', mktime(0, 0, 0, $order->payment_details['cc_exp_month'], 1, $order->payment_details['cc_exp_year'])),
    'BILLINGPERIOD' => $unit,
    'BILLINGFREQUENCY' => $length,
    // if TOTALBILLINGCYCLES = 0 the payments continue until the profile is
    // canceled or suspended.
    'TOTALBILLINGCYCLES' => $fee->remaining_intervals > 0 ? $fee->remaining_intervals : 0,
    'AMT' => round($fee->fee_amount, 2),
    'EMAIL' => substr($order->primary_email, 0, 127),
    // The number of scheduled payments that can fail before the profile is
    // automatically suspended.
    // TODO: Remove hardcoding.
    'MAXFAILEDPAYMENTS' => 1,
  );
  $nvp_request['CURRENCYCODE'] = variable_get('uc_paypal_wpp_currency', 'USD');

  // Add optional NVP request parameters.
  if (!empty($order->billing_first_name)) {
    $nvp_request['FIRSTNAME'] = substr($order->billing_first_name, 0, 25);
  }
  if (!empty($order->billing_last_name)) {
    $nvp_request['LASTNAME'] = substr($order->billing_last_name, 0, 25);
  }
  if (!empty($order->billing_street1)) {
    $nvp_request['STREET'] = substr($order->billing_street1, 0, 100);
  }
  if (!empty($order->billing_street2)) {
    $nvp_request['STREET2'] = substr($order->billing_street2, 0, 100);
  }
  if (!empty($order->billing_city)) {
    $nvp_request['CITY'] = substr($order->billing_city, 0, 40);
  }
  if (!empty($order->billing_country)) {
    $billing_country = uc_get_country_data(array(
      'country_id' => $order->billing_country,
    ));
    if ($billing_country === FALSE) {
      $billing_country = array(
        0 => array(
          'country_iso_code_2' => 'US',
        ),
      );
    }
    $nvp_request['COUNTRYCODE'] = $billing_country[0]['country_iso_code_2'];
    if (!empty($order->billing_zone)) {
      $nvp_request['STATE'] = uc_get_zone_code($order->billing_zone);
    }
  }
  if (!empty($order->billing_postal_code)) {
    $nvp_request['ZIP'] = check_plain($order->billing_postal_code);
  }
  if (!empty($order->billing_phone)) {
    $nvp_request['PHONENUM'] = substr($order->billing_phone, 0, 20);
  }

  // Only add trial if we have to wait to start payments. We make sure the trail
  // length is bigger then 1, otherwise the first month will be charged 0$.
  if ($trial_length > 1) {
    $nvp_request['TRIALBILLINGPERIOD'] = $trial_unit;
    $nvp_request['TRIALBILLINGFREQUENCY'] = $trial_length;
    $nvp_request['TRIALTOTALBILLINGCYCLES'] = 1;
    $nvp_request['TRIALAMT'] = 0;
  }
  if (variable_get('uc_credit_cvv_enabled', TRUE)) {
    $nvp_request['CVV2'] = $order->payment_details['cc_cvv'];
  }

  // Post the request, and parse the response.
  $nvp_response = uc_paypal_api_request($nvp_request, variable_get('uc_paypal_wpp_server', 'https://api-3t.sandbox.paypal.com/nvp'));
  $types = uc_credit_transaction_types();

  // Get the $amount and $data from the fee object.
  $amount = $fee->fee_amount;
  $data = $data = $fee->data;
  $context = array(
    'revision' => 'formatted-original',
    'type' => 'amount',
  );
  $options = array(
    'sign' => FALSE,
    'thou' => FALSE,
    'dec' => '.',
  );
  switch ($nvp_response['ACK']) {
    case 'SuccessWithWarning':
      watchdog('uc_payment', '<b>@type succeeded with a warning.</b>!paypal_message', array(
        '!paypal_message' => _uc_paypal_build_error_messages($nvp_response),
        '@type' => $types[$data['txn_type']],
      ), WATCHDOG_WARNING, l(t('view order'), 'admin/store/orders/' . $fee->order_id));

    // Fall through.
    case 'Success':
      $message = t('<b>PayPal Recurring Profile Setup</b><br /><b>Recurring Profile Amount: </b>@amount @currency<br /><b>Recurring Profile ID: </b>@profile_id', array(
        '@amount' => $nvp_request['AMT'],
        '@currency' => $nvp_request['CURRENCYCODE'],
        '@profile_id' => $nvp_response['PROFILEID'],
      ));
      $result = array(
        'success' => TRUE,
        'comment' => t('PayPal Recurring Payment Profile ID: @profile_id', array(
          '@profile_id' => $nvp_response['PROFILEID'],
        )),
        'message' => $message,
        'data' => check_plain($nvp_response['PROFILEID']),
        'uid' => $user->uid,
      );

      // We need to save the rfid, we don't have it yet.
      if (!property_exists($fee, 'rfid') || !$fee->rfid) {
        $fee->rfid = uc_recurring_fee_user_save($fee);
      }

      // Save the subscription so we have the information.
      uc_recurring_hosted_subscription_save($fee->rfid, $nvp_response['PROFILEID']);

      // Log the IPN to the database.
      // TODO Please review the conversion of this statement to the D7 database API syntax.

      /* db_query("INSERT INTO {uc_payment_paypal_ipn} (order_id, txn_id, txn_type, mc_gross, status, receiver_email, payer_email, received) VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', %d)", $order->order_id, $nvp_response['TRANSACTIONID'], 'web_accept', $amount, 'Completed', '', $order->primary_email, REQUEST_TIME) */
      $id = db_insert('uc_payment_paypal_ipn')
        ->fields(array(
        'order_id' => $order->order_id,
        'txn_id' => $nvp_response['CORRELATIONID'],
        'txn_type' => 'web_accept',
        'mc_gross' => $amount,
        'status' => 'Completed',
        'receiver_email' => '',
        'payer_email' => $order->primary_email,
        'received' => REQUEST_TIME,
      ))
        ->execute();
      break;
    case 'FailureWithWarning':

    // Fall through.
    case 'Failure':
      $message = t('<b>Recurring Payment Setup Failed.</b>') . _uc_paypal_build_error_messages($nvp_response);
      $result = array(
        'success' => FALSE,
        'message' => $message,
        'uid' => $user->uid,
      );
      break;
    default:
      $message = t('Unexpected acknowledgement status: @status', array(
        '@status' => $nvp_response['ACK'],
      ));
      $result = array(
        'success' => NULL,
        'message' => $message,
        'uid' => $user->uid,
      );
      break;
  }
  uc_order_comment_save($fee->order_id, $user->uid, $message, 'admin');

  // Log this only if payment money wasn't actually captured.
  if (!empty($result['success']) && !in_array($data['txn_type'], array(
    UC_CREDIT_AUTH_ONLY,
  ))) {

    // The transaction was successful. We need to populate some data in the
    // fee object, as we are now returning to uc_recurring_process_order()
    // and the result (e.g. the mesasge and the user ID) need to be passed back
    // to uc_payment_process().
    $fee->data['nvp result'] = $result;
  }
  return $result['success'];
}