You are here

protected function PayPalWebsitePaymentsPro::chargeCard in Ubercart 8.4

Called when a credit card should be processed.

@todo Replace the return array with a typed object.

Parameters

\Drupal\uc_order\OrderInterface $order: The order that is being processed. Credit card details supplied by the user are available in $order->payment_details[].

float $amount: The amount that should be charged.

string $txn_type: The transaction type, one of the UC_CREDIT_* constants.

string $reference: (optional) The payment reference, where needed for specific transaction types.

Return value

array Returns an associative array with the following members:

  • "success": TRUE if the transaction succeeded, FALSE otherwise.
  • "message": a human-readable message describing the result of the transaction.
  • "log_payment": TRUE if the transaction should be regarded as a successful payment.
  • "uid": The user ID of the person logging the payment, or 0 if the payment was processed automatically.
  • "comment": The comment string, markup allowed, to enter in the payment log.
  • "data": Any data that should be serialized and stored with the payment.

Overrides CreditCardPaymentMethodBase::chargeCard

File

payment/uc_paypal/src/Plugin/Ubercart/PaymentMethod/PayPalWebsitePaymentsPro.php, line 100

Class

PayPalWebsitePaymentsPro
Defines the PayPal Website Payments Pro payment method.

Namespace

Drupal\uc_paypal\Plugin\Ubercart\PaymentMethod

Code

