class PayPalExpressCheckout in Ubercart 8.4
Defines the PayPal Express Checkout payment method.
Plugin annotation
@UbercartPaymentMethod(
id = "paypal_ec",
name = @Translation("PayPal Express Checkout")
)
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements DerivativeInspectionInterface, PluginInspectionInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
- class \Drupal\uc_payment\PaymentMethodPluginBase implements ContainerFactoryPluginInterface, PaymentMethodPluginInterface
- class \Drupal\uc_paypal\Plugin\Ubercart\PaymentMethod\PayPalPaymentMethodPluginBase
- class \Drupal\uc_paypal\Plugin\Ubercart\PaymentMethod\PayPalExpressCheckout implements ExpressPaymentMethodPluginInterface, OffsitePaymentMethodPluginInterface
- class \Drupal\uc_paypal\Plugin\Ubercart\PaymentMethod\PayPalPaymentMethodPluginBase
- class \Drupal\uc_payment\PaymentMethodPluginBase implements ContainerFactoryPluginInterface, PaymentMethodPluginInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
Expanded class hierarchy of PayPalExpressCheckout
File
- payment/
uc_paypal/ src/ Plugin/ Ubercart/ PaymentMethod/ PayPalExpressCheckout.php, line 22
Namespace
Drupal\uc_paypal\Plugin\Ubercart\PaymentMethodView source
class PayPalExpressCheckout extends PayPalPaymentMethodPluginBase implements ExpressPaymentMethodPluginInterface, OffsitePaymentMethodPluginInterface {
/**
* The payment method entity ID that is using this plugin.
*
* @var string
*/
protected $methodId;
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return parent::defaultConfiguration() + [
'ec_landingpage_style' => 'Billing',
'ec_rqconfirmed_addr' => FALSE,
'ec_review_shipping' => TRUE,
'ec_review_company' => TRUE,
'ec_review_phone' => TRUE,
'ec_review_comment' => TRUE,
'wpp_cc_txn_type' => 'Sale',
];
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
// Generic PayPal settings from base class.
$form = parent::buildConfigurationForm($form, $form_state);
// Express Checkout specific settings.
$form['ec_landingpage_style'] = [
'#type' => 'radios',
'#title' => $this
->t('Default PayPal landing page'),
'#options' => [
'Billing' => $this
->t('Credit card submission form.'),
'Login' => $this
->t('Account login form.'),
],
'#default_value' => $this->configuration['ec_landingpage_style'],
];
$form['ec_rqconfirmed_addr'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Require Express Checkout users to use a PayPal confirmed shipping address.'),
'#default_value' => $this->configuration['ec_rqconfirmed_addr'],
];
$form['ec_review_shipping'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Enable the shipping select form on the Review payment page.'),
'#default_value' => $this->configuration['ec_review_shipping'],
];
$form['ec_review_company'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Enable the company name box on the Review payment page.'),
'#default_value' => $this->configuration['ec_review_company'],
];
$form['ec_review_phone'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Enable the contact phone number box on the Review payment page.'),
'#default_value' => $this->configuration['ec_review_phone'],
];
$form['ec_review_comment'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Enable the comment text box on the Review payment page.'),
'#default_value' => $this->configuration['ec_review_comment'],
];
$form['wpp_cc_txn_type'] = [
'#type' => 'radios',
'#title' => $this
->t('Payment action'),
'#description' => $this
->t('"Complete sale" will authorize and capture the funds at the time the payment is processed.<br>"Authorization" will only reserve funds on the card to be captured later through your PayPal account.'),
'#options' => [
'Sale' => $this
->t('Complete sale'),
'Authorization' => $this
->t('Authorization'),
],
'#default_value' => $this->configuration['wpp_cc_txn_type'],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->configuration['ec_landingpage_style'] = $form_state
->getValue('ec_landingpage_style');
$this->configuration['ec_rqconfirmed_addr'] = $form_state
->getValue('ec_rqconfirmed_addr');
$this->configuration['ec_review_shipping'] = $form_state
->getValue('ec_review_shipping');
$this->configuration['ec_review_company'] = $form_state
->getValue('ec_review_company');
$this->configuration['ec_review_phone'] = $form_state
->getValue('ec_review_phone');
$this->configuration['ec_review_comment'] = $form_state
->getValue('ec_review_comment');
$this->configuration['wpp_cc_txn_type'] = $form_state
->getValue('wpp_cc_txn_type');
parent::submitConfigurationForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function orderView(OrderInterface $order) {
$txn_id = $this->database
->query("SELECT txn_id FROM {uc_payment_paypal_ipn} WHERE order_id = :id ORDER BY received ASC", [
':id' => $order
->id(),
])
->fetchField();
if (empty($txn_id)) {
$txn_id = $this
->t('Unknown');
}
$build['#markup'] = $this
->t('Transaction ID:<br />@txn_id', [
'@txn_id' => $txn_id,
]);
return $build;
}
/**
* Redirect to PayPal Express Checkout Mark Flow.
*
* This is used when the user does not use the cart button, but follows the
* normal checkout process and selects Express Checkout as a payment method.
*
* @param array $form
* An associative array containing the structure of the form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current state of the form.
* @param \Drupal\uc_order\OrderInterface $order
* The order that is being processed.
*
* @return array
* The form structure.
*/
public function buildRedirectForm(array $form, FormStateInterface $form_state, OrderInterface $order = NULL) {
$session = \Drupal::service('session');
if ($session
->has('TOKEN') && $session
->has('PAYERID')) {
// If the session variables are set, then the user already gave their
// details via Shortcut Flow, so we do not need to redirect them here.
return [];
}
$address = $order
->getAddress('delivery');
$request = [
'METHOD' => 'SetExpressCheckout',
'RETURNURL' => Url::fromRoute('uc_paypal.ec_complete', [], [
'absolute' => TRUE,
])
->toString(),
'CANCELURL' => Url::fromRoute('uc_cart.checkout_review', [], [
'absolute' => TRUE,
])
->toString(),
'AMT' => uc_currency_format($order
->getTotal(), FALSE, FALSE, '.'),
'CURRENCYCODE' => $order
->getCurrency(),
'PAYMENTACTION' => $this->configuration['wpp_cc_txn_type'],
'DESC' => $this
->t('Order @order_id at @store', [
'@order_id' => $order
->id(),
'@store' => uc_store_name(),
]),
'INVNUM' => $order
->id() . '-' . REQUEST_TIME,
'REQCONFIRMSHIPPING' => $this->configuration['ec_rqconfirmed_addr'],
'ADDROVERRIDE' => 1,
'BUTTONSOURCE' => 'Ubercart_ShoppingCart_EC_US',
'NOTIFYURL' => Url::fromRoute('uc_paypal.ipn', [], [
'absolute' => TRUE,
])
->toString(),
'SHIPTONAME' => substr($address
->getFirstName() . ' ' . $address
->getLastName(), 0, 32),
'SHIPTOSTREET' => substr($address
->getStreet1(), 0, 100),
'SHIPTOSTREET2' => substr($address
->getStreet2(), 0, 100),
'SHIPTOCITY' => substr($address
->getCity(), 0, 40),
'SHIPTOSTATE' => $address
->getZone(),
'SHIPTOCOUNTRYCODE' => $address
->getCountry(),
'SHIPTOZIP' => substr($address
->getPostalCode(), 0, 20),
'PHONENUM' => substr($address
->getPhone(), 0, 20),
'LANDINGPAGE' => $this->configuration['ec_landingpage_style'],
];
if (!$order
->isShippable()) {
$request['NOSHIPPING'] = 1;
unset($request['ADDROVERRIDE']);
}
$response = $this
->sendNvpRequest($request);
if ($response['ACK'] != 'Success') {
\Drupal::logger('uc_paypal')
->error('NVP API request failed with @code: @message', [
'@code' => $response['L_ERRORCODE0'],
'@message' => $response['L_LONGMESSAGE0'],
]);
return $this
->t('PayPal reported an error: @code: @message', [
'@code' => $response['L_ERRORCODE0'],
'@message' => $response['L_LONGMESSAGE0'],
]);
}
$session
->set('TOKEN', $response['TOKEN']);
$sandbox = strpos($this->configuration['wpp_server'], 'sandbox') > 0 ? 'sandbox.' : '';
$url = 'https://www.' . $sandbox . 'paypal.com/cgi-bin/webscr?cmd=_express-checkout&useraction=commit&token=' . $response['TOKEN'];
$form['#action'] = $url;
$form['actions'] = [
'#type' => 'actions',
];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this
->t('Submit order'),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function orderSubmit(OrderInterface $order) {
$session = \Drupal::service('session');
$shipping = 0;
if (is_array($order->line_items)) {
foreach ($order->line_items as $item) {
if ($item['type'] == 'shipping') {
$shipping += $item['amount'];
}
}
}
$tax = 0;
if (\Drupal::moduleHandler()
->moduleExists('uc_tax')) {
foreach (uc_tax_calculate($order) as $tax_item) {
$tax += $tax_item->amount;
}
}
$subtotal = $order
->getTotal() - $tax - $shipping;
$response = $this
->sendNvpRequest([
'METHOD' => 'DoExpressCheckoutPayment',
'TOKEN' => $session
->get('TOKEN'),
'PAYMENTACTION' => $this->configuration['wpp_cc_txn_type'],
'PAYERID' => $session
->get('PAYERID'),
'AMT' => uc_currency_format($order
->getTotal(), FALSE, FALSE, '.'),
'DESC' => $this
->t('Order @order_id at @store', [
'@order_id' => $order
->id(),
'@store' => uc_store_name(),
]),
'INVNUM' => $order
->id() . '-' . REQUEST_TIME,
'BUTTONSOURCE' => 'Ubercart_ShoppingCart_EC_US',
'NOTIFYURL' => Url::fromRoute('uc_paypal.ipn', [], [
'absolute' => TRUE,
])
->toString(),
'ITEMAMT' => uc_currency_format($subtotal, FALSE, FALSE, '.'),
'SHIPPINGAMT' => uc_currency_format($shipping, FALSE, FALSE, '.'),
'TAXAMT' => uc_currency_format($tax, FALSE, FALSE, '.'),
'CURRENCYCODE' => $order
->getCurrency(),
]);
if ($response['ACK'] != 'Success') {
\Drupal::logger('uc_paypal')
->error('NVP API request failed with @code: @message', [
'@code' => $response['L_ERRORCODE0'],
'@message' => $response['L_LONGMESSAGE0'],
]);
return $this
->t('PayPal reported an error: @code: @message', [
'@code' => $response['L_ERRORCODE0'],
'@message' => $response['L_LONGMESSAGE0'],
]);
}
$session
->remove('TOKEN');
$session
->remove('PAYERID');
}
/**
* {@inheritdoc}
*/
public function getExpressButton($method_id) {
$this->methodId = $method_id;
return [
'#type' => 'image_button',
'#name' => 'paypal_ec',
'#src' => 'https://www.paypal.com/en_US/i/btn/btn_xpressCheckoutsm.gif',
'#title' => $this
->t('Checkout with PayPal.'),
'#submit' => [
'::submitForm',
[
$this,
'submitExpressForm',
],
],
];
}
/**
* Submit callback for the express checkout button.
*/
public function submitExpressForm(array &$form, FormStateInterface $form_state) {
$items = \Drupal::service('uc_cart.manager')
->get()
->getContents();
if (empty($items)) {
$this
->messenger()
->addMessage($this
->t('You do not have any items in your shopping cart.'));
return;
}
$order = Order::create([
'uid' => \Drupal::currentUser()
->id(),
'payment_method' => $this->methodId,
]);
$order->products = [];
foreach ($items as $item) {
$order->products[] = $item
->toOrderProduct();
}
$order
->save();
$response = $this
->sendNvpRequest([
'METHOD' => 'SetExpressCheckout',
'RETURNURL' => Url::fromRoute('uc_paypal.ec_review', [], [
'absolute' => TRUE,
])
->toString(),
'CANCELURL' => Url::fromRoute('uc_cart.cart', [], [
'absolute' => TRUE,
])
->toString(),
'AMT' => uc_currency_format($order
->getSubtotal(), FALSE, FALSE, '.'),
'CURRENCYCODE' => $order
->getCurrency(),
'PAYMENTACTION' => $this->configuration['wpp_cc_txn_type'],
'DESC' => $this
->t('Order @order_id at @store', [
'@order_id' => $order
->id(),
'@store' => uc_store_name(),
]),
'INVNUM' => $order
->id() . '-' . REQUEST_TIME,
'REQCONFIRMSHIPPING' => $this->configuration['ec_rqconfirmed_addr'],
'BUTTONSOURCE' => 'Ubercart_ShoppingCart_EC_US',
'NOTIFYURL' => Url::fromRoute('uc_paypal.ipn', [], [
'absolute' => TRUE,
])
->toString(),
'LANDINGPAGE' => $this->configuration['ec_landingpage_style'],
]);
if ($response['ACK'] != 'Success') {
\Drupal::logger('uc_paypal')
->error('NVP API request failed with @code: @message', [
'@code' => $response['L_ERRORCODE0'],
'@message' => $response['L_LONGMESSAGE0'],
]);
$this
->messenger()
->addError($this
->t('PayPal reported an error: @code: @message', [
'@code' => $response['L_ERRORCODE0'],
'@message' => $response['L_LONGMESSAGE0'],
]));
return;
}
$session = \Drupal::service('session');
$session
->set('cart_order', $order
->id());
$session
->set('TOKEN', $response['TOKEN']);
$sandbox = strpos($this->configuration['wpp_server'], 'sandbox') > 0 ? 'sandbox.' : '';
$url = 'https://www.' . $sandbox . 'paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=' . $response['TOKEN'];
$form_state
->setResponse(new TrustedRedirectResponse($url));
}
/**
* Form constructor for the express checkout review form.
*/
public function getExpressReviewForm(array $form, FormStateInterface $form_state, OrderInterface $order) {
// Required by QuotePane::prepare().
$form['#tree'] = TRUE;
// @todo Replace with PayPal shipping callback?
// @todo Make a simpler way of getting and applying shipping quotes.
if ($this->configuration['ec_review_shipping'] && \Drupal::moduleHandler()
->moduleExists('uc_quote') && $order
->isShippable()) {
/** @var \Drupal\uc_cart\CheckoutPanePluginInterface $pane */
$pane = \Drupal::service('plugin.manager.uc_cart.checkout_pane')
->createInstance('quotes');
$pane
->prepare($order, $form, $form_state);
$form['panes']['quotes'] = [
'#type' => 'details',
'#title' => $this
->t('Shipping cost'),
'#open' => TRUE,
];
$form['panes']['quotes'] += $pane
->view($order, $form, $form_state);
$form['panes']['quotes']['quotes']['quote_option']['#required'] = TRUE;
unset($form['panes']['quotes']['#description']);
unset($form['panes']['quotes']['quote_button']);
}
$address = $order
->getAddress('delivery');
// @todo Replace with "BUSINESS" from PayPal.
if ($this->configuration['ec_review_company']) {
$form['delivery_company'] = [
'#type' => 'textfield',
'#title' => $this
->t('Company'),
'#description' => $order
->isShippable() ? $this
->t('Leave blank if shipping to a residence.') : '',
'#default_value' => $address
->getCompany(),
];
}
// @todo Replace with "SHIPTOPHONENUM" from PayPal.
if ($this->configuration['ec_review_phone']) {
$form['delivery_phone'] = [
'#type' => 'textfield',
'#title' => $this
->t('Contact phone number'),
'#default_value' => $address
->getPhone(),
'#size' => 24,
];
}
// @todo Replace with "NOTE" from PayPal.
if ($this->configuration['ec_review_comment']) {
$form['order_comments'] = [
'#type' => 'textarea',
'#title' => $this
->t('Order comments'),
'#description' => $this
->t('Special instructions or notes regarding your order.'),
];
}
return $form;
}
/**
* Form constructor for the express checkout review form.
*/
public function submitExpressReviewForm(array $form, FormStateInterface $form_state, OrderInterface $order) {
if (!empty($form['panes']['quotes']['quotes'])) {
\Drupal::service('plugin.manager.uc_cart.checkout_pane')
->createInstance('quotes')
->prepare($order, $form, $form_state);
}
$address = $order
->getAddress('delivery');
if ($this->configuration['ec_review_company']) {
$address
->setCompany($form_state
->getValue('delivery_company'));
}
if ($this->configuration['ec_review_phone']) {
$address
->setPhone($form_state
->getValue('delivery_phone'));
}
$order
->setAddress('delivery', $address);
if ($this->configuration['ec_review_comment'] && $form_state
->getValue('order_comments')) {
$this->database
->delete('uc_order_comments')
->condition('order_id', $order
->id())
->execute();
uc_order_comment_save($order
->id(), 0, $form_state
->getValue('order_comments'), 'order');
}
$order
->save();
}
/**
* Sends a request to the PayPal NVP API.
*/
public function sendNvpRequest($params) {
$host = $this->configuration['wpp_server'];
$params += [
'USER' => $this->configuration['api']['api_username'],
'PWD' => $this->configuration['api']['api_password'],
'SIGNATURE' => $this->configuration['api']['api_signature'],
'VERSION' => '3.0',
];
try {
$response = \Drupal::httpClient()
->request('POST', $host, [
'form_params' => $params,
]);
parse_str($response
->getBody(), $output);
return $output;
} catch (TransferException $e) {
\Drupal::logger('uc_paypal')
->error('NVP API request failed with HTTP error %error.', [
'%error' => $e
->getMessage(),
]);
}
}
}
Members
Name![]() |
Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DependencySerializationTrait:: |
protected | property | An array of entity type IDs keyed by the property name of their storages. | |
DependencySerializationTrait:: |
protected | property | An array of service IDs keyed by property name used for serialization. | |
DependencySerializationTrait:: |
public | function | 1 | |
DependencySerializationTrait:: |
public | function | 2 | |
MessengerTrait:: |
protected | property | The messenger. | 29 |
MessengerTrait:: |
public | function | Gets the messenger. | 29 |
MessengerTrait:: |
public | function | Sets the messenger. | |
PaymentMethodPluginBase:: |
protected | property | The database service. | |
PaymentMethodPluginBase:: |
public | function |
Returns the form or render array to be displayed at checkout. Overrides PaymentMethodPluginInterface:: |
5 |
PaymentMethodPluginBase:: |
public | function |
Called when checkout is submitted with this payment method selected. Overrides PaymentMethodPluginInterface:: |
3 |
PaymentMethodPluginBase:: |
public | function |
Returns the payment method review details. Overrides PaymentMethodPluginInterface:: |
3 |
PaymentMethodPluginBase:: |
public | function |
Returns the payment method title to be used on the checkout review page. Overrides PaymentMethodPluginInterface:: |
2 |
PaymentMethodPluginBase:: |
public static | function |
Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface:: |
|
PaymentMethodPluginBase:: |
public | function |
Called when an order is being viewed by a customer. Overrides PaymentMethodPluginInterface:: |
2 |
PaymentMethodPluginBase:: |
public | function |
Gets this plugin's configuration. Overrides ConfigurableInterface:: |
|
PaymentMethodPluginBase:: |
public | function |
Returns the payment method label with logo. Overrides PaymentMethodPluginInterface:: |
3 |
PaymentMethodPluginBase:: |
public | function |
Called when an order is being deleted. Overrides PaymentMethodPluginInterface:: |
1 |
PaymentMethodPluginBase:: |
public | function |
Called when an order is being edited with this payment method. Overrides PaymentMethodPluginInterface:: |
3 |
PaymentMethodPluginBase:: |
public | function |
Called when an order is being submitted after being edited. Overrides PaymentMethodPluginInterface:: |
1 |
PaymentMethodPluginBase:: |
public | function |
Called when an order is being loaded with this payment method. Overrides PaymentMethodPluginInterface:: |
3 |
PaymentMethodPluginBase:: |
public | function |
Called when an order is being saved with this payment method. Overrides PaymentMethodPluginInterface:: |
3 |
PaymentMethodPluginBase:: |
public | function |
Sets the configuration for this plugin instance. Overrides ConfigurableInterface:: |
|
PaymentMethodPluginBase:: |
public | function |
Form validation handler. Overrides PluginFormInterface:: |
|
PaymentMethodPluginBase:: |
public | function |
Constructs the PaymentMethodPluginBase object. Overrides PluginBase:: |
|
PayPalExpressCheckout:: |
protected | property | The payment method entity ID that is using this plugin. | |
PayPalExpressCheckout:: |
public | function |
Form constructor. Overrides PayPalPaymentMethodPluginBase:: |
|
PayPalExpressCheckout:: |
public | function |
Redirect to PayPal Express Checkout Mark Flow. Overrides OffsitePaymentMethodPluginInterface:: |
|
PayPalExpressCheckout:: |
public | function |
Gets default configuration for this plugin. Overrides PayPalPaymentMethodPluginBase:: |
|
PayPalExpressCheckout:: |
public | function |
Form constructor. Overrides ExpressPaymentMethodPluginInterface:: |
|
PayPalExpressCheckout:: |
public | function | Form constructor for the express checkout review form. | |
PayPalExpressCheckout:: |
public | function |
Called when an order is being submitted with this payment method. Overrides PaymentMethodPluginBase:: |
|
PayPalExpressCheckout:: |
public | function |
Called when an order is being viewed by an administrator. Overrides PaymentMethodPluginBase:: |
|
PayPalExpressCheckout:: |
public | function | Sends a request to the PayPal NVP API. | |
PayPalExpressCheckout:: |
public | function |
Form submission handler. Overrides PayPalPaymentMethodPluginBase:: |
|
PayPalExpressCheckout:: |
public | function | Submit callback for the express checkout button. | |
PayPalExpressCheckout:: |
public | function | Form constructor for the express checkout review form. | |
PluginBase:: |
protected | property | Configuration information passed into the plugin. | 1 |
PluginBase:: |
protected | property | The plugin implementation definition. | 1 |
PluginBase:: |
protected | property | The plugin_id. | |
PluginBase:: |
constant | A string which is used to separate base plugin IDs from the derivative ID. | ||
PluginBase:: |
public | function |
Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the definition of the plugin implementation. Overrides PluginInspectionInterface:: |
3 |
PluginBase:: |
public | function |
Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface:: |
|
PluginBase:: |
public | function | Determines if the plugin is configurable. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |