View source
<?php
namespace Drupal\commerce_robokassa\Plugin\Commerce\PaymentGateway;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_payment\Entity\PaymentInterface;
use Drupal\commerce_payment\PaymentMethodTypeManager;
use Drupal\commerce_payment\PaymentTypeManager;
use Drupal\commerce_payment\Plugin\Commerce\PaymentGateway\OffsitePaymentGatewayBase;
use Drupal\commerce_price\Entity\Currency;
use Drupal\commerce_price\Price;
use Drupal\commerce_price\RounderInterface;
use Drupal\Component\Datetime\TimeInterface;
use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use GuzzleHttp\Client;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
class RobokassaPayment extends OffsitePaymentGatewayBase implements RobokassaPaymentInterface {
protected $rounder;
protected $languageManager;
protected $httpClient;
protected $logger;
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, PaymentTypeManager $payment_type_manager, PaymentMethodTypeManager $payment_method_type_manager, TimeInterface $time, RounderInterface $rounder, LanguageManagerInterface $language_manager, Client $http_client, LoggerInterface $logger) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $payment_type_manager, $payment_method_type_manager, $time);
$this->rounder = $rounder;
$this->languageManager = $language_manager;
$this->httpClient = $http_client;
$this->logger = $logger;
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('entity_type.manager'), $container
->get('plugin.manager.commerce_payment_type'), $container
->get('plugin.manager.commerce_payment_method_type'), $container
->get('datetime.time'), $container
->get('commerce_price.rounder'), $container
->get('language_manager'), $container
->get('http_client'), $container
->get('logger.factory')
->get('commerce_robokassa'));
}
public function defaultConfiguration() {
return [
'MrchLogin' => '',
'pass1' => '',
'pass2' => '',
'server_url_live' => 'https://auth.robokassa.ru/Merchant/Index.aspx',
'server_url_test' => 'https://auth.robokassa.ru/Merchant/Index.aspx',
'hash_type' => 'md5',
'show_robokassa_fee_message' => TRUE,
'allowed_currencies' => [],
'logging' => '',
] + parent::defaultConfiguration();
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
$form['MrchLogin'] = [
'#type' => 'textfield',
'#title' => $this
->t('login'),
'#description' => t('Your robokassa login'),
'#default_value' => $this->configuration['MrchLogin'],
'#required' => TRUE,
];
$form['pass1'] = [
'#type' => 'textfield',
'#title' => $this
->t('First password'),
'#description' => t('Password 1'),
'#default_value' => $this->configuration['pass1'],
'#required' => TRUE,
];
$form['pass2'] = [
'#type' => 'textfield',
'#title' => $this
->t('Second password'),
'#description' => t('Password 2'),
'#default_value' => $this->configuration['pass2'],
'#required' => TRUE,
];
$form['server_url_live'] = [
'#type' => 'textfield',
'#title' => $this
->t('Server URL'),
'#default_value' => $this->configuration['server_url_live'],
];
$form['server_url_test'] = [
'#type' => 'textfield',
'#title' => $this
->t('Server Test URL'),
'#default_value' => $this->configuration['server_url_test'],
];
$form['hash_type'] = [
'#type' => 'radios',
'#title' => $this
->t('Hash type'),
'#options' => [
'md5' => 'md5',
'ripemd160' => 'ripemd160',
'sha1' => 'sha1',
'sha256' => 'sha256',
'sha384' => 'sha384',
'sha512' => 'sha512',
],
'#default_value' => $this->configuration['hash_type'],
'#required' => TRUE,
];
$form['allowed_currencies'] = [
'#type' => 'checkboxes',
'#title' => $this
->t('Currencies'),
'#options' => $this
->paymentMethodsList(),
'#default_value' => $this->configuration['allowed_currencies'],
];
$form['show_robokassa_fee_message'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Show robokassa fee message'),
'#default_value' => $this->configuration['show_robokassa_fee_message'],
];
$form['logging'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Logging'),
'#default_value' => $this->configuration['logging'],
];
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['MrchLogin'] = $values['MrchLogin'];
if (!empty($values['pass1'])) {
$this->configuration['pass1'] = $values['pass1'];
}
if (!empty($values['pass2'])) {
$this->configuration['pass2'] = $values['pass2'];
}
$this->configuration['server_url_live'] = $values['server_url_live'];
$this->configuration['server_url_test'] = $values['server_url_test'];
$this->configuration['hash_type'] = $values['hash_type'];
$this->configuration['show_robokassa_fee_message'] = $values['show_robokassa_fee_message'];
$this->configuration['allowed_currencies'] = $values['allowed_currencies'];
$this->configuration['logging'] = $values['logging'];
}
}
function paymentMethodsList() {
$url = 'https://auth.robokassa.ru/Merchant/WebService/Service.asmx/GetCurrencies';
$data = [
'MerchantLogin' => $this->configuration['MrchLogin'],
'Language' => $this->languageManager
->getCurrentLanguage()
->getId() == 'ru' ? 'ru' : 'en',
];
$response = $this->httpClient
->get($url, [
'query' => $data,
]);
$xmlstring = $response
->getBody()
->getContents();
$xml = simplexml_load_string($xmlstring, "SimpleXMLElement", LIBXML_NOCDATA);
$json = json_encode($xml);
$array = json_decode($json, TRUE);
$ret = [];
if (!isset($array['Groups'])) {
return $ret;
}
foreach ($array['Groups'] as $groups) {
foreach ($groups as $group) {
foreach ($group['Items'] as $item) {
if (isset($item['@attributes'])) {
$item = array(
$item,
);
}
foreach ($item as $currency) {
$ret[$currency['@attributes']['Label']] = $currency['@attributes']['Name'];
}
}
}
}
return $ret;
}
public function onReturn(OrderInterface $order, Request $request) {
drupal_set_message($this
->t('Payment was processed'));
}
public function onNotify(Request $request) {
$payment = $this
->doValidatePost($request);
if (!$payment) {
return FALSE;
}
$payment
->setState('completed');
$payment
->save();
}
protected function doCancel(PaymentInterface $payment, array $status_response) {
$payment
->setState('authorization_expired');
$payment
->save();
return TRUE;
}
public function doValidatePost(Request $request, $is_interaction = TRUE) {
$data = $request->request
->all();
if (empty($data)) {
$this->logger
->warning('Interaction URL accessed with no POST data submitted.');
return FALSE;
}
$required_keys = array(
'OutSum',
'InvId',
);
if ($is_interaction) {
$required_keys[] = 'SignatureValue';
}
$unavailable_required_keys = array_diff_key(array_flip($required_keys), $data);
if (!empty($unavailable_required_keys)) {
$this->logger
->warning('Missing POST keys. POST data: <pre>!data</pre>', array(
'!data' => print_r($unavailable_required_keys, TRUE),
));
return FALSE;
}
if (empty($this->configuration['MrchLogin'])) {
$info = array(
'!settings' => print_r($this->configuration, 1),
'!data' => print_r($data, TRUE),
);
$this->logger
->warning('Missing merchant ID. POST data: <pre>!data</pre> <pre>!settings</pre>', $info);
return FALSE;
}
if ($is_interaction) {
if ($this->configuration) {
$robo_sign = $data['SignatureValue'];
$signature_data = array(
$data['OutSum'],
$data['InvId'],
$this->configuration['pass2'],
);
if (isset($data['shp_trx_id'])) {
$signature_data[] = 'shp_trx_id=' . $data['shp_trx_id'];
}
$sign = hash($this->configuration['hash_type'], implode(':', $signature_data));
if (Unicode::strtoupper($robo_sign) != Unicode::strtoupper($sign)) {
$this->logger
->warning('Missing Signature. 1 POST data: !data', array(
'!data' => print_r($data, TRUE),
));
return FALSE;
}
}
}
try {
$payment = $this->entityTypeManager
->getStorage('commerce_payment')
->load($data['shp_trx_id']);
} catch (InvalidPluginDefinitionException $e) {
$this->logger
->warning('Missing transaction id. POST data: !data', array(
'!data' => print_r($data, TRUE),
));
return FALSE;
}
$amount = new Price($data['OutSum'], $payment
->getAmount()
->getCurrencyCode());
if (!$payment instanceof PaymentInterface) {
$this->logger
->warning('Missing transaction id. POST data: !data', array(
'!data' => print_r($data, TRUE),
));
return FALSE;
}
if (!$payment
->getAmount()
->equals($amount)) {
$this->logger
->warning('Missing transaction id amount. POST data: !data', array(
'!data' => print_r($data, TRUE),
));
return FALSE;
}
return $payment;
}
public function setLocalState(PaymentInterface $payment, $remote_status) {
switch ($remote_status) {
case 'success':
$payment
->setState('completed');
break;
case 'fail':
$payment
->setState('authorization_voided');
break;
}
}
}