View source
<?php
namespace Drupal\commerce_sermepa\Plugin\Commerce\PaymentGateway;
use CommerceRedsys\Payment\Sermepa as SermepaApi;
use Drupal\commerce\Response\NeedsRedirectException;
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\HasPaymentInstructionsInterface;
use Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\OffsitePaymentGatewayBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
class Sermepa extends OffsitePaymentGatewayBase implements HasPaymentInstructionsInterface {
protected $currentRouteMatch;
protected $lock;
protected $logger;
protected $languageManager;
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
$instance->currentRouteMatch = $container
->get('current_route_match');
$instance->lock = $container
->get('lock');
$instance->logger = $container
->get('logger.factory')
->get('commerce_sermepa');
$instance->languageManager = $container
->get('language_manager');
return $instance;
}
public function defaultConfiguration() {
return [
'merchant_name' => '',
'merchant_code' => '',
'merchant_group' => '',
'merchant_password' => '',
'merchant_terminal' => '',
'merchant_paymethods' => [],
'merchant_consumer_language' => '001',
'currency' => '978',
'transaction_type' => '0',
'instructions' => [
'value' => '',
'format' => 'plain_text',
],
] + parent::defaultConfiguration();
}
public function setConfiguration(array $configuration) {
parent::setConfiguration($configuration);
if (!isset($this->configuration['merchant_paymethods'])) {
$this->configuration['merchant_paymethods'][] = 'C';
}
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
$configuration = $this
->getConfiguration();
$form['merchant_name'] = [
'#type' => 'textfield',
'#title' => $this
->t('Merchant name'),
'#default_value' => $configuration['merchant_name'],
'#size' => 60,
'#maxlength' => SermepaApi::getMerchantNameMaxLength(),
'#required' => TRUE,
];
$form['merchant_code'] = [
'#type' => 'textfield',
'#title' => $this
->t('Merchant code'),
'#default_value' => $configuration['merchant_code'],
'#size' => 60,
'#maxlength' => SermepaApi::getMerchantCodeMaxLength(),
'#required' => TRUE,
];
$form['merchant_group'] = [
'#type' => 'textfield',
'#title' => $this
->t('Merchant group'),
'#default_value' => $configuration['merchant_group'],
'#size' => 60,
'#maxlength' => SermepaApi::getMerchantGroupMaxLength(),
'#required' => FALSE,
];
$form['merchant_password'] = [
'#type' => 'textfield',
'#title' => $this
->t('SHA256 merchant password'),
'#default_value' => $configuration['merchant_password'],
'#size' => 60,
'#maxlength' => SermepaApi::getMerchantPasswordMaxLength(),
'#required' => TRUE,
];
$form['merchant_terminal'] = [
'#type' => 'textfield',
'#title' => $this
->t('Merchant terminal'),
'#default_value' => $configuration['merchant_terminal'],
'#size' => 5,
'#maxlength' => SermepaApi::getMerchantTerminalMaxLength(),
'#required' => TRUE,
];
$form['merchant_paymethods'] = [
'#type' => 'select',
'#title' => $this
->t('Merchant payment methods'),
'#options' => SermepaApi::getAvailablePaymentMethods(),
'#default_value' => $configuration['merchant_paymethods'],
'#size' => 8,
'#required' => TRUE,
'#multiple' => TRUE,
];
$form['merchant_consumer_language'] = [
'#type' => 'select',
'#title' => $this
->t('Merchant consumer language'),
'#options' => SermepaApi::getAvailableConsumerLanguages(),
'#default_value' => $configuration['merchant_consumer_language'],
'#required' => TRUE,
];
$form['currency'] = [
'#type' => 'select',
'#title' => $this
->t('Currency'),
'#options' => $this
->getAvailableCurrencies(),
'#default_value' => $configuration['currency'],
'#required' => TRUE,
];
$form['transaction_type'] = [
'#type' => 'select',
'#title' => $this
->t('Transaction type'),
'#options' => SermepaApi::getAvailableTransactionTypes(),
'#default_value' => $configuration['transaction_type'],
'#required' => TRUE,
];
$form['instructions'] = [
'#type' => 'text_format',
'#title' => $this
->t('Payment instructions'),
'#description' => $this
->t('Shown the end of checkout, after the customer has placed their order.'),
'#default_value' => $configuration['instructions']['value'],
'#format' => $configuration['instructions']['format'],
];
return $form;
}
public function getUnknowFallbackLanguage() {
$default = $this
->getConfiguration();
return isset($default['merchant_consumer_language']) && $default['merchant_consumer_language'] == '000' ? $this
->getSermepaCurrentLanguage() : $default['merchant_consumer_language'];
}
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::submitConfigurationForm($form, $form_state);
if (!$form_state
->getErrors()) {
$values = $form_state
->getValue($form['#parents']);
$values['merchant_paymethods'] = array_filter($values['merchant_paymethods']);
$configuration = $this
->getConfiguration();
foreach ($this
->defaultConfiguration() as $name => $default_value) {
$configuration[$name] = $values[$name];
}
$this
->setConfiguration($configuration);
}
}
public function buildPaymentInstructions(PaymentInterface $payment) {
$configuration = $this
->getConfiguration();
$instructions = [];
if (!empty($configuration['instructions']['value'])) {
$instructions = [
'#type' => 'processed_text',
'#text' => $configuration['instructions']['value'],
'#format' => $configuration['instructions']['format'],
];
}
return $instructions;
}
public function onReturn(OrderInterface $order, Request $request) {
if ($this->lock
->lockMayBeAvailable($this
->getLockName($order))) {
$this
->processRequest($request, $order);
}
else {
$this->lock
->wait($this
->getLockName($order));
}
$order_storage = $this->entityTypeManager
->getStorage('commerce_order');
$updated_order = $order_storage
->loadUnchanged($order
->id());
if ($updated_order
->getState()
->getId() != $order
->getState()
->getId()) {
$step_id = $this->currentRouteMatch
->getParameter('step');
$checkout_flow = $order
->get('checkout_flow')
->first()
->get('entity')
->getTarget()
->getValue();
$checkout_flow_plugin = $checkout_flow
->getPlugin();
$redirect_step_id = $checkout_flow_plugin
->getNextStepId($step_id);
throw new NeedsRedirectException(Url::fromRoute('commerce_checkout.form', [
'commerce_order' => $updated_order
->id(),
'step' => $redirect_step_id,
])
->toString());
}
$this
->messenger()
->addStatus($this
->t('Your payment has been completed successfully.'));
}
public function onNotify(Request $request) {
try {
$this
->processRequest($request);
} catch (\Exception $exception) {
}
}
public function processRequest(Request $request, OrderInterface $order = NULL) {
$feedback = [
'Ds_SignatureVersion' => $request
->get('Ds_SignatureVersion'),
'Ds_MerchantParameters' => $request
->get('Ds_MerchantParameters'),
'Ds_Signature' => $request
->get('Ds_Signature'),
];
if (empty($feedback['Ds_SignatureVersion']) || empty($feedback['Ds_MerchantParameters']) || empty($feedback['Ds_Signature'])) {
throw new PaymentGatewayException('Bad feedback response, missing feedback parameter.');
}
$payment_method_settings = $this
->getConfiguration();
$gateway = new SermepaApi($payment_method_settings['merchant_name'], $payment_method_settings['merchant_code'], $payment_method_settings['merchant_terminal'], $payment_method_settings['merchant_password'], $this
->getMode());
$parameters = $gateway
->decodeMerchantParameters($feedback['Ds_MerchantParameters']);
$order_id = $parameters['Ds_MerchantData'];
if ($order === NULL) {
$order_storage = $this->entityTypeManager
->getStorage('commerce_order');
$order = $order_storage
->load($order_id);
}
if ($order === NULL || $order
->id() != $order_id) {
$this->logger
->warning('The received order ID and the argument order ID does not match.');
}
if ($this->lock
->acquire($this
->getLockName($order))) {
if (!$gateway
->validSignatures($feedback)) {
$this->lock
->release($this
->getLockName($order));
throw new PaymentGatewayException('Bad feedback response, signatures does not match.');
}
if ($gateway
->authorizedResponse($parameters['Ds_Response'])) {
$payment_storage = $this->entityTypeManager
->getStorage('commerce_payment');
$payments = $payment_storage
->getQuery()
->condition('payment_gateway', $this->parentEntity
->id())
->condition('order_id', $order
->id())
->condition('remote_id', $parameters['Ds_AuthorisationCode'])
->execute();
if (empty($payments)) {
$payment = $payment_storage
->create([
'state' => 'authorization',
'amount' => $order
->getTotalPrice(),
'payment_gateway' => $this->parentEntity
->id(),
'order_id' => $order
->id(),
'test' => $this
->getMode() == 'test',
'remote_id' => $parameters['Ds_AuthorisationCode'],
'remote_state' => SermepaApi::handleResponse($parameters['Ds_Response']),
'authorized' => $this->time
->getRequestTime(),
]);
$status_mapping = $this
->getStatusMapping();
if (isset($status_mapping[$this
->getConfiguration()['transaction_type']])) {
$payment
->setState($status_mapping[$this
->getConfiguration()['transaction_type']]);
}
if (!$order
->get('payment_method')
->isEmpty()) {
$credit_card = $order
->get('payment_method')
->first()
->get('entity')
->getTarget()
->getValue();
$payment
->set('payment_method', $credit_card)
->save();
}
$payment
->save();
}
$this->lock
->release($this
->getLockName($order));
return TRUE;
}
$this->lock
->release($this
->getLockName($order));
throw new PaymentGatewayException('Failed attempt, the payment could not be made.');
}
}
protected function getAvailableCurrencies() {
$sermepa_currencies = SermepaApi::getAvailableCurrencies();
$currency_storage = $this->entityTypeManager
->getStorage('commerce_currency');
$currency_ids = $currency_storage
->getQuery()
->condition('numericCode', array_keys($sermepa_currencies), 'IN')
->execute();
$available_currencies = [];
if ($currency_ids) {
$enabled_currencies = $currency_storage
->loadMultiple($currency_ids);
foreach ($enabled_currencies as $currency) {
$available_currencies[$currency
->getNumericCode()] = $currency
->getName();
}
}
return $available_currencies;
}
protected function getStatusMapping($status = NULL) {
$mapping = [
'0' => 'completed',
'1' => 'authorization',
'2' => 'authorization',
'3' => 'refunded',
'5' => 'completed',
'6' => 'completed',
'7' => 'authorization',
'8' => 'authorization',
'9' => 'authorization_expired',
'O' => 'authorization',
'P' => 'authorization',
'Q' => 'authorization',
'R' => 'completed',
'S' => 'completed',
];
if (isset($status) && isset($mapping[$status])) {
return $mapping[$status];
}
return $mapping;
}
protected function getLockName(OrderInterface $order) {
return 'commerce_sermepa_process_request_' . $order
->uuid();
}
protected function getSermepaCurrentLanguage() {
$drupal_current = $this->languageManager
->getCurrentLanguage()
->getId();
$map = $this
->getOptionsWithContryCode();
return in_array($drupal_current, $map) ? array_search($drupal_current, $map) : '002';
}
public function getOptionsWithContryCode() {
return [
'000' => 'zxx',
'001' => 'es',
'002' => 'en',
'003' => 'ca',
'004' => 'fr',
'005' => 'de',
'006' => 'nl',
'007' => 'it',
'008' => 'sv',
'009' => 'pt',
'010' => 'va',
'011' => 'pl',
'012' => 'gl',
'013' => 'eu',
'208' => 'da',
];
}
}