ITS-25: uploaded the module (#1)

* ITS-25: uploaded the module

* ITS-25: added a configuration

* ITS-25: added constant

* ITS-25: minor changes

* ITS-25: minor fix

* ITS-25: corrections after the review

* ITS-25: fix currency

* ITS-25: camelCase

* ITS-25: added getHeaders()
This commit is contained in:
Anatoly Cherkasov 2017-04-03 11:38:18 +03:00 committed by GitHub
parent 56618604d1
commit 333388ab5c
12 changed files with 1248 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,94 @@
# rbkmoney-cms-opencart
# rbkmoney-cms-opencart
### Установка и настройка модуля
#### Установка
1. Первый способ
Заархивируйте папку `upload` в `zip` архив и переименуйте его в `rbkmoney-payment.ocmod.zip`
После чего необходимо зайти в `Extension Installer`, нажать `Upload` и выбрать архив для установки: `rbkmoney-payment.ocmod.zip`
2. Второй способ
Для установки модуля скопируйте содержимое каталога `upload`:
```
<OpenCart>/admin/
<OpenCart>/catalog/
```
#### Настройка модуля
Затем в панели администратора установите и настройте его:
```
Extensions > Payments > RBKmoney нажать [Install]
Extensions > Payments > RBKmoney нажать [Edit] и заполнить необходимые настройки
```
Для начала приема платежей на Вашем сайте необходимо:
- Зарегистрироваться на https://dashboard.rbk.money
- Получить необходимые данные для настройки модуля
- Настроить модуль
#### Совместимость
- Opencart 2.0
- Opencart 2.1
- Opencart 2.2
В списке совместимости нет вашей версии Opencart 2.x? Напишите нам обращение - это ускорит процесс адаптации модуля под вашу систему.
#### Проблемы и решения
1. Ошибка: FTP должен быть включен в настройках
Два варианта решения:
- Если при установке модуля из админки отображается эта ошибка - вам нужно установить бесплатную FTP QuickFix модификацию localcopy.ocmod.xml. Она установиться без проблем через тот же установщик дополнений, только после установки не забудьте обновить модификации и затем можете приступать к установке любых модулей на Opencart 2.
- Также решить эту ошибку можно по другому: прописать доступы к FTP в админке Система > Настройки > Магазин > вкладка FTP.
2. Ошибка: Доступ запрещен!
Если вы видите сообщение "Доступ запрещен! У Вас нет прав для доступа к этой странице. Если она Вам нужна, обратитесь к администратору." - нужно дать права администраторам на управление модулем или страницей.
Решение: в админке Opencart 2 переходим в Система > Пользователи > Группы пользователей > Администраторы и здесь нажимаем "Выделить все" ниже обоих блоков, затем Сохранить.
3. Ошибка: Недопустимый тип файла!
Если модуль - это один XML файл, то его расширение должно быть .ocmod.xml
Если модуль - это ocmod.zip архив, то его не нужно распаковывать, а устанавливать как есть. В таком архиве обязательно должна быть папка upload (может быть пустой), а также могут быть файлы модификаций: install.xml, install.php, install.sql. Никаких других файлов в корне архива быть не должно.
Читайте подробнее как [устанавливать модули в Opencart 2](https://opencart2x.ru/blog/install-module)
4. Ошибка: Каталог, содержащий файлы для загрузки не может быть найден!
Эта ошибка означает, что в загружаемом архиве отсутсвует папка upload. Даже если у модуля нет файлов, кроме модификаций - эта папка должна присутствовать в архиве модуля .ocmod.zip, тогда она должна оставаться пустой.
5. Ошибка: Модификатор использует тот же ID код который вы пытаетесь загрузить!
Эта ошибка означает, что вы пытаетесь установить модификатор, который уже установлен или, возможно, у какого-то вашего модуля такой же ID.
Для решения этой ошибки вам нужно перед установкой удалить старую версию модификации в разделе Модули > Модификации.
Если такого модуля у вас нет, но совпадает ID, тогда нужно поменять значение параметра `<code>` в устанавливаемом модификаторе XML, сделать этот параметр уникальным дописав несколько символов.
6. Ошибка: `Warning: DOMDocument::loadXML(): CData section not finished`
Эта ошибка означает, что вы пытаетесь установить слишком объемный xml-модификатор.
Количество символов в `ocmod.xml` файле не должно превышать 65535.
Для решения ошибки нужно разбить xml-файл модификации на несколько частей, главное - не забыть задавать каждой уникальное значение в `<code>`, можно добавлять к текущему значению цифры 1,2,3... как идентификаторы части.
Еще одним способом решения есть изменения типа в поля, где храняться модификации, в таблице `'oc_modification'` базы данных. Нужно выполнить следующий SQL-запрос:
```
ALTER TABLE oc_modification CHANGE xml xml MEDIUMTEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ;
```

View File

@ -0,0 +1,215 @@
<?php
/**
* Class ControllerPaymentRBKmoneyPayment
*/
class ControllerPaymentRBKmoneyPayment extends Controller
{
private $error = array();
private $settings = array(
'common_parameters' => array(
'heading_title',
'text_edit',
'text_yes',
'text_no',
'button_save',
'button_cancel',
// Enable/Disable module
'entry_status',
'help_status',
'text_enabled',
'text_disabled',
// Sort order module
'entry_sort_order',
'help_sort_order',
// Enable logs for module
'entry_logs',
// Geo Zone
'text_all_zones',
'entry_geo_zone',
'help_geo_zone',
// Other parameters
'entry_order_status',
'help_order_status',
'entry_shop_id',
'help_shop_id',
'entry_form_path_logo',
'help_form_path_logo',
'entry_form_company_name',
'help_form_company_name',
'entry_private_key',
'help_private_key',
'entry_callback_public_key',
'help_callback_public_key',
'entry_currency',
'help_currency',
'entry_order_status_progress',
'help_order_status_progress',
'entry_notify_url',
'help_notify_url',
),
'fields' => array(
'rbkmoney_payment_status',
'rbkmoney_payment_sort_order',
'rbkmoney_payment_geo_zone_id',
'rbkmoney_payment_logs',
'rbkmoney_payment_order_status_id',
'rbkmoney_payment_order_status_progress_id',
'rbkmoney_payment_form_path_logo',
'rbkmoney_payment_form_company_name',
'rbkmoney_payment_shop_id',
'rbkmoney_payment_private_key',
'rbkmoney_payment_callback_public_key',
),
'errors' => array(
'error_shop_id',
'error_private_key',
'error_callback_public_key',
),
'validate' => array(
array(
'field' => 'rbkmoney_payment_shop_id',
'error_name' => 'error_shop_id',
),
array(
'field' => 'rbkmoney_payment_private_key',
'error_name' => 'error_private_key',
),
array(
'field' => 'rbkmoney_payment_callback_public_key',
'error_name' => 'error_callback_public_key',
),
),
);
public function index()
{
$data['rbkmoney_payment_version'] = '1.1 for OpenCart 2.x';
$this->load->language('payment/rbkmoney_payment');
$this->document->setTitle($this->language->get('heading_title'));
$this->load->model('setting/setting');
$this->load->model('localisation/geo_zone');
$data['geo_zones'] = $this->model_localisation_geo_zone->getGeoZones();
if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
$this->model_setting_setting->editSetting('rbkmoney_payment', $this->request->post);
$this->session->data['success'] = $this->language->get('text_success');
$this->response->redirect($this->prepareUrlLink('extension/payment'));
}
$data['error_warning'] = (isset($this->error['warning'])) ? $this->error['warning'] : '';
$data['breadcrumbs'] = [
array(
'text' => $this->language->get('text_home'),
'href' => $this->prepareUrlLink('common/dashboard')
),
array(
'text' => $this->language->get('text_payment'),
'href' => $this->prepareUrlLink('extension/payment')
),
array(
'text' => $this->language->get('heading_title'),
'href' => $this->prepareUrlLink('payment/rbkmoney_payment')
)
];
$this->settings['buttons'] = array(
'action' => $this->prepareUrlLink('payment/rbkmoney_payment'),
'cancel' => $this->prepareUrlLink('extension/payment'),
);
foreach ($this->settings['errors'] as $error) {
$data[$error] = $this->getErrorByName($error);
}
foreach ($this->settings['buttons'] as $name => $value) {
$data[$name] = $this->language->get($value);
}
foreach ($this->settings['common_parameters'] as $common_parameter) {
$data[$common_parameter] = $this->language->get($common_parameter);
}
foreach ($this->settings['fields'] as $field) {
$data[$field] = $this->getConfigByField($field);
}
$this->load->model('localisation/order_status');
$data['order_statuses'] = $this->model_localisation_order_status->getOrderStatuses();
$data['notify_url'] = $this->getNotifyUrl();
$data['header'] = $this->load->controller('common/header');
$data['column_left'] = $this->load->controller('common/column_left');
$data['footer'] = $this->load->controller('common/footer');
$this->response->setOutput($this->load->view('payment/rbkmoney_payment', $data));
}
/**
* Validate parameters
*
* @return bool
*/
protected function validate()
{
if (!$this->user->hasPermission('modify', 'payment/rbkmoney_payment')) {
$this->error['warning'] = $this->language->get('error_permission');
}
foreach ($this->settings['validate'] as $validate) {
if (!$this->request->post[$validate['field']]) {
$this->error[$validate['error_name']] = $this->language->get($validate['error_name']);
}
}
return !$this->error;
}
private function getNotifyUrl()
{
return HTTPS_CATALOG . 'index.php?route=payment/rbkmoney_payment/notify';
}
private function getConfigByField($fieldName)
{
return (isset($this->request->post[$fieldName]))
? $this->request->post[$fieldName]
: $this->config->get($fieldName);
}
private function prepareUrlLink($link)
{
return $this->url->link($link, 'token=' . $this->session->data['token'], 'SSL');
}
private function getErrorByName($name, $default_message = '')
{
return (isset($this->error[$name])) ? $this->error[$name] : $default_message;
}
}
?>

View File

@ -0,0 +1,60 @@
<?php
// Heading
$_['heading_title'] = 'RBKmoney';
$_['text_edit'] = 'Edit RBKmoney';
// Text
$_['text_payment'] = 'Payment';
$_['text_success'] = 'Settings module updated';
// Displays a logo and a link in the list of payment modules
$_['text_rbkmoney_payment'] = '<a href="https://rbk.money" onclick="return !window.open(this.href)"> <img src = "view/image/payment/rbkmoney_payment.png" alt="RBKmoney" title="RBKmoney" style="border: 1px solid #EEEEEE;" /> </a>';
$_['text_yes'] = 'Yes';
$_['text_no'] = 'No';
$_['entry_logs'] = 'Enable logs';
// Common settings
$_['entry_status'] = 'Status:';
$_['help_status'] = 'Status';
$_['entry_sort_order'] = 'Sort order:';
$_['help_sort_order'] = 'Sort order';
$_['entry_geo_zone'] = 'Geographical area';
$_['help_geo_zone'] = 'Geographical area';
// RBKmoney settings
$_['entry_shop_id'] = 'Shop ID:';
$_['help_shop_id'] = 'Number of the merchant\'s shop system RBKmoney';
$_['error_shop_id'] = 'Shop ID is required';
$_['entry_order_status'] = 'Order status after the payment';
$_['help_order_status'] = 'Order status after the payment.';
$_['entry_order_status_progress'] = 'Order Status after invoicing:';
$_['help_order_status_progress'] = 'Order Status after invoicing.';
$_['entry_form_path_logo'] = 'Logo in payment form:';
$_['help_form_path_logo'] = 'Your logo for payment form';
$_['entry_form_company_name'] = 'Company name in payment form:';
$_['help_form_company_name'] = 'Your company name for payment form';
$_['entry_private_key'] = 'Private key:';
$_['help_private_key'] = 'The private key in the system RBK Money.';
$_['error_private_key'] = 'Private key is required';
$_['entry_callback_public_key'] = 'Callback public key:';
$_['help_callback_public_key'] = 'Callback public key';
$_['error_callback_public_key'] = 'Callback public key is required';
$_['entry_notify_url'] = 'Notification URL:';
$_['help_notify_url'] = 'This address is to be inserted in a private office RBK Money';
// Common error
$_['error_permission'] = 'You are not allowed to control this unit';
?>

View File

@ -0,0 +1,60 @@
<?php
// Heading
$_['heading_title'] = 'RBKmoney';
$_['text_edit'] = 'Редактирование RBKmoney';
// Text
$_['text_payment'] = 'Оплата';
$_['text_success'] = 'Настройки модуля обновлены!';
// Displays a logo and a link in the list of payment modules
$_['text_rbkmoney_payment'] = '<a href="https://rbk.money" onclick="return !window.open(this.href)"> <img src = "view/image/payment/rbkmoney_payment.png" alt="RBKmoney" title="RBKmoney" style="border: 1px solid #EEEEEE;" /> </a>';
$_['text_yes'] = 'Да';
$_['text_no'] = 'Нет';
$_['entry_logs'] = 'Включить логи';
// Common settings
$_['entry_status'] = 'Статус:';
$_['help_status'] = 'Статус';
$_['entry_sort_order'] = 'Sort order:';
$_['help_sort_order'] = 'Sort order';
$_['entry_geo_zone'] = 'Географическая зона';
$_['help_geo_zone'] = 'Географическая зона';
// RBKmoney settings
$_['entry_shop_id'] = 'Shop ID:';
$_['help_shop_id'] = 'Номер магазина мерчанта в системе RBKmoney';
$_['error_shop_id'] = 'Shop ID обязателен';
$_['entry_order_status'] = 'Статус заказа после оплаты:';
$_['help_order_status'] = 'Статус заказа после оплаты';
$_['entry_order_status_progress'] = 'Статус заказа после выставления счета:';
$_['help_order_status_progress'] = 'Статус заказа после выставления счета';
$_['entry_form_path_logo'] = 'Логотип в платежной форме:';
$_['help_form_path_logo'] = 'Путь к логотипу отображаемого в платежной форме';
$_['entry_form_company_name'] = 'Название компании в платежной форме:';
$_['help_form_company_name'] = 'Название компании отображаемой в платежной форме';
$_['entry_private_key'] = 'Приватный ключ:';
$_['help_private_key'] = 'Приватный ключ в системе RBKmoney';
$_['error_private_key'] = 'Приватный ключ обязателен';
$_['entry_callback_public_key'] = 'Публичный ключ для обработчика уведомления:';
$_['help_callback_public_key'] = 'Публичный ключ для обработчика уведомления в системе RBKmoney';
$_['error_callback_public_key'] = 'Публичный ключ для обработчика уведомления обязателен';
$_['entry_notify_url'] = 'URL для оповещения о платеже:';
$_['help_notify_url'] = 'Этот адрес необходимо будет добавить в настройках личного кабинета в системе RBKmoney';
// Common error
$_['error_permission'] = 'У Вас нет прав для управления этим модулем!';
?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,281 @@
<?php echo $header; ?><?php echo $column_left; ?>
<div id="content">
<div class="page-header">
<div class="container-fluid">
<div class="pull-right">
<button type="submit" form="form-globalpay" data-toggle="tooltip" title="<?php echo $button_save; ?>"
class="btn btn-primary"><i class="fa fa-save"></i></button>
<a href="<?php echo $cancel; ?>" data-toggle="tooltip" title="<?php echo $button_cancel; ?>"
class="btn btn-default"><i class="fa fa-reply"></i></a></div>
<h1><?php echo $heading_title; ?></h1>
<ul class="breadcrumb">
<?php foreach ($breadcrumbs as $breadcrumb) { ?>
<li><a href="<?php echo $breadcrumb['href']; ?>"><?php echo $breadcrumb['text']; ?></a></li>
<?php } ?>
</ul>
</div>
</div>
<div class="container-fluid">
<?php if ($error_warning) { ?>
<div class="alert alert-danger"><i class="fa fa-exclamation-circle"></i> <?php echo $error_warning; ?>
<button type="button" class="close" data-dismiss="alert">&times;</button>
</div>
<?php } ?>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><i class="fa fa-pencil"></i><?php echo $text_edit; ?></h3>
</div>
<div class="panel-body">
<form action="<?php echo $action; ?>" method="post" enctype="multipart/form-data"
id="form-rbkmoney-payment" class="form-horizontal">
<table width=100%>
<tr>
<td width=10 valign=top>
<a href="https://rbk.money" onclick="return !window.open(this.href)">
<img src="view/image/payment/rbkmoney_payment.png" alt="RBKmoney"
title="RBKmoney" style="border: 1px solid #EEEEEE;"/>
</a>
</td>
</tr>
</table>
<div class="tab-content">
<!-- Shop ID -->
<div class="form-group required">
<label class="col-sm-2 control-label" for="rbkmoney_payment_shop_id">
<?php echo $entry_shop_id; ?>
<span data-toggle="tooltip" title="<?php echo $help_shop_id; ?>"></span>
</label>
<div class="col-sm-10">
<input type="text" name="rbkmoney_payment_shop_id"
value="<?php echo $rbkmoney_payment_shop_id; ?>"
placeholder="<?php echo $help_shop_id; ?>" id="input-shop-id"
class="form-control"/>
<?php if ($error_shop_id) { ?>
<div class="text-danger"><?php echo $error_shop_id; ?></div>
<?php } ?>
</div>
</div>
<!-- From path to logo -->
<div class="form-group">
<label class="col-sm-2 control-label" for="rbkmoney_form_path_logo">
<span data-toggle="tooltip" title="<?php echo $help_form_path_logo; ?>">
<?php echo $entry_form_path_logo; ?>
</span>
</label>
<div class="col-sm-10">
<input type="text" name="rbkmoney_payment_form_path_logo" value="<?php echo $rbkmoney_payment_form_path_logo; ?>"
placeholder="<?php echo $help_form_path_logo; ?>" id="rbkmoney_payment_form_path_logo"
class="form-control"/>
</div>
</div>
<!-- From company name -->
<div class="form-group">
<label class="col-sm-2 control-label" for="rbkmoney_form_company_name">
<span data-toggle="tooltip" title="<?php echo $help_form_company_name; ?>">
<?php echo $entry_form_company_name; ?>
</span>
</label>
<div class="col-sm-10">
<input type="text" name="rbkmoney_payment_form_company_name" value="<?php echo $rbkmoney_payment_form_company_name; ?>"
placeholder="<?php echo $help_form_company_name; ?>" id="rbkmoney_payment_form_company_name"
class="form-control"/>
</div>
</div>
<!-- Private key -->
<div class="form-group required">
<label class="col-sm-2 control-label" for="rbkmoney_payment_private_key">
<?php echo $entry_private_key; ?>
<span data-toggle="tooltip" title="<?php echo $help_private_key; ?>"></span>
</label>
<div class="col-sm-10">
<input type="text" name="rbkmoney_payment_private_key"
value="<?php echo $rbkmoney_payment_private_key; ?>"
placeholder="<?php echo $help_private_key; ?>" id="input-private_key"
class="form-control"/>
<?php if ($error_private_key) { ?>
<div class="text-danger"><?php echo $error_private_key; ?></div>
<?php } ?>
</div>
</div>
<!-- Callback public key -->
<div class="form-group required">
<label class="col-sm-2 control-label" for="rbkmoney_payment_callback_public_key">
<?php echo $entry_callback_public_key; ?>
<span data-toggle="tooltip" title="<?php echo $help_callback_public_key; ?>"></span>
</label>
<div class="col-sm-10">
<input type="text" name="rbkmoney_payment_callback_public_key"
value="<?php echo $rbkmoney_payment_callback_public_key; ?>"
placeholder="<?php echo $help_callback_public_key; ?>"
id="input-callback_public_key"
class="form-control"/>
<?php if ($error_callback_public_key) { ?>
<div class="text-danger"><?php echo $error_callback_public_key; ?></div>
<?php } ?>
</div>
</div>
<!-- Payment sort order -->
<div class="form-group">
<label class="col-sm-2 control-label" for="rbkmoney_payment_sort_order">
<span data-toggle="tooltip" title="<?php echo $help_sort_order; ?>">
<?php echo $entry_sort_order; ?>
</span>
</label>
<div class="col-sm-10">
<input type="text" name="rbkmoney_payment_sort_order"
value="<?php echo $rbkmoney_payment_sort_order; ?>"
placeholder="<?php echo $help_sort_order; ?>" id="rbkmoney_payment_sort_order"
class="form-control"/>
</div>
</div>
<!-- Enable/Disable -->
<div class="form-group">
<label class="col-sm-2 control-label" for="rbkmoney_payment_status">
<span data-toggle="tooltip" title="<?php echo $help_status; ?>">
<?php echo $entry_status; ?>
</span>
</label>
<div class="col-sm-10">
<select name="rbkmoney_payment_status" id="rbkmoney_payment_status"
class="form-control">
<?php if ($rbkmoney_payment_status) { ?>
<option value="1" selected="selected"><?php echo $text_enabled; ?></option>
<option value="0"><?php echo $text_disabled; ?></option>
<?php } else { ?>
<option value="1"><?php echo $text_enabled; ?></option>
<option value="0" selected="selected"><?php echo $text_disabled; ?></option>
<?php } ?>
</select>
</div>
</div>
<!-- Notify URL -->
<div class="form-group">
<label class="col-sm-2 control-label" for="input-callback">
<span data-toggle="tooltip" title="<?php echo htmlspecialchars($help_notify_url); ?>">
<?php echo $entry_notify_url; ?>
</span>
</label>
<div class="col-sm-10">
<textarea rows="1" readonly id="input-callback"
class="form-control"><?php echo $notify_url; ?></textarea>
</div>
</div>
<!-- Payment order status -->
<div class="form-group">
<label class="col-sm-2 control-label" for="rbkmoney_payment_order_status_id">
<span data-toggle="tooltip" title="<?php echo $help_order_status; ?>">
<?php echo $entry_order_status; ?>
</span>
</label>
<div class="col-sm-10">
<select name="rbkmoney_payment_order_status_id" id="rbkmoney_payment_order_status_id" class="form-control">
<?php foreach ($order_statuses as $order_status) { ?>
<?php if ($order_status['order_status_id'] == $rbkmoney_payment_order_status_id) { ?>
<option value="<?php echo $order_status['order_status_id']; ?>" selected="selected"><?php echo $order_status['name']; ?></option>
<?php } else { ?>
<option value="<?php echo $order_status['order_status_id']; ?>">
<?php echo $order_status['name']; ?>
</option>
<?php } ?>
<?php } ?>
</select>
</div>
</div>
<!-- Payment order status progress -->
<div class="form-group">
<label class="col-sm-2 control-label" for="rbkmoney_payment_order_status_progress_id">
<span data-toggle="tooltip" title="<?php echo $help_order_status_progress; ?>">
<?php echo $entry_order_status_progress; ?>
</span>
</label>
<div class="col-sm-10">
<select name="rbkmoney_payment_order_status_progress_id" id="rbkmoney_payment_order_status_progress_id" class="form-control">
<?php foreach ($order_statuses as $order_status) { ?>
<?php if ($order_status['order_status_id'] == $rbkmoney_payment_order_status_progress_id) { ?>
<option value="<?php echo $order_status['order_status_id']; ?>" selected="selected">
<?php echo $order_status['name']; ?>
</option>
<?php } else { ?>
<option value="<?php echo $order_status['order_status_id']; ?>">
<?php echo $order_status['name']; ?>
</option>
<?php } ?>
<?php } ?>
</select>
</div>
</div>
<!-- Geo zone -->
<div class="form-group">
<label class="col-sm-2 control-label" for="rbkmoney_payment_geo_zone_id">
<span data-toggle="tooltip" title="<?php echo $help_geo_zone; ?>">
<?php echo $entry_geo_zone; ?>
</span>
</label>
<div class="col-sm-10">
<select name="rbkmoney_payment_geo_zone_id" id="rbkmoney_payment_geo_zone_id" class="form-control">
<option value="0"><?php echo $text_all_zones; ?></option>
<?php foreach ($geo_zones as $geo_zone) { ?>
<?php if ($geo_zone['geo_zone_id'] == $rbkmoney_payment_geo_zone_id) { ?>
<option value="<?php echo $geo_zone['geo_zone_id']; ?>" selected="selected">
<?php echo $geo_zone['name']; ?>
</option>
<?php } else { ?>
<option value="<?php echo $geo_zone['geo_zone_id']; ?>">
<?php echo $geo_zone['name']; ?>
</option>
<?php } ?>
<?php } ?>
</select>
</div>
</div>
<!-- Enable logs -->
<div class="form-group">
<label class="col-sm-2 control-label">
<?php echo $entry_logs; ?>
</label>
<div class="col-sm-10">
<label class="radio-inline">
<?php if ($rbkmoney_payment_logs) { ?>
<input type="radio" name="rbkmoney_payment_logs" value="1" checked="checked" />
<?php echo $text_yes; ?>
<?php } else { ?>
<input type="radio" name="rbkmoney_payment_logs" value="1" />
<?php echo $text_yes; ?>
<?php } ?>
</label>
<label class="radio-inline">
<?php if (!$rbkmoney_payment_logs) { ?>
<input type="radio" name="rbkmoney_payment_logs" value="0" checked="checked" />
<?php echo $text_no; ?>
<?php } else { ?>
<input type="radio" name="rbkmoney_payment_logs" value="0" />
<?php echo $text_no; ?>
<?php } ?>
</label>
</div>
</div>
</div>
</form>
<div style="text-align:center; color:#555555;">RBKmoney v<?php echo $rbkmoney_payment_version; ?></div>
</div>
</div>
</div>
</div>
<?php echo $footer; ?>

View File

@ -0,0 +1,169 @@
<?php
class ControllerPaymentRbkmoneyPayment extends Controller
{
const HEADER_OK = "HTTP/1.0 200 OK";
const HEADER_BAD_REQUEST = "HTTP/1.0 400 Bad Request";
const INVOICE_ID = 'invoice_id';
const PAYMENT_ID = 'payment_id';
const AMOUNT = 'amount';
const CURRENCY = 'currency';
const CREATED_AT = 'created_at';
const METADATA = 'metadata';
const STATUS = 'status';
const SIGNATURE = 'HTTP_X_SIGNATURE';
const ORDER_ID = 'order_id';
const OPENSSL_VERIFY_SIGNATURE_IS_CORRECT = 1;
const CHECKOUT_URL = 'https://checkout.rbk.money/payframe/payframe.js';
public function index()
{
$data['button_confirm'] = $this->language->get('button_confirm');
$data['button_back'] = $this->language->get('button_back');
$this->load->language('payment/rbkmoney_payment');
$this->load->model('checkout/order');
$this->load->model('payment/rbkmoney_payment');
$data['action'] = static::CHECKOUT_URL;
$data['shop_id'] = $this->config->get('rbkmoney_payment_shop_id');
$data['form_path_logo'] = $this->config->get('rbkmoney_payment_form_path_logo');
$data['form_company_name'] = $this->config->get('rbkmoney_payment_form_company_name');
$data['private_key'] = $this->config->get('rbkmoney_payment_private_key');
$data['success_redirect_url'] = $this->url->link('payment/rbkmoney_payment/success_url_redirect');
$data['failed_redirect_url'] = $this->url->link('payment/rbkmoney_payment/failed_url_redirect');
$order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']);
$data['amount'] = number_format($order_info['total'], 2, '.', '');
$data['currency'] = $order_info['currency_code'];
$data['order_id'] = $this->session->data['order_id'];
$invoiceId = '';
$invoice_access_token = '';
try {
$invoiceId = $this->model_payment_rbkmoney_payment->createInvoice($order_info);
$invoice_access_token = $this->model_payment_rbkmoney_payment->createAccessToken($invoiceId);
$this->model_checkout_order->addOrderHistory(
$this->session->data['order_id'],
$this->config->get('rbkmoney_payment_order_status_progress_id')
);
} catch (Exception $ex) {
$logs = array();
$logs['error']['message'] = $ex->getMessage();
$data['errormsg'] = $ex->getMessage();
$this->model_payment_rbkmoney_payment->logger('exception', $logs);
}
$data['invoice_id'] = $invoiceId;
$data['invoice_access_token'] = $invoice_access_token;
return $this->load->view('payment/rbkmoney_payment', $data);
}
/**
* http{s}://{your-site}/index.php?route=payment/rbkmoney_payment/success_url_redirect
*/
public function success_url_redirect()
{
header('Location: ' . $this->url->link('checkout/success'), true, 301);
exit();
}
/**
* http{s}://{your-site}/index.php?route=payment/rbkmoney_payment/failed_url_redirect
*/
public function failed_url_redirect()
{
header('Location: ' . $this->url->link('checkout/payment'), true, 301);
exit();
}
/**
* http{s}://{your-site}/index.php?route=payment/rbkmoney_payment/callback
*/
public function callback()
{
$body = file_get_contents('php://input');
$logs = array(
'request' => array(
'method' => 'POST',
'data' => $body,
),
);
$method = 'notification';
$this->load->model('payment/rbkmoney_payment');
$this->model_payment_rbkmoney_payment->logger($method, $logs);
if (empty($_SERVER[static::SIGNATURE])) {
$logs['error']['message'] = 'Сигнатура отсутствует';
$this->outputWithLogger($method, $logs);
}
$required_fields = array(
static::INVOICE_ID,
static::PAYMENT_ID,
static::AMOUNT,
static::CURRENCY,
static::CREATED_AT,
static::METADATA,
static::STATUS
);
$data = json_decode($body, TRUE);
foreach ($required_fields as $field) {
if (empty($data[$field])) {
$logs['error']['message'] = 'Отсутствует обязательное поле';
$this->outputWithLogger($method, $logs);
}
}
if (empty($data[static::METADATA][static::ORDER_ID])) {
$logs['error']['message'] = 'Отсутствует номер заказа';
$this->outputWithLogger($method, $logs);
}
$signature = base64_decode($_SERVER[static::SIGNATURE]);
$public_key = $this->config->get('rbkmoney_payment_callback_public_key');
if (!$this->model_payment_rbkmoney_payment->verification_signature($body, $signature, $public_key)) {
$logs['error']['message'] = 'Сигнатура не совпадает';
$this->outputWithLogger($method, $logs);
}
$orderId = $data[static::METADATA][static::ORDER_ID];
if (!$order_info = $this->model_checkout_order->getOrder($orderId)) {
$logs['error']['message'] = 'Заказ ' . $orderId . ' не найден';
$this->outputWithLogger($method, $logs);
}
if ($order_info['order_status_id'] == 0) {
$this->model_checkout_order->addOrderHistory($order_info['order_id'], $this->config->get('rbkmoney_payment_order_status_id'), 'RBKmoney');
$logs['order_info'] = $order_info;
$this->outputWithLogger($method, $logs, self::HEADER_OK);
}
if (($data[static::STATUS] == 'paid') && ($order_info['order_status_id'] != $this->config->get('rbkmoney_payment_order_status_id'))) {
$this->model_checkout_order->addOrderHistory($order_info['order_id'], $this->config->get('rbkmoney_payment_order_status_id'), 'RBKmoney', TRUE);
$logs['order_info'] = $order_info;
$this->outputWithLogger($method, $logs, self::HEADER_OK);
} else {
$logs['error']['message'] = 'Заказ ' . $orderId . ' уже имеет финальный статус';
$this->outputWithLogger($method, $logs);
}
}
private function outputWithLogger($method, &$logs, $header = self::HEADER_BAD_REQUEST)
{
$this->load->model('payment/rbkmoney_payment');
$this->model_payment_rbkmoney_payment->logger($method, $logs);
$this->response->setOutput(header($header));
exit();
}
}

View File

@ -0,0 +1,5 @@
<?php
// Text
$_['text_title'] = 'RBKmoney';
?>

View File

@ -0,0 +1,5 @@
<?php
// Text
$_['text_title'] = 'RBKmoney';
?>

View File

@ -0,0 +1,287 @@
<?php
class ModelPaymentRbkmoneyPayment extends Model
{
/**
* Create invoice settings
*/
const CREATE_INVOICE_TEMPLATE_DUE_DATE = 'Y-m-d\TH:i:s\Z';
const CREATE_INVOICE_DUE_DATE = '+1 days';
private $api_url = 'https://api.rbk.money/v1/';
/**
* Get payment method
*
* @param $address
* @param $total
* @return array
*/
public function getMethod($address, $total)
{
$this->load->language('payment/rbkmoney');
if ($this->config->get('rbkmoney_payment_status')) {
$query = $this->db->query("SELECT * FROM " . DB_PREFIX . "zone_to_geo_zone WHERE geo_zone_id = '" . (int)$this->config->get('rbkmoney_payment_geo_zone_id') . "' AND country_id = '" . (int)$address['country_id'] . "' AND (zone_id = '" . (int)$address['zone_id'] . "' OR zone_id = '0')");
if (!$this->config->get('rbkmoney_payment_geo_zone_id')) {
$status = TRUE;
} elseif ($query->num_rows) {
$status = TRUE;
} else {
$status = FALSE;
}
} else {
$status = FALSE;
}
$method_data = array();
if ($status) {
$method_data = array(
'code' => 'rbkmoney_payment',
'title' => $this->language->get('text_title'),
'terms' => '',
'sort_order' => $this->config->get('rbkmoney_payment_sort_order')
);
}
return $method_data;
}
/**
* Create a new invoice.
*
* @param array $order_info
* @return mixed
*/
public function createInvoice(array $order_info)
{
$headers = $this->getHeaders();
$data = [
'shopID' => (int)$this->config->get('rbkmoney_payment_shop_id'),
'amount' => $this->prepareAmount($order_info['total']),
'metadata' => $this->prepareMetadata($order_info['order_id']),
'dueDate' => $this->prepareDueDate(),
'currency' => strtoupper($order_info['currency_code']),
'product' => $order_info['order_id'],
'description' => $this->getProductDescription(),
];
$url = $this->prepareApiUrl('processing/invoices');
$response = $this->send($url, 'POST', $headers, json_encode($data, true), 'init_invoice');
$invoice_encode = json_decode($response['body'], true);
return (!empty($invoice_encode['id'])) ? $invoice_encode['id'] : '';
}
private function getHeaders() {
$headers = array();
$headers[] = 'X-Request-ID: ' . uniqid();
$headers[] = 'Authorization: Bearer ' . $this->config->get('rbkmoney_payment_private_key');
$headers[] = 'Content-type: application/json; charset=utf-8';
$headers[] = 'Accept: application/json';
return $headers;
}
/**
* Get product descriptions from the shopping cart
*
* @return string
*/
private function getProductDescription()
{
$products = '';
$i = 0;
foreach ($this->cart->getProducts() as $product) {
if ($i == 0)
$products .= $product['quantity'] . ' x ' . $product['name'];
else
$products .= ', ' . $product['quantity'] . ' x ' . $product['name'];
$i++;
}
if (mb_strlen($products, 'UTF-8') > 255) {
$products = mb_substr($products, 0, 252, 'UTF-8') . '...';
}
return $products;
}
/**
* Create a new token to access the specified invoice.
*
* @param $invoice_id
* @return string
* @throws Exception
*/
public function createAccessToken($invoice_id)
{
if (empty($invoice_id)) {
throw new Exception('Не передан обязательный параметр invoice_id');
}
$headers = $this->getHeaders();
$url = $this->prepareApiUrl('processing/invoices/' . $invoice_id . '/access_tokens');
$response = $this->send($url, 'POST', $headers, '', 'access_tokens');
if ($response['http_code'] != 201) {
throw new Exception('Возникла ошибка при создании токена для инвойса');
}
$response_decode = json_decode($response['body'], true);
$access_token = !empty($response_decode['payload']) ? $response_decode['payload'] : '';
return $access_token;
}
/**
* Send request
*
* @param $url
* @param $method
* @param array $headers
* @param string $data
* @param string $type
* @return mixed
* @throws Exception
*/
private function send($url, $method, $headers = [], $data = '', $type = '')
{
$logs = array(
'request' => array(
'url' => $url,
'method' => $method,
'headers' => $headers,
'data' => $data,
),
);
$this->logger($type . ': request', $logs);
if (empty($url)) {
throw new Exception('Не передан обязательный параметр url');
}
$allowed_methods = ['POST'];
if (!in_array($method, $allowed_methods)) {
$this->logger(__CLASS__, $logs);
throw new Exception('Unsupported method ' . $method);
}
$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['response'] = $response;
$this->logger($type . ': response', $logs);
curl_close($curl);
return $response;
}
/**
* Prepare due date
*
* @return string
*/
private function prepareDueDate()
{
date_default_timezone_set('UTC');
return date(static::CREATE_INVOICE_TEMPLATE_DUE_DATE, strtotime(static::CREATE_INVOICE_DUE_DATE));
}
/**
* Prepare metadata
*
* @param $order_id
* @return array
*/
private function prepareMetadata($order_id)
{
return [
'cms' => 'opencart',
'cms_version' => VERSION,
'module' => 'rbkmoney_payment',
'order_id' => $order_id,
];
}
/**
* Prepare amount (e.g. 124.24 -> 12424)
*
* @param $amount int
* @return int
*/
private function prepareAmount($amount)
{
return number_format($amount, 2, '.', '') * 100;
}
/**
* Prepare API URL
*
* @param string $path
* @param array $query_params
* @return string
*/
private function prepareApiUrl($path = '', $query_params = [])
{
$url = rtrim($this->api_url, '/') . '/' . $path;
if (!empty($query_params)) {
$url .= '?' . http_build_query($query_params);
}
return $url;
}
/**
* Verification signature
*
* @param $data
* @param $signature
* @param $public_key
* @return bool
*/
public function verificationSignature($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_ALGO_SHA256);
return ($verify == static::OPENSSL_VERIFY_SIGNATURE_IS_CORRECT);
}
/**
* Data logging
*
* @param $method
* @param $message
*/
public function logger($method, $message)
{
if ($this->config->get('rbkmoney_payment_logs')) {
$this->log->write('rbkmoney ' . $method . '. ' . print_r($message, true));
}
}
}

View File

@ -0,0 +1,19 @@
<?php if (!empty($errormsg)) { ?>
<?php echo $errormsg ?>
<?php } else { ?>
<script src="<?php echo $action ?>" class="rbkmoney-checkout"
data-invoice-id="<?php echo $invoice_id; ?>"
data-invoice-access-token="<?php echo $invoice_access_token; ?>"
data-endpoint-success="<?php echo $success_redirect_url; ?>"
data-endpoint-failed="<?php echo $failed_redirect_url; ?>"
data-amount="<?php echo $amount ?>"
data-currency="<?php echo $currency ?>"
<?php if (!empty($form_company_name)) { ?>
data-name="<?php echo $form_company_name ?>"
<?php } ?>
<?php if (!empty($form_path_logo)) { ?>
data-logo="<?php echo $form_path_logo ?>"
<?php } ?>
>
</script>
<?php } ?>