protected function chargeCard(OrderInterface $order, $amount, $txn_type, $reference = NULL) {
  if ($txn_type == UC_CREDIT_PRIOR_AUTH_CAPTURE) {
    $nvp_request = [
      'METHOD' => 'DoCapture',
      'AUTHORIZATIONID' => $reference,
      'AMT' => uc_currency_format($amount, FALSE, FALSE, '.'),
      'CURRENCYCODE' => $order
        ->getCurrency(),
      'COMPLETETYPE' => 'Complete',
    ];
  }
  else {
    if (intval($order->payment_details['cc_exp_month']) < 10) {
      $expdate = '0' . $order->payment_details['cc_exp_month'] . $order->payment_details['cc_exp_year'];
    }
    else {
      $expdate = $order->payment_details['cc_exp_month'] . $order->payment_details['cc_exp_year'];
    }
    $cc_type = NULL;
    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 (is_null($cc_type)) {
      $cc_type = $this
        ->cardType($order->payment_details['cc_number']);
      if ($cc_type === FALSE) {
        $this
          ->messenger()
          ->addError($this
          ->t('The credit card type did not pass validation.'));
        \Drupal::logger('uc_paypal')
          ->error('Could not figure out cc type: @number / @type', [
          '@number' => $order->payment_details['cc_number'],
          '@type' => $order->payment_details['cc_type'],
        ]);
        return [
          'success' => FALSE,
        ];
      }
    }

    // PayPal doesn't accept IPv6 addresses.
    $ip_address = ltrim(\Drupal::request()
      ->getClientIp(), '::ffff:');
    $address = $order
      ->getAddress('billing');
    $nvp_request = [
      'METHOD' => 'DoDirectPayment',
      'PAYMENTACTION' => $txn_type == UC_CREDIT_AUTH_ONLY ? 'Authorization' : 'Sale',
      'IPADDRESS' => $ip_address,
      'AMT' => uc_currency_format($amount, FALSE, FALSE, '.'),
      'CREDITCARDTYPE' => $cc_type,
      'ACCT' => $order->payment_details['cc_number'],
      'EXPDATE' => $expdate,
      'CVV2' => $order->payment_details['cc_cvv'],
      'FIRSTNAME' => substr($address
        ->getFirstName(), 0, 25),
      'LASTNAME' => substr($address
        ->getLastName(), 0, 25),
      'STREET' => substr($address
        ->getStreet1(), 0, 100),
      'STREET2' => substr($address
        ->getStreet2(), 0, 100),
      'CITY' => substr($address
        ->getCity(), 0, 40),
      'STATE' => $address
        ->getZone(),
      'ZIP' => $address
        ->getPostalCode(),
      'COUNTRYCODE' => $address
        ->getCountry(),
      'CURRENCYCODE' => $order
        ->getCurrency(),
      'DESC' => $this
        ->t('Order @order_id at @store', [
        '@order_id' => $order
          ->id(),
        '@store' => uc_store_name(),
      ]),
      'INVNUM' => $order
        ->id() . '-' . REQUEST_TIME,
      'BUTTONSOURCE' => 'Ubercart_ShoppingCart_DP_US',
      'NOTIFYURL' => Url::fromRoute('uc_paypal.ipn', [], [
        'absolute' => TRUE,
      ])
        ->toString(),
      'EMAIL' => substr($order
        ->getEmail(), 0, 127),
      'PHONENUM' => substr($address
        ->getPhone(), 0, 20),
    ];
    if ($order
      ->isShippable()) {
      $address = $order
        ->getAddress('delivery');
      $nvp_request += [
        'SHIPTONAME' => substr($address
          ->getFirstName() . ' ' . $address
          ->getLastName(), 0, 25),
        'SHIPTOSTREET' => substr($address
          ->getStreet1(), 0, 100),
        'SHIPTOSTREET2' => substr($address
          ->getStreet2(), 0, 100),
        'SHIPTOCITY' => substr($address
          ->getCity(), 0, 40),
        'SHIPTOSTATE' => $address
          ->getZone(),
        'SHIPTOZIP' => $address
          ->getPostalCode(),
        'SHIPTOCOUNTRYCODE' => $address
          ->getCountry(),
      ];
    }
  }
  $nvp_response = $this
    ->sendNvpRequest($nvp_request);
  $types = uc_credit_transaction_types();
  switch ($nvp_response['ACK']) {
    case 'SuccessWithWarning':
      \Drupal::logger('uc_paypal')
        ->warning('<b>@type succeeded with a warning.</b>@paypal_message', [
        '@paypal_message' => $this
          ->buildErrorMessages($nvp_response),
        '@type' => $types[$txn_type],
        'link' => $order
          ->toLink($this
          ->t('view order'))
          ->toString(),
      ]);

    // Fall through.
    case 'Success':
      $message = $this
        ->t('<b>@type</b><br /><b>Success: </b>@amount @currency', [
        '@type' => $types[$txn_type],
        '@amount' => uc_currency_format($nvp_response['AMT'], FALSE),
        '@currency' => $nvp_response['CURRENCYCODE'],
      ]);
      if ($txn_type != UC_CREDIT_PRIOR_AUTH_CAPTURE) {
        $message .= '<br />' . $this
          ->t('<b>Address:</b> @avscode', [
          '@avscode' => $this
            ->avscodeMessage($nvp_response['AVSCODE']),
        ]);
        $message .= '<br />' . $this
          ->t('<b>CVV2:</b> @cvvmatch', [
          '@cvvmatch' => $this
            ->cvvmatchMessage($nvp_response['CVV2MATCH']),
        ]);
      }
      $result = [
        'success' => TRUE,
        'comment' => $this
          ->t('PayPal transaction ID: @transactionid', [
          '@transactionid' => $nvp_response['TRANSACTIONID'],
        ]),
        'message' => $message,
        'data' => [
          'module' => 'uc_paypal',
          'txn_id' => (string) SafeMarkup::checkPlain($nvp_response['TRANSACTIONID']),
        ],
        'uid' => \Drupal::currentUser()
          ->id(),
      ];

      // If this was an authorization only transaction...
      if ($txn_type == UC_CREDIT_AUTH_ONLY) {

        // Log the authorization to the order.
        uc_credit_log_authorization($order
          ->id(), $nvp_response['TRANSACTIONID'], $nvp_response['AMT']);
      }
      elseif ($txn_type == UC_CREDIT_PRIOR_AUTH_CAPTURE) {
        uc_credit_log_prior_auth_capture($order
          ->id(), $reference);
      }

      // Log the IPN to the database.
      $this->database
        ->insert('uc_payment_paypal_ipn')
        ->fields([
        'order_id' => $order
          ->id(),
        'txn_id' => $nvp_response['TRANSACTIONID'],
        'txn_type' => 'web_accept',
        'mc_gross' => $amount,
        'status' => 'Completed',
        'payer_email' => $order
          ->getEmail(),
        'received' => REQUEST_TIME,
      ])
        ->execute();
      break;
    case 'FailureWithWarning':

    // Fall through.
    case 'Failure':
      $message = $this
        ->t('<b>@type failed.</b>', [
        '@type' => $types[$txn_type],
      ]) . $this
        ->buildErrorMessages($nvp_response);
      $result = [
        'success' => FALSE,
        'message' => $message,
        'uid' => \Drupal::currentUser()
          ->id(),
      ];
      break;
    default:
      $message = $this
        ->t('Unexpected acknowledgement status: @status', [
        '@status' => $nvp_response['ACK'],
      ]);
      $result = [
        'success' => NULL,
        'message' => $message,
        'uid' => \Drupal::currentUser()
          ->id(),
      ];
      break;
  }
  uc_order_comment_save($order
    ->id(), \Drupal::currentUser()
    ->id(), $message, 'admin');

  // Don't log this as a payment money wasn't actually captured.
  if (in_array($txn_type, [
    UC_CREDIT_AUTH_ONLY,
  ])) {
    $result['log_payment'] = FALSE;
  }
  return $result;
}