2,551

(4 ответов, оставленных в Сторонние модули, темы оформления для ReadyScript)

Неплохо)

Александр пишет:

    У Вас включено отображение ошибок уберите его и будет 404. И второе, а как собственно он у Вас оказался в корзине если вы его удалили?

Товар был занесен в корзину покупателем, потом в 1С товар был удален. Такая ситуация не редкая. Показывать 404, в данном случае, не правильно. Нужно как-то сообщить покупателю, что заказанный товар больше не поставляется.

1Ска никаких данных о том удалён товар или нет не присылает, по крайней мере в последних версиях формата я такого не видел, в начальных бывало.  Ваш вариант, это сделать так, чтобы товар в выгрузку у Вас не попадал. Задав нужные значения фильтра в 1С. У Вас есть настройки обмена данными (Веб-сайт->Настройка модулей->Обмен данными->Вкладка каталог товаров). Здесь Вы можете настроить, что делать с товарами не присутствующими в выгрузке. И поставить либо удалить, либо скрыть такие товары. Если произвести полную выгрузку(именно полную), то такие товары у Вас либо удаляться, либо в публичной части будут не видны.

У Вас включено отображение ошибок уберите его и будет 404. И второе, а как собственно он у Вас оказался в корзине если вы его удалили?

Да, всё по аналогии.

Всё просто. Судя по всему у Вас молодёжная тема оформления и это шаблон со списком заказов. Если да, то тогда смотрим в файл:

/templates/fashion ну или Ваша тема/moduleview/shop/myorders.tpl

Ищем в коде строку:

{if $order->getPayment()->hasDocs()}
     {assign var=type_object value=$order->getPayment()->getTypeObject()}
     {foreach $type_object->getDocsName() as $key=>$doc}
     <a href="{$type_object->getDocUrl($key)}" target="_blank">{$doc.title}</a><br>
     {/foreach}            
{/if}

Здесь перебираются документы, которые служат для вывода на печать.

Поэтому ставим проверку на имя документа и вставляем свой код:

{foreach $type_object->getDocsName() as $key=>$doc}
     <pre>
      {var_dump($doc)}
     </pre>
     {if $doc.title!="квитанция"}
     <a href="{$type_object->getDocUrl($key)}" target="_blank">{$doc.title}</a><br>
     {else}
          Сюда вставляем свой код
     {/if}
{/foreach}    

Можно, это же простой шаблон, но вопрос в другом. А вы как PDF документ делать будете? Сами сканировать?

Получилось?

Скорее всего Вам подойдёт вызов метода static_call. С ним можно ознакомится в документации.
Он позволит Вам вызвать свою функцию(public static) из своего класса и вернуть результат.

Например у нас есть  класс CustomApiв вашем модуле /modules/custom/model/customapi.inc.php. В нём Вы запишите свой метод, который вернёт все объекты заказов принадлежащих пользователю:

namespace Custom\Model;

class CustomApi {
    
    public static function getMyOrders(){
        $list = array();
        //Смотрим, а авторизованы ли мы, чтобы получить текущего пользователя
        if (\RS\Application\Auth::isAuthorize()){
           //Получим ORM объект текущего пользователя
            $user = \RS\Application\Auth::getCurrentUser();
            
            //Далее делаем запрос к БД, чтобы получить заказы пользователя
            $list = \RS\Orm\Request::make()
                    ->from(new \Shop\Model\Orm\Order()) //Обращение к таблице заказа через объект заказа
                    ->where(array( //Условие
                        'user_id' => $user['id'], //id пользователя
                    ))
                    ->where('status < 4') //Нужные нам статусы заказа < 4, т.к. статусы заказов должны быть менее выполнен и закрыт (4). Посмотреть статусы можно в Магазин -> Статусы заказов
                    ->objects(); //Выполнить запрос и получить в виде объектов заказы
        }
        return $list; 
        
    }
}

А в шаблоне просто делаем следующий вызов:

{static_call var=list callback=['\Custom\Model\CustomApi','getMyOrders']}
<pre>
{var_dump($list)}
</pre>

Пробуйте

2,559

(3 ответов, оставленных в Вопросы по работе с системой)

Исправим, напишите пожалуйтса в support@readyscript.ru

2,560

(8 ответов, оставленных в Вопросы по работе с системой)

Ну вообще-то и так можно. Но есть способ лучше, который ничего не трогает.
Все печатные формы находятся по этому пути:

/shop/model/printform/

И если заглянуть в один из классов, то в строке с функцией getTemplate() можно увидеть путь к шаблону, который и формирует документы. Например рассмотрим deliverynote.inc.php:

function getTemplate()
    {
        return '%shop%/printform/deliverynote.tpl';
    }

Если взглянуть на документацию по шаблонам, то эта запись означает, что шаблон будет искаться в папке модуля shop:

/modules/shop/view/printform/deliverynote.tpl

, либо смотрит есть ли шаблон с тем же названием здесь:

/templates/ВАША ТЕМА/moduleview/shop/printform/deliverynote.tpl

то тогда применяет его.

Значит, если мы хотим придать свою форму, то тупо копируем шаблон:

/modules/shop/view/printform/deliverynote.tpl

в

/templates/ВАША ТЕМА/moduleview/shop/printform/deliverynote.tpl

И тогда можем писать в него всё, что угодно.

Пробуйте!

2,561

(6 ответов, оставленных в Вопросы по работе с системой)

Спасибо!
Исправил. Выйдет в ближайшем обновлении исправление.
Дело вот в чём:
Данная ошибка происходит потому что, событие openInDialog (открытие в диалоговом окне страницы с помощью класса inDialog) срабатывает только на тег <a>. А в многомерных комплектациях эта кнопка представлена в виде тега <span>
Чтобы переназначить назначение события на открытие в диалоговом окне нужно вызывать событие 'new-content'. В обновлении в файле

/modules/catalog/view/js/jquery.filter.js должно вызываться это событие с помощью

.trigger('new-content');

Те кто модифицировал тему самостоятельно или не хочет ждать или клонировал тему нужно сделать следующее:
в файле

/templates/ВАША ТЕМА/resource/js/theme.js

почти в самом конце нужно заменить:

$('a.inDialog', e.target).openInDialog();

на

$('.inDialog', e.target).openInDialog();

Это нужно сделать обязательно для собственных тем оформления.

Также для тех, кому нужно срочно чтобы всё работало не дожидаясь обновления, то идём в

/modules/catalog/view/js/jquery.filter.js

и меняем строку:

$(data.options.targetList).html(response.html);

на

$(data.options.targetList).html(response.html).trigger('new-content');

Пробуйте

2,562

(5 ответов, оставленных в Вопросы по работе с системой)

Здесь имеет место быть особенность создания заказа через админ. панель.
Так как в данном случае сперва создается пустой заказ, и лишь потом добавляются товары. А списание происходит именно при создании заказа.

У нас в планах есть задача по изменению алгоритма создания заказа, поэтому решение будет в одной из следующих версий.

А посмотреть какой итоговый запрос у Вас получается можно так:

var_dump(\RS\Orm\Request::make()
    ->from(new Orm\Product, 'A')
    ->join(new Orm\Second, 'A.id = B.product_id', 'B')
    ->where('A.num > 0')
    ->toSql());

или ещё проще:

echo \RS\Orm\Request::make()
    ->from(new Orm\Product, 'A')
    ->join(new Orm\Second, 'A.id = B.product_id', 'B')
    ->where('A.num > 0');

А вообще лучше всего пользоваться современными редакторами для подсветки подсказок. Я например использую phpED 9. И тогда можно будет получить подсказки с описанием методов легко.

2,564

(3 ответов, оставленных в Вопросы по работе с системой)

Можно будет, я думаю. Напишите пожелание, а там после выхода маркетплэйса, может и сделаем.

2,565

(4 ответов, оставленных в Вопросы по работе с системой)

Спасибо. Но с пакетным включением товара, так и не разобрался: выбирал массово товары, а опцию видимости в каталоге, так и не нашел. По указанной ссылке, тоже нет.

Когда выделите нажимайте справа внизу редактировать. И потом в появившемся окне поставьте галочку напротив поля "Показывать товар".
После чего нажимаем сохранить.

В общем, алгоритм такой:
1. Смотрим статью про создание тем оформления и разбираемся.
2. Клонируем тему fashion и переделываем название и файл theme.xml под себя. (Если не сделать так, при следующем обновлении правки затрутся)
3. Переключаемся на новую тему.
4. Файл шаблона вывода списка товаров в категории находится в
/templates/ВАША ТЕМА/moduleview/catalog/product_list.tpl
5. Переносим строки с {$category.description} куда нам нужно.

Всё.

2,567

(3 ответов, оставленных в Вопросы по работе с системой)

Добрый день
Ну это скорее частный для Вас случай. Поэтому лучше это реализовать отдельным модулем для Вас.
Вы можете почитать вот эту статью - о создании блок контроллера. И создать свой собственный блок контроллер.
За рекомендуемые товары отвечает /modules/catalog/controller/block/recommended.inc.php
Вы можете из него себе переделать вывод, чтобы он выполнял нужные Вам функции.

Есть ли возможность прикреплять Рекомендуемые целой категорией?

Пока нет такого функционала.
Такое вообще возможно, но это надо программировать, отдельным полем для сохранения ещё и категорий.
Поэтому Вы можете либо самостоятельно запрограммировать, либо заказать другим разработчикам, либо нам такой функционал.

2,568

(10 ответов, оставленных в Вопросы по работе с системой)

Исправил ошибку клонирования. Выйдет в ближайшем обновлении.

2,569

(6 ответов, оставленных в Вопросы по работе с системой)

Если ссылку сделать вот так:

<a href="#" class="inDialog">ASDAF</a>

то всплывает текущая карточка товара.

Естественно. Это урл сам на себя просто с пустым якарем.


<a href="/templates/luchski/test.html" class="inDialog">TEST</a></p>

Дело вот в чём, inDialog ожидает json, который содержит поле html. Его выдают все страницы системы, если к ним обращаться через AJAX. Если вы хотите, открыть сторонний файл html. То тогда вот так:

<a href="/templates/default/test.html" onclick="$(this).colorbox();">Открыть</a>

И будет Вам счастье. smile

2,570

(10 ответов, оставленных в Вопросы по работе с системой)

да, последнее обновление по лицензии

Например, версия "Каталога товаров" - 2.0.0.121

Ольга и Сергей. Напишите на support@readyscript.ru доступы в админку, FTP и описание процесса тестирования и мы у Вас проверим.

Всем привет.
Довольно часто, приходится слышать от украинских покупателей, что хотелось бы кроме Robokassa ещё видеть у себя в способах оплаты Interkass-у. Недавно мы это реализовали и сделали отдельным модулем. Но в большинстве случаев люди немножко не понимают, как сделать им тоже самое для своего сайта, если заказчик им заказал интеграцию с каким-либо сервисом. Ну вот сегодня настал тот день, когда я раскрою все тайны и всё станет я думаю яснее.

Тем кому лень всё изучать даю прямую ссылку на готовый модуль smile



Скачать готовый модуль интеграции интеркассы для ReadyScript - распаковать в папку /modules/. В Веб-сайт->Настройка модулей сбросить кэш, перезагрузить страницу и установить модуль.



Задача сделать свой собственный дополнительный модуль, который позволит проводить платежи через Interkassa.
Вот как это можно сделать?
Смотрим документацию здесь по этому сервису. Всё довольно просто.

Предварительно для разработки нужно будет включить ошибки. Смотрим сюда.

Шаг 1. Сделаем свой собственный модуль.

В папке modules создаём папку с названием Вашего модуля(interkassa в нашем случае) и в ней создаём папку config
В этой папке создаём файл file.inc.php с данными описывающими модуль и пишем следующее содержимое:

<?php
namespace Interkassa\Config;
use \RS\Orm\Type;

/**
* Конфигурационный файл модуля
*/
class File extends \RS\Orm\ConfigObject
{ 
    
    /**
    * Возвращает значения свойств модуля по-умолчанию
    * 
    * @return array
    */
    public static function getDefaultValues()
    {
        return array(
            'name' => t('Интеркасса'), //Название нашего модуля
            'description' => t('Платёжная система - Интеркасса'), //Описание модуля
            'version' => '1.0.0.0', //Версия вашего модуля
            'author' => 'Сведения об авторе', //Сведения об авторе
        );
    }     
    
}

После чего заходим в админ панель в  "Веб-сайт" -> "Настройка модулей" и на этой странице сбрасываем кэш.
Появится наш модуль с названием "Интеркасса". Заходим в наш модуль. И нажимаем "установить модуль".
Всё модуль в системе зарегистрирован.


Шаг 2. Создание файла с хуком для добавления своего типа оплаты

В системе существует так называемая система хуков, которая позволяет встраиваться в различные места системы и выполнять свои функции. Документация по хукам находится здесь. Всё основано на том, что нужно указать в файле handlers свой нужный символьный идентификатор хука и потом создать public static function c таким же названием, только вырезав из него символы "." (точка) и "-" тире. Идём на страницу этой документации и спускаемся в низ до таблицы. Для нашего случая нам нужен хук payment.gettypes.
Т.е. нам нужно пропиcать bind этого алиаса хука и создать функцию с таким же названием вырезав лишнее.

Итак алиас будет выглядеть так:

function init()
    {
        $this
            ->bind('payment.gettypes');
    }

и функция соотвественно:

/**
    * Добавляем новый вид оплаты - Интеркасса
    * 
    * @param array $list - массив уже существующих типов оплаты
    * @return array
    */
    public static function paymentGetTypes($list)

Почему $list и как узнать что передаётся в хук? Смотрим внимательно в документацию по хукам в колонку "Тип параметра" напротив строки с "payment.gettypes".

В функцию paymentGetTypes поступает массив с типами оплаты со всей системы, а мы его просто дополним, добавив новый элемент в массив. Элементом массива будет класс который мы создадим и именно он будет обрабатывать все запросы от Interkassa.

Итак cоздаём файл handlers.inc.php в папке config. Пишем в него следующее содержимое:

<?php
namespace Interkassa\Config;
use \RS\Orm\Type as OrmType;

/**
* Класс предназначен для объявления событий, которые будет прослушивать данный модуль и обработчиков этих событий.
*/
class Handlers extends \RS\Event\HandlerAbstract
{
    function init()
    {
        $this
            ->bind('payment.gettypes');
    }
    
    /**
    * Добавляем новый вид оплаты - Интеркасса
    * 
    * @param array $list - массив уже существующих типов оплаты, который собирается со всей системы
    * @return array
    */
    public static function paymentGetTypes($list)
    {
        $list[] = new \Interkassa\Model\PaymentType\Interkassa(); //Интеркасса. Класс который мы создадим и будет обрабатывать все запросы к интеркассе.   
        return $list;
    }
}

Шаг 3. Создаём класс для интеркассы, который хранит все сведения.

Все классы модулей оплат вшитые в дистрибутив находятся в /modules/shop/model/paymenttype/.
Проще всего создавать свой класс оплаты на основе уже имеющихся в этой папке. Например для interkassa я переделывал из robokassa, т.к. алгоритм примерно схож.

Итак создаём файл в папке с нашим модулем по пути:
/modules/interkassa/model/paymenttype/interkassa.inc.php

Имя класса будет Interkassa, которая будет наследником абстрактного класса оплат \Shop\Model\PaymentType\AbstractType

<?php
namespace Interkassa\Model\PaymentType;
use \RS\Orm\Type;
use \Shop\Model\Orm\Transaction;

/**
* Способ оплаты - Interkassa
*/
class Interkassa extends \Shop\Model\PaymentType\AbstractType

Пропишем в соответствии с документацией interkassa наши константы

const
        API_URL     = "https://sci.interkassa.com/", //URL Api для взаимодействия
        PAYWAYS_URL = "https://api.interkassa.com/v1/paysystem-input-payway", //URL Api для получения полниго списка типов оплат
        IP_DIAPOZON = "85.10.225."; //Диапозон IP адресов интеркассы с которых должны приходить запросы

Разберём следующие стандартные функции создающего нами класса:

Функция getTitle() должна возвращать имя Вашего способа оплаты в Вашем модуле.

/**
    * Возвращает название расчетного модуля (типа доставки)
    * 
    * @return string
    */
    function getTitle()
    {
        return t('Интеркасса');
    }

Функция getDescription() должна возвращать описание вашего типа оплаты

/**
    * Возвращает описание типа оплаты. Возможен HTML
    * 
    * @return string
    */
    function getDescription()
    {
        return t('Оплата через агрегатор платежей "Интеркасса"');
    }

Функция getShortName() должна возвращать короткое имя (Именно на латиницей!) Вашего типа оплаты. Это нужно для того чтобы переключатся между типами оплаты и именно это название пойдёт как идентификатор Вашего типа оплаты внутри системы. Должно быть уникально по сравнению с теми что уже есть в системе.

/**
* Возвращает идентификатор данного типа оплаты. (только англ. буквы)
* 
* @return string
*/
function getShortName()
{
     return 'interkassa';
}

Функция isPostQuery() должна возвращать булевое значение. Если true, то пользователь будет перенаправлен на систему оплаты POST запросом. Если эту функцию не указывать, то пользователь будет переходить GET запросом на страницу оплаты.
Зачем это нужно? Дело вот в чем.
Когда пользователь совершает оплату и переходит на последнюю страницу (Завершение заказа), то ему предоставляется кнопка, которая либо возвращает пользователя на главную страницу либо даёт сформированную ссылку на систему оплаты. Эта функция отвечает как раз каким способом(GET или POST запросом) пользователь перейдёт на сайт системы оплаты.
В нашем случаем нам нужно POST поэтому:

/**
* Отправка данных с помощью POST?
* 
*/
function isPostQuery()
{
      return true;
}

Функция getFormObject() должна возвращать дополнительную форму для способа оплаты. Дело в том, что в способе оплаты по умолчанию уже есть набор постоянных полей. Но в соответствии с документациями часто требуется указать дополнительные параметры которые должен заполнить. Например Api ключ и Api пароль как в нашем случае. Поэтому при выборе класса оплаты будет ajax запросом подгружена форма с полями, которые мы укажем.
А также бывает часто нужно вывести дополнительную информацию для пользователя, чтобы он её вставил в настройках. Например для нашего случая в настройках интеркассы нужно ввести url которые будут обрабатывать приходящие запросы(будет рассмотрено ниже).
В этой функции реализуется возврат массива ORM объектов полей. Подробнее об этих полях можно почитать в документации.

Итак на основе документации по интеркассе получим следующее:

    /**
    * Возвращает ORM объект для генерации формы или null
    * 
    * @return \RS\Orm\FormObject | null
    */
    function getFormObject()
    {
        $properties = new \RS\Orm\PropertyIterator(array(
            'ik_co_id' => new Type\String(array(
                'maxLength' => 255,
                'description' => t('Checkout ID - индетификатор кассы'),
                
            )),
            'secret_key' => new Type\String(array(
                'description' => t('Секретный ключ'),
                'hint' => t('Указан на странице Вашей кассы'),
                'template' => '%interkassa%/form/payment/interkassa/secret_key.tpl'
            )),
            'test_key' => new Type\String(array(
                'description' => t('Тестовый ключ'),
                'hint' => t('Указан на странице Вашей кассы')
            )),
            'language' => new Type\String(array(
                'maxLength' => 5,
                'description' => t('Язык интерфейса'),
                'listFromArray' => array(array(
                    0    => t('Определяется Интеркассой'),
                    'ru' => t('Русский'),
                    'ua' => t('Украинский'),
                    'en' => t('Английский'),
                ))
            )),
            'ik_pw_via' => new Type\String(array(
                'maxLength' => 255,
                'description' => t('Тип оплаты:'),
                'default' => 0,
                'list' => array(array($this,'getPayways')),
            )),
            '__help__' => new Type\Mixed(array(
                'description' => t(''),
                'visible' => true,  
                'template' => '%interkassa%/form/payment/interkassa/help.tpl'
            )), 
        ));
        
        return new \RS\Orm\FormObject($properties);
    }

Поле __help__ как раз служит для получения отрендеренного шаблона с данными для вставки в настройки системы оплаты (Шаблон в ключе 'template').
%interkassa% - означает, что путь для поиска шаблона будет строится из папки с шаблонами модуля interkassa, а именно - /modules/interkassa/view/

Также приведём код в файлах шаблонов которые нам понадобятся для полей где указан ключ 'template'.

В этом шаблоне будут указаны 3 ссылки для вставки в настройки интеркассы. Url надо формировать в соотвествии с маршрутами в системе для оплаты.
Маршруты для этих урлов можно посмотреть в /modules/shop/config/handlers.inc.php в методе getRoutes.

В шаблоне сгенерировать урл можно конструкцией

{$router->getUrl('shop-front-onlinepay', [Act=>result, PaymentType=>$payment_type->getShortName()], true)}
//в итоге будет
//http://ВАШДОМЕН/onlinepay/interkassa/result/
//т.е. http://ВАШДОМЕН/onlinepay/Ваш класс/метод/

/modules/interkassa/view/form/payment/interkassa/help.tpl:

<h3>Настройка аккаунта Интеркасса</h3>


<p>Укажите алгоритм подписи у Вашей кассы - <b>MD5</b></p>

<p>Укажите эти URL в настройках Вашей кассы:</p>  

<b>URL ожидания проведения платежа: </b><br>
<a target="_blank" href="{$router->getUrl('shop-front-onlinepay', [Act=>result, PaymentType=>$payment_type->getShortName()], true)}">
    {$router->getUrl('shop-front-onlinepay', [Act=>result, PaymentType=>$payment_type->getShortName()], true)}
</a>

<br><br>

<b>URL взаимодействия платежа: </b><br>
<a target="_blank" href="{$router->getUrl('shop-front-onlinepay', [Act=>result, PaymentType=>$payment_type->getShortName()], true)}">
    {$router->getUrl('shop-front-onlinepay', [Act=>result, PaymentType=>$payment_type->getShortName()], true)}
</a>

<br><br>

<b>URL успешной оплаты: </b><br>
<a target="_blank" href="{$router->getUrl('shop-front-onlinepay', [Act=>success, PaymentType=>$payment_type->getShortName()], true)}">
    {$router->getUrl('shop-front-onlinepay', [Act=>success, PaymentType=>$payment_type->getShortName()], true)}
</a>

<br><br>

<b>URL неуспешной оплаты: </b><br>
<a target="_blank" href="{$router->getUrl('shop-front-onlinepay', [Act=>fail, PaymentType=>$payment_type->getShortName()], true)}">
    {$router->getUrl('shop-front-onlinepay', [Act=>fail, PaymentType=>$payment_type->getShortName()], true)}
</a>

<p>Укажите методы для всех URL - <b>POST</b></p>


/modules/interkassa/view/form/payment/interkassa/secret_key.tpl:

Это шаблон интересен тем, что здесь используется POST AJAX запрос в зависимости значения поля с секретным ключом и возвращаемый результат вставляется в соответствующие поле(выпадающий список).
Зачем? Дело в том, что в соответсвии с документацией пользователь при построеннии запроса на оплату может указывать канал оплаты, либо не указывать его и тогда ему будет доступен выбоор всех каналов оплат в интеркассе.

Для построения такого запроса нам нужно сформированить запрос на тотже url где мы находимся в админке но с параметром ?do=userAct.

Получить такой url можно так:

{$router->getAdminUrl('userAct')}

Также надо передать следующие параметры:
userAct - Метод который будет выполнятся в нашем классе и вернёт информацию (В нашем случае staticGetPaywaysByCheckoutID)
paymentObj - название латиницей класса типа оплаты в системе
interkassa - название латиницей папки вашего модуля
params - объект с параметрами дополнительными для передачи в наш статический метод

Обработка приходящего запроса будет в методе actionUserAct() в файле:
/modules/shop/controller/admin/paymentctrl.inc.php

В итоге выглядит так:

data     : {
                      'userAct'     : 'staticGetPaywaysByCheckoutID',
                      'paymentObj'  : 'interkassa',
                      'module'      : 'interkassa',
                      'params'      :{
                          'checkout_id' : $(".formbox input[name='data[ik_co_id]']").val(),
                          'secret_key'  : val
                      }
}

Полный текст файла

<div id="interkassaSecretKey" data-url="{$router->getAdminUrl('userAct')}" data-default-title="{t('-Все типы оплат-')}">
   {include file=$field->getOriginalTemplate()} 
</div>

<script type="text/javascript">
   $.allReady(function() {
       var aj;
       
       /**
       * Назначаем действие на текстовое поле с id кассы, если будет введен текст, 
       * то шлём запрос на сервер, чтобы он нам вернул нам доступные пути оплаты через интеркассу
       *
       */
       $("#interkassaSecretKey input[name='data[secret_key]']").off('keyup').on('keyup',function(){
           
           var val    = $(this).val();
           var select = $("select[name='data[ik_pw_via]']");
           
           
           if (val.length<16){ //Если символов не хватаем в списке будет пункт "Все"
              select.empty().append('<option value="0">'+ $("#interkassaSecretKey").data('defaultTitle')+'</option>'); 
           }else{ //Если есть ключ пробуем запросить пути оплаты для данной кассы
              if (typeof(aj)=='object'){
                 aj.abort(); 
              }  
              aj = $.ajaxQuery({
                  type     : "POST",
                  url      : $("#interkassaSecretKey").data('url'),
                  data     : {
                      'userAct'     : 'staticGetPaywaysByCheckoutID',
                      'paymentObj'  : 'interkassa',
                      'module'      : 'interkassa',
                      'params'      :{
                          'checkout_id' : $(".formbox input[name='data[ik_co_id]']").val(),
                          'secret_key'  : val
                      }
                  },
                  dataType : "json",
                  success  : function(responce){
                     select.empty();
                     
                     if (responce['data']['list'].length>0){
                        //Добавим возможные значения
                        $(responce['data']['list']).each(function(i){
                           select.append('<option value="'+responce['data']['list'][i]['key']+'">'+responce['data']['list'][i]['value']+'</option>'); 
                        });  
                        
                     }
                     
                  }
              });
              
           }
       });
   });
</script>

А метод в нашем классе будет таким:

/**
    * Получает возможные пути оплаты для привязанной к вам кассы
    * 
    * @param array|string $data - id кассы или массив параметров, среди которых, должен быть ключ "checkout_id"
    */
    public static function staticGetPaywaysByCheckoutID($data)
    {
        $_this = new self();
        
        $_this->setOption('secret_key',$data['secret_key']);
        $_this->setOption('ik_co_id',$data['checkout_id']);
        $data = $_this->getPayways();
        
        $payways = array();
        foreach ($data as $key=>$value){
           $payways[] = array(
              'key' => $key,  
              'value' => $value,  
           ); 
        }
        
        return array('list' => $payways);
    }

Функция canOnlinePay() должна возвращать булевое значение. Если true, то значит что это тип оплаты через внешнюю систему оплаты и должен на последнем шаге заказа оправить пользователя на url оплаты через систему оплаты. Если false, то этот тип оплаты не перенаправляет пользователя на систему оплаты, а перенаправляет на главную станицу. При этом наш класс оплаты формирует документы для обработки или отправки. Примерами служит тип оплаты "Счёт" и "Квитанция ПД4" для оплаты. Тем кому нужна реализация именно таких типов оплат без перехода на страницу внешних сервисов смотрите файлы:

/modules/shop/model/paymenttype/bill.inc.php и /modules/shop/model/paymenttype/formpd4.inc.php

/**
* Возвращает true, если данный тип поддерживает проведение платежа через интернет
* 
* @return bool
*/
function canOnlinePay()
    {
        return true;
    }


Шаг 4. Создаём основные функции в нашем классе для обмена информации.

Есть 5 основных функции для нашего класса, которые являются обязательными. Дело в том, что в процессе оплаты через онлайн сервисы оплаты требуется обмен информацией с системой оплаты и Вашим сайтом. Обмен происходит по определённым url в системе. Всего из 3:

1. url успешной оплаты
2. url не успешной оплаты
3. url который нужен для обмена информацией с системой онлайн оплаты и сайтом. Например, сведения, что оплата прошла успешно и нужно зарегистрировать изменения или нужно подтверждение от нашего сайта, которое скажет что оплатить данный счёт можно. Всё зависит от API системы онлайн оплаты к которой подключаемся.

В процессе обмена информацией между сайтом и системой онлайн оплаты обязательно должен передаваться id транзакции, который система онлайн оплаты возвращает. Он может быть передан как дополнительным параметром от системы Вашему сайту, либо одном из основным, в зависимости от API системы онлайн оплаты к которой подключаемся. А мы в своём случае должны получить данный id транзакции чтобы понять, какая сейчас транзакции происходит.


Идём по порядку по функциям:

1. getTransactionIdFromRequest(\RS\Http\Request $request)
При создании транзакции на онлайн оплату(происходит всегда, когда пользователь переходит на сайт оплаты нажимая кнопку завершить заказ). Транзакции присваивается уникальный идентификатор. Как его получить будет рассмотрено ниже. Удалять транзакции из базы вручную нельзя категорически, т.к. каждая новая последующая транзакция обладает своей уникальной подписью, которая основывается на всех предыдущих подписях транзакций. Если всё же вы так сделали, то придётся удалить все транзакции из системы в соответствующей таблице.


 
Эта функция(getTransactionIdFromRequest) служит для того, чтобы указать в каком параметре во входящих запросах от системы онлайн оплаты нам пришёл id транзации на оплату. В нашем случае придёт запрос со значением параметра с именем "ik_pm_no".

    /**
    * Возвращает ID заказа исходя из REQUEST-параметров соотвествующего типа оплаты
    * Используется только для Online-платежей
    * 
    * @return mixed
    */
    function getTransactionIdFromRequest(\RS\Http\Request $request)
    {
        return $request->request('ik_pm_no', TYPE_INTEGER, false);
    }

2. getPayUrl(\Shop\Model\Orm\Transaction $transaction)
Эта функция подготавливает ссылку  с параметрами, по которой перейдёт пользователь на систему оплаты для совершения платежа. Ссылка будет присвоена кнопке "Завершить заказ" на последней стадии оформления заказа.
В общем главная функция этой функции это составить правильный урл с параметрами для перенаправления пользователя на url оплаты.

Получить id транзакции можно так:

$inv_id = $transaction->id; //Получаем id транзакции

Также для получения параметров из дополнительных полей, которые мы создавали в функции getFormObject() можно делать так:

$field = $this->getOption('Имя поля',Значение поля по умолчанию, если не задано(не обязательный параметр));

//Т.е. получение значения поля формы с именем "ik_co_id"
$params['ik_co_id'] = $this->getOption('ik_co_id');

//Или с параметром по умолчанию
$way        = $this->getOption('ik_pw_via',0); //Тип канала оплаты

Если нам нужен GET запрос, то нужно сформировать просто строку с url. Если это POST запрос для системы, то мы возвращаем url API системы онлайн оплаты. И с помощью метода $this->addPostParams($params); добавим параметры для POST запроса.

В итоге для нашего POST запроса будет так:

/**
    * Возвращает URL для перехода на сайт сервиса оплаты
    * 
    * @param \Shop\Model\Orm\Transaction $transaction - ORM объект транзакции
    * @return string
    */
    function getPayUrl(\Shop\Model\Orm\Transaction $transaction)
    {
        
        $order      = $transaction->getOrder(); //Данные о заказе
        /**
        * @var mixed
        */
        $user       = $order->getUser(); //Пользователь который должен оплатить
        
        $inv_id     = $transaction->id;
        $out_summ   = round($transaction->cost, 2);
        $in_cur     = $this->getPaymentCurrency();
        $way        = $this->getOption('ik_pw_via',0); //Тип канала оплаты

        $params = array();
        $params['ik_co_id'] = $this->getOption('ik_co_id'); //ID кассы
        $params['ik_pm_no'] = $inv_id;
        $params['ik_cur']   = $in_cur;
        $params['ik_am']    = $out_summ;
        $params['ik_am_t']  = "invoice"; //Выбор способа оплаты будет на стороне интеркассы
        $params['ik_desc']  = t("Оплата заказа №").$order['order_num'];
        if ( $language = $this->getLanguage() ) {
           $params['ik_loc'] = $language; 
        }
        $params['ik_cli']  = $user['e_mail']; //Контакты покупателя
        
        //принудительно указываем метод post и url
        $router            = \RS\Router\Manager::obj();
        
        //Обработать process|payway|payways|payways_calc
        $params['ik_act'] = 'payways'; 
        if ($way){ //Если нужно отобразить все типы оплат
            $params['ik_act']    = 'payway';
            $params['ik_pw_via'] = $way; 
        }   
        
        $params['ik_int']  = 'web';     //Формат ответов json|web
        $params['ik_sign'] = $this->getParamsSign($params);
        
        $this->addPostParams($params); //Добавляем параметры для POST запроса
        
        return self::API_URL; //url пост запроса
    }


3. onResult(\Shop\Model\Orm\Transaction $transaction, \RS\Http\Request $request)
Эта фукция самая пожалуй главная, на неё должны приходить все запросы на обработку от системы. Например в нашем случае мы при помощи неё проверяем пришедшие данные из интеркассы, подтверждаем воможность оплаты данного платежа и проверяем статус оплаты. См. документацию интекассы

В итоге имеем:

  
    /**
    * Обработка запросов от интеркассы
    * 
    * @param \Shop\Model\Orm\Transaction $transaction - объект транзакции
    * @param \RS\Http\Request $request - объект запросов
    * @return string
    */
    function onResult(\Shop\Model\Orm\Transaction $transaction, \RS\Http\Request $request)
    {
        
        if (!$this->checkIPsDiapozon()){
           $exception = new \Shop\Model\PaymentType\ResultException(t('Неправильный диапозон IP адресов'));
           $exception->setResponse('Wrong IPs');
           throw $exception; 
        }
        
        if (!$this->checkMainParams($transaction, $request)){
           $exception = new \Shop\Model\PaymentType\ResultException(t('Главные параметры указаные в настройках интеркассы не прошли проверку'));
           $exception->setResponse('Wrong main params');
           throw $exception;  
        }
        
        //Смотрим текущий статус
        $status = $request->request('ik_inv_st',TYPE_STRING,0);
        
        switch($status){
            case "success":
                return 'OK'.$transaction->id;
                break;
            case "process":
                $exception = new \Shop\Model\PaymentType\ResultException(t('Неудачно совершённый платёж'));
                $exception->setResponse('Payment status progress');
                $exception->setUpdateTransaction(false);
                throw $exception;  
                break;
            case "waitAccept": //Если долгое ожидание проведения платежа, то пользователь перенаправляется к нам
                \RS\Application\Application::getInstance()->headers->addHeader('Location',$request->getSelfAbsoluteHost());
                break;
            case "fail":
            default:
               $exception = new \Shop\Model\PaymentType\ResultException(t('Неудачно совершённый платёж'));
               $exception->setResponse('Payment failed');
               throw $exception;   
               break;
        }
        
        return 'OK'.$transaction->id;
    }

В методе присутвует вызов исключений \Shop\Model\PaymentType\ResultException он очень важен т.к. он позволяет генерировать исключения, чтобы они сохранялись в системе, а также отдавали информацию для платёжной системе об итоге обработки их запроса.
Рассмотрим на прямом примере:

//Создаём класс исключения и в параметре передаём какой текст сохранится в системе у этой транзакции
$exception = new \Shop\Model\PaymentType\ResultException(t('Неудачно совершённый платёж'));
//Генерируем ответ на запрос для интеркассы
$exception->setResponse('Payment status progress');
//Устанавливаем флаг того, что статус транзакции не обновлять при сбошенном обновлении иначе платёж не удастся 
$exception->setUpdateTransaction(false);
//Бросаем исключение
throw $exception;  

Теперь поясню по результатам, которые надо возвращать с помощью этой функции(onResult):

1. В этом методе если будет брошено исключение, то статус транзакции установится в fail(неуспешно) и для нового платежа надо будет генерировать новое обращение к системе. Нужно, чтобы поставить статус что оплата провалилась. В интеркассу улетит сообщение $exception->setResponse

2. Если будет брошено исключение, но при этом будет использоваться функция $exception->setUpdateTransaction(false); и в аргумете будет false, то будет брошено исключение не влияющее на транзакцию, повторное обращение к сайту с этим платежом будет возможно и статус у транзакции не изменится. Например нужно, чтобы просто вернуть информацию о платеже системе онлайн оплаты, но статус транзакции при этом ещё не должен быть изменён.

3. Если исключение не будет брошено, а просто будет возвращён текст:

//Например
return 'OK'.$transaction->id;

То в систему онлайн оплаты улетит OKid транзакции и статут транзакции установится в успешный.



4. onFail(\Shop\Model\Orm\Transaction $transaction, \RS\Http\Request $request)
Эта функция не обязательна, т.к. имеется в родительском классе. По сути она показывает страницу с не успешным статусом оплаты на Вашем сайте. Для нашего случая внутри функции устанавливается ещё и статус транзакции.

/**
    * Вызывается при открытии страницы неуспешного проведения платежа 
    * Используется только для Online-платежей
    * 
    * @param \Shop\Model\Orm\Transaction $transaction
    * @param \RS\Http\Request $request
    * @return void 
    */
    function onFail(\Shop\Model\Orm\Transaction $transaction, \RS\Http\Request $request)
    {
        $transaction['status'] = $transaction::STATUS_FAIL;
        $transaction->update();
    }

5. onSuccess(\Shop\Model\Orm\Transaction $transaction, \RS\Http\Request $request)
Эта функция не обязательна, т.к. имеется в родительском классе. По сути она показывает страницу с успешным статусом оплаты на Вашем сайте.


Итого получаем такой файл:

<?php
namespace Interkassa\Model\PaymentType;
use \RS\Orm\Type;
use \Shop\Model\Orm\Transaction;

/**
* Способ оплаты - Interkassa
*/
class Interkassa extends \Shop\Model\PaymentType\AbstractType
{
    const
        API_URL     = "https://sci.interkassa.com/", //URL Api для взаимодействия
        PAYWAYS_URL = "https://api.interkassa.com/v1/paysystem-input-payway", //URL Api для получения полниго списка типов оплат
        IP_DIAPOZON = "85.10.225."; //Диапозон IP адресов интеркассы с которых должны приходить запросы
    
    /**
    * Возвращает название расчетного модуля (типа доставки)
    * 
    * @return string
    */
    function getTitle()
    {
        return t('Интеркасса');
    }
    
    /**
    * Возвращает описание типа оплаты. Возможен HTML
    * 
    * @return string
    */
    function getDescription()
    {
        return t('Оплата через агрегатор платежей "Интеркасса"');
    }
    
    /**
    * Возвращает идентификатор данного типа оплаты. (только англ. буквы)
    * 
    * @return string
    */
    function getShortName()
    {
        return 'interkassa';
    }
    
    /**
    * Отправка данных с помощью POST?
    * 
    */
    function isPostQuery()
    {
        return true;
    }
    
    /**
    * Возвращает ORM объект для генерации формы или null
    * 
    * @return \RS\Orm\FormObject | null
    */
    function getFormObject()
    {
        $properties = new \RS\Orm\PropertyIterator(array(
            'ik_co_id' => new Type\String(array(
                'maxLength' => 255,
                'description' => t('Checkout ID - индетификатор кассы'),
                
            )),
            'secret_key' => new Type\String(array(
                'description' => t('Секретный ключ'),
                'hint' => t('Указан на странице Вашей кассы'),
                'template' => '%interkassa%/form/payment/interkassa/secret_key.tpl'
            )),
            'test_key' => new Type\String(array(
                'description' => t('Тестовый ключ'),
                'hint' => t('Указан на странице Вашей кассы')
            )),
            'language' => new Type\String(array(
                'maxLength' => 5,
                'description' => t('Язык интерфейса'),
                'listFromArray' => array(array(
                    0    => t('Определяется Интеркассой'),
                    'ru' => t('Русский'),
                    'ua' => t('Украинский'),
                    'en' => t('Английский'),
                ))
            )),
            'ik_pw_via' => new Type\String(array(
                'maxLength' => 255,
                'description' => t('Тип оплаты:'),
                'default' => 0,
                'list' => array(array($this,'getPayways')),
            )),
            '__help__' => new Type\Mixed(array(
                'description' => t(''),
                'visible' => true,  
                'template' => '%interkassa%/form/payment/interkassa/help.tpl'
            )), 
        ));
        
        return new \RS\Orm\FormObject($properties);
    }
    
    
    /**
    * Возвращает true, если данный тип поддерживает проведение платежа через интернет
    * 
    * @return bool
    */
    function canOnlinePay()
    {
        return true;
    }
    
    /**
    * Возвращает URL для перехода на сайт сервиса оплаты
    * 
    * @param Transaction $transaction - ORM объект транзакции
    * @return string
    */
    function getPayUrl(\Shop\Model\Orm\Transaction $transaction)
    {
        
        $order      = $transaction->getOrder(); //Данные о заказе
        /**
        * @var mixed
        */
        $user       = $order->getUser(); //Пользователь который должен оплатить
        
        $inv_id     = $transaction->id;
        $out_summ   = round($transaction->cost, 2);
        $in_cur     = $this->getPaymentCurrency();
        $way        = $this->getOption('ik_pw_via',0); //Тип канала оплаты

        $params = array();
        $params['ik_co_id'] = $this->getOption('ik_co_id'); //ID кассы
        $params['ik_pm_no'] = $inv_id;
        $params['ik_cur']   = $in_cur;
        $params['ik_am']    = $out_summ;
        $params['ik_am_t']  = "invoice"; //Выбор способа оплаты будет на стороне интеркассы
        $params['ik_desc']  = t("Оплата заказа №").$order['order_num'];
        if ( $language = $this->getLanguage() ) {
           $params['ik_loc'] = $language; 
        }
        $params['ik_cli']  = $user['e_mail']; //Контакты покупателя
        
        //принудительно указываем метод post и url
        $router            = \RS\Router\Manager::obj();
        
        //Обработать process|payway|payways|payways_calc
        $params['ik_act'] = 'payways'; 
        if ($way){ //Если нужно отобразить все типы оплат
            $params['ik_act']    = 'payway';
            $params['ik_pw_via'] = $way; 
        }   
        
        $params['ik_int']  = 'web';     //Формат ответов json|web
        $params['ik_sign'] = $this->getParamsSign($params); 
        
        $this->addPostParams($params); //Добавляем параметры для POST запроса
        
        return self::API_URL; //url пост запроса
    }
    

    
    /**
    * Получает все варианты оплаты 
    * 
    * @param string $checkout_id - id кассы
    */
    function getPayways()
    {
        
        $params = array();
        
        $params['ik_co_id'] = $this->getOption('ik_co_id','');
        $params['ik_pm_no'] = 'PAYWAYS_1';
        $params['ik_am']    = 1;
        $params['ik_desc']  = 'Look up my payways';
        $params['ik_act']   = 'payways';
        $params['ik_int']   = 'json';
        $params['ik_sign']  = $this->getParamsSign($params);
        
        // Create a stream
        $opts = array(
            'http'=>array(
                'method'=>"GET",
            )
        );
        
        $context = stream_context_create($opts);
        $params = http_build_query($params);
        // Получим оплаты, которые привязаны к кассе
        $data = json_decode(file_get_contents(self::API_URL."?".$params, false, $context));

        // Подготовим массив
        $payways = array(0 => t('-Все типы оплат-'));
        
        if (isset($data->resultMsg) && $data->resultMsg=="Success"){ //Если всё прошло успешно и мы получили типы путей оплаты
            foreach($data->resultData->paywaySet as $way){
                $payways[$way->als] = mb_strtoupper($way->ser)." - ".mb_strtoupper($way->curAls);
            }
        }
        asort($payways);

        return $payways;
    }
    
    /**
    * Получает возможные пути оплаты для привязанной к вам кассы
    * 
    * @param array|string $data - id кассы или массив параметров, среди которых, должен быть ключ "checkout_id"
    */
    public static function staticGetPaywaysByCheckoutID($data)
    {
        $_this = new self();
        
        $_this->setOption('secret_key',$data['secret_key']);
        $_this->setOption('ik_co_id',$data['checkout_id']);
        $data = $_this->getPayways();
        
        $payways = array();
        foreach ($data as $key=>$value){
           $payways[] = array(
              'key' => $key,  
              'value' => $value,  
           ); 
        }
        
        return array('list' => $payways);
    }
    
    /**
    * Получает нужную подпись для разных режимов
    * 
    * @param boolean $test - флаг, что нужно использовать тестовый ключ
    */
    private function getRightSign($test = false)
    {
        if ($test && ($this->getOption('ik_pw_via',false) == "test_interkassa_test_xts")){
           file_put_contents(__DIR__.'/file.txt',date('Y-m-d H:i:s')."\n"."345435\n",FILE_APPEND);  
           return $this->getOption('test_key',''); 
        }
        return $this->getOption('secret_key','');
    }
    
    /**
    * Получает подпись для платежа формируемая по правилам Интеркассы
    * 
    * @param array $params - массив параметров
    * @param boolean $test - флаг, что нужно использовать тестовый ключ
    */
    private function getParamsSign( $params, $test = false )
    {
        unset($params['ik_sign']); //Удаляем из данных строку подписи 
        ksort($params, SORT_STRING); //Сортируем по ключам в алфовитном порядке
        array_push($params, $this->getRightSign($test)); //Конкатинируем символом ":"
        return base64_encode(md5(implode($params, ":"), true)); //MD5 в бинарном виде в кодированном base64
    }
    
    /**
    * Получает язык в котором будет представлен интерфейс Интеркассы
    */
    private function getLanguage()
    {
       return $this->getOption('language',0) ? $this->getOption('language',0) : false; 
    }
    
    /**
    * Проверяет диапозон IP адреса. Проверяет IP адреса интеркассы
    * 
    * @return boolean
    */ 
    private function checkIPsDiapozon()
    {
       $ip = $_SERVER['REMOTE_ADDR']; 
       if (stripos($ip, self::IP_DIAPOZON)===false){
          return false; 
       } 
       return true;
    }
    
    /**
    * Получает трех символьный код базовой валюты в которой ведётся оплата
    * 
    */
    private function getPaymentCurrency()
    {
       /**
       * @var \Catalog\Model\Orm\Currency
       */
       $currency = \RS\Orm\Request::make()
                        ->from(new \Catalog\Model\Orm\Currency())
                        ->where(array(
                           'public'  => 1,
                           'is_base'  => 1,
                        ))
                        ->object(); 
       return $currency ? $currency->title : false;
    }
    
    
    
    /**
    * Проверяем подпись запроса
    * 
    * @param string $sign - подпись запроса
    */
    private function checkSign($sign, $test = false)
    {
        $ik = array();
        foreach ($_REQUEST as $key=>$value){
           if (stripos('ik_')!==false){
              $ik[$key] = $value;  
           }
        }
        $my_sign = $this->getParamsSign($ik, $test); //Получаем нами сформированную подпись
        // Проверка корректности подписи
        return $my_sign == $sign;
    }
    
    /**
    * Проверяет основные параметры приходящие от интеркассы сравнивая с теми, что уснавлены в настройках системы
    * 
    * @param \Shop\Model\Orm\Transaction $transaction - объект транзакции
    * @param \RS\Http\Request $request - объект запросов
    */
    private function checkMainParams(\Shop\Model\Orm\Transaction $transaction, \RS\Http\Request $request)
    {
        $ik_co_id  = $request->request('ik_co_id',TYPE_STRING,'');
        $ik_am     = $request->request('ik_am',TYPE_STRING,'');
        $ik_inv_st = $request->request('ik_inv_st',TYPE_STRING,'');
        $ik_sign   = $request->request('ik_sign',TYPE_STRING,'');
        
        if ( $ik_co_id != $this->getOption('ik_co_id','') ) {
            return 'ID кассы';
        }
        if ( $ik_am != round($transaction->cost, 2) ) {
            return 'Сумма платежа';
        }
        if (!in_array($ik_inv_st,array('process','success','fail','waitAccept'))) {
            return 'параметр ik_inv_st='.$ik_inv_st;
        }
        $ik = array();
        foreach ($_REQUEST as $key=>$value){
           if (stripos('ik_')!==false){
              $ik[$key] = $value;  
           }
        }
        $test = ($request->request('ik_pw_via',TYPE_STRING,'') == "test_interkassa_test_xts");
        if (!$this->checkSign($ik_sign, $test)){
            return 'Неправильная подпись. Параметр ik_sign='.$ik_sign." ".$this->getParamsSign($ik);
        }
        return true;
    }
    
    /**
    * Возвращает ID заказа исходя из REQUEST-параметров соотвествующего типа оплаты
    * Используется только для Online-платежей
    * 
    * @return mixed
    */
    function getTransactionIdFromRequest(\RS\Http\Request $request)
    {
        return $request->request('ik_pm_no', TYPE_INTEGER, false);
    }
    
    /**
    * Обработка запросов от интеркассы
    * 
    * @param \Shop\Model\Orm\Transaction $transaction - объект транзакции
    * @param \RS\Http\Request $request - объект запросов
    * @return string
    */
    function onResult(\Shop\Model\Orm\Transaction $transaction, \RS\Http\Request $request)
    {
        
        if (!$this->checkIPsDiapozon()){
           $exception = new \Shop\Model\PaymentType\ResultException(t('Неправильный диапозон IP адресов'));
           $exception->setResponse('Wrong IPs');
           throw $exception; 
        }
        
        if (!$this->checkMainParams($transaction, $request)){
           $exception = new \Shop\Model\PaymentType\ResultException(t('Главные параметры указаные в настройках интеркассы не прошли проверку'));
           $exception->setResponse('Wrong main params');
           throw $exception;  
        }
        
        //Смотрим текущий статус
        $status = $request->request('ik_inv_st',TYPE_STRING,0);
        
        switch($status){
            case "success":
                return 'OK'.$transaction->id;
                break;
            case "process":
                $exception = new \Shop\Model\PaymentType\ResultException(t('Неудачно совершённый платёж'));
                $exception->setResponse('Payment status progress');
                $exception->setUpdateTransaction(false);
                throw $exception;  
                break;
            case "waitAccept": //Если долгое ожидание проведения платежа, то пользователь перенаправляется к нам
                \RS\Application\Application::getInstance()->headers->addHeader('Location',$request->getSelfAbsoluteHost());
                break;
            case "fail":
            default:
               $exception = new \Shop\Model\PaymentType\ResultException(t('Неудачно совершённый платёж'));
               $exception->setResponse('Payment failed');
               throw $exception;   
               break;
        }
        
        return 'OK'.$transaction->id;
    }
    
    /**
    * Вызывается при открытии страницы неуспешного проведения платежа 
    * Используется только для Online-платежей
    * 
    * @param \Shop\Model\Orm\Transaction $transaction
    * @param \RS\Http\Request $request
    * @return void 
    */
    function onFail(\Shop\Model\Orm\Transaction $transaction, \RS\Http\Request $request)
    {
        $transaction['status'] = $transaction::STATUS_FAIL;
        $transaction->update();
    }
    
}

Как отлаживать всё это дело?
Я лично все запросы которые пришли на url пишу в файл. Например так:

//Пишет в текущую папку в файл info.txt весь массив запроса
file_put_contents(__DIR__."/info.txt","\n".var_export($_REQUEST,true),FILE_APPEND);

2,572

(6 ответов, оставленных в Вопросы по работе с системой)

А чем Вас наш colorboх не устраивает? Если вы пользуетесь нашей темой оформления, то вы можете ссылке указать класс inDialog. У Вас откроется ссылка в всплывающем окне.
В theme.js должна быть строка $('.inDialog').openInDialog();
А сама функция openInDialog лежит в common.js

2,573

(6 ответов, оставленных в Вопросы по работе с системой)

Насколько я помню lightbox, то там как и с фотками подсовываете просто урл у ссылки на нужный html документ.

2,574

(10 ответов, оставленных в Вопросы по работе с системой)

Опишите пожалуйста по шагам, как тестировали и что делали пожалуйста. И лучше если в support@readyscript.ru. Мы буем тестировать и если что выпустим обновление с исправлением.

2,575

(6 ответов, оставленных в Вопросы по работе с системой)

Да нет в том то и дело, просто хотелось понять для какой темы требуется.
Вам видимо придётся свой модуль дописать, который будет ещё и возвращать в json доступные фильтры. Но это довольно не тривиальная задача. Попробуйте посмотреть вот эту статью по созданию блок контроллера и на основе блок контроллера фильтров сделать свой блок контроллер.
Блок контроллер находится по пути:
/modules/catalog/controller/block/sidefilters.inc.php

Либо можно подменить существующий блок контроллер своим файлом. Создав в тойже папки файл
/modules/catalog/controller/block/sidefilters.my.inc.php

Вам надо будет проверять у подготовленных товаров какие характеристики доступны и возвращать.

Либо можно нам такую разработку заказать на этой странице, но задача не простая сразу скажу, т.к. там будет множество кейсов.

Либо можно как-то пересмотреть структуру поместив в разные папки майки и футболки и давать прямые ссылки на них. Я думаю это будет самое малозатратное.