You are here

public function ExpressCheckout::onReturn in Commerce PayPal 8

Processes the "return" request.

This method should only be concerned with creating/completing payments, the parent order does not need to be touched. The order state is updated automatically when the order is paid in full, or manually by the merchant (via the admin UI).

Parameters

\Drupal\commerce_order\Entity\OrderInterface $order: The order.

\Symfony\Component\HttpFoundation\Request $request: The request.

Throws

\Drupal\commerce_payment\Exception\PaymentGatewayException Thrown when the request is invalid or the payment failed.

Overrides OffsitePaymentGatewayBase::onReturn

File

src/Plugin/Commerce/PaymentGateway/ExpressCheckout.php, line 216

Class

ExpressCheckout
Provides the Paypal Express Checkout payment gateway.

Namespace

Drupal\commerce_paypal\Plugin\Commerce\PaymentGateway

Code

public function onReturn(OrderInterface $order, Request $request) {
  $order_express_checkout_data = $order
    ->getData('paypal_express_checkout');
  if (empty($order_express_checkout_data['token'])) {
    throw new PaymentGatewayException('Token data missing for this PayPal Express Checkout transaction.');
  }

  // GetExpressCheckoutDetails API Operation (NVP).
  // Shows information about an Express Checkout transaction.
  $paypal_response = $this
    ->getExpressCheckoutDetails($order);

  // If the request failed, exit now with a failure message.
  if ($paypal_response['ACK'] == 'Failure') {
    throw new PaymentGatewayException($paypal_response['PAYMENTREQUESTINFO_0_LONGMESSAGE'], $paypal_response['PAYMENTREQUESTINFO_n_ERRORCODE']);
  }

  // Set the Payer ID used to finalize payment.
  $order_express_checkout_data['payerid'] = $paypal_response['PAYERID'];

  // Note: There is no need to save the order here, because it will be
  // saved by the Commerce PaymentController after onReturn() completes.
  $order
    ->setData('paypal_express_checkout', $order_express_checkout_data);

  // If the user is anonymous, add their PayPal e-mail to the order.
  if (empty($order->mail)) {
    $order
      ->setEmail($paypal_response['EMAIL']);
  }

  // DoExpressCheckoutPayment API Operation (NVP).
  // Completes an Express Checkout transaction.
  $paypal_response = $this
    ->doExpressCheckoutDetails($order);

  // Nothing to do for failures for now - no payment saved.
  if (isset($paypal_response['PAYMENTINFO_0_PAYMENTSTATUS']) && $paypal_response['PAYMENTINFO_0_PAYMENTSTATUS'] == 'Failed') {
    throw new PaymentGatewayException($paypal_response['PAYMENTINFO_0_LONGMESSAGE'], $paypal_response['PAYMENTINFO_0_ERRORCODE']);
  }
  if ($paypal_response['ACK'] == 'Failure') {

    // When a buyer's funding source fails, the DoExpressCheckoutPayment and
    // DoAuthorization call, a 10486 error is returned.
    // @link https://developer.paypal.com/docs/classic/express-checkout/ht_ec_fundingfailure10486/
    if (isset($paypal_response['L_ERRORCODE0']) && $paypal_response['L_ERRORCODE0'] == "10486") {
      $message = $paypal_response['L_LONGMESSAGE0'];
      throw new PaymentGatewayException("{$message} Express Checkout payment failed due to a bad funding source; it is possible that the transaction exceeded the buyer's card limit.", $paypal_response['L_ERRORCODE0']);
    }
    throw new PaymentGatewayException($paypal_response['L_LONGMESSAGE0'], $paypal_response['L_ERRORCODE0']);
  }
  $payment_storage = $this->entityTypeManager
    ->getStorage('commerce_payment');
  $payment = $payment_storage
    ->create([
    'state' => 'authorization',
    'amount' => $order
      ->getTotalPrice(),
    'payment_gateway' => $this->entityId,
    'order_id' => $order
      ->id(),
    'remote_id' => $paypal_response['PAYMENTINFO_0_TRANSACTIONID'],
    'remote_state' => $paypal_response['PAYMENTINFO_0_PAYMENTSTATUS'],
  ]);
  $status_mapping = $this
    ->getStatusMapping();
  if (isset($status_mapping[$paypal_response['PAYMENTINFO_0_PAYMENTSTATUS']])) {
    $payment
      ->setState($status_mapping[$paypal_response['PAYMENTINFO_0_PAYMENTSTATUS']]);
  }
  $payment
    ->save();
}