View source
<?php
namespace Drupal\commerce_paypal\Plugin\Commerce\PaymentGateway;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_payment\Entity\PaymentInterface;
use Drupal\commerce_payment\Exception\PaymentGatewayException;
use Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\OffsitePaymentGatewayBase;
use Drupal\commerce_paypal\Event\PayflowLinkRequestEvent;
use Drupal\commerce_paypal\Event\PayPalEvents;
use Drupal\commerce_price\Calculator;
use Drupal\commerce_price\Price;
use Drupal\commerce_product\Entity\ProductVariationInterface;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Utility\Html;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use GuzzleHttp\Exception\BadResponseException;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
class PayflowLink extends OffsitePaymentGatewayBase implements PayflowLinkInterface {
const BUTTON_SOURCE = 'CommerceGuys_Cart_PFL';
protected $logger;
protected $httpClient;
protected $time;
protected $moduleHandler;
protected $eventDispatcher;
protected $messenger;
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$instance->logger = $container
->get('logger.channel.commerce_paypal');
$instance->httpClient = $container
->get('http_client');
$instance->moduleHandler = $container
->get('module_handler');
$instance->eventDispatcher = $container
->get('event_dispatcher');
$instance->messenger = $container
->get('messenger');
return $instance;
}
public function defaultConfiguration() {
return [
'partner' => 'PayPal',
'vendor' => '',
'user' => '',
'password' => '',
'trxtype' => 'S',
'redirect_mode' => 'post',
'reference_transactions' => FALSE,
'emailcustomer' => FALSE,
'log' => [
'request' => 0,
'response' => 0,
],
] + parent::defaultConfiguration();
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
$form['service_description'] = [
'#markup' => $this
->t('Accept payment securely on your site via credit card, debit card, or PayPal using a merchant account of your choice. This payment gateway requires a PayPal Payflow Link account. <a href="@url">Sign up here</a> and edit these settings to start accepting payments.', [
'@url' => 'https://www.paypal.com/webapps/mpp/referral/paypal-payflow-link?partner_id=VZ6B9QLQ8LZEE',
]),
'#weight' => '-100',
];
$form['partner'] = [
'#type' => 'textfield',
'#title' => $this
->t('Partner'),
'#default_value' => $this->configuration['partner'],
'#required' => TRUE,
'#description' => $this
->t('Either PayPal or the name of the reseller who registered your Payflow Link account.'),
];
$form['vendor'] = [
'#type' => 'textfield',
'#title' => $this
->t('Vendor'),
'#default_value' => $this->configuration['vendor'],
'#required' => TRUE,
'#description' => $this
->t('The merchant login ID you chose when you created your Payflow Link account.'),
];
$form['user'] = [
'#type' => 'textfield',
'#title' => $this
->t('User'),
'#default_value' => $this->configuration['user'],
'#required' => TRUE,
'#description' => $this
->t('The name of the user on the account you want to use to process transactions or the merchant login if you have not created users.'),
];
$form['password'] = [
'#type' => 'password',
'#title' => $this
->t('Password'),
'#default_value' => $this->configuration['password'],
'#required' => TRUE,
'#description' => $this
->t('The password created for the user specified in the previous textfield.'),
];
$form['trxtype'] = [
'#type' => 'select',
'#title' => $this
->t('Default transaction type'),
'#default_value' => $this->configuration['trxtype'],
'#required' => TRUE,
'#options' => [
'S' => $this
->t('Sale - authorize and capture the funds at the time the payment is processed'),
'A' => $this
->t('Authorization - reserve funds on the card to be captured later through your PayPal account'),
],
];
$form['redirect_mode'] = [
'#type' => 'radios',
'#title' => $this
->t('Checkout redirect mode'),
'#description' => $this
->t('Your payment processor and Payflow Link account settings may limit which of these payment options are actually available on the payment form.'),
'#default_value' => $this->configuration['redirect_mode'],
'#required' => TRUE,
'#options' => [
'post' => $this
->t('Redirect to the hosted checkout page via POST through an automatically submitted form'),
'get' => $this
->t('Redirect to the hosted checkout page immediately with a GET request'),
],
];
$form['reference_transactions'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Enable reference transactions for payments captured through this Payflow Link account.'),
'#description' => $this
->t('Contact PayPal if you are unsure if this option is available to you.'),
'#default_value' => $this->configuration['reference_transactions'],
];
$form['emailcustomer'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Instruct PayPal to e-mail payment receipts to your customers upon payment.'),
'#default_value' => $this->configuration['emailcustomer'],
];
$form['log'] = [
'#type' => 'checkboxes',
'#title' => $this
->t('Log the following messages for debugging'),
'#options' => [
'request' => $this
->t('API request messages'),
'response' => $this
->t('API response messages'),
],
'#default_value' => $this->configuration['log'],
];
return $form;
}
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::submitConfigurationForm($form, $form_state);
if (!$form_state
->getErrors()) {
$values = $form_state
->getValue($form['#parents']);
$this->configuration['partner'] = $values['partner'];
$this->configuration['vendor'] = $values['vendor'];
$this->configuration['user'] = $values['user'];
$this->configuration['password'] = $values['password'];
$this->configuration['trxtype'] = $values['trxtype'];
$this->configuration['redirect_mode'] = $values['redirect_mode'];
$this->configuration['reference_transactions'] = $values['reference_transactions'];
$this->configuration['emailcustomer'] = $values['emailcustomer'];
$this->configuration['log'] = $values['log'];
}
}
public function refundPayment(PaymentInterface $payment, Price $amount = NULL) {
$this
->assertPaymentState($payment, [
'completed',
'partially_refunded',
]);
$amount = $amount ?: $payment
->getAmount();
$this
->assertRefundAmount($payment, $amount);
$nvp = [
'TRXTYPE' => 'C',
'ORIGID' => $payment
->getRemoteId(),
'AMT' => Calculator::trim($amount
->getNumber()),
];
$order = $payment
->getOrder();
$response = $this
->apiRequest('pro', $nvp, $order);
if (intval($response['RESULT']) === 0) {
$old_refunded_amount = $payment
->getRefundedAmount();
$new_refunded_amount = $old_refunded_amount
->add($amount);
if ($new_refunded_amount
->lessThan($payment
->getAmount())) {
$payment
->setState('partially_refunded');
}
else {
$payment
->setState('refunded');
}
$payment
->setRemoteState('C');
$payment
->setRefundedAmount($new_refunded_amount);
$payment
->save();
}
else {
throw new PaymentGatewayException($this
->t('Refund failed: @reason', [
'@reason' => $response['RESPMSG'],
]), $response['RESULT']);
}
}
public function canRefundPayment(PaymentInterface $payment) {
$valid_types = [
'S',
'D',
'C',
];
if (!in_array($payment
->getRemoteState(), $valid_types)) {
return FALSE;
}
if (!in_array($payment
->getState()
->getId(), [
'completed',
'partially_refunded',
])) {
return FALSE;
}
if ($payment
->getCompletedTime() && $payment
->getCompletedTime() < strtotime('-60 days')) {
return FALSE;
}
return TRUE;
}
public function voidPayment(PaymentInterface $payment) {
$nvp = [
'TRXTYPE' => 'V',
'ORIGID' => $payment
->getRemoteId(),
];
$order = $payment
->getOrder();
$response = $this
->apiRequest('pro', $nvp, $order);
if (!empty($this
->getConfiguration()['log']['response'])) {
$this->logger
->debug('Payflow server response: @param', [
'@param' => new FormattableMarkup('<pre>' . print_r($response, 1) . '</pre>', []),
]);
}
if (intval($response['RESULT']) === 0) {
$payment->remote_id = $response['PNREF'];
$payment->state = 'voided';
$payment->remote_state = 'V';
}
else {
throw new PaymentGatewayException('Prior authorization capture failed, so the payment will remain in a pending status.');
}
$payment
->save();
}
public function canVoidPayment(PaymentInterface $payment) {
$valid_types = [
'A',
'Pending',
];
if (!in_array($payment
->getRemoteState(), $valid_types)) {
return FALSE;
}
if ($payment
->getState()
->getId() !== 'pending') {
return FALSE;
}
if ($payment
->getCompletedTime() && $payment
->getCompletedTime() < strtotime('-29 days')) {
return FALSE;
}
return TRUE;
}
public function canCapturePayment(PaymentInterface $payment) {
return $this
->canVoidPayment($payment);
}
public function capturePayment(PaymentInterface $payment, Price $amount = NULL) {
$amount = $amount ?: $payment
->getAmount();
$order = $payment
->getOrder();
$nvp = [
'TRXTYPE' => 'D',
'ORIGID' => $payment
->getRemoteId(),
'AMT' => Calculator::trim($amount
->getNumber()),
'CAPTURECOMPLETE' => 'Y',
];
$response = $this
->apiRequest('pro', $nvp, $order);
if (!empty($this->getConfiguration['log']['response'])) {
$this->logger
->debug('Payflow server response: @param', [
'@param' => new FormattableMarkup('<pre>' . print_r($response, 1) . '</pre>', []),
]);
}
switch (intval($response['RESULT'])) {
case 0:
$payment->amount = $amount;
$payment->remote_id = $response['PNREF'];
$payment->state = 'completed';
$payment->remote_state = 'D';
break;
default:
throw new PaymentGatewayException($this
->t('Capture failed: @reason.', [
'@reason' => $response['RESPMSG'],
]), $response['RESULT']);
}
$payment
->save();
}
public function onCancel(OrderInterface $order, Request $request) {
$this->messenger
->addMessage($this
->t('You have canceled payment at PayPal but may resume the checkout process here when you are ready.'));
$order
->unsetData('commerce_payflow');
}
public function onReturn(OrderInterface $order, Request $request) {
$parameter_bag = $request->request;
$received_parameters = $parameter_bag
->all();
$configuration = $this
->getConfiguration();
$payment_storage = $this->entityTypeManager
->getStorage('commerce_payment');
if (!empty($configuration['silent_post_logging']) && $configuration['silent_post_logging'] == 'full_post') {
$this->logger
->notice('Customer returned from Payflow with the following POST data: !data', [
'!data' => '<pre>' . Html::escape(print_r($received_parameters, TRUE)) . '</pre>',
]);
}
if (!empty($configuration['log']['response'])) {
$this->logger
->notice('Payflow server response: @response', [
'@response' => new FormattableMarkup('<pre>' . print_r($received_parameters, 1) . '</pre>', []),
]);
}
if (isset($received_parameters['RESULT']) && !in_array(intval($received_parameters['RESULT']), [
0,
126,
])) {
$message = $this
->resultMessage($received_parameters['RESULT']);
throw new PaymentGatewayException($message);
}
if (!empty($received_parameters['TRXTYPE'])) {
$trxtype = $received_parameters['TRXTYPE'];
}
elseif (!empty($received_parameters['TYPE'])) {
$trxtype = $received_parameters['TYPE'];
}
else {
$trxtype = $configuration['trxtype'];
}
$state = '';
if (intval($received_parameters['RESULT']) == 0) {
switch ($trxtype) {
case 'S':
$state = 'completed';
break;
case 'A':
default:
$state = 'pending';
break;
}
}
elseif (intval($received_parameters['RESULT']) == 126) {
$state = 'pending';
}
$commerce_payment = $payment_storage
->create([
'state' => $state,
'amount' => $order
->getBalance(),
'payment_gateway' => $this->parentEntity
->id(),
'order_id' => $order
->id(),
'remote_id' => $received_parameters['PNREF'],
'remote_state' => $trxtype,
]);
if (!empty($received_parameters['PENDINGREASON']) && $received_parameters['PENDINGREASON'] != 'completed') {
$commerce_payment
->setState('pending');
}
$commerce_payment
->save();
}
public function buildPaymentOperations(PaymentInterface $payment) {
$operations = parent::buildPaymentOperations($payment);
$operations['reference'] = [
'title' => $this
->t('Reference'),
'page_title' => $this
->t('Refund payment'),
'plugin_form' => 'reference-payment',
'access' => $this
->canReferencePayment($payment),
];
return $operations;
}
protected function getDefaultForms() {
$default_forms = parent::getDefaultForms();
$default_forms['reference-payment'] = 'Drupal\\commerce_paypal\\PluginForm\\PaymentReferenceForm';
return $default_forms;
}
public function createSecureToken(OrderInterface $order) {
$cancel_url = Url::fromRoute('commerce_payment.checkout.cancel', [
'commerce_order' => $order
->id(),
'step' => 'payment',
], [
'absolute' => TRUE,
])
->toString();
$return_url = Url::fromRoute('commerce_payment.checkout.return', [
'commerce_order' => $order
->id(),
'step' => 'payment',
], [
'absolute' => TRUE,
])
->toString();
$nvp = [
'CREATESECURETOKEN' => 'Y',
'SECURETOKENID' => $order
->getData('commerce_payflow')['tokenid'],
'TRXTYPE' => $this->configuration['trxtype'],
'AMT' => Calculator::trim($order
->getTotalPrice()
->getNumber()),
'CURRENCY' => $order
->getTotalPrice()
->getCurrencyCode(),
'INVNUM' => $order
->id() . '-' . $this->time
->getRequestTime(),
'BUTTONSOURCE' => self::BUTTON_SOURCE,
'ERRORURL' => $return_url,
'RETURNURL' => $return_url,
'CANCELURL' => $cancel_url,
'DISABLERECEIPT' => 'TRUE',
'TEMPLATE' => 'TEMPLATEA',
'CSCREQUIRED' => 'TRUE',
'CSCEDIT' => 'TRUE',
'URLMETHOD' => 'POST',
];
$billing_profile = $order
->getBillingProfile();
if ($billing_profile && !$billing_profile
->get('address')
->isEmpty()) {
$billing_address = $billing_profile
->get('address')
->first()
->getValue();
if (is_array($billing_address)) {
$nvp += [
'BILLTOEMAIL' => mb_substr($order
->getEmail(), 0, 60),
'BILLTOFIRSTNAME' => mb_substr($billing_address['given_name'], 0, 45),
'BILLTOLASTNAME' => mb_substr($billing_address['family_name'], 0, 45),
'BILLTOSTREET' => mb_substr($billing_address['address_line1'], 0, 150),
'BILLTOCITY' => mb_substr($billing_address['locality'], 0, 45),
'BILLTOSTATE' => mb_substr($billing_address['administrative_area'], 0, 2),
'BILLTOCOUNTRY' => mb_substr($billing_address['country_code'], 0, 2),
'BILLTOZIP' => mb_substr($billing_address['postal_code'], 0, 10),
];
}
}
if (!empty($this->configuration['emailcustomer'])) {
$nvp['EMAILCUSTOMER'] = 'TRUE';
}
$shipping_profile = $order
->getBillingProfile();
if ($shipping_profile && !$shipping_profile
->get('address')
->isEmpty()) {
$shipping_address = $shipping_profile
->get('address')
->first()
->getValue();
if (is_array($shipping_address)) {
$nvp += [
'SHIPTOFIRSTNAME' => mb_substr($shipping_address['given_name'], 0, 45),
'SHIPTOLASTNAME' => mb_substr($shipping_address['family_name'], 0, 45),
'SHIPTOSTREET' => mb_substr($shipping_address['address_line1'], 0, 150),
'SHIPTOCITY' => mb_substr($shipping_address['locality'], 0, 45),
'SHIPTOSTATE' => mb_substr($shipping_address['administrative_area'], 0, 2),
'SHIPTOCOUNTRY' => mb_substr($shipping_address['country_code'], 0, 2),
'SHIPTOZIP' => mb_substr($shipping_address['postal_code'], 0, 10),
];
}
}
$nvp += $this
->itemizeOrder($order);
$response = $this
->apiRequest('pro', $nvp, $order);
if (isset($response['RESULT']) && $response['RESULT'] == '0') {
return $response['SECURETOKEN'];
}
return NULL;
}
public function getRedirectUrl(OrderInterface $order = NULL) {
$configuration = $this
->getConfiguration();
$mode = $configuration['mode'];
$redirect_mode = $configuration['redirect_mode'];
$url = '';
switch ($mode) {
case 'test':
$url = 'https://pilot-payflowlink.paypal.com/';
break;
case 'live':
$url = 'https://payflowlink.paypal.com/';
break;
}
if ($redirect_mode === 'get' && !empty($order)) {
$commerce_payflow_data = $order
->getData('commerce_payflow');
if (empty($commerce_payflow_data['token']) || empty($commerce_payflow_data['tokenid'])) {
return '';
}
$query = [
'SECURETOKEN' => $commerce_payflow_data['token'],
'SECURETOKENID' => $commerce_payflow_data['tokenid'],
];
if ($mode === 'test') {
$query['MODE'] = 'TEST';
}
$url = Url::fromUri($url, [
'query' => $query,
])
->toString();
}
return $url;
}
public function referencePayment(PaymentInterface $payment, Price $amount = NULL) {
$amount = $amount ?: $payment
->getAmount();
$order = $payment
->getOrder();
$nvp = [
'BUTTONSOURCE' => self::BUTTON_SOURCE,
'TRXTYPE' => 'S',
'ORIGID' => $payment
->getRemoteId(),
'AMT' => Calculator::trim($amount
->getNumber()),
'TENDER' => 'C',
];
$response = $this
->apiRequest('pro', $nvp, $order);
if (isset($response['RESULT']) && intval($response['RESULT']) === 0) {
$new_payment = $this->entityTypeManager
->getStorage('commerce_payment')
->create([
'state' => 'completed',
'amount' => $amount,
'payment_gateway' => $payment
->getPaymentGatewayId(),
'order_id' => $order
->id(),
'remote_id' => $response['PNREF'] ?? '',
'remote_state' => 'S',
]);
$new_payment
->save();
}
else {
throw new PaymentGatewayException($this
->t('Reference transaction failed: @reason.', [
'@reason' => $response['RESPMSG'],
]), $response['RESULT']);
}
}
protected function itemizeOrder(OrderInterface $order) {
$nvp = [];
$items_total = new Price('0', $order
->getTotalPrice()
->getCurrencyCode());
$i = 0;
foreach ($order
->getItems() as $item) {
$item_amount = Calculator::trim($item
->getUnitPrice()
->getNumber());
$nvp += [
'L_NAME' . $i => $item
->getTitle(),
'L_COST' . $i => $item_amount,
'L_QTY' . $i => $item
->getQuantity(),
];
$purchased_entity = $item
->getPurchasedEntity();
if ($purchased_entity instanceof ProductVariationInterface) {
$sku = $purchased_entity
->getSku();
}
else {
$sku = $purchased_entity
->getOrderItemTitle();
}
$nvp += [
'L_SKU' . $i => $sku,
];
$items_total = $items_total
->add($item
->getTotalPrice());
$i++;
}
$tax_amount = new Price('0', $order
->getTotalPrice()
->getCurrencyCode());
$adjustments = [];
foreach ($order
->collectAdjustments() as $adjustment) {
if ($adjustment
->isIncluded()) {
continue;
}
if ($adjustment
->getType() === 'tax') {
$tax_amount = $tax_amount
->add($adjustment
->getAmount());
}
else {
$type = $adjustment
->getType();
$source_id = $adjustment
->getSourceId();
if (empty($source_id)) {
$key = count($adjustments);
}
else {
$key = $type . '_' . $source_id;
}
if (empty($adjustments[$key])) {
$adjustments[$key] = [
'type' => $type,
'label' => (string) $adjustment
->getLabel(),
'total' => $adjustment
->getAmount(),
];
}
else {
$adjustments[$key]['total'] = $adjustments[$key]['total']
->add($adjustment
->getAmount());
}
}
}
$i = 0;
foreach ($adjustments as $adjustment) {
$adjustment_amount = Calculator::trim($adjustment['total']
->getNumber());
$nvp += [
'L_NAME' . $i => $adjustment['label'],
'L_COST' . $i => $adjustment_amount,
'L_QTY' . $i => 1,
];
$items_total = $items_total
->add($adjustment['total']);
$i++;
}
$nvp['ITEMAMT'] = Calculator::trim($items_total
->getNumber());
if (!$tax_amount
->isZero()) {
$nvp['TAXAMT'] = Calculator::trim($tax_amount
->getNumber());
}
return $nvp;
}
protected function apiRequest($api, array $nvp = [], $order = NULL) {
$configuration = $this
->getConfiguration();
$mode = $configuration['mode'];
if ($api === 'pro') {
$url = $this
->getProServerUrl();
}
else {
$url = $this
->getRedirectUrl();
}
$nvp += [
'PARTNER' => $configuration['partner'],
'VENDOR' => $configuration['vendor'],
'USER' => $configuration['user'],
'PWD' => $configuration['password'],
'MODE' => $mode === 'test' ? 'TEST' : 'LIVE',
];
$event = new PayflowLinkRequestEvent($nvp, $order);
$this->eventDispatcher
->dispatch(PayPalEvents::PAYFLOW_LINK_REQUEST, $event);
$nvp = $event
->getNvpData();
if ($configuration['log']['request'] === 'request') {
$log_nvp = $nvp;
$log_nvp['PWD'] = str_repeat('X', strlen($log_nvp['PWD']));
if (!empty($log_nvp['ACCT'])) {
$log_nvp['ACCT'] = str_repeat('X', strlen($log_nvp['ACCT']) - 4) . mb_substr($log_nvp['ACCT'], -4);
}
if (!empty($log_nvp['CVV2'])) {
$log_nvp['CVV2'] = str_repeat('X', strlen($log_nvp['CVV2']));
}
$this->logger
->debug('Payflow API request to @url: @param', [
'@url' => $url,
'@param' => new FormattableMarkup('<pre>' . print_r($log_nvp, 1) . '</pre>', []),
]);
}
$pairs = [];
foreach ($nvp as $key => $value) {
$pairs[] = $key . '=' . str_replace([
'&',
'=',
'#',
], [
'',
], $value);
}
$body = implode('&', $pairs);
try {
$response = $this->httpClient
->post($url, [
'headers' => [
'Content-Type' => 'text/namevalue',
'Content-Length' => strlen($body),
],
'body' => $body,
'timeout' => 45,
]);
} catch (BadResponseException $exception) {
$this->logger
->error($exception
->getResponse()
->getBody()
->getContents());
throw new PaymentGatewayException('Redirect to PayPal failed. Please try again or contact an administrator to resolve the issue.');
}
$result = $response
->getBody()
->getContents();
$response = [];
foreach (explode('&', $result) as $nvp) {
list($key, $value) = explode('=', $nvp);
$response[urldecode($key)] = urldecode($value);
}
if (!empty($configuration['log']['response'])) {
$this->logger
->debug('Payflow server response: @param', [
'@param' => new FormattableMarkup('<pre>' . print_r($response, 1) . '</pre>', []),
]);
}
return $response;
}
private function getProServerUrl() {
switch ($this
->getConfiguration()['mode']) {
case 'test':
return 'https://pilot-payflowpro.paypal.com/';
case 'live':
return 'https://payflowpro.paypal.com/';
}
return '';
}
protected function resultMessage($result) {
switch (intval($result)) {
case 0:
return $this
->t('Transaction approved.');
case 1:
return $this
->t('Account authentication error. Please contact an administrator to resolve this issue.');
case 5:
case 26:
return $this
->t('The Payflow hosted checkout page is not configured for use. Please contact an administrator to resolve this issue.');
case 2:
case 25:
return $this
->t('You have attempted to use an invalid payment method. Please check your payment information and try again.');
case 3:
return $this
->t('The specified transaction type is not appropriate for this transaction.');
case 4:
case 6:
return $this
->t('The payment request specified an invalid amount format or currency code. Please contact an administrator to resolve this issue.');
case 7:
case 8:
case 9:
case 10:
case 19:
case 20:
return $this
->t('The payment request included invalid parameters. Please contact an administrator to resolve this issue.');
case 11:
case 115:
case 160:
case 161:
case 162:
return $this
->t('The payment request timed out. Please try again or contact an administrator to resolve the issue.');
case 12:
case 13:
case 22:
case 23:
case 24:
return $this
->t('Payment declined. Please check your payment information and try again.');
case 27:
case 28:
case 29:
case 30:
case 31:
case 32:
case 33:
case 34:
case 35:
case 36:
case 37:
case 52:
case 99:
case 100:
case 101:
case 102:
case 103:
case 104:
case 105:
case 106:
case 107:
case 108:
case 109:
case 110:
case 111:
case 113:
case 116:
case 118:
case 120:
case 121:
case 122:
case 132:
case 133:
case 150:
case 151:
return $this
->t('The transaction failed at PayPal. Please contact an administrator to resolve this issue.');
case 50:
case 51:
return $this
->t('Payment was declined due to insufficient funds or transaction limits. Please check your payment information and try again.');
case 112:
return $this
->t('Address and Zip code do not match. Please check your payment information and try again.');
case 114:
return $this
->t('Card Security Code (CSC) does not match. Please check your payment information and try again.');
case 117:
case 125:
case 127:
case 128:
return $this
->t('Payment was declined due to merchant fraud settings. Please contact an administrator to resolve this issue.');
case 126:
return $this
->t('Payment was flagged for review by the merchant. We will validate the payment and update your order as soon as possible.');
}
return $this
->t('Unknown result code.');
}
private function canReferencePayment(PaymentInterface $payment) {
$supported_states = [
'S',
'A',
'D',
'V',
'C',
'Pending',
'Completed',
'Voided',
'Refunded',
];
if (!in_array($payment
->getRemoteState(), $supported_states)) {
return FALSE;
}
if ($payment
->getCompletedTime() && $payment
->getCompletedTime() < strtotime('-365 days')) {
return FALSE;
}
if (empty($this
->getConfiguration()['reference_transactions'])) {
return FALSE;
}
return TRUE;
}
}