В первую очередь скажу, что этот пост будет полезен только тем, кто более менее разбирается в PHP.
И так, я вкратце расскажу принцип работы платежных систем в старой версии корзины (до конструктора из 2.2.0)
По многих причинам корзина не может расширяться плагинами поэтому ниже мы будем писать хаки.
Допустим у нас есть агрегатор платежей
Начиная отсюда я буду считать, что у меня есть вымышленная(!) классическая платежная система
- Она называется myPayment
- Чтобы создать заказ мне нужно отправить через GET или POST на http://merchant.mypayment.com/ массив
- - логин продавца
- - номер заказа
- - сумма
- - хеш - цифровая подпись, образованная через md5 ($orderId : $amount, $password)
- После оплаты на сайт зайдет робот и мне нужно сравнить его хеш со своим и если все нормально, то ставим отметку "оплачено".
Разбираем payment.php
Основной файл, который отвечает за работу с платежными системами - это jbuniversal\framework\controllers\payment.php
На самом деле это контроллер, которая собрал в себя почти всю логику работы.
Сейчас мы в нем увидим жесткие условия для работы с PayPal, Interkassa, Robokassa
Вы можете найти тут такие методы как
_init() - делает минимально необходимые проверки заказа (существование). Так же содержит важную функцию, как определение заказа по внешнему ID
index() - отвечает за страницу с выбором платежной системы. Здесь проверяется, включен ли способ оплаты, и если да, то подготавливаются данные и рендерится HTML код формы.
paymentCallback() - Метод, который отвечает за валидацию заказа и отметку об оплате. Он нужен только для роботов и вернет что-то только если на него правильно отправить POST запрос.
Где хранить настройки ?
Откройте файл jbuniversal\config\basket.xml
И по аналогии добавим в низу
<!-- myPayment--> <param name="@spacer-mypayment" type="jbspacer" default="MyPayment"/> <param name="mypayment-enabled" type="jbbool" default="0" label="MyPayment"/> <param name="mypayment-login" type="text" default="" label="Login" /> <param name="mypayment-password" type="text" default="" label="Password"/>
Это добавит опции вкл/логин/пароль в настройках каталога корзины.
Сохранятся они будут в базу данных как параметры каталога.
Рендеринг формы оплаты
По аналогии с одним из существующих способов добавим код рендеринга
<?php // myPayment if ((int)$appParams->get('mypayment-enabled', 0)) { // проверяем, включена ли система // готовим данные для HTML-формы $params = new stdClass(); // берем логин и пароль из настроек и избавляемся от случайных пробелов $params->login = JString::trim($appParams->get('mypayment-login')); $params->password = JString::trim($appParams->get('mypayment-password')); // генерируем подпись (смотрите документацию вашего агрегатора) $params->hash = md5(implode(':', array($params->login, $totalSumm, $this->password))); // прочие не менее важные параметры формы $params->amount = $totalSumm; $params->orderId = $this->orderId; $params->summFormated = $totalSummFormated; $this->payments['mypayment'] = $this->app->data->create($params); } ?>
Открываем этот файл (он содержит общую разметку для выбора платежной системы)
jbuniversal\templates\catalog\renderer\payment\_default.php и добавляем
<?php if ((int)$view->appParams->get('global.jbzoo_cart_config.mypayment-enabled', 0)) { echo '<div class="width25">'; // попутно можно подогнать ширину echo $this->app->jblayout->render('payment_mypayment', $view->payments['mypayment']); echo '</div>'; } ?>
Теперь создаем шаблон для формы jbuniversal\templates\catalog\renderer\payment_mypayment\_default.php
Переменная $data - это объект JSONData, который будет хранить все то что мы подготовили в index()
<form action="http://merchant.mypayment.com/" method=POST> <input type="hidden" name="mypay_login" value="<?php echo $data->get('login'); ?>"> <input type="hidden" name="mypay_order_id" value="<?php echo $data->get('orderId'); ?>"> <input type="hidden" name="mypay_amount" value="<?php echo $data->get('amount'); ?>"> <input type="hidden" name="mypay_hash" value="<?php echo $data->get('hash'); ?>"> <input type="submit" class="add-to-cart" value="<?php echo JText::_('JBZOO_PAYMENT_BUTTON'); ?>"/> </form>
Платежный робот и валидация заказа
Валидация у нас будет с помощью робота, который автомаически заходит на наш сайт по специальному адресу (status)
Адрес этот заранее указан в настройках мерчанта у myPayment
Первое что нам нужно сделать, это определить что робот является именно от myPayment
Для этого в _init() проверяем внешнюю переменную из реквеста, которая отвечает за номер заказа.
Обычно в этом нет никаких проблем, т.к каждая система имеет свое уникальное именование.
Для удобства используем константу
const TYPE_MYPAYMENT = 'MyPayment';
Код определения id оплаченного заказа
<?php ... // тут я проверяю $_REQUEST['mypay_order_id'], у вас может быть другая. } else if ($orderId = (int)$this->_jbrequest->get('mypay_order_id')) { $this->systemType = self::TYPE_MYPAYMENT; $this->orderId = $orderId; } else if ( ... ) { .... ?>
Проверяем данные, с которыми к нам пожаловал робот
Снова по аналогии с другими платежными системами вставляем свой код в paymentCallback()
<?php if ($this->systemType == self::TYPE_MYPAYMENT) { // подготавливаем свои переменные $login = JString::trim($this->appParams->get('global.jbzoo_cart_config.mypayment-login')); $password = JString::trim($this->appParams->get('global.jbzoo_cart_config.mypayment-password')); $myHash = md5($login . ':' . $password . ':' . $this->orderId); // берем $merchantHash = $_REQUEST['mypay_hash']; // без Joomla API, чтобы ничего не стереть if ($merchantHash === $myHash) { // совпали ли подписи? // Все отлично, готовим данные для сохранения в наш заказ $args = array( 'date' => $this->app->date->create()->toSQL(), // текущая дата 'system' => $this->systemType, // имя платежной системы 'additionalState' => null // сюда можно добавить свои произвольные переменные (массиом) ); // отмечаем заказ как оплаченный $this->orderDetails->callback('paymentCallback', $args); // говорим роботу на его языке, что все отлично и он тоже может быть спокоен jexit('OK' . $this->orderId); } else { // прогоняем робота фатальной ошибкой. Валидация не прошла! throw new AppException('No valid hash'); } } ?>
Вот и все!
И сразу важные замечания.
- Использовал в качестве примера простейшую выдуманную платежную систему. Поэтому у вас будут свои переменные и свои способы валидации. Возможно что и тех и других будет гораздо больше.
- В качестве рабочего примера рекомендую смотреть реализацию Робокассы. Она имеет очень простое API без наворотов.
- Я лишь описал принцип работы, чтобы дать понять с чего начинать.
Т.к довольно большая часть действий происходит в фоне, то рекомендую использовать какой-нибудь логгер переменных в файл.
Это поможет понять что отправляет робот. Зачастую там есть полезная информация вроде конкретного способа оплаты.
Сам я всегда пользуюсь jbdump
Подключаем класс и дампим
jbdump::log($_REQUEST);
Затем смотрим содержимое папки /logs/ рядом с классом.
Так же на форуме есть другие обсуждения. Вот что вспомнил я
(список на самом деле большой, но у меня действительно нет времени. Поиск на форуме работает )
http://forum.jbzoo.c...rivat24-liqpay/
http://forum.jbzoo.c...ziny-jbzoo-160/