ITS-22: added module (#1)

* ITS-22: added module

* ITS-22: update module

* ITS-22: update README.md

* ITS-22: modified README.md

* ITS-22: update currency in create invoice

* ITS-22: modified README.md

* ITS-22: added default uc_rbkmoney_log

* ITS-22: post review fix

* ITS-22: added if

* ITS-22: added constants

* ITS-22: added link

* ITS-22: rename module

* ITS-22: rename module in README.md

* ITS-22: update constant
This commit is contained in:
Anatoly Cherkasov 2018-05-21 19:16:43 +03:00 committed by Anton Kuranda
parent c562f3307a
commit 2186c3dca3
10 changed files with 997 additions and 1 deletions

53
.gitignore vendored Normal file
View File

@ -0,0 +1,53 @@
# Created by .ignore support plugin (hsz.mobi)
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
*.DS_Store
*.iml
## Directory-based project format:
.idea/
# if you remove the above rule, at least ignore the following:
# User-specific stuff:
# .idea/workspace.xml
# .idea/tasks.xml
# .idea/dictionaries
# Sensitive or high-churn files:
# .idea/dataSources.ids
# .idea/dataSources.xml
# .idea/sqlDataSources.xml
# .idea/dynamic.xml
# .idea/uiDesigner.xml
# Gradle:
# .idea/gradle.xml
# .idea/libraries
# Mongo Explorer plugin:
# .idea/mongoSettings.xml
## File-based project format:
*.ipr
*.iws
## Plugin-specific files:
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
# Target folder
target

View File

@ -1 +1,23 @@
# rbkmoney-cms-drupal-ubercart
# Drupal uc_rbkmoney module
Модуль оплаты `rbkmoney_checkout_ubercart` необходим для интеграции с сервисом [RBKmoney](http://rbk.money/) на базе CMS Drupal и компонента [Drupal ubercart](https://www.drupal.org/project/ubercart).
### Требования к CMS Drupal:
* версия `7.x`;
* компонент `Ubercart`. Модуль тестировался на `Ubercart 7.x-3.10`
### Установка и настройка
С установкой и настройкой модуля можно ознакомиться в документации самого [модуля](https://www.drupal.org/sandbox/antonlva/rbkmoney_checkout_ubercart)
### Нашли ошибку или у вас есть предложение по улучшению модуля?
Пишите нам support@rbkmoney.com
При обращении необходимо:
* Указать наименование CMS и компонента магазина, а также их версии
* Указать версию платежного модуля (доступна в списке меню `Модули`)
* Описать проблему или предложение
* Приложить снимок экрана (для большей информативности)

View File

@ -0,0 +1,19 @@
# Drupal uc_rbkmoney module
Платежный модуль для Ubercart, позволяющий принимать платежи через систему RBKmoney.
Модуль отправляет запрос платежа платежной системе, и обрабатывает возвращаемый ответ, меняя в соответствии с ним статус заказа.
### Установка и настройка
Модуль находится в папке `rbkmoney_checkout_ubercart`
1. Установка. Копируем папку с модулем в каталог `/sites/all/modules`
2. Включаем модуль на странице `/admin/build/modules`, раздел **Ubercart - payment**
3. Настройка осуществляется по адресу `/admin/store/settings/uc_rbkmoney`
1. Прописываем ShopId магазина (берем из личного кабинета)
2. Копируем приватный ключ (берем из личного кабинета)
3. Копируем публичный ключ для обработки уведомлений (берем из личного кабинета)
4. Указать в личном кабинете callback URL для обработки уведомлений о смене статуса инвойса: https://<your-site>/rbkmoney_checkout_ubercart/callback/result
Пожалуйста, обязательно делайте бекапы!

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,138 @@
<?php
/**
* Callback URL for RBKmoney server response
*
* @see https://rbkmoney.github.io/webhooks-events-api/
*/
function rbkmoney_checkout_ubercart_callback_result()
{
$type = 'callback_result';
$content = file_get_contents('php://input');
_rbkmoney_checkout_ubercart_logger($type, "<pre>%logs</pre>", ['%logs' => var_export(['content' => $content], TRUE)]);
if (empty($_SERVER[SIGNATURE])) {
http_response_code(HTTP_CODE_BAD_REQUEST);
_rbkmoney_checkout_ubercart_logger($type, "Webhook notification signature missing. <pre>%logs</pre>", ['%logs' => var_export(['content' => $content], TRUE)]);
echo json_encode(array('message' => 'Webhook notification signature missing'));
exit();
}
$params_signature = _rbkmoney_checkout_ubercart_get_parameters_content_signature($_SERVER[SIGNATURE]);
if (empty($params_signature[SIGNATURE_ALG])) {
_rbkmoney_checkout_ubercart_logger($type, "Missing required parameter " . SIGNATURE_ALG . " signature. <pre>%logs</pre>", ['%logs' => var_export(['content' => $content], TRUE)]);
http_response_code(HTTP_CODE_BAD_REQUEST);
echo json_encode(array('message' => 'Missing required parameter ' . SIGNATURE_ALG));
exit();
}
if (empty($params_signature[SIGNATURE_DIGEST])) {
_rbkmoney_checkout_ubercart_logger($type, "Missing required parameter " . SIGNATURE_DIGEST . " signature. <pre>%logs</pre>", ['%logs' => var_export(['content' => $content], TRUE)]);
http_response_code(HTTP_CODE_BAD_REQUEST);
echo json_encode(array('message' => 'Missing required parameter ' . SIGNATURE_DIGEST));
exit();
}
$signature = _rbkmoney_checkout_ubercart_urlsafe_b64decode($params_signature[SIGNATURE_DIGEST]);
if (!_rbkmoney_checkout_ubercart_verification_signature($content, $signature, MERCHANT_CALLBACK_PUBLIC_KEY)) {
_rbkmoney_checkout_ubercart_logger($type, "Webhook notification signature mismatch. <pre>%logs</pre>",
['%logs' => var_export([
$_SERVER[SIGNATURE],
$content,
$signature,
MERCHANT_CALLBACK_PUBLIC_KEY
], TRUE)]);
http_response_code(HTTP_CODE_BAD_REQUEST);
echo json_encode(array('message' => 'Webhook notification signature mismatch'));
exit();
}
$required_fields = [INVOICE, EVENT_TYPE];
$data = json_decode($content, TRUE);
foreach ($required_fields as $field) {
if (empty($data[$field])) {
_rbkmoney_checkout_ubercart_logger($type, " One or more required fields are missing <pre>%logs</pre>",
['%logs' => var_export([
'input_content' => $content,
'required_fields' => $required_fields
], TRUE)]);
http_response_code(HTTP_CODE_BAD_REQUEST);
echo json_encode(array('message' => 'One or more required fields are missing'));
exit();
}
}
$current_shop_id = (int)variable_get('uc_rbkmoney_shop_id');
if ($data[INVOICE][INVOICE_SHOP_ID] != $current_shop_id) {
_rbkmoney_checkout_ubercart_logger($type, ' Webhook notification ' . INVOICE_SHOP_ID . ' mismatch<pre>%logs</pre>', ['%logs' => var_export($content, TRUE)]);
http_response_code(HTTP_CODE_BAD_REQUEST);
echo json_encode(array('message' => INVOICE_SHOP_ID . ' is missing'));
exit();
}
if (empty($data[INVOICE][INVOICE_METADATA][ORDER_ID])) {
_rbkmoney_checkout_ubercart_logger($type, ORDER_ID . ' is missing <pre>%logs</pre>', ['%logs' => var_export($content, TRUE)]);
http_response_code(HTTP_CODE_BAD_REQUEST);
echo json_encode(array('message' => ORDER_ID . ' is missing'));
exit();
}
$order_id = $data[INVOICE][INVOICE_METADATA][ORDER_ID];
$order = uc_order_load($order_id);
$order_amount = _rbkmoney_checkout_ubercart_prepare_amount($order->order_total);
$invoice_amount = $data[INVOICE][INVOICE_AMOUNT];
if ($order_amount != $invoice_amount) {
_rbkmoney_checkout_ubercart_logger($type, 'Received amount vs Order amount mismatch <pre>%logs</pre>', ['%logs' => var_export($content, TRUE)]);
http_response_code(HTTP_CODE_BAD_REQUEST);
echo json_encode(array('message' => 'Received amount vs Order amount mismatch'));
exit();
}
$allowed_event_types = [EVENT_TYPE_INVOICE_PAID, EVENT_TYPE_INVOICE_CANCELLED];
if (in_array($data[EVENT_TYPE], $allowed_event_types)) {
$invoice_status = $data[INVOICE][INVOICE_STATUS];
_rbkmoney_checkout_ubercart_update_status_order($order_id, $invoice_status);
}
exit();
}
function _rbkmoney_checkout_ubercart_urlsafe_b64decode($string)
{
$data = str_replace(array('-', '_'), array('+', '/'), $string);
$mod4 = strlen($data) % 4;
if ($mod4) {
$data .= substr('====', $mod4);
}
return base64_decode($data);
}
function _rbkmoney_checkout_ubercart_urlsafe_b64encode($string)
{
$data = base64_encode($string);
return str_replace(array('+', '/'), array('-', '_'), $data);
}
function _rbkmoney_checkout_ubercart_get_parameters_content_signature($content_signature)
{
preg_match_all(SIGNATURE_PATTERN, $content_signature, $matches, PREG_PATTERN_ORDER);
$params = array();
$params[SIGNATURE_ALG] = !empty($matches[1][0]) ? $matches[1][0] : '';
$params[SIGNATURE_DIGEST] = !empty($matches[2][0]) ? $matches[2][0] : '';
return $params;
}
function _rbkmoney_checkout_ubercart_verification_signature($data = '', $signature = '', $public_key = '')
{
if (empty($data) || empty($signature) || empty($public_key)) {
return FALSE;
}
$public_key_id = openssl_get_publickey($public_key);
if (empty($public_key_id)) {
return FALSE;
}
$verify = openssl_verify($data, $signature, $public_key_id, OPENSSL_SIGNATURE_ALG);
return ($verify == OPENSSL_VERIFY_SIGNATURE_IS_CORRECT);
}

View File

@ -0,0 +1,143 @@
<?php
/**
* Define payment statuses
*/
define('UC_RBKMONEY_STATUS_FAILED', 'cancelled');
define('UC_RBKMONEY_STATUS_SUCCESS', 'paid');
define('ANONYMOUS_USER_ID', 0);
/**
* Module data
*/
define('MODULE_NAME', 'rbkmoney_checkout_ubercart');
define('MODULE_BASE_PATH', base_path() . drupal_get_path('module', MODULE_NAME));
/**
* Api URL
*/
define('API_URL', 'https://api.rbk.money/v1/');
/**
* Merchant settings
*/
define('MERCHANT_PRIVATE_KEY', trim(variable_get('uc_rbkmoney_merchant_private_key', 'merchant_private_key')));
define('MERCHANT_CALLBACK_PUBLIC_KEY', trim(variable_get('uc_rbkmoney_merchant_callback_public_key', 'merchant_callback_public_key')));
/**
* Payment form
*/
define('BASE_URL', $GLOBALS['base_url']);
define('PAYMENT_FORM_URL', 'https://checkout.rbk.money/checkout.js');
define('PAYMENT_FORM_SUCCESS_URL', BASE_URL . '/'.MODULE_NAME.'/success');
define('PAYMENT_FORM_PATH_IMG_LOGO', BASE_URL . MODULE_BASE_PATH . '/images/logo_default.png');
/**
* Payment method logo
*/
define('PAYMENT_METHOD_PATH_IMG_LOGO', MODULE_BASE_PATH . '/images/logo_rbkmoney.png');
/**
* Payment form default css button
*/
define('PAYMENT_FORM_DEFAULT_CSS_BUTTON', trim(variable_get('uc_rbkmoney_payform_css_button', '
button.rbkmoney-button {
border: 1px solid #e4e4e4;
border-bottom: 1px solid #b4b4b4;
border-left-color: #d2d2d2;
border-right-color: #d2d2d2;
color: #2f2f2f;
cursor: pointer;
text-align: center;
margin-top: 2px;
margin-bottom: 1em;
margin-right: 0.6em;
padding: 4px 17px;
border-radius: 15px;
background: #eee;
box-shadow: none;
font: normal 0.929em/1.1em "Lucida Grande", "Lucida Sans Unicode", Verdana, sans-serif;
}
button.rbkmoney-button:hover {
background: #dedede;
}'
)));
/**
* Create invoice settings
*/
define('CREATE_INVOICE_TEMPLATE_DUE_DATE', 'Y-m-d\TH:i:s\Z');
define('CREATE_INVOICE_DUE_DATE', '+1 days');
/**
* Constants for Callback
*/
define('SIGNATURE', 'HTTP_CONTENT_SIGNATURE');
define('SIGNATURE_ALG', 'alg');
define('SIGNATURE_DIGEST', 'digest');
define('SIGNATURE_PATTERN', "|alg=(\S+);\sdigest=(.*)|i");
define('EVENT_TYPE', 'eventType');
// EVENT TYPE INVOICE
define('EVENT_TYPE_INVOICE_CREATED', 'InvoiceCreated');
define('EVENT_TYPE_INVOICE_PAID', 'InvoicePaid');
define('EVENT_TYPE_INVOICE_CANCELLED', 'InvoiceCancelled');
define('EVENT_TYPE_INVOICE_FULFILLED', 'InvoiceFulfilled');
// EVENT TYPE PAYMENT
define('EVENT_TYPE_PAYMENT_STARTED', 'PaymentStarted');
define('EVENT_TYPE_PAYMENT_PROCESSED', 'PaymentProcessed');
define('EVENT_TYPE_PAYMENT_CAPTURED', 'PaymentCaptured');
define('EVENT_TYPE_PAYMENT_CANCELLED', 'PaymentCancelled');
define('EVENT_TYPE_PAYMENT_FAILED', 'PaymentFailed');
define('INVOICE', 'invoice');
define('INVOICE_ID', 'id');
define('INVOICE_SHOP_ID', 'shopID');
define('INVOICE_STATUS', 'status');
define('INVOICE_DUE_DATE', 'dueDate');
define('INVOICE_AMOUNT', 'amount');
define('INVOICE_CURRENCY', 'currency');
define('INVOICE_REASON', 'reason');
define('INVOICE_METADATA', 'metadata');
define('ORDER_ID', 'order_id');
define('PAYMENT', 'payment');
define('PAYMENT_ID', 'id');
define('PAYMENT_AMOUNT', 'amount');
define('PAYMENT_CURRENCY', 'currency');
define('PAYMENT_STATUS', 'status');
/**
* Api params
*/
define('API_INVOICE_ID', 'invoice_id');
/**
* Openssl verify
*/
define('OPENSSL_VERIFY_SIGNATURE_IS_CORRECT', 1);
define('OPENSSL_VERIFY_SIGNATURE_IS_INCORRECT', 0);
define('OPENSSL_VERIFY_ERROR', -1);
define('OPENSSL_SIGNATURE_ALG', OPENSSL_ALGO_SHA256);
/**
* HTTP CODE
*/
define('HTTP_CODE_OK', 200);
define('HTTP_CODE_CREATED', 201);
define('HTTP_CODE_MOVED_PERMANENTLY', 301);
define('HTTP_CODE_BAD_REQUEST', 400);
define('HTTP_CODE_INTERNAL_SERVER_ERROR', 500);
/**
* HTTP METHOD
*/
define('HTTP_METHOD_GET', 'GET');
define('HTTP_METHOD_POST', 'POST');

View File

@ -0,0 +1,8 @@
name = RBKmoney
description = Provide RBKmoney payment gateway
package = "Ubercart - payment"
core = 7.x
php = 5.x
configure = admin/store/settings/rbkmoney_checkout_ubercart
dependencies[] = uc_payment
project = rbkmoney

View File

@ -0,0 +1,20 @@
<?php
/**
* @file
* Uninstall function for the rbkmoney_checkout_ubercart module.
*/
/**
* Implements hook_uninstall().
*/
function rbkmoney_checkout_ubercart_uninstall() {
variable_del('uc_rbkmoney_shop_id');
variable_del('uc_rbkmoney_merchant_private_key');
variable_del('uc_rbkmoney_merchant_callback_public_key');
variable_del('uc_rbkmoney_payform_path_logo');
variable_del('uc_rbkmoney_payform_button_label');
variable_del('uc_rbkmoney_payform_company_name');
variable_del('uc_rbkmoney_payform_description');
variable_del('uc_rbkmoney_log');
}

View File

@ -0,0 +1,593 @@
<?php
/**
* @file
* Integrates RBKmoney's payment service.
*/
module_load_include('inc', 'rbkmoney_checkout_ubercart', 'includes/rbkmoney_checkout_ubercart_settings');
/**
* Implements hook_permission().
*/
function rbkmoney_checkout_ubercart_permission()
{
return [
'administer rbkmoney_checkout_ubercart' => [
'title' => t('Administer RBKmoney'),
'description' => t('Access RBKmoney administration page.'),
],
];
}
/**
* Implements hook_menu().
*/
function rbkmoney_checkout_ubercart_menu()
{
$items['admin/store/settings/rbkmoney_checkout_ubercart'] = [
'title' => 'RBKmoney',
'description' => 'Settings RBKmoney payment gateway',
'page callback' => 'drupal_get_form',
'page arguments' => ['rbkmoney_checkout_ubercart_setup'],
'access arguments' => ['administer rbkmoney_checkout_ubercart'],
'type' => MENU_NORMAL_ITEM,
];
$items['rbkmoney_checkout_ubercart/success'] = [
'title' => 'Internal Data',
'page callback' => 'rbkmoney_checkout_ubercart_payment_end',
'page arguments' => ['success'],
'access arguments' => ['access content'],
'type' => MENU_CALLBACK,
];
$items['rbkmoney_checkout_ubercart/callback/result'] = [
'title' => 'Callback',
'page callback' => 'rbkmoney_checkout_ubercart/callback/result',
'access arguments' => ['access content'],
'type' => MENU_CALLBACK,
'file' => 'includes/rbkmoney_checkout_ubercart_callback.pages.inc',
];
return $items;
}
/**
* Callback for settings page.
*/
function rbkmoney_checkout_ubercart_setup()
{
$form['uc_rbkmoney_help'] = [
'#markup' => t('Настройки платежного модуля RBKmoney'),
];
$form['vertical_tabs'] = array(
'#type' => 'vertical_tabs',
'#default_tab' => 'edit-tab1',
);
$form['tab1'] = array(
'#type' => 'fieldset',
'#title' => t('Обязательные настройки'),
'#collapsible' => TRUE,
'#group' => 'vertical_tabs',
);
$form['tab1']['uc_rbkmoney_shop_id'] = [
'#type' => 'textfield',
'#title' => t('ID магазина'),
'#default_value' => variable_get('uc_rbkmoney_shop_id', '1'),
'#description' => t(''),
'#required' => TRUE,
];
$form['tab1']['uc_rbkmoney_merchant_callback_public_key'] = [
'#type' => 'textarea',
'#title' => t('Ключ подписи получаемых на Webhook уведомлений из <a href=\'!dblog\'>https://dashboard.rbk.money/api/webhooks</a>',
['!dblog' => "https://dashboard.rbk.money/api/webhooks"]),
'#default_value' => MERCHANT_CALLBACK_PUBLIC_KEY,
'#description' => t(''),
'#rows' => 10,
'#cols' => 10,
'#resizable' => FALSE,
'#weight' => 10,
'#required' => TRUE,
];
$form['tab1']['uc_rbkmoney_merchant_private_key'] = [
'#type' => 'textarea',
'#title' => t('Ваш ключ для доступа к API из <a href=\'!dblog\'>https://dashboard.rbk.money/api/key</a>',
['!dblog' => "https://dashboard.rbk.money/api/key"]),
'#default_value' => MERCHANT_PRIVATE_KEY,
'#description' => t(''),
'#rows' => 10,
'#cols' => 10,
'#resizable' => FALSE,
'#weight' => 10,
'#required' => TRUE,
];
$form['tab2'] = array(
'#type' => 'fieldset',
'#title' => t('Кастомизация формы оплаты'),
'#collapsible' => TRUE,
'#group' => 'vertical_tabs',
);
$form['tab2']['uc_rbkmoney_payform_path_logo'] = [
'#type' => 'textfield',
'#title' => t('URL логотипа для отображения на форме оплаты'),
'#default_value' => variable_get('uc_rbkmoney_payform_path_logo', PAYMENT_FORM_PATH_IMG_LOGO),
'#description' => t(''),
'#required' => FALSE,
];
$form['tab2']['uc_rbkmoney_payform_button_label'] = [
'#type' => 'textfield',
'#title' => t('Текст кнопки открытия формы оплаты'),
'#default_value' => variable_get('uc_rbkmoney_payform_button_label', ''),
'#description' => t(''),
'#required' => FALSE,
];
$form['tab2']['uc_rbkmoney_payform_description'] = [
'#type' => 'textfield',
'#title' => t('Описание в форме оплаты'),
'#default_value' => variable_get('uc_rbkmoney_payform_description', ''),
'#description' => t(''),
'#required' => FALSE,
];
$form['tab2']['uc_rbkmoney_payform_company_name'] = [
'#type' => 'textfield',
'#title' => t('Название магазина для отображения на форме оплаты'),
'#default_value' => variable_get('uc_rbkmoney_payform_company_name', ''),
'#description' => t(''),
'#required' => FALSE,
];
$form['tab2']['uc_rbkmoney_payform_css_button'] = [
'#type' => 'textarea',
'#title' => t('Стилизация кнопки открытия формы оплаты'),
'#default_value' => variable_get('uc_rbkmoney_payform_css_button', PAYMENT_FORM_DEFAULT_CSS_BUTTON),
'#description' => t(''),
'#rows' => 10,
'#cols' => 10,
'#resizable' => FALSE,
'#weight' => 10,
'#required' => FALSE,
];
$form['tab3'] = array(
'#type' => 'fieldset',
'#title' => t('Дополнительные настройки'),
'#collapsible' => TRUE,
'#group' => 'vertical_tabs',
);
$form['tab3']['common_settings']['uc_rbkmoney_log'] = [
'#type' => 'radios',
'#title' => t('Сохранять лог RBKmoney API в <a href=\'!dblog\'>system log</a>',
['!dblog' => url(BASE_URL . '/#overlay=admin/reports/dblog')]),
'#options' => [1 => t('Yes'), 0 => t('No')],
'#default_value' => variable_get('uc_rbkmoney_log', 1),
];
$form['tab4'] = array(
'#type' => 'fieldset',
'#title' => t('Документация'),
'#collapsible' => TRUE,
'#group' => 'vertical_tabs',
);
$form['tab4']['docs_integrations'] = array(
'#type' => 'item',
'#markup' => t(l('Документация по интеграции', 'https://rbkmoney.github.io/docs',
['attributes' =>
['target' => '_blank']
])),
);
$form['tab4']['docs_webhooks'] = array(
'#type' => 'item',
'#markup' => t(l('Документация для работы с вебхуками', 'https://rbkmoney.github.io/webhooks-events-api/',
['attributes' =>
['target' => '_blank']
])),
);
$form['tab4']['docs_checkout'] = array(
'#type' => 'item',
'#markup' => t(l('Документация по кастомизации платежной формы', 'https://rbkmoney.github.io/docs/integrations/checkout/#html-api',
['attributes' =>
['target' => '_blank']
])),
);
return system_settings_form($form);
}
/**
* Implements hook_uc_payment_method().
*/
function rbkmoney_checkout_ubercart_uc_payment_method()
{
$img = theme('image', [
'path' => PAYMENT_METHOD_PATH_IMG_LOGO,
'alt' => 'RBKmoney',
'attributes' => [
'class' => 'system_logo'
]
]
);
$title = t('RBKmoney') . '<br />' . $img;
$methods[] = [
'id' => 'rbkmoney',
'name' => t('RBKmoney'),
'title' => $title,
'desc' => t('RBKmoney'),
'weight' => 1,
'callback' => 'uc_payment_method_rbkmoney',
'checkout' => TRUE,
//'no_gateway' => TRUE,
];
return $methods;
}
/**
* Implements hook_payment_method
*/
function uc_payment_method_rbkmoney()
{
return;
}
/**
* Implements hook_form_alter() for uc_cart_checkout_review_form().
*/
function rbkmoney_checkout_ubercart_form_alter(&$form, &$form_state, $form_id)
{
$order_id = isset($_SESSION['cart_order']) ? intval($_SESSION['cart_order']) : 0;
if ($form_id == 'uc_cart_checkout_review_form' && $order_id > 0) {
$order = uc_order_load($order_id);
if ($order->payment_method == 'rbkmoney') {
unset($form['actions']['submit']);
if (empty($_SESSION[API_INVOICE_ID])) {
$response = _rbkmoney_checkout_ubercart_create_invoice($order);
$response_decode = drupal_json_decode($response['body']);
$invoice_id = !empty($response_decode['id']) ? $response_decode['id'] : '';
$_SESSION[API_INVOICE_ID] = $invoice_id;
} else {
$invoice_id = $_SESSION[API_INVOICE_ID];
}
$access_token = _rbkmoney_checkout_ubercart_create_invoice_access_token($invoice_id);
$company_name = (!empty(variable_get('uc_rbkmoney_payform_company_name'))) ? 'data-name="' . variable_get('uc_rbkmoney_payform_company_name') . '"' : '';
$company_logo = (!empty(variable_get('uc_rbkmoney_payform_path_logo'))) ? 'data-logo="' . variable_get('uc_rbkmoney_payform_path_logo') . '"' : '';
$button_label = (!empty(variable_get('uc_rbkmoney_payform_button_label'))) ? 'data-label="' . variable_get('uc_rbkmoney_payform_button_label') . '"' : '';
$description = (!empty(variable_get('uc_rbkmoney_payform_description'))) ? 'data-description="' . variable_get('uc_rbkmoney_payform_description') . '"' : '';
$payframe = '<form action="' . PAYMENT_FORM_SUCCESS_URL . '" method="' . HTTP_METHOD_GET . '">
<script src="' . PAYMENT_FORM_URL . '" class="rbkmoney-checkout"
data-invoice-id="' . $invoice_id . '"
data-invoice-access-token="' . $access_token . '"
' . $company_name . '
' . $company_logo . '
' . $button_label . '
' . $description . '
>
</script>
</form>';
$css_button = '<style>' . strip_tags(variable_get('uc_rbkmoney_payform_css_button', PAYMENT_FORM_DEFAULT_CSS_BUTTON)) . '</style>';
$form['#prefix'] = '<table><tr><td>';
$form['#suffix'] = '</td><td>' . $css_button . $payframe . '</td></tr></table>';
}
}
}
/**
* Returns the description and subtotal of the products on an order.
*/
function _rbkmoney_checkout_ubercart_product_details($items)
{
$desc = '';
if (!empty($items)) {
foreach ($items as $item) {
if (!empty($desc)) {
$desc .= ', ';
}
$desc .= $item->qty . 'x ' . check_plain($item->title);
}
}
return $desc;
}
function rbkmoney_checkout_ubercart_hook_form($form, &$form_state, $order)
{
$order = uc_order_load($_SESSION['cart_order']);
$form['shopId'] = [
'#type' => 'hidden',
'#value' => variable_get('uc_rbkmoney_shop_id'),
];
$form['orderId'] = [
'#type' => 'hidden',
'#value' => $order->order_id,
];
$form['amount'] = [
'#type' => 'hidden',
'#value' => $order->order_total,
];
$form['user_email'] = [
'#type' => 'hidden',
'#value' => $order->primary_email,
];
$form['#action'] = '#';
$form['submit'] = [
'#type' => 'button',
'#value' => t('Place your order'),
'#attributes' => ['class' => ['ctools-use-modal']],
'#id' => 'go'
];
return $form;
}
/**
* Payment request.
*/
function rbkmoney_checkout_ubercart_submit_form($form, &$form_state, $order)
{
$order = uc_order_load($_SESSION['cart_order']);
$form['shopId'] = [
'#type' => 'hidden',
'#value' => variable_get('uc_rbkmoney_shop_id'),
];
$form['orderId'] = [
'#type' => 'hidden',
'#value' => $order->order_id,
];
$form['amount'] = [
'#type' => 'hidden',
'#value' => $order->order_total,
];
$form['user_email'] = [
'#type' => 'hidden',
'#value' => $order->primary_email,
];
$form['#action'] = '#';
$form['submit'] = [
'#type' => 'button',
'#value' => t('Place your order'),
'#attributes' => ['class' => ['ctools-use-modal']],
'#id' => 'go'
];
return $form;
}
/**
* Callback redirect from RBKmoney site.
*/
function rbkmoney_checkout_ubercart_payment_end($arg)
{
switch ($arg) {
case 'success':
if (isset($_SESSION['cart_order'])) {
$_SESSION['uc_checkout'][$_SESSION['cart_order']]['do_complete'] = TRUE;
if (!empty($_SESSION[API_INVOICE_ID])) unset($_SESSION[API_INVOICE_ID]);
drupal_goto('cart/checkout/complete');
}
break;
case 'fail':
if (isset($_SESSION['cart_order'])) {
unset($_SESSION['cart_order']);
if (!empty($_SESSION[API_INVOICE_ID])) unset($_SESSION[API_INVOICE_ID]);
drupal_set_message(t('Your payment has been declined.'), 'error');
drupal_goto('cart');
}
break;
}
return;
}
function _rbkmoney_checkout_ubercart_create_invoice_access_token($invoice_id)
{
$url = _rbkmoney_checkout_ubercart_prepare_api_url('processing/invoices/' . $invoice_id . '/access_tokens');
$headers = _rbkmoney_checkout_ubercart_prepare_headers();
$response = _rbkmoney_checkout_ubercart_send($url, $headers, '', 'access_tokens');
if ($response['http_code'] != HTTP_CODE_CREATED) {
drupal_set_message(t('An error occurred while creating Invoice Access Token'), 'error');
drupal_goto('cart');
}
$response_decode = drupal_json_decode($response['body']);
$access_token = !empty($response_decode['payload']) ? $response_decode['payload'] : '';
return $access_token;
}
function _rbkmoney_checkout_ubercart_create_invoice($order)
{
$data = [
'shopID' => (int)variable_get('uc_rbkmoney_shop_id'),
'amount' => _rbkmoney_checkout_ubercart_prepare_amount($order->order_total),
'metadata' => _rbkmoney_checkout_ubercart_prepare_metadata($order),
'dueDate' => _rbkmoney_checkout_ubercart_prepare_due_date(),
'currency' => $order->currency,
'product' => $order->order_id,
'description' => _rbkmoney_checkout_ubercart_product_details($order->products),
];
$url = _rbkmoney_checkout_ubercart_prepare_api_url('processing/invoices');
$headers = _rbkmoney_checkout_ubercart_prepare_headers();
$response = _rbkmoney_checkout_ubercart_send($url, $headers, drupal_json_encode($data), 'init_invoice');
if ($response['http_code'] != HTTP_CODE_CREATED) {
drupal_set_message(t('An error occurred while creating invoice'), 'error');
drupal_goto('cart');
}
return $response;
}
function _rbkmoney_checkout_ubercart_prepare_headers()
{
$headers = [];
$headers[] = 'X-Request-ID: ' . uniqid();
$headers[] = 'Authorization: Bearer ' . MERCHANT_PRIVATE_KEY;
$headers[] = 'Content-type: application/json; charset=utf-8';
$headers[] = 'Accept: application/json';
return $headers;
}
/**
* Prepare due date
* @return string
*/
function _rbkmoney_checkout_ubercart_prepare_due_date()
{
date_default_timezone_set('UTC');
return date(CREATE_INVOICE_TEMPLATE_DUE_DATE, strtotime(CREATE_INVOICE_DUE_DATE));
}
/**
* Prepare metadata
*
* @param $order Object
* @return array
*/
function _rbkmoney_checkout_ubercart_prepare_metadata($order)
{
return [
'cms' => 'drupal',
'cms_version' => VERSION,
'module' => MODULE_NAME,
'order_id' => $order->order_id,
];
}
/**
* Prepare amount (e.g. 124.24 -> 12424)
*
* @param $amount int
* @return int
*/
function _rbkmoney_checkout_ubercart_prepare_amount($amount)
{
if ($amount < 0) {
drupal_set_message(t('Requested amount less than allowed'), 'error');
drupal_goto('cart');
}
return $amount * 100;
}
function _rbkmoney_checkout_ubercart_send($url = '', $headers = [], $data = '', $type = '')
{
$request = [
'url' => $url,
'method' => HTTP_METHOD_POST,
'body' => $data,
'headers' => $headers,
];
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_POST, TRUE);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$body = curl_exec($curl);
$info = curl_getinfo($curl);
$curl_errno = curl_errno($curl);
$response['http_code'] = $info['http_code'];
$response['body'] = $body;
$response['error'] = $curl_errno;
$logs = [
'request' => $request,
'response' => $response,
];
_rbkmoney_checkout_ubercart_logger($type, "<pre>%logs</pre>", ['%logs' => var_export($logs, TRUE)]);
curl_close($curl);
return $response;
}
/**
* Update status order
*
* @param string $order_id
* @param string $invoice_status
*/
function _rbkmoney_checkout_ubercart_update_status_order($order_id = '', $invoice_status = '')
{
_rbkmoney_checkout_ubercart_logger('update_status_order_req', 'order_id: ' . $order_id . '; invoice status: ' . $invoice_status);
$order = uc_order_load($order_id);
// if the user is anonymous - always equals zero
$uid = isset($order->uid) ? $order->uid : ANONYMOUS_USER_ID;
switch ($invoice_status) {
case UC_RBKMONEY_STATUS_FAILED:
uc_order_update_status($order_id, 'canceled');
uc_order_comment_save($order_id, $uid, t('Order canceled'), $type = 'admin', $status = 1, $notify = FALSE);
$status = UC_RBKMONEY_STATUS_FAILED;
break;
case UC_RBKMONEY_STATUS_SUCCESS:
uc_payment_enter($order_id, 'RBKmoney', $order->order_total, $uid, NULL, NULL);
uc_order_update_status($order_id, 'completed');
uc_cart_complete_sale($order);
uc_order_comment_save($order_id, $uid, t('RBKmoney: payment successful'), $type = 'admin', $status = 1, $notify = FALSE);
$status = UC_RBKMONEY_STATUS_SUCCESS;
break;
default:
$status = $invoice_status;
break;
}
_rbkmoney_checkout_ubercart_logger('update_status_order_res', 'order status: ' . $status . '; order_id: ' . $order_id);
}
function _rbkmoney_checkout_ubercart_prepare_api_url($path = '', $query_params = [])
{
$url = rtrim(API_URL, '/') . '/' . $path;
if (!empty($query_params)) {
$url .= '?' . http_build_query($query_params);
}
return $url;
}
function _rbkmoney_checkout_ubercart_logger($type, $message, $variables = [])
{
if (variable_get('uc_rbkmoney_log', 1)) {
watchdog(MODULE_NAME . '_' . $type, $message, $variables);
}
}