View source
<?php
namespace Drupal\commerce_braintree\Plugin\Commerce\CheckoutPane;
use Drupal\commerce_braintree\ErrorHelper;
use Drupal\commerce_braintree\Plugin\Commerce\PaymentGateway\HostedFieldsInterface;
use Drupal\commerce_checkout\Plugin\Commerce\CheckoutFlow\CheckoutFlowInterface;
use Drupal\commerce_checkout\Plugin\Commerce\CheckoutPane\CheckoutPaneBase;
use Drupal\commerce_payment\Exception\PaymentGatewayException;
use Drupal\commerce_price\Calculator;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Form\FormStateInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class Braintree3DSReview extends CheckoutPaneBase {
protected $logger;
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, CheckoutFlowInterface $checkout_flow = NULL) {
$instance = parent::create($container, $configuration, $plugin_id, $plugin_definition, $checkout_flow);
$instance
->setLogger($container
->get('logger.channel.commerce_payment'));
return $instance;
}
public function setLogger(LoggerInterface $logger) {
$this->logger = $logger;
return $this;
}
public function isVisible() {
if ($this->order
->get('payment_method')
->isEmpty() || $this->order
->get('payment_gateway')
->isEmpty() || !$this->order
->get('payment_gateway')->entity) {
return FALSE;
}
$payment_gateway = $this->order
->get('payment_gateway')->entity;
if (!$payment_gateway
->getPlugin() instanceof HostedFieldsInterface) {
return FALSE;
}
$configuration = $payment_gateway
->getPlugin()
->getConfiguration();
if (empty($configuration['3d_secure'])) {
return FALSE;
}
$payment_method = $this->order
->get('payment_method')->entity;
if (!$payment_method
->isReusable() || $payment_method
->getType()
->getPluginId() !== 'credit_card') {
return FALSE;
}
return TRUE;
}
public function buildPaneForm(array $pane_form, FormStateInterface $form_state, array &$complete_form) {
$payment_method = $this->order
->get('payment_method')->entity;
$braintree_plugin = $this->order
->get('payment_gateway')->entity
->getPlugin();
try {
$result = $braintree_plugin
->createPaymentMethodNonce($payment_method
->getRemoteId());
$pane_form['#attached']['library'][] = 'commerce_braintree/checkout-review';
$amount = Calculator::trim($this->order
->getBalance()
->getNumber());
$pane_form['#attached']['drupalSettings']['commerceBraintree'] = [
'clientToken' => $braintree_plugin
->generateClientToken(),
'formId' => $complete_form['#id'],
'amount' => $amount,
'nonce' => $result->paymentMethodNonce->nonce,
'bin' => $result->paymentMethodNonce->details['bin'],
'email' => $this->order
->getEmail(),
];
$pane_form['payment_errors'] = [
'#type' => 'markup',
'#markup' => '<div id="payment-errors"></div>',
'#weight' => -200,
];
$pane_form['payment_method_nonce'] = [
'#type' => 'hidden',
'#attributes' => [
'class' => [
'braintree-nonce',
],
],
];
} catch (\Braintree\Exception $e) {
ErrorHelper::handleException($e);
} catch (PaymentGatewayException $e) {
$this->logger
->error($e
->getMessage());
$message = $this
->t('We encountered an unexpected error processing your payment method. Please try again later.');
$this
->messenger()
->addError($message);
$this->checkoutFlow
->redirectToStep($this
->getErrorStepId());
}
$cacheability = new CacheableMetadata();
$cacheability
->addCacheableDependency($this->order);
$cacheability
->setCacheMaxAge(0);
$cacheability
->applyTo($pane_form);
return $pane_form;
}
public function validatePaneForm(array &$pane_form, FormStateInterface $form_state, array &$complete_form) {
$error_step_id = $this
->getErrorStepId();
$values = $form_state
->getValue($pane_form['#parents']);
if (empty($values['payment_method_nonce'])) {
$this->logger
->error('Missing payment method nonce.');
$message = $this
->t('We encountered an unexpected error processing your payment method. Please try again later.');
$this
->messenger()
->addError($message);
$this->checkoutFlow
->redirectToStep($error_step_id);
}
$braintree_plugin = $this->order
->get('payment_gateway')->entity
->getPlugin();
$configuration = $braintree_plugin->configuration;
try {
$paymentMethodNonce = $braintree_plugin
->findPaymentMethodNonce($values['payment_method_nonce']);
$result = $paymentMethodNonce->threeDSecureInfo;
$required = isset($configuration['3d_secure']) && $configuration['3d_secure'] == 'required';
ErrorHelper::handleErrors3ds($result, $required);
} catch (\Braintree\Exception $e) {
ErrorHelper::handleException($e);
} catch (PaymentGatewayException $e) {
$this->logger
->error($e
->getMessage());
$message = $this
->t('We encountered an unexpected error processing your payment method. Please try again later.');
$this
->messenger()
->addError($message);
$this->checkoutFlow
->redirectToStep($error_step_id);
}
}
public function submitPaneForm(array &$pane_form, FormStateInterface $form_state, array &$complete_form) {
$values = $form_state
->getValue($pane_form['#parents']);
$payment_method = $this->order
->get('payment_method')->entity;
$three_d_payment_method = $payment_method
->createDuplicate();
$three_d_payment_method
->setRemoteId($values['payment_method_nonce']);
$three_d_payment_method
->setReusable(FALSE);
$three_d_payment_method
->save();
$this->order
->set('payment_method', $payment_method);
}
protected function getErrorStepId() {
$step_id = $this->checkoutFlow
->getPane('payment_information')
->getStepId();
if ($step_id == '_disabled') {
throw new \RuntimeException('Cannot get the step ID for the payment_information pane. The pane is disabled.');
}
return $step_id;
}
}