version opencart 3 (#1)
BIN
RBKmoney.ocmod.zip
Normal file
164
README.md
@ -1,2 +1,162 @@
|
||||
# rbkmoney-cms-opencart_3
|
||||
Opencart: payment module, provides payments through RBKmoney payment system
|
||||
# rbkmoney-cms-opencart
|
||||
|
||||
Пожалуйста, обязательно делайте бекапы!
|
||||
|
||||
Модуль разрабатывался и тестировался на Opencart 3
|
||||
|
||||
|
||||
#### Требования
|
||||
|
||||
- PHP 5.4 (минимум)
|
||||
- OpenSSL - 1.0.2k-fips (минимум)
|
||||
- Curl
|
||||
|
||||
#### Доступные ставки НДС для корзины
|
||||
|
||||
- ничего не указано - без НДС
|
||||
- 0 - 0% НДС
|
||||
- 10 - 10% НДС
|
||||
- 18 - 18% НДС
|
||||
|
||||
|
||||
### Установка и настройка модуля
|
||||
|
||||
|
||||
#### Установка без архива
|
||||
|
||||
Для установки модуля скопируйте содержимое каталога `upload`:
|
||||
|
||||
```
|
||||
<OpenCart>/admin/
|
||||
<OpenCart>/catalog/
|
||||
```
|
||||
|
||||
|
||||
#### Установка с архивом
|
||||
|
||||
Заархивируйте папку `upload` в `zip` архив и переименуйте его в `rbkmoney-payment.ocmod.zip`
|
||||
|
||||
После чего необходимо зайти в `Extension Installer`
|
||||
|
||||
![Extension Installer](images/extension_Installer.png)
|
||||
|
||||
нажать `Upload` и выбрать архив для установки: `rbkmoney-payment.ocmod.zip`
|
||||
|
||||
![Upload](images/upload.png)
|
||||
|
||||
|
||||
|
||||
#### Настройка модуля
|
||||
|
||||
В панели администратора установите и настройте его:
|
||||
|
||||
```
|
||||
Extensions > Payments > RBKmoney нажать [Install]
|
||||
```
|
||||
|
||||
![Payments](images/payments.png)
|
||||
|
||||
![Module](images/module.png)
|
||||
|
||||
|
||||
#### Для начала приема платежей на Вашем сайте осталось совсем немного
|
||||
|
||||
```
|
||||
Extensions > Payments > RBKmoney нажать [Edit] и заполнить необходимые настройки
|
||||
```
|
||||
|
||||
![Settings](images/settings.png)
|
||||
|
||||
|
||||
Настройте плагин в соответствии с данными из [личного кабинета RBKmoney](https://dashboard.rbk.money).
|
||||
|
||||
`Shop ID` - идентификатор магазина из RBKmoney. Скопируйте его в Личном кабинете RBKmoney в разделе Детали магазина, поле Идентификатор;
|
||||
|
||||
`Private key` - ключ для доступа к API. Скопируйте его в Личном кабинете RBKmoney в разделе API Ключ
|
||||
|
||||
`Callback public key` - ключ для обработки уведомлений о смене статуса
|
||||
|
||||
- Заходим в личный кабинет RBKmoney: Создать Webhook;
|
||||
- Вставляем в поле URL вида `http://your-site/index.php?route=payment/rbkmoney_payment/callback`, скопированного из `Notification URL`
|
||||
- Выбираем Типы событий `InvoicePaid` и `Invoice Canсelled`;
|
||||
- после создания Webhook-а копируем Публичный ключ после нажатия Показать детали;
|
||||
- скопированный ключ вставляем в поле `Callback public key` на странице настроек модуля;
|
||||
|
||||
|
||||
- Сохраните изменения и проведите тестовый платеж
|
||||
|
||||
|
||||
В настройках модуля можно включить или отключить логирование `Advanced settings / Enable logs`
|
||||
|
||||
![Advanced settings](images/advanced_settings.png)
|
||||
|
||||
C ними можно ознакомиться `Tools / Error logs`
|
||||
|
||||
![Tools](images/tools.png)
|
||||
|
||||
Выглядит это так:
|
||||
|
||||
![Error logs](images/error_logs.png)
|
||||
|
||||
|
||||
### Нашли ошибку или у вас есть предложение по улучшению модуля?
|
||||
|
||||
Пишите нам support@rbkmoney.com При обращении необходимо:
|
||||
|
||||
- Указать наименование CMS и компонента магазина, а также их версии
|
||||
- Указать версию платежного модуля
|
||||
- Описать проблему или предложение
|
||||
- Приложить снимок экрана (для большей информативности)
|
||||
|
||||
|
||||
|
||||
#### Возможные проблемы и их решения
|
||||
|
||||
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 ;
|
||||
```
|
||||
|
BIN
images/advanced_settings.png
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
images/error_logs.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
images/extension_Installer.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
images/module.png
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
images/payments.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
images/settings.png
Normal file
After Width: | Height: | Size: 254 KiB |
BIN
images/tools.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
images/upload.png
Normal file
After Width: | Height: | Size: 36 KiB |
189
upload/admin/controller/extension/payment/rbkmoney.php
Normal file
@ -0,0 +1,189 @@
|
||||
<?php
|
||||
class ControllerExtensionPaymentRbkmoney extends Controller {
|
||||
private $error = array();
|
||||
|
||||
public function index() {
|
||||
$this->load->language('extension/payment/rbkmoney');
|
||||
|
||||
$this->document->setTitle($this->language->get('heading_title'));
|
||||
$data['text_enabled'] = $this->language->get('text_enabled');
|
||||
$data['text_disabled'] = $this->language->get('text_disabled');
|
||||
|
||||
$this->load->model('setting/setting');
|
||||
|
||||
if (($this->request->server['REQUEST_METHOD'] == 'POST') && $this->validate()) {
|
||||
$this->model_setting_setting->editSetting('payment_rbkmoney', $this->request->post);
|
||||
|
||||
$this->session->data['success'] = $this->language->get('text_success');
|
||||
|
||||
$this->response->redirect($this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=payment', true));
|
||||
}
|
||||
|
||||
if (isset($this->error['warning'])) {
|
||||
$data['error_warning'] = $this->error['warning'];
|
||||
} else {
|
||||
$data['error_warning'] = '';
|
||||
}
|
||||
|
||||
if (isset($this->error['shop_id'])) {
|
||||
$data['error_shop_id'] = $this->error['shop_id'];
|
||||
} else {
|
||||
$data['error_shop_id'] = '';
|
||||
}
|
||||
|
||||
if (isset($this->error['merchant_private_key'])) {
|
||||
$data['error_merchant_private_key'] = $this->error['merchant_private_key'];
|
||||
} else {
|
||||
$data['error_merchant_private_key'] = '';
|
||||
}
|
||||
|
||||
if (isset($this->error['rbkmoney_public_key'])) {
|
||||
$data['error_rbkmoney_public_key'] = $this->error['rbkmoney_public_key'];
|
||||
} else {
|
||||
$data['error_rbkmoney_public_key'] = '';
|
||||
}
|
||||
|
||||
$data['breadcrumbs'] = array();
|
||||
|
||||
$data['breadcrumbs'][] = array(
|
||||
'text' => $this->language->get('text_home'),
|
||||
'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'], true)
|
||||
);
|
||||
|
||||
$data['breadcrumbs'][] = array(
|
||||
'text' => $this->language->get('text_extension'),
|
||||
'href' => $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=payment', true)
|
||||
);
|
||||
|
||||
$data['breadcrumbs'][] = array(
|
||||
'text' => $this->language->get('heading_title'),
|
||||
'href' => $this->url->link('extension/payment/rbkmoney', 'user_token=' . $this->session->data['user_token'], true)
|
||||
);
|
||||
|
||||
$data['action'] = $this->url->link('extension/payment/rbkmoney', 'user_token=' . $this->session->data['user_token'], true);
|
||||
|
||||
$data['cancel'] = $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=payment', true);
|
||||
|
||||
if (isset($this->request->post['payment_rbkmoney_shop_id'])) {
|
||||
$data['payment_rbkmoney_shop_id'] = $this->request->post['payment_rbkmoney_shop_id'];
|
||||
} else {
|
||||
$data['payment_rbkmoney_shop_id'] = $this->config->get('payment_rbkmoney_shop_id');
|
||||
}
|
||||
|
||||
if (isset($this->request->post['payment_rbkmoney_merchant_private_key'])) {
|
||||
$data['payment_rbkmoney_merchant_private_key'] = $this->request->post['payment_rbkmoney_merchant_private_key'];
|
||||
} else {
|
||||
$data['payment_rbkmoney_merchant_private_key'] = $this->config->get('payment_rbkmoney_merchant_private_key');
|
||||
}
|
||||
|
||||
if (isset($this->request->post['payment_rbkmoney_rbkmoney_public_key'])) {
|
||||
$data['payment_rbkmoney_rbkmoney_public_key'] = $this->request->post['payment_rbkmoney_rbkmoney_public_key'];
|
||||
} else {
|
||||
$data['payment_rbkmoney_rbkmoney_public_key'] = $this->config->get('payment_rbkmoney_rbkmoney_public_key');
|
||||
}
|
||||
|
||||
|
||||
if (isset($this->request->post['payment_rbkmoney_order_status_id'])) {
|
||||
$data['payment_rbkmoney_order_status_id'] = $this->request->post['payment_rbkmoney_order_status_id'];
|
||||
} elseif ($this->config->has('payment_rbkmoney_order_status_id')) {
|
||||
$data['payment_rbkmoney_order_status_id'] = $this->config->get('payment_rbkmoney_order_status_id');
|
||||
} else {
|
||||
$data['payment_rbkmoney_order_status_id'] = '5';
|
||||
}
|
||||
|
||||
|
||||
if (isset($this->request->post['payment_rbkmoney_order_status_progress_id'])) {
|
||||
$data['payment_rbkmoney_order_status_progress_id'] = $this->request->post['payment_rbkmoney_order_status_progress_id'];
|
||||
} elseif ($this->config->has('payment_rbkmoney_order_status_progress_id')) {
|
||||
$data['payment_rbkmoney_order_status_progress_id'] = $this->config->get('payment_rbkmoney_order_status_progress_id');
|
||||
} else {
|
||||
$data['payment_rbkmoney_order_status_progress_id'] = '2';
|
||||
}
|
||||
|
||||
|
||||
if (isset($this->request->post['payment_rbkmoney_order_status_cancelled_id'])) {
|
||||
$data['payment_rbkmoney_order_status_cancelled_id'] = $this->request->post['payment_rbkmoney_order_status_cancelled_id'];
|
||||
} elseif ($this->config->has('payment_rbkmoney_order_status_cancelled_id')) {
|
||||
$data['payment_rbkmoney_order_status_cancelled_id'] = $this->config->get('payment_rbkmoney_order_status_cancelled_id');
|
||||
} else {
|
||||
$data['payment_rbkmoney_order_status_cancelled_id'] = '7';
|
||||
}
|
||||
|
||||
|
||||
$this->load->model('localisation/order_status');
|
||||
|
||||
$data['order_statuses'] = $this->model_localisation_order_status->getOrderStatuses();
|
||||
|
||||
|
||||
|
||||
if (isset($this->request->post['payment_rbkmoney_form_company_name'])) {
|
||||
$data['payment_rbkmoney_form_company_name'] = $this->request->post['payment_rbkmoney_form_company_name'];
|
||||
} else {
|
||||
$data['payment_rbkmoney_form_company_name'] = $this->config->get('payment_rbkmoney_form_company_name');
|
||||
}
|
||||
|
||||
if (isset($this->request->post['payment_rbkmoney_form_button_label'])) {
|
||||
$data['payment_rbkmoney_form_button_label'] = $this->request->post['payment_rbkmoney_form_button_label'];
|
||||
} else {
|
||||
$data['payment_rbkmoney_form_button_label'] = $this->config->get('payment_rbkmoney_form_button_label');
|
||||
}
|
||||
|
||||
if (isset($this->request->post['payment_rbkmoney_form_description'])) {
|
||||
$data['payment_rbkmoney_form_description'] = $this->request->post['payment_rbkmoney_form_description'];
|
||||
} else {
|
||||
$data['payment_rbkmoney_form_description'] = $this->config->get('payment_rbkmoney_form_description');
|
||||
}
|
||||
|
||||
if (isset($this->request->post['payment_rbkmoney_geo_zone_id'])) {
|
||||
$data['payment_rbkmoney_geo_zone_id'] = $this->request->post['payment_rbkmoney_geo_zone_id'];
|
||||
} else {
|
||||
$data['payment_rbkmoney_geo_zone_id'] = $this->config->get('payment_rbkmoney_geo_zone_id');
|
||||
}
|
||||
|
||||
$this->load->model('localisation/geo_zone');
|
||||
|
||||
$data['geo_zones'] = $this->model_localisation_geo_zone->getGeoZones();
|
||||
|
||||
|
||||
|
||||
if (isset($this->request->post['payment_rbkmoney_status'])) {
|
||||
$data['payment_rbkmoney_status'] = $this->request->post['payment_rbkmoney_status'];
|
||||
} else {
|
||||
$data['payment_rbkmoney_status'] = $this->config->get('payment_rbkmoney_status');
|
||||
}
|
||||
|
||||
if (isset($this->request->post['payment_rbkmoney_sort_order'])) {
|
||||
$data['payment_rbkmoney_sort_order'] = $this->request->post['payment_rbkmoney_sort_order'];
|
||||
} else {
|
||||
$data['payment_rbkmoney_sort_order'] = $this->config->get('payment_rbkmoney_sort_order');
|
||||
}
|
||||
|
||||
$data['notify_url'] = HTTPS_CATALOG . 'index.php?route=extension/payment/rbkmoney/callback';
|
||||
|
||||
$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('extension/payment/rbkmoney', $data));
|
||||
}
|
||||
|
||||
private function validate() {
|
||||
if (!$this->user->hasPermission('modify', 'extension/payment/rbkmoney')) {
|
||||
$this->error['warning'] = $this->language->get('error_permission');
|
||||
}
|
||||
|
||||
if (!$this->request->post['payment_rbkmoney_shop_id']) {
|
||||
$this->error['shop_id'] = $this->language->get('error_shop_id');
|
||||
}
|
||||
|
||||
if (!$this->request->post['payment_rbkmoney_merchant_private_key']) {
|
||||
$this->error['merchant_private_key'] = $this->language->get('error_merchant_private_key');
|
||||
}
|
||||
|
||||
if (!$this->request->post['payment_rbkmoney_rbkmoney_public_key']) {
|
||||
$this->error['rbkmoney_public_key'] = $this->language->get('error_rbkmoney_public_key');
|
||||
}
|
||||
|
||||
return !$this->error;
|
||||
}
|
||||
}
|
37
upload/admin/language/en-gb/extension/payment/rbkmoney.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
// Heading
|
||||
$_['heading_title'] = 'RBKmoney';
|
||||
|
||||
// Text
|
||||
$_['text_extension'] = 'Extensions';
|
||||
$_['text_success'] = 'Success: You have modified RBKmoney account details!';
|
||||
$_['text_edit'] = 'Edit RBKmoney';
|
||||
$_['text_rbkmoney'] = '<a target="_BLANK" href="https://welcome.rbk.money/"><img src="view/image/payment/rbkmoney.png" alt="RBKmoney Website" title="RBKmoney Website" style="border: 1px solid #EEEEEE;" /></a>';
|
||||
$_['text_live'] = 'Live';
|
||||
$_['text_sandbox'] = 'Sandbox';
|
||||
|
||||
// Entry
|
||||
$_['entry_shop_id'] = 'Shop ID';
|
||||
$_['entry_merchant_private_key'] = 'Api Private Key';
|
||||
$_['entry_rbkmoney_public_key'] = 'Callback Public Key';
|
||||
$_['entry_form_company_name'] = 'Company name in payment form:';
|
||||
$_['entry_form_button_label'] = 'Button label in payment form:';
|
||||
$_['entry_form_description'] = 'Description in payment form:';
|
||||
$_['entry_order_status'] = 'Order status if payment success:';
|
||||
$_['entry_order_status_progress'] = 'Order Status after invoicing:';
|
||||
$_['entry_order_status_cancelled'] = 'Order Status if payment failed or cancelled:';
|
||||
$_['entry_geo_zone'] = 'Geo Zone';
|
||||
$_['entry_status'] = 'Status';
|
||||
$_['entry_sort_order'] = 'Sort Order';
|
||||
$_['entry_notify_url'] = 'Webhooks URL';
|
||||
// Help
|
||||
$_['help_form_company_name'] = 'Your company name for payment form';
|
||||
$_['help_form_button_label'] = 'Your button label for payment form';
|
||||
$_['help_form_description'] = 'Your description for payment form';
|
||||
$_['help_rbkmoney_setup'] = '<a target="_blank" href="https://github.com/rbkmoney/rbkmoney-cms-opencart">Click here</a> to learn how to set up RBKmoney';
|
||||
|
||||
// Error
|
||||
$_['error_permission'] = 'Warning: You do not have permission to modify payment rbkmoney!';
|
||||
$_['error_shop_id'] = 'Shop ID required!';
|
||||
$_['error_merchant_private_key'] = 'Merchant Api Key required!';
|
||||
$_['error_rbkmoney_public_key'] = 'Public Key required!';
|
45
upload/admin/language/ru-ru/extension/payment/rbkmoney.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
// Heading
|
||||
$_['heading_title'] = 'RBKmoney';
|
||||
|
||||
// Text
|
||||
$_['text_extension'] = 'Расширения';
|
||||
$_['text_all_zones'] = 'Все географические зоны';
|
||||
$_['text_enabled'] = 'Включен';
|
||||
$_['text_disabled'] = 'Выключен';
|
||||
$_['text_home'] ='Home';
|
||||
|
||||
|
||||
|
||||
|
||||
$_['text_success'] = 'Настройки модуля RBKmoney успешно обновлены!';
|
||||
$_['text_edit'] = 'Редактирование RBKmoney';
|
||||
$_['text_rbkmoney'] = '<a target="_BLANK" href="https://welcome.rbk.money/"><img src="view/image/payment/rbkmoney.png" alt="RBKmoney Website" title="RBKmoney Website" style="border: 1px solid #EEEEEE;" /></a>';
|
||||
$_['text_live'] = 'Live';
|
||||
$_['text_sandbox'] = 'Sandbox';
|
||||
|
||||
// Entry
|
||||
$_['entry_shop_id'] = 'Идентификатор магазина';
|
||||
$_['entry_merchant_private_key'] = 'Приватный ключ';
|
||||
$_['entry_rbkmoney_public_key'] = 'Публичный ключ';
|
||||
$_['entry_form_company_name'] = 'Название компании в платежной форме:';
|
||||
$_['entry_form_button_label'] = 'Надпись на кнопке в платежной форме:';
|
||||
$_['entry_form_description'] = 'Дополнительное описание в платежной форме:';
|
||||
$_['entry_order_status'] = 'Статус заказа после оплаты:';
|
||||
$_['entry_order_status_progress'] = 'Статус заказа после выставления счета:';
|
||||
$_['entry_order_status_cancelled'] = 'Статус заказа после неуспешной оплаты:';
|
||||
$_['entry_geo_zone'] = 'Географическая зона';
|
||||
$_['entry_status'] = 'Статус:';
|
||||
$_['entry_sort_order'] = 'Порядок сортировки';
|
||||
$_['entry_notify_url'] = 'URL для оповещения о платеже:';
|
||||
// Help
|
||||
$_['help_form_company_name'] = 'Название компании отображаемой в платежной форме';
|
||||
$_['help_form_button_label'] = 'Надпись на кнопке в платежной форме';
|
||||
$_['help_form_description'] = 'Дополнительное описание в платежной форме:';
|
||||
$_['help_rbkmoney_setup'] = '<a target="_blank" href="https://github.com/rbkmoney/rbkmoney-cms-opencart">Click here</a> to learn how to set up RBKmoney';
|
||||
|
||||
// Error
|
||||
$_['error_permission'] = 'Warning: You do not have permission to modify payment rbkmoney!';
|
||||
$_['error_shop_id'] = 'Shop ID обязателен';
|
||||
$_['error_merchant_private_key'] = 'Api Key обязателен';
|
||||
$_['error_rbkmoney_public_key'] = 'Public Key обязателен';
|
BIN
upload/admin/view/image/payment/rbkmoney.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
164
upload/admin/view/template/extension/payment/rbkmoney.twig
Normal file
@ -0,0 +1,164 @@
|
||||
{{ header }}{{ column_left }}
|
||||
<div id="content">
|
||||
<div class="page-header">
|
||||
<div class="container-fluid">
|
||||
<div class="pull-right">
|
||||
<button type="submit" form="form-payment" data-toggle="tooltip" title="{{ button_save }}" class="btn btn-primary"><i class="fa fa-save"></i></button>
|
||||
<a href="{{ cancel }}" data-toggle="tooltip" title="{{ button_cancel }}" class="btn btn-default"><i class="fa fa-reply"></i></a></div>
|
||||
<h1>{{ heading_title }}</h1>
|
||||
<ul class="breadcrumb">
|
||||
{% for breadcrumb in breadcrumbs %}
|
||||
<li><a href="{{ breadcrumb.href }}">{{ breadcrumb.text }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
{% if error_warning %}
|
||||
<div class="alert alert-danger alert-dismissible"><i class="fa fa-exclamation-circle"></i> {{ error_warning }}
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title"><i class="fa fa-pencil"></i> {{ text_edit }}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form action="{{ action }}" method="post" enctype="multipart/form-data" id="form-payment" class="form-horizontal">
|
||||
<div class="tab-content">
|
||||
<div class="form-group required">
|
||||
<label class="col-sm-2 control-label" for="entry-shop-id">{{ entry_shop_id }}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" name="payment_rbkmoney_shop_id" value="{{ payment_rbkmoney_shop_id }}" placeholder="{{ entry_shop_id }}" id="entry-shop-id" class="form-control"/>
|
||||
{% if error_shop_id %}
|
||||
<div class="text-danger">{{ error_shop_id }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group required">
|
||||
<label class="col-sm-2 control-label" for="entry-merchant-private-key">{{ entry_merchant_private_key }}</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea name="payment_rbkmoney_merchant_private_key" rows="10" placeholder="{{ entry_merchant_private_key }}" id="entry-merchant-private-key" class="form-control">{{ payment_rbkmoney_merchant_private_key }}</textarea>
|
||||
{% if error_merchant_private_key %}
|
||||
<div class="text-danger">{{ error_merchant_private_key }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group required">
|
||||
<label class="col-sm-2 control-label" for="entry-rbkmoney-public-key">{{ entry_rbkmoney_public_key }}</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea name="payment_rbkmoney_rbkmoney_public_key" rows="5" placeholder="{{ entry_rbkmoney_public_key }}" id="entry-rbkmoney-public-key" class="form-control">{{ payment_rbkmoney_rbkmoney_public_key }}</textarea>
|
||||
{% if error_rbkmoney_public_key %}
|
||||
<div class="text-danger">{{ error_rbkmoney_public_key }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="input-notify-url">{{ entry_notify_url }}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" readonly value="{{ notify_url }}" id="input-notify-url" class="form-control" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="input-status">{{ entry_status }}</label>
|
||||
<div class="col-sm-10">
|
||||
<select name="payment_rbkmoney_status" id="input-status" class="form-control">
|
||||
{% if payment_rbkmoney_status %}
|
||||
<option value="1" selected="selected">{{ text_enabled }}</option>
|
||||
<option value="0">{{ text_disabled }}</option>
|
||||
{% else %}
|
||||
<option value="1">{{ text_enabled }}</option>
|
||||
<option value="0" selected="selected">{{ text_disabled }}</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="input-order-status">{{ entry_order_status }}</label>
|
||||
<div class="col-sm-10">
|
||||
<select name="payment_rbkmoney_order_status_id" id="input-order-status" class="form-control">
|
||||
{% for order_status in order_statuses %}
|
||||
{% if order_status.order_status_id == payment_rbkmoney_order_status_id %}
|
||||
<option value="{{ order_status.order_status_id }}" selected="selected">{{ order_status.name }}</option>
|
||||
{% else %}
|
||||
<option value="{{ order_status.order_status_id }}">{{ order_status.name }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="input-order-status-progress">{{ entry_order_status_progress }}</label>
|
||||
<div class="col-sm-10">
|
||||
<select name="payment_rbkmoney_order_status_progress_id" id="input-order-status-progress" class="form-control">
|
||||
{% for order_status in order_statuses %}
|
||||
{% if order_status.order_status_id == payment_rbkmoney_order_status_progress_id %}
|
||||
<option value="{{ order_status.order_status_id }}" selected="selected">{{ order_status.name }}</option>
|
||||
{% else %}
|
||||
<option value="{{ order_status.order_status_id }}">{{ order_status.name }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="input-order-status-cancelled">{{ entry_order_status_cancelled }}</label>
|
||||
<div class="col-sm-10">
|
||||
<select name="payment_rbkmoney_order_status_cancelled_id" id="input-order-status-cancelled" class="form-control">
|
||||
{% for order_status in order_statuses %}
|
||||
{% if order_status.order_status_id == payment_rbkmoney_order_status_cancelled_id %}
|
||||
<option value="{{ order_status.order_status_id }}" selected="selected">{{ order_status.name }}</option>
|
||||
{% else %}
|
||||
<option value="{{ order_status.order_status_id }}">{{ order_status.name }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="input-form-company-name"><span data-toggle="tooltip" title="{{ help_form_company_name }}">{{ entry_form_company_name }}</span></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" name="payment_rbkmoney_form_company_name" value="{{ payment_rbkmoney_form_company_name }}" placeholder="{{ entry_form_company_name }}" id="input-form-company-name" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="input-form-button-label"><span data-toggle="tooltip" title="{{ help_form_button_label }}">{{ entry_form_button_label }}</span></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" name="payment_rbkmoney_form_button_label" value="{{ payment_rbkmoney_form_button_label }}" placeholder="{{ entry_form_button_label }}" id="input-form-button-label" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="input-form-description"><span data-toggle="tooltip" title="{{ help_form_description }}">{{ entry_form_description }}</span></label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" name="payment_rbkmoney_form_description" value="{{ payment_rbkmoney_form_description }}" placeholder="{{ entry_form_description }}" id="input-form-description" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="input-geo-zone">{{ entry_geo_zone }}</label>
|
||||
<div class="col-sm-10">
|
||||
<select name="payment_rbkmoney_geo_zone_id" id="input-geo-zone" class="form-control">
|
||||
<option value="0">{{ text_all_zones }}</option>
|
||||
{% for geo_zone in geo_zones %}
|
||||
{% if geo_zone.geo_zone_id == payment_rbkmoney_geo_zone_id %}
|
||||
<option value="{{ geo_zone.geo_zone_id }}" selected="selected">{{ geo_zone.name }}</option>
|
||||
{% else %}
|
||||
<option value="{{ geo_zone.geo_zone_id }}">{{ geo_zone.name }}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="input-sort-order">{{ entry_sort_order }}</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" name="payment_rbkmoney_sort_order" value="{{ payment_rbkmoney_sort_order }}" placeholder="{{ entry_sort_order }}" id="input-sort-order" class="form-control"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="alert alert-info">{{ help_rbkmoney_setup }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ footer }}
|
203
upload/catalog/controller/extension/payment/rbkmoney.php
Normal file
@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
class ControllerExtensionPaymentRBKmoney extends Controller
|
||||
{
|
||||
const HEADER_OK = "HTTP/1.0 200 OK";
|
||||
const HEADER_BAD_REQUEST = "HTTP/1.0 400 Bad Request";
|
||||
|
||||
/**
|
||||
* Constants for Callback
|
||||
*/
|
||||
|
||||
const ORDER_ID = 'order_id';
|
||||
|
||||
const EVENT_TYPE = 'eventType';
|
||||
const EVENT_TYPE_INVOICE_PAID = 'InvoicePaid';
|
||||
const EVENT_TYPE_INVOICE_CANCELLED = 'InvoiceCancelled';
|
||||
|
||||
const INVOICE = 'invoice';
|
||||
const INVOICE_ID = 'id';
|
||||
const INVOICE_SHOP_ID = 'shopID';
|
||||
const INVOICE_METADATA = 'metadata';
|
||||
const INVOICE_STATUS = 'status';
|
||||
const INVOICE_AMOUNT = 'amount';
|
||||
|
||||
const CALLBACK_STATUS_UNPAID = 'unpaid';
|
||||
const CALLBACK_STATUS_CANCELLED = 'cancelled';
|
||||
const CALLBACK_STATUS_PAID = 'paid';
|
||||
const CALLBACK_STATUS_REFUNDED = 'refunded';
|
||||
const CALLBACK_STATUS_FULFILLED = 'fulfilled';
|
||||
|
||||
const SIGNATURE = 'HTTP_CONTENT_SIGNATURE';
|
||||
const SIGNATURE_ALG = 'alg';
|
||||
const SIGNATURE_DIGEST = 'digest';
|
||||
const SIGNATURE_PATTERN = "|alg=(\S+);\sdigest=(.*)|i";
|
||||
|
||||
|
||||
const OPENSSL_VERIFY_SIGNATURE_IS_CORRECT = 1;
|
||||
|
||||
const CHECKOUT_URL = 'https://checkout.rbk.money/checkout.js';
|
||||
|
||||
public function index()
|
||||
{
|
||||
$data['button_confirm'] = $this->language->get('button_confirm');
|
||||
$data['button_back'] = $this->language->get('button_back');
|
||||
|
||||
$this->load->language('extension/payment/rbkmoney');
|
||||
$this->load->model('checkout/order');
|
||||
$this->load->model('extension/payment/rbkmoney');
|
||||
|
||||
$data['payment_form_url'] = static::CHECKOUT_URL;
|
||||
$data['payment_form_success_url'] = $this->url->link('checkout/success');
|
||||
$data['form_css_button'] = strip_tags($this->config->get('payment_rbkmoney_form_css_button'));
|
||||
$data['shop_id'] = $this->config->get('payment_rbkmoney_shop_id');
|
||||
$data['form_company_name'] = $this->config->get('payment_rbkmoney_form_company_name');
|
||||
$data['form_button_label'] = $this->config->get('payment_rbkmoney_form_button_label');
|
||||
$data['form_description'] = $this->config->get('payment_rbkmoney_form_description');
|
||||
$data['private_key'] = $this->config->get('payment_rbkmoney_merchant_private_key');
|
||||
|
||||
$order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']);
|
||||
|
||||
$data['order_id'] = $this->session->data['order_id'];
|
||||
|
||||
$response = array();
|
||||
$data['invoice_id'] = "";
|
||||
$data['invoice_access_token'] = "";
|
||||
|
||||
try {
|
||||
$responseCreateInvoice = $this->model_extension_payment_rbkmoney->createInvoice($order_info);
|
||||
$response = json_decode($responseCreateInvoice['body'], true);
|
||||
$this->model_checkout_order->addOrderHistory(
|
||||
$this->session->data['order_id'],
|
||||
$this->config->get('payment_rbkmoney_order_status_progress_id')
|
||||
);
|
||||
} catch (Exception $ex) {
|
||||
$logs = array();
|
||||
$logs['error']['message'] = $ex->getMessage();
|
||||
$data['errormsg'] = $ex->getMessage();
|
||||
$this->model_extension_payment_rbkmoney->logger('exception', $logs);
|
||||
}
|
||||
|
||||
if (isset($response["invoice"])) {
|
||||
$data['invoice_id'] = $response["invoice"]["id"];
|
||||
$data['invoice_access_token'] = $response["invoiceAccessToken"]["payload"];
|
||||
}
|
||||
|
||||
if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/extension/payment/rbkmoney')) {
|
||||
return $this->load->view($this->config->get('config_template') . '/template/extension/payment/rbkmoney', $data);
|
||||
} else {
|
||||
return $this->load->view('extension/payment/rbkmoney', $data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* http{s}://{your-site}/index.php?route=payment/rbkmoney/callback
|
||||
*/
|
||||
public function callback()
|
||||
{
|
||||
$content = file_get_contents('php://input');
|
||||
$logs = array(
|
||||
'request' => array(
|
||||
'method' => 'POST',
|
||||
'data' => $content,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
$method = 'notification';
|
||||
$this->load->model('extension/payment/rbkmoney');
|
||||
$this->model_extension_payment_rbkmoney->logger($method, $logs);
|
||||
|
||||
if (empty($_SERVER[static::SIGNATURE])) {
|
||||
$logs['error']['message'] = 'Webhook notification signature missing';
|
||||
return $this->outputWithLogger($method, $logs, $logs['error']['message']);
|
||||
}
|
||||
|
||||
$logs['signature'] = $_SERVER[static::SIGNATURE];
|
||||
|
||||
$params_signature = $this->model_extension_payment_rbkmoney->getParametersContentSignature($_SERVER[static::SIGNATURE]);
|
||||
if (empty($params_signature[static::SIGNATURE_ALG])) {
|
||||
$logs['error']['message'] = 'Missing required parameter ' . static::SIGNATURE_ALG;
|
||||
return $this->outputWithLogger($method, $logs, $logs['error']['message']);
|
||||
}
|
||||
|
||||
if (empty($params_signature[static::SIGNATURE_DIGEST])) {
|
||||
$logs['error']['message'] = 'Missing required parameter ' . static::SIGNATURE_DIGEST;
|
||||
return $this->outputWithLogger($method, $logs, $logs['error']['message']);
|
||||
}
|
||||
|
||||
$signature = $this->model_extension_payment_rbkmoney->urlSafeB64decode($params_signature[static::SIGNATURE_DIGEST]);
|
||||
$public_key = trim($this->config->get('payment_rbkmoney_rbkmoney_public_key'));
|
||||
if (!$this->model_extension_payment_rbkmoney->verificationSignature($content, $signature, $public_key)) {
|
||||
$logs['error']['message'] = 'Webhook notification signature mismatch';
|
||||
return $this->outputWithLogger($method, $logs, $logs['error']['message']);
|
||||
}
|
||||
|
||||
$required_fields = [static::INVOICE, static::EVENT_TYPE];
|
||||
$data = json_decode($content, TRUE);
|
||||
|
||||
foreach ($required_fields as $field) {
|
||||
if (empty($data[$field])) {
|
||||
$logs['error']['message'] = 'One or more required fields are missing';
|
||||
return $this->outputWithLogger($method, $logs, $logs['error']['message']);
|
||||
}
|
||||
}
|
||||
|
||||
$current_shop_id = $this->config->get('payment_rbkmoney_shop_id');
|
||||
if ($data[static::INVOICE][static::INVOICE_SHOP_ID] != $current_shop_id) {
|
||||
$logs['error']['message'] = static::INVOICE_SHOP_ID . ' is missing';
|
||||
return $this->outputWithLogger($method, $logs, $logs['error']['message']);
|
||||
}
|
||||
|
||||
|
||||
if (empty($data[static::INVOICE][static::INVOICE_METADATA][static::ORDER_ID])) {
|
||||
$logs['error']['message'] = static::ORDER_ID . ' is missing';
|
||||
return $this->outputWithLogger($method, $logs, $logs['error']['message']);
|
||||
}
|
||||
|
||||
|
||||
$order_id = $data[static::INVOICE][static::INVOICE_METADATA][static::ORDER_ID];
|
||||
$this->load->model('checkout/order');
|
||||
|
||||
if (!$order_info = $this->model_checkout_order->getOrder($order_id)) {
|
||||
$logs['error']['message'] = 'Order ' . $order_id . ' is missing';
|
||||
return $this->outputWithLogger($method, $logs, $logs['error']['message']);
|
||||
}
|
||||
|
||||
if (!empty($order_info['total'])) {
|
||||
$order_amount = (int)$this->model_extension_payment_rbkmoney->prepareAmount($order_info['total']);
|
||||
$invoice_amount = (int)$data[static::INVOICE][static::INVOICE_AMOUNT];
|
||||
if ($order_amount != $invoice_amount) {
|
||||
$logs['order_info'] = $order_info;
|
||||
$logs['error']['message'] = 'Received amount ' . $order_amount . ' vs Order amount mismatch ' . $data[static::INVOICE][static::INVOICE_AMOUNT];
|
||||
return $this->outputWithLogger($method, $logs, $logs['error']['message']);
|
||||
}
|
||||
}
|
||||
|
||||
$allowedEventTypes = array(static::EVENT_TYPE_INVOICE_PAID, static::EVENT_TYPE_INVOICE_CANCELLED);
|
||||
if (in_array($data[static::EVENT_TYPE], $allowedEventTypes)) {
|
||||
|
||||
$invoiceStatus = $data[static::INVOICE][static::INVOICE_STATUS];
|
||||
if (($invoiceStatus == static::CALLBACK_STATUS_PAID) && ($order_info['order_status_id'] != $this->config->get('payment_rbkmoney_order_status_id'))) {
|
||||
$this->model_checkout_order->addOrderHistory($order_info['order_id'], $this->config->get('payment_rbkmoney_order_status_id'), 'RBKmoney', TRUE);
|
||||
} elseif (($invoiceStatus == static::CALLBACK_STATUS_CANCELLED) && ($order_info['order_status_id'] != $this->config->get('payment_rbkmoney_order_status_cancelled_id'))) {
|
||||
$this->model_checkout_order->addOrderHistory($order_info['order_id'], $this->config->get('payment_rbkmoney_order_status_cancelled_id'), 'RBKmoney', TRUE);
|
||||
}
|
||||
|
||||
return $this->outputWithLogger($method, $logs, 'OK', self::HEADER_OK);
|
||||
}
|
||||
|
||||
return $this->outputWithLogger($method, $logs, 'FINISH', self::HEADER_OK);
|
||||
}
|
||||
|
||||
private function outputWithLogger($method, &$logs, $message, $header = self::HEADER_BAD_REQUEST)
|
||||
{
|
||||
$response = array('message' => $message);
|
||||
$this->load->model('extension/payment/rbkmoney');
|
||||
$this->model_extension_payment_rbkmoney->logger($method, $logs);
|
||||
$this->response->addHeader($header);
|
||||
$this->response->setOutput(json_encode($response));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
// Text
|
||||
$_['text_title'] = 'RBKmoney';
|
||||
|
||||
?>
|
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
// Text
|
||||
$_['text_title'] = 'RBKmoney';
|
||||
|
||||
?>
|
324
upload/catalog/model/extension/payment/rbkmoney.php
Normal file
@ -0,0 +1,324 @@
|
||||
<?php
|
||||
|
||||
class ModelExtensionPaymentRBKmoney 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';
|
||||
|
||||
const SIGNATURE = 'HTTP_CONTENT_SIGNATURE';
|
||||
const SIGNATURE_ALG = 'alg';
|
||||
const SIGNATURE_DIGEST = 'digest';
|
||||
const SIGNATURE_PATTERN = "|alg=(\S+);\sdigest=(.*)|i";
|
||||
|
||||
private $api_url = 'https://api.rbk.money/v2/';
|
||||
|
||||
public function getMethod($address, $total)
|
||||
{
|
||||
$this->load->language('extension/payment/rbkmoney');
|
||||
|
||||
if ($this->config->get('payment_rbkmoney_status')) {
|
||||
|
||||
$query = $this->db->query("SELECT * FROM " . DB_PREFIX . "zone_to_geo_zone WHERE geo_zone_id = '" . (int)$this->config->get('payment_rbkmoney_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('payment_rbkmoney_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',
|
||||
'title' => $this->language->get('text_title'),
|
||||
'terms' => '',
|
||||
'sort_order' => $this->config->get('payment_rbkmoney_sort_order')
|
||||
);
|
||||
}
|
||||
|
||||
return $method_data;
|
||||
}
|
||||
|
||||
private function getHeaders()
|
||||
{
|
||||
$headers = array();
|
||||
$headers[] = 'X-Request-ID: ' . uniqid();
|
||||
$headers[] = 'Authorization: Bearer ' . $this->config->get('payment_rbkmoney_merchant_private_key');
|
||||
$headers[] = 'Content-type: application/json; charset=utf-8';
|
||||
$headers[] = 'Accept: application/json';
|
||||
return $headers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function createInvoice(array $order_info)
|
||||
{
|
||||
$data = [
|
||||
'shopID' => $this->config->get('payment_rbkmoney_shop_id'),
|
||||
'amount' => $this->prepareAmount($order_info['total']),
|
||||
'metadata' => $this->prepareMetadata($order_info['order_id']),
|
||||
'dueDate' => $this->prepareDueDate(),
|
||||
'currency' => $order_info['currency_code'],
|
||||
'product' => $order_info['order_id'],
|
||||
'cart' => $this->prepareCart(),
|
||||
'description' => $this->getProductDescription(),
|
||||
];
|
||||
|
||||
$url = $this->prepareApiUrl('processing/invoices');
|
||||
$headers = $this->getHeaders();
|
||||
return $this->send($url, 'POST', $headers, json_encode($data, true), 'init_invoice');
|
||||
}
|
||||
|
||||
private function prepareCart()
|
||||
{
|
||||
$lines = array();
|
||||
foreach ($this->cart->getProducts() as $product) {
|
||||
$item = array();
|
||||
$item['product'] = $product['name'];
|
||||
$item['quantity'] = (int)$product['quantity'];
|
||||
|
||||
$tax = $this->tax->calculate($product['price'], $product['tax_class_id'], $this->config->get('config_tax'));
|
||||
|
||||
$price = round($tax, 2, PHP_ROUND_HALF_UP);
|
||||
$item['price'] = $this->prepareAmount($price);
|
||||
|
||||
$tax_rates = $this->tax->getRates($product['price'], $product['tax_class_id']);
|
||||
if (!empty($tax_rates)) {
|
||||
|
||||
foreach ($tax_rates as $rate) {
|
||||
$rate = $this->getRate($rate['rate']);
|
||||
if ($rate != null) {
|
||||
$taxMode = [
|
||||
'type' => 'InvoiceLineTaxVAT',
|
||||
'rate' => $rate,
|
||||
];
|
||||
$item['taxMode'] = $taxMode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
$lines[] = $item;
|
||||
}
|
||||
|
||||
$shippingMethod = "";
|
||||
if (isset($this->session->data['shipping_method'])) {
|
||||
$shippingMethod = $this->session->data['shipping_method'];
|
||||
}
|
||||
|
||||
if (!empty($shippingMethod)) {
|
||||
|
||||
if (isset($shippingMethod['cost']) && $shippingMethod['cost'] > 0) {
|
||||
$item = array();
|
||||
$item['product'] = $shippingMethod['title'];
|
||||
$item['quantity'] = 1;
|
||||
|
||||
$tax = $this->tax->calculate($shippingMethod['cost'], $shippingMethod['tax_class_id'], $this->config->get('config_tax'));
|
||||
$price = round($tax, 2, PHP_ROUND_HALF_UP);
|
||||
$item['price'] = $this->prepareAmount($price);
|
||||
|
||||
// Shipping always 18%
|
||||
$taxMode = [
|
||||
'type' => 'InvoiceLineTaxVAT',
|
||||
'rate' => "18%",
|
||||
];
|
||||
$item['taxMode'] = $taxMode;
|
||||
|
||||
$lines[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $lines;
|
||||
}
|
||||
|
||||
private function getRate($rate)
|
||||
{
|
||||
switch ($rate) {
|
||||
case '0':
|
||||
case '0.0000':
|
||||
return '0%';
|
||||
break;
|
||||
case '10':
|
||||
case '10.0000':
|
||||
return '10%';
|
||||
break;
|
||||
case '18':
|
||||
case '18.0000':
|
||||
return '18%';
|
||||
break;
|
||||
case '10/100':
|
||||
return '10/110';
|
||||
break;
|
||||
case '18/118':
|
||||
return '18/118';
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private function send($url, $method = "POST", $headers = array(), $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('Required url parameter not passed');
|
||||
}
|
||||
|
||||
$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',
|
||||
'order_id' => $order_id,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare amount (e.g. 124.24 -> 12424)
|
||||
*
|
||||
* @param $amount int
|
||||
* @return int
|
||||
*/
|
||||
public function prepareAmount($amount)
|
||||
{
|
||||
return number_format($amount, 2, '.', '') * 100;
|
||||
}
|
||||
|
||||
private function prepareApiUrl($path = '', $query_params = array())
|
||||
{
|
||||
$url = rtrim($this->api_url, '/') . '/' . $path;
|
||||
if (!empty($query_params)) {
|
||||
$url .= '?' . http_build_query($query_params);
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
public function urlSafeB64decode($string)
|
||||
{
|
||||
$data = str_replace(array('-', '_'), array('+', '/'), $string);
|
||||
$mod4 = strlen($data) % 4;
|
||||
if ($mod4) {
|
||||
$data .= substr('====', $mod4);
|
||||
}
|
||||
return base64_decode($data);
|
||||
}
|
||||
|
||||
public function urlSafeB64encode($string)
|
||||
{
|
||||
$data = base64_encode($string);
|
||||
return str_replace(array('+', '/'), array('-', '_'), $data);
|
||||
}
|
||||
|
||||
public function getParametersContentSignature($content_signature)
|
||||
{
|
||||
preg_match_all(static::SIGNATURE_PATTERN, $content_signature, $matches, PREG_PATTERN_ORDER);
|
||||
$params = array();
|
||||
$params[static::SIGNATURE_ALG] = !empty($matches[1][0]) ? $matches[1][0] : '';
|
||||
$params[static::SIGNATURE_DIGEST] = !empty($matches[2][0]) ? $matches[2][0] : '';
|
||||
return $params;
|
||||
}
|
||||
|
||||
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 == 1);
|
||||
}
|
||||
|
||||
public function logger($method, $message)
|
||||
{
|
||||
// if ($this->config->get('rbkmoney_logs')) {
|
||||
$this->log->write('rbkmoney ' . $method . '. ' . print_r($message, true));
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
{% if (errormsg is not empty) %}
|
||||
{{ errormsg }}
|
||||
{% else %}
|
||||
{% if (form_css_button is not empty) %}
|
||||
<style>
|
||||
{{ form_css_button }}
|
||||
</style>
|
||||
{% endif %}
|
||||
|
||||
<form action="{{ payment_form_success_url }}" method="POST">
|
||||
<script src="{{ payment_form_url }}" class="rbkmoney-checkout"
|
||||
data-invoice-id="{{ invoice_id }}"
|
||||
data-invoice-access-token="{{ invoice_access_token }}"
|
||||
{% if (form_company_name is not empty) %}
|
||||
data-name="{{ form_company_name }}"
|
||||
{% endif %}
|
||||
{% if (form_button_label is not empty) %}
|
||||
data-label="{{ form_button_label }}"
|
||||
{% endif %}
|
||||
{% if (form_description is not empty) %}
|
||||
data-description="{{ form_description }}"
|
||||
{% endif %}
|
||||
>
|
||||
</script>
|
||||
</form>
|
||||
{% endif %}
|