В статье "Создаем плагин Hikashop (счет на оплату) - часть 1 " мы создали стандартный счет на оплату на собственной "платежной странице" сайта. Но на практике абсолютно все платежные плагины на конечной стадии переходят на платежную платформу банка-эквайера. К сожалению, Сбербанк на текущий момент официально не предоставляет платежные модули (плагины) для интернет-магазина Hikasop_Joomla , а продвигает интернет-магазин Yoom.shop - поэтому попробуем создать его сами.
Проведем анализ опубликованных платежных плагинов Альфа-банка, РФИ-банка, Тинькофф-банка и Сберегательного банка и создадим таблицу, в которой проанализируем структуру (параметры настройки, функции, запросы), наличие API-файлов и количество файлов PHP , участвующие в процессе прохождения платежа.
Начнем, как ни странно, с анализа платежных плагинов для JoomShopping - он опубликован всеми банками и доступен для анализа
Платежная платформа банка |
Альфа |
РФИ |
Тинькофф |
Сбербанк |
Стандарт JoomShopping |
название плагина | pm_rbspayment | pm_rficb | pm_tinkoff | pm_rbspayment | pm_paysto |
кол-во файлов в zip | 5 | 3 | 8 | 5 | 5 |
форма для админ.панели | adminparamsform.php | adminparamsform.php | adminparamsform.php | adminparamsform.php | adminparamsform.php |
адреса шлюзов | include.php | - | include.php | - | |
используется для заполнения значениями формы (админ.панель) | paymentform.php | paymentForms.php | paymentform.php | paymentform.php | paymentform.php |
подключает параметры значений из формы (админ.панели) для передачи на шлюз с помощью функций платежной платформы | pm_rbspayment.php | pm_rficb.php | pm_tinkoff.php | pm_rbspayment.php | pm_paysto.php |
организует передачу товарной корзины (заказа) на платежную страницу | rbs_discount.php | - | - | rbs_discount.php | - |
подключение к базе данных, передача параметров и получение уведомлений | - | - | notification.php | - | paysto_notify.php |
- | - | page_not_ok.php | - | - | |
- | - | page_ok.php | - | - | |
- | - | success.php | - | - | |
- | TinkoffMerchantAPI.php | - | - | ||
форма для отправки данных на платежную платформу | - | - | - | - | endform.php |
дополнительные папки | - | imges, lanquaqe | lanquaqe | - | images, lanquaqe |
Дата выхода плагина | 2019 | 2018 | 2019 | 2017-2018 | 2012 |
Создадим аналогичную таблицу для Hikashop, которая поможет нам в дальнейшем копировать и заменять код php в нашем создаваемом платежном плагине с названием sberbank_hikashop
Платежная платформа банка |
РФИ |
Тинькофф |
Сбербанк |
Стандарт Hikashop |
название плагина | hikashop_rfibank | joomla_hikashop | rbs | palpay_hikashop |
количество файлов в zip | 2 | 7 | - | 2 |
установщик плагина | rficb.xml | tinkoff.xml | - | palpay.xml |
адреса платежных шлюзов | - | - | - | - |
используется для заполнения значениями формы (админ.панель) | rficb.php | tinkoff_configuration.php | - | paypay.php |
подключает параметры значений из формы (админ.панели) для передачи на шлюз с помощью функций платежной платформы, | rficb.php | tinkoff.php | - | palpay.php |
организует передачу товарной корзины (заказа) на платежную страницу | rficb.php | - | - | palpay.php |
подключение к базе данных, передача параметров и получение уведомлений | rficb.php | notification.php | - | palpay.php |
ввод данных банковской карты | rficb.php | TinkoffToken.php | - | palpay.php |
TinkoffMerchantAPI.php | - | - | ||
форма для отправки данных на платежную платформу | rficb.php |
tinkoff_end.php |
- | palpay_end.php |
дополнительные папки | icons | - | - | icons |
Дата выхода плагина | 2018 | декабрь 2018 | отсутст. | 2020 |
Таким образом, из анализа видно, что стандартный платежный модуль (плагин) для Joomla3 состоит в JoomShopping из пяти файлов php, а в Hikashop плагин для оплаты банковскими картами может состоять всего из из 2-х файлов.
Отмечу тот факт, что среди 2-х официально представленных плагинов плагин РФИ банка предпочтительнее - он может принимать оплату через разные платежные платформы, в т.ч. через Яндекс.Деньги и Qiwi. А регистрация в РФИ банке (получение секретного ключа и id интернет-магазина) предполагает и бонус в виде использования отдельного платежного виджета оплаты картами для платформе Joomla (используется тот же секретный ключ и id) , что существенно расширяет возможности оплаты товара на сайте (даже без установки Hikashop).
Итак начнем.
Любой платежный плагин для Hikashop должен состоять из следующих обязательных аттрибутов:
var $pluginConfig = array ( ... )
public function onAfterOrderConfirm (&$order, &$methods, $method_id) { ...}
public function onPaymentNotification (&$statuses) { ... }
Специальная конфигурация платежного плагина $pluginConfig
Для отправки параметров корзины на платежную платформу внутри плагина на специальной вкладке конфигурации (переменная $pluginConfig ) создадим переменные в соответствии с требованиями Сбербанка, которые можно выбирать в дальнейшем (администативная панель Hikashop --> способы оплаты --> плагин) из выпадающего списка.
// перед class подключить файлы: даст шлюз + типовые функции - предварительно разместить в папке будущего плагина
require_once(__DIR__ . '/include.php'); require_once(__DIR__ . '/rbs_discount.php');
class plgHikashoppaymentSberbank1 extends hikashopPaymentPlugin {
var $name = 'sberbank1'; //использование в названии слов sberbank или rbs var $accepted_currencies = array("RUB"); var $multiple = true;
//запись var $pluginConfig( ) в Hikashop заменяет сразу два файла JoomShopping: adminparamsform.php + paymentform.php
var $pluginConfig = array( 'rbs_merchant_login' => array('Логин магазина (TERMINAL_ID)', 'input'), 'rbs_merchant_password' => array('Секретный пароль (SECRET_KEY)','input'),
'email_company' => array('Email банка-эквайера','input'), // от тинькофф - возможно не то 'TEST_MODE'=> array('Тестовый режим','boolean','1'), 'rbs_test_mode'=> array('Выбор платежного шлюза','list',array( 'RBS_TEST_URL' => 'тестовый', 'RBS_PROD_URL' => 'рабочий', )),
'rbs_two_stage'=> array('Использовать двухстадийные платежи','boolean','0'),
//'rbs_two_stage'=> array('Стадийность платежей','list',array( //'1state' => 'одностадийный', //'2state' => 'двухстадийный', // )),
'enable_taxation'=> array('Включить налогообложение','boolean','1'), //
'rbs_tax_system'=> array('Система налогобложения','list',array( // от 0 до 5 rbs 'osn' => 'общая', 'usn_income' => 'упрощенная, доход', 'usn_income_outcome'=> 'упрощенная, доход минус расход', 'envd' => 'единый налог на вмененный доход',
'esn' => 'единый сельхозхозяйственный налог', 'patent' => 'патентная система налогообложения', )),
//'rbs_tax'=> array('Ставка налогобложения','list',array( //используются настройки Hikashop //'1' => 'НДС 20%', //'2' => 'НДС 18%', //'3'=> 'НДС 10%', //'4' => 'НДС 0%', //'5' =>'РАСЧЕТНАЯ 20/120', //)),
'rbs_send_order'=> array('Передача товарной корзины на шлюз','boolean','0'), 'rbs_ffd_version'=> array('Формат фискальных документов','list',array( 'v10' => '1.0', 'v105' => '1.05', //'v110' => '1.10', )),
'rbs_ffd_paymentMethodType'=> array('Типы оплаты','list',array( //payment_metod - тинькофф 'full_prepayment' => 'Полная предоплата до момента передачи предмета расчета', 'prepayment' => 'Частичная предоплата до момента передачи предмета расчета', 'advanse'=> 'Аванс', 'full_payment' => 'Полная оплата в момент передачи предмета расчета', 'partial_payment' =>'Частичная оплата предмета расчета в момент его передачи с последующей оплатой в кредит', 'credit' =>'Передача предмета расчета без его оплаты с последующей оплатой в кредит', 'credit_payment' =>'Оплата предмета расчета после его передачи с оплатой в кредит', )),
'rbs_ffd_paymentObjectType'=> array('Типы оплачиваемой позиции','list',array( //payment_object - тинькофф 'commodity' => 'Товар', // от 1 до 13 rbs 'excise' => 'Подакцизный товар', 'job' => 'Работа', 'servise' => 'Услуга', 'gambling_bet' => 'Ставка азартной игры', 'gambling_prize' => 'Выигрыш азартной игры', 'lottery' => 'Лотерейный билет', 'lottery_prize' => 'Выигрыш лотереи', 'intellectual_activity' => 'Представление РИД', 'payment' => 'Платеж', 'agent_commission' => 'Агентское вознаграждение', 'composite' => 'Составной предмет расчета', 'another' => 'Иной предмет расчета', )), 'cancel_url' => array('CANCEL_URL','html',''), 'return_url' => array('RETURN_URL','html',''), 'notify_url' => array('NOTIFY_URL','html',''), 'invalid_status' => array('INVALID_STATUS', 'orderstatus'), 'verified_status' => array('VERIFIED_STATUS', 'orderstatus'),
'pending_status' => array('PENDING_STATUS', 'orderstatus'), //
'refunded_status' => array('REFUNDED_STATUS', 'orderstatus'), //
'language'=> array('Язык ','list',array( //
'ru' => 'русский',
'en' => 'английский',)), );
//используемые адреса платежных шлюзов - 3 записи отражены в файле include.php
define('API_URL_PROD', 'https://securepayments.sberbank.ru/payment/rest/');
define('API_URL_TEST', 'https://3dsec.sberbank.ru/payment/rest/');
define('TEST_MODE', true);
//самый простой вариант для передачи параметров на шлюз - №заказа и сумма
$args = Array(
'userName' => $this->payment_params->rbs_merchant_login ,
'password' => $this->payment_params->rbs_merchant_password,
'amount' => round($order->cart->full_total->prices[0]->price_value_with_tax,2),
'orderNumber' => $order->order_id,
'returnUrl' => JURI::root() . 'index.php?option...',
'jsonParams' => json_encode(array('CMS' => 'Joomla 3.x', 'Module-Version' => VERSION)), );
...сюда будем добавлять новые необходимые параметры...
);
Функция - конструктор обеспечивает автоматическое заполнение админ-панели параметрами, указанными в функции __construct ( )
function __construct(&$subject, $config) { $this->pluginConfig['notification'][0] = JText::sprintf('ALLOW_NOTIFICATIONS_FROM_X','Sberbank'); $this->pluginConfig['cancel_url'][2] = HIKASHOP_LIVE."index.php?option=com_hikashop&ctrl=order&task=cancel_order"; $this->pluginConfig['return_url'][2] = HIKASHOP_LIVE."index.php?option=com_hikashop&ctrl=checkout&task=after_end"; $this->pluginConfig['notify_url'][2] = HIKASHOP_LIVE.'index.php?option=com_hikashop&ctrl=checkout&task=notify¬if_payment='.$this->name.'&tmpl=component'; return parent::__construct($subject, $config); }
Единственный параметр - returnUrl (среди похожих есть также return_url ) - использующийся при проведении транзакций платежей - плавающий
Вся прелесть подхода Сбербанка к разработке платежного плагина для JoomShopping состояла в том, что для корректировки адреса шлюза надо было заменить всего 2 строчки кода, что использовал Альфа-банк (copy-paste)
//замена адреса платежных шлюзов - эти две записи отражены в файле include.php от Альфа-банка
define('API_URL_PROD', 'https://pay.alfabank.ru/payment/rest/');
define('API_URL_TEST', 'https://web.rbsuat.ru/payment/rest/');
Основной файл для платежного модуля JoomShopping - это pm_rbspayment.php. В нем первоначально подлючаются файлы include.php и rbs_discount.php При этом PHP проверит, включался ли уже данный файл или нет - если да, не будет включать его еще раз - это происходит через запись require_once
require_once(dirname(__FILE__) . '/include.php');
require_once(dirname(__FILE__) . '/rbs_discount.php');
Также может встречаться и выражение include_once - включает и выполняет указанный файл во время выполнения скрипта (если код из файла уже один раз был включен, он не будет повторно включаться и не будет выполняться повторно, а вернёт TRUE
)
include_once __DIR__ . '/include.php';
include_once 'TinkoffToken.php';
Изначально по названию файла rbs_discount.php я не обратил пристального внимания на этот файл. Ну скидка и есть скидка - так переводится слово "discount" - обойдусь без неё...без скидки. Оказалось, это так называемый API - файл --- файл, идущий со всеми платежными модулями, независимо от самой платформы интернет-магазина ( Hikashop, JoomShopping, VirtueMart ). Просто разработчик сюда скопировал основные функции , которые будут работать на любых платформах, только успевай подставлять аргументы. У этого файла свой уникальный класс - rbsDiscount - он может работать в свою очередь как внутри класса pm_rbspayment, который является расширением класса PaymentRoot , так и автономно, т.е. выстраивается цепочка взаимосвязей rbsDiscount --> pm_rbspayment --> PaymentRoot
Тинькофф-банк также пошел по этому пути - у него есть файл TinkoffMerchantAPI.php - он тоже универсален и используется на всех платформах интернет-магазинов от разработчиков Тинькофф Банка. В нем используется класс TinkoffMerchantAPI, который расширяет класс TinkoffToken. Сам файл TinkoffToken.php представляет собой функцию шифрования значения пароля банковской карты в хэш.
//пример файла tinkoffToken.php
class TinkoffToken { public static function getToken($data, $secret_key) { $data['Password'] = $secret_key; ksort($data); if (isset($data['Token'])) { unset($data['Token']); } $values = implode('', array_values($data)); return hash('sha256', $values); //string } }
Вернемся к созданию плагина. Для Сбербанка передача корзины на платежный шлюз для дальнейшего использования осуществляется с помощью многократного переобразования агрументов переменной $ arrOrder = array ('basket' => array( ) ) через множество функций (обнуление --> первичное получение --> возможность преобразования --> нормализация --> дальнейшее использование). Передача позиций корзины (можества товаров) осуществляется через переменную $orderBundle в формате
$orderBundle['cartItems']['items'][ ]
. В стандартном платежном плагине Hikashop для этого используются значения массива $ vars = array ( ).
Кроме самой корзины или заказа, платформа Сбербанка ждет от интернет-магазина получение $arg = array ( ) [ или $rbs_arg = array ( ) как вариант] Требование платформы оплаты Сбербанка через $arg получить значения
// для Hikashop нахождение значений актуально через следующие выражения
$args = Array(
//обязательные параметры
'userName' => $this->payment_params->rbs_merchant_login ,
'password' => $this->payment_params->rbs_merchant_password,
'orderNumber' => $order->order_id,
'amount' => round($order->cart->full_total->prices[0]->price_value_with_tax,2),
'returnUrl' => $return_url,
'jsonParams' => json_encode(
array(
'CMS' => 'Joomla 3.x',
'Module-Version' => self:: VERSION,
'Name' => $order->cart->$address_type->address_firstname, ,
'Last' => $order->cart->$address_type->address_lastname, ,
)
),
// необязательные, но необходимые параметры...
'failUrl' => $cancel_url,
'lanquaqe' => $lanq,
'description' => ,
//новые неизвестные для Hikashop параметры
);
Для поиска недостающих переменных воспользуемся методом JFactory:: get ( ).
$action_adr = при различных условиях возможные значения RBS_TEST_URL / RBS_PROD_URL плюс дополнения через оператор конкатенации ('.') . ='register.do' / . = 'registerPreAuth' /
// заполнение переменных по аналогии rbs_payment.php
$config = & hikashop_config(); $arg ['taxSystem'] = $this->payment_params->rbs_tax_system; $order_items = $order->cart->products; $items = array ( );
$itemsCnt = 1; $orderBundle = [ ];
$orderBundle['customerDetails'] = array {
'email' => $order->email;
};
/*заполнение массива данных корзины*/
foreach ($order_items as $product) { //$value (JoomShopping) это $product (Hikashop)
$item = array ( );
$item_tax = $product->order_product_tax;
if ($item_tax == 20) {$tax_type = 6;} // проверить числа
else if ($item_tax == 18) {$tax_type = 3;}
else if ($item_tax == 10) {$tax_type = 2;}
else if ($item_tax == 0) {$tax_type = 1;}
else {$tax_type = 0;}
$product_price = ceil($product->product_item_price * 100);
$item['positionId'] = $itemsCnt++;
$item['name'] = $product->order_product_name;
$item['quantity'] = array(
'value' => $product->order_product_quantity,
'measure' => 'шт',
);
$item['itemAmount'] = $product->order_product_price * $product->order_product_quantity;
$item['itemCode'] = $product->order_product_code;
$item['tax'] = array(
'taxType' => $product->order_product_tax_info, // непонятно
);
$item['itemPrice'] = $product->order_product_price;
// FFD 1.05 версия и выше if ($this->payment_params->rbs_ffd_version == 'v105') { $attributes = array(); $attributes[] = array( "name" => "paymentMethod", "value" => $this->payment_params->rbs_ffd_paymentMethodType ); $attributes[] = array( "name" => "paymentObject", "value" => $this->payment_params->rbs_ffd_paymentObjectType ); $item['itemAttributes']['attributes'] = $attributes; }
$orderBundle['cartItems']['items'][] = $item; }
// Расчет скидки (и удалить стоимость доставки)
if ($order->order_shipping_price > 0) { //непонятно
$amount -= ceil($order->order_shipping_price * 100); // подключение rbs_discount.php выполнено ранее
//ceil — Округляет дробь в большую сторону 10,1 -> 11
} $discountHelper = new rbsDiscount(); //новый класс с помощью rbs_discount.php $discount = $discountHelper->discoverDiscount($amount, $orderBundle['cartItems']['items']); if ($discount > 0) { $discountHelper->setOrderDiscount($discount); $recalculatedPositions = $discountHelper->normalizeItems($orderBundle['cartItems']['items']); $orderBundle['cartItems']['items'] = $recalculatedPositions; }
// ПОЗИЦИЯ ПОСТАВКИ еще не смотрел if ($order->order_shipping > 0) { $itemShipment['positionId'] = $itemsCnt; $itemShipment['name'] = 'Доставка'; $itemShipment['quantity'] = array( 'value' => 1, 'measure' => 'шт' ); $itemShipment['itemAmount'] = $itemShipment['itemPrice'] = ceil($order->order_shipping * 100); $itemShipment['itemCode'] = 'Delivery'; //todo // $itemShipment['tax'] = array( // 'taxType' => $this->ofd_taxType // ); // FFD 1.05 added if ($pmconfigs['rbs_ffd_version'] == 'v105') { $attributes = array(); $attributes[] = array( "name" => "paymentMethod", "value" => $pmconfigs['rbs_ffd_paymentMethodType'] ); $attributes[] = array( "name" => "paymentObject", "value" => 4 ); $itemShipment['itemAttributes']['attributes'] = $attributes; } $orderBundle['cartItems']['items'][] = $itemShipment; }
статья в редактировании...