minicart pro ( ** tehnoklimat21.ru ** )

В первой части  "Создаем плагин Hikashop (счет на оплату) - часть 1 мы организовали вывод счета  на оплату на платежной странице плагина самым простым способом - "в лоб" - создали теги HTML и подставили в поля с помощью PHP параметры созданного заказа.  Создали режим отладки  (кнопка вкл./выкл.), задействовали служебную функцию   writeToLog  и  создали свою logger для просмотра информации о параметрах

и совершаемых действиях , а также попробовали организовать процесс уведомлений об оплате и подтвержения заказа на примере  кода от плагина PalPay . 

Стандартная установка плагина Example Hikashop 1.1
Пример работы плагина Example Hikashop

Отмечу сразу,  для правильной работы любого платежного плагина  значение параметра ' notification ' должно быть включено - "получать уведомления о статусе заказа (об оплате)".  Должен быть настроен и параметр ' notify_url ' (callback_url)   , об этом упоминают  разработчики Hikashop.  Но со Сбербанком этот вариант не прокатит - сначала надо попросить техподдержку о включении вкладки уведомлений в личном кабинете (по умолчанию личный кабинет не имеет никаких опций)

 Не смотря на свое потраченное время для поиска нужной информации, хочется поделиться "секретами", о которых я узнал, изучая PHP и отлаживая работу плагина HIKASHOP по оплате банковской картой через платежный шлюз Сбербанка.

СЕКРЕТ №1

Начнем, казалось с самого простого - использования функции writeToLog  в режиме отладки.   Функция упоминается почти в каждом плагине от Hikashop - от 1-ого раза до 50-и раз - и ни одной ссылки, ни одного пояснения на русском языке, куда потом смотреть, чтобы видеть  результаты её работы.

Разработчики Hikashop вскользь упоминают - " Файл журнала платежей доступен в конфигурации HikaShop в разделе файлов - и всё.  Меня лично очень задело, что я долго не мог найти этот чёртов журнал, даже "создал" (читай --> нашел в интернете и скопировал + понял  как работает)  за это время 2-3 шт.  аналогичных функций, которые создавали свой лог-файл ( .log) уже внутри папки нашего модифицированного плагина banktransfer (в моем случае "bank" )

 Местонажождение "журнала платежей" оказалось тривиально простым --> заходим в    конфигурацию  HIKASHOP (система -> конфигурация) 

Находите на вкладке конфигурация пункт  файлы  --> наводите курсор и попадаете на вкладку файлы --> находите поле лог файл оплат и нажимаете кнопку  Просмотреть отчет 

 В зависимости от количества использования функции writeToLog в плагине отладочная информация может отображаться либо в виде строки или массива, при этом отбражаюся время создания (использования) и название плагина в системе Hikashop (в нашем примере - "bank")

Сам файл по умолчанию сохраняется по пути :    media/com_hikashop/upload/safe/logs/report_210632903.log    

Не поленился, зашёл в папку   logs   - там всего 1 файл  с невероятным количеством строчек непроведенных платежей с ошибкой Could not load any order for your notification 521 - ( "Не удалось загрузить заказ для вашего уведомления 521** " )

** - в данном случае ошибка возникала из-за простого "тупого" копирования функции writeToLog из одной функции в другую без изменения параметров.

Прочитать записи функции writeToLog  в разделе function onPaymentNotification(&$statuses)  у Вас не получиться, пока Вы не организуете (через техподдержку или самостоятельно) передачу данных от сайта к платежному шлюзу и обратно, т.е. не наладите получение уведомлений об оплате. 

СЕКРЕТ №2 (уведомления)

 Разработчики модулей оплаты  неохотно берутся за  адаптацию платежного плагина  HIKASHOP_JOOMLA  для оплаты через СБЕРБАНК - в отличие от других платформ интернет-магазинов, таких как JOOMSHOPPING_JOOMLA , VIRTUEMART_JOOMLA , где все манипуляции с запросами: отправка и получение через php://input осуществляются только в  основном (единственном) файле ,   в Hikashop  при реализации скриптов php задействованы файла: основной файл php и end-файл php  (файл  может отвечать за отправку данных, внешний вид и ещё за кое-что),  при этом всё управление (отправка и получение дополнительных запросов), как правило,   осуществляется в основном файле - в этом вся и  заморочка.

Если взять стандартную ситуацию: когда корректные данные для запроса сформированы в основном файле php с помощью функций (например, $this->requestData = $this->getRequestData($order);) и проведена отправка запроса register.do методом post на  тестовый шлюз сайта Сбербанка    https://3dsec.sberbank.ru/payment/rest/  через форму end-файл php мы получаем  json-файл на стороне шлюза

{"orderId":"6d47c3d5-f262-7e25-8168-cae15e3b7f98",   "formUrl":"Страница оплаты - URL сбербанка - тестовый режим"}

На этом Вы потеряете управление - т.к. получение уведомлений от Сбербанка не осуществляется (из end-файла вызвать функцию через $this-> становиться невозможно - поэтому требуется дополнительный php скрипт для выхода из этой патовой ситуации .

Но все же реализовать оплату через платежный шлюз Сбербанка без уведомлений  по методу REST для новичка-разработчика скриптов php дело не такое уж сложное - достаточно подготовить данные для запроса (через $requestData) и использовать стандартную функцию запроса  - $response = $this->gateway('register.do', $requestData);

define('GATEWAY_URL', 'https://3dsec.sberbank.ru/payment/rest/');
$method = 'register.do';

function gateway($method, $data) {
        $curl = curl_init();                      // Инициализируем запрос
        curl_setopt_array($curl, array(
            CURLOPT_URL => GATEWAY_URL.$method,   // Полный адрес метода
            CURLOPT_RETURNTRANSFER => true,       // Возвращать ответ
            CURLOPT_POST => true, // Метод POST
            CURLOPT_POSTFIELDS => http_build_query($data) // Данные в запросе
        ));
        $response = curl_exec($curl);             // Выполняем запрос
         
        $response = json_decode($response, true); // Декодируем из JSON в массив
        curl_close($curl);                        // Закрываем соединение
        return $response;                         // Возвращаем ответ
    }

 То есть достаточно выполнить в   public function onAfterOrderConfirm(&$order,&$methods,$method_id)  3-4 процедуры:

 - получить$requestData = array ( со всеми обязательными паметрами )

- обеспечить кодировку json (приведена часть кода): $requestData['orderBundle'] = json_encode($order_bundle, JSON_UNESCAPED_UNICODE);

- осуществить правильный запрос по методу Сбербанка -( register.do   и др. стандартные методы) - с помощью созданной функции  public function gateway($method, $data) - через запись $this->gateway('register.do', $requestData);

- правильно использовать полученные параметры ($requestData и $response) для нашего php скрипта.

Личный кабинет Сбербанка, доступ к которому осуществляется на этапе создания и тестирования скрипта оплаты, в отличие от других платежных систем не предоставляет почти никакой информации по организации уведомлений о платежах, т.е. не предоставляет возможности создания страницы успешной оплаты, страницы неудачной транзакции, нет там и протокола HTTP по уведомлениям с указанием пути notification.php, как это организовано, например в TINKOFF (тинькофф-банк) или RFICB (рфи-банк) - есть лишь маленькая кнопка помощи - "написать письмо в техподдержку" - где можно осуществить в том числе запрос о подключении вкладки уведомлений для тестового режима.

Помощи от программистов Сбербанка на этапе разработки плагина  не будет, будет лишь ссылка все на тот же сайт https://developer.sberbank.ru - "вся информация  для разработки плагина Вам предоставлена"

Нигде не упоминается  и об notify_url - его просто нет априори в  API Сбербанка , поэтому все уведомления от платежного шлюза приходят  обратно на return_url, и Вам надо переадресовать их самостоятельно в скрипте основного файла (пока разбираюсь..) на notify_url

 СЕКРЕТ №3 (ответ приходит - плагин не реагирует)

Формат общения  между нашим платежным плагином  и платежным шлюзом стандартный - через формат JSON.

Обработка файлов из  json - формата банка в  php-формат   (по методу REST осуществляется через библиотеку  cURL) необходима для передачи  покупателю ссылки на страницу оплаты Сбербанка  и  уникального идентификационного номера платежа  ,

{"orderId":"6d47c3d5-f262-7e25-8168-cae15e3b7f98",   "formUrl":"Страница оплаты - URL сбербанка - тестовый режим"}

Конечно, "настоящие" php-программисты с своим уровнем знаний просто посмеются над моими рассуждениями - но наша задача : "малой кровью" обеспечить работоспособность плагина. Поэтому продолжаем..

Есть несколько вариантов создания запросов
  1.  public function gateway($method, $data) (p.s. - рассмотрена выше).
  2. создание какой-нибудь самописанной функции php.
  3. использование опубликованных на github-e  библиотек через composer (автоматическая загрузка всех необходимых файлов в папку  vender  в указанном каталоге на вашем сайте) - voronkovich/sberbank-acquiring-client  или guzzle/guzzlehttp.

Попытки пробить "дыру" в стене непонимания алгоритма взаимодействия своего  хостинга  BEGET  и плагина  HIKASHOP - на хостинге заблокированы суперглобальные переменные типа $_POST - натолкнули на использование в проекте "СОЗДАЕМ ПЛАГИН HIKASHOP " инструмента для управления зависимостями в PHP COMPOSER (а именно использование уже готовой библиотеки voronkovich/sberbank-acquiring-client в создаваемом (почти готовом) плагине plg_hikashoppayment_sberbank)

 СЕКРЕТ №4 (использование composer упрощает работу в разы)

Изучение темы, что такое пакетный менеджер "COMPOSER" заняло у меня  несколько дней -  а установка требуемого пакета (максимальной версии) через composer на свой сайт  никак не давалась. Оказалось хостинг beget имеет свои особенности (для  различных хостингов может иметь различный код для инсталяции), На самом хостинг beget composer уже установлен по умолчанию и имеет по умолчанию версию PHP 5.6.40.

ВАЖНО !!!       Версия PHP, которая задается в разделе САЙТЫ (ПАНЕЛЬ УПРАВЛЕНИЯ) не влияет на консольную версию PHP (ПАНЕЛЬ TEPMINAL) - её надо задать вручную 

Как оказалось для beget необходимо сначала перейти в нужную папку [локальная установка пакета] ---> (cd ваш сайт/public_html/....), а затем через выбранную вами версию composer (например, composer-php8.0 require .......) установить нужный пакет.

Простая запись composer require dompdf/dompdf предложит установить только минимальную стабильную версию dompdf.

Но на тот момент я этого не знал и  инсталяция скачанного пакета  посредством composer на выходе всех процедур дали незапланированный результат (установку минимальной версии пакета v0.8.3 для минимальной версии PHP - 5.4):

РЕЗУЛЬТАТ:

СОЗДАНИЕ в папке плагина кроме уже помещенного туда (созданного) composer.json  дополнительных  каталогов и файлов : папку vendor (файл autoload.php) и composer.lock (для страховки при изменении зависимых библиотек composer). По умолчанию а папку vendor будут установлены все зависимые библиотеки composer-a, на которых построен проект dompdf/dompdf )

Перед начинающим изучать PHP сразу возникают множество преград по воплощению этой идеи:

  • как установить composer  (глобально - в корневую папку хостинга или локально  - в специально созданную папку composer_setup  внутри одного из сайтов на хостинге -->  замечу, это не дало преимуществ по задействованию PHP более высокого уровня - "7.3" )
  • как установить требуемую библиотеку composer (в нашем случаеdompdf/dompdf ) в конкретную папку на сайте хостинга : путь для примера к папке вашего сайта на хостинге beget будет таким  cd gantry21/public_html/plugins/hikashoppayment/alipay , где alipay - экспериментальная папка для примера создаваемого плагина, куда мы подгружаем библиотеку, а gantry21 - корневая папка хостинга
  • cd gantry21/public_html/plugins/hikashoppayment/example
  • cd xn--21-6kctplhjfk5bi5a.xn--p1ai/public_html/plugins/hikashoppayment/example

 ПЕРВОНАЧАЛЬНАЯ УСТАНОВКА:

Читая статьи в интернете, заметил что все разработчики php , использующие composer применяют термин "установить в свой проект", но что это значит по отношению к HIKASHOP и как это сделать КОНКРЕТНО нигде не упоминается - вот и пришлось методом проб и ошибок понять, что

  1. composer устанавливается на хостинг  только при помощи  панели terminal (на хостинге beget это кнопка-вкладка слева на экране при включенном SSH )  
  2. устанавливать composer лучше глобально (это обеспечивает минимальный  код в панели terminal  )
  3. все  опубликованные в интернете библиотеки composer можно найти на https://github.com или на репозитарии  https://packagist.org
  4. для использования на своем сайте уже созданной библиотеки достаточно разместить в вашей папке плагина hikashop файл composer.json (это может быть созданный вами или скопированный с готовой библиотеки код в формате json с обязательным аттрибутом require )
  5. так как  инсталяция библиотек осуществляется только через панель terminal хостинга, в  панели terminal нужно использовать всего 2 команды : cd (для перехода в конкретную папку) и composer install (для инсталяции папки зависимых библиотек vendor и файла autoload.php для подключения всех задействованных классов)
  6. результат в нужной папке дополнительно появится каталог vendor и файл composer.lock
  7. внутри папки vendor появится файл autoload.php ,  нам необходимо его подключить в основном файле вашего плагина 
  8. подключение осуществляется через запись  require_once __DIR__ . '/vendor/autoload.php';
  9. Если Вы не знаете какие пакеты установить, чтобы не было конфликтов -  лучше выполнить стандартную процедуры : сначала перейти в terminal по указанному пути в папку sberbank через cd gantry21/public_html/plugins/hikashoppayment/sberbank (при этом папка sberbank создана заранее), а затем в панели terminal хостинга выполнить команду - composer require voronkovich/sberbank-acquiring-client. На выходе имеем:
  10. И последнее, без панели terminal сам  composer не установить.
  11. Чтобы использовать все библиотеки composer'a в самом начале основного файла php надо создать целый буклет подключений (какие библиотеки запросов использовать - решать Вам) - рекомендую для начала использовать Voronkovich\SberbankAcquiring  - есть все заявленные Сбербанком методы запросов. ПЛЮС - минимум дополнительного кода. МИНУС - нет класса "интерфейса" (php:\\input) для  получения уведомлений от шлюза 
defined('_JEXEC') or die('Restricted access');

include_once "vendor/autoload.php";

use Voronkovich\SberbankAcquiring\Client;
use Voronkovich\SberbankAcquiring\Currency;
use Voronkovich\SberbankAcquiring\OrderStatus;
use Voronkovich\SberbankAcquiring\HttpClient\HttpClientInterface;
use Voronkovich\SberbankAcquiring\HttpClient\GuzzleAdapter;
use Voronkovich\SberbankAcquiring\HttpClient\CurlClient;
use Voronkovich\SberbankAcquiring\Exception\ActionException;
use Voronkovich\SberbankAcquiring\Exception\BadResponseException;
use Voronkovich\SberbankAcquiring\Exception\ResponseParsingException;
use Voronkovich\SberbankAcquiring\Exception\NetworkException;
use Voronkovich\SberbankAcquiring\Exception\SberbankAcquiringException;

use GuzzleHttp\Psr7\AppendStream;
use GuzzleHttp\Psr7\BufferStream;
use GuzzleHttp\Psr7\CachingStream;
use GuzzleHttp\Psr7\DroppingStream;
use GuzzleHttp\Psr7\FnStream;
use GuzzleHttp\Psr7\InflateStream;
use GuzzleHttp\Psr7\LazyOpenStream;
use GuzzleHttp\Psr7\LimitStream;
use GuzzleHttp\Psr7\MessageTrait;
use GuzzleHttp\Psr7\MultipartStream;
use GuzzleHttp\Psr7\NoSeekStream;
use GuzzleHttp\Psr7\PumpStream;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\Rfc7230;
use GuzzleHttp\Psr7\ServerRequest;
use GuzzleHttp\Psr7\Stream;
use GuzzleHttp\Psr7\StreamDecoratorTrait;
use GuzzleHttp\Psr7\StreamWrapper;
use GuzzleHttp\Psr7\UploadedFile;
use GuzzleHttp\Psr7\Uri;
use GuzzleHttp\Psr7\UriNormalizer;
use GuzzleHttp\Psr7\UriResolver;



use GuzzleHttp\Promise\AggregateException;
use GuzzleHttp\Promise\CancellationException;
use GuzzleHttp\Promise\Coroutine;
use GuzzleHttp\Promise\EachPromise;
use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Promise\PromisorInterface;
use GuzzleHttp\Promise\RejectedPromise;
use GuzzleHttp\Promise\RejectionPromise;
use GuzzleHttp\Promise\TaskQueue;
use GuzzleHttp\Promise\TaskQueueInterface;


use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UploadedFileInterface;
use Psr\Http\Message\UriInterface;

use GuzzleHttp\Client as Guzzle;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\MessageFormatter;
use GuzzleHttp\Middleware;
use GuzzleHttp\Pool;
use GuzzleHttp\PrepaveBodyMiddleware;
use GuzzleHttp\RedirectMiddleware;
use GuzzleHttp\RequestOptions;
use GuzzleHttp\RetryMiddleware;
use GuzzleHttp\TransferStats;
use GuzzleHttp\UriTemplate;
use GuzzleHttp\Utils;



use GuzzleHttp\Cookie; 
use GuzzleHttp\Cookie\CookieJarInrerface; 
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Cookie\FileCookieJar; 
use GuzzleHttp\Cookie\SessionCookieJar; 
use GuzzleHttp\Cookie\SetCookie; 
use GuzzleHttp\Exception;
//use GuzzleHttp\Exception\BadResponseException;// дает ошибку 500 - такой файл есть у voronkovich!!!
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\InvalidArgumentException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\SeekException;
use GuzzleHttp\Exception\ServerException;
use GuzzleHttp\Exception\TooManyRedirectsException;
use GuzzleHttp\Exception\TransferException;

use GuzzleHttp\Handler; 
use GuzzleHttp\Handler\CurlFactory; 
use GuzzleHttp\Handler\CurlFactoryInterface; 
use GuzzleHttp\Handler\CurlHandler; 
use GuzzleHttp\Handler\CurlMultiHandler; 
use GuzzleHttp\Handler\EasyHandle;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\Handler\Proxy;
use GuzzleHttp\Handler\streeamHandler;

 Управлять кодом стало значительно "легче" - теперь можно преобразовывать любые зависимости:

echo print_r('new GuzzleHttp\Client()',true)  ;
$clientGuzzle = new GuzzleHttp\Client();
$options = [
            'auth' => [$this->payment_params->merchant_login, $this->payment_params->merchant_password],
            'form_params' => $this->requestData,
           ];
       
$response = $clientGuzzle->request('POST', 'https://3dsec.sberbank.ru/payment/rest/register.do', $options);

$arr = $response->getBody();
echo $arr;
echo "json_decode(response->getBody())"; $FormUrl = json_decode($arr,true); 
echo print_r($FormUrl,true);
echo print_r($FormUrl['orderId'],true);
echo print_r($FormUrl['formUrl'],true);
echo "теперь можно выполнить - header('Location: ' . FormUrl['formUrl']) - и перейти на сайт оплаты Сбербанка "; 
echo '  ';

 

Но настоящей "загадкой" в HIKASHOP является функция public function onPaymentNotification(&$statuses), ней мы будем разбираться отдельно и здесь не всё так просто.

статья в редактировании ...