mirror of
https://github.com/valitydev/rbkmoney-cms-drupal-ubercart.git
synced 2024-11-06 02:15:23 +00:00
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:
parent
c562f3307a
commit
2186c3dca3
53
.gitignore
vendored
Normal file
53
.gitignore
vendored
Normal 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
|
24
README.md
24
README.md
@ -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 и компонента магазина, а также их версии
|
||||
* Указать версию платежного модуля (доступна в списке меню `Модули`)
|
||||
* Описать проблему или предложение
|
||||
* Приложить снимок экрана (для большей информативности)
|
||||
|
19
rbkmoney_checkout_ubercart/README.md
Normal file
19
rbkmoney_checkout_ubercart/README.md
Normal 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
|
||||
|
||||
Пожалуйста, обязательно делайте бекапы!
|
BIN
rbkmoney_checkout_ubercart/images/logo_default.png
Normal file
BIN
rbkmoney_checkout_ubercart/images/logo_default.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
BIN
rbkmoney_checkout_ubercart/images/logo_rbkmoney.png
Normal file
BIN
rbkmoney_checkout_ubercart/images/logo_rbkmoney.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
@ -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);
|
||||
}
|
@ -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');
|
@ -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
|
@ -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');
|
||||
}
|
593
rbkmoney_checkout_ubercart/rbkmoney_checkout_ubercart.module
Normal file
593
rbkmoney_checkout_ubercart/rbkmoney_checkout_ubercart.module
Normal 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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user