В этом разделе
Структура обработчика
Автоматизированные обработчики служб доставки позволяют программным образом
реализовать произвольную логику расчёта стоимости доставки на основе параметров
заказа и собственных настроек. Алгоритмы расчёта могут быть произвольными -
фиксированная стоимость, запросы к удаленным web-сервисам, расчёт на основе
собственных таблиц данных и т.д.
Обработчик представляет собой класс или набор функций следующей
структуры:
Метод |
Описание |
Описание обработчика |
Функция, возвращающая описание обработчика, названия методов, список
профилей обработчика и пр. |
Настройки обработчика |
Функция, возвращающая массив настроек обработчика |
Обработка настроек |
Набор функций, отвечающий за подготовку настроек к занесению в БД и
обратное преобразование. |
Проверка совместимости |
Метод, осуществляющий проверку совместимости профилей данного
обработчика с заказом. |
Функция расчёта |
Метод, осуществляющий расчёт стоимости доставки на основе настроек
обработчика и параметров заказа. |
Поскольку работать с набором отдельных функций неудобно, рекомендуется
объединить их в класс (пространство имен). Исходя из этой рекомендации будет
идти дальнейшее описание, а также, реализован приводимый пример. В примере
обработчик "Курьерская доставки" реализован в виде класса
CDeliveryMySimple .
Описание обработчика
Описание обработчика представляет собой метод, возвращающий ассоциативный
массив следующей структуры:
Параметр |
Описание |
SID |
Уникальный строковой идентификатор обработчика. |
NAME |
Название обработчика. |
DESCRIPTION |
Текстовое описание обработчика |
DESCRIPTION_INNER |
Внутреннее описание обработчика, отображаемое при конфигурации
обработчика в Панели Управления. |
BASE_CURRENCY |
Идентификатор базовой валюты обработчика |
HANDLER |
Путь к файлу обработчика. Нужен для корректного автоматического
копирования обработчика (ещё не реализовано). В подавляющем большинстве
случаев достаточно значения __FILE__ |
GETCONFIG |
Название метода, возвращающего массив настроек валидатора. В случае
реализации обработчика в виде класса, значение представляет собой массив
("имя_класса", "имя_метода"). |
DBSETSETINGS |
Название метода, отвечающего за проверку настроек обработчика и
преобразование массива настроек в строку для сохранения. В случае
реализации обработчика в виде класса, значение представляет собой массив
("имя_класса", "имя_метода"). В случае отсутствия этого метода массив
настроек будет сохранен в базу в сериализованном виде. |
DBGETSETTINGS |
Название метода, отвечающего за обратное преобразование строки
настроек обработчика в массив. В случае реализации обработчика в виде
класса, значение представляет собой массив ("имя_класса",
"имя_метода"). |
COMPABILITY |
Название метода, отвечающего за дополнительную проверку совместимости
профилей обработки с параметрами заказа. Если метод отсутствует,
дополнительная проверка не будет проводиться. В случае реализации
обработчика в виде класса, значение представляет собой массив
("имя_класса", "имя_метода"). |
CALCULATOR |
Название метода, осуществляющего расчёт стоимости доставки. В случае
реализации обработчика в виде класса, значение представляет собой массив
("имя_класса", "имя_метода"). |
PROFILES |
Массив профилей обработки. Должен содержать хотя бы один профиль.
Формат описания см. ниже. |
Описание профилей представляет собой массив следующего формата:
"строковой_идентификато_профиля" => array(
"TITLE" => "название_профиля",
"DESCRIPTION" => "описание_профиля",
// веса указываются в граммах
"RESTRICTIONS_WEIGHT" => array(минимальный_вес, максимальный_вес),
// суммы указываются в базовой валюте обработчика
"RESTRICTIONS_SUM" => array(минимальная_сумма_заказа, максимальная_сумма_заказа)
);
Если массив RESTRICTIONS_WEIGHT или RESTRICTIONS_SUM содержит один элемент,
то он считается минимальным значением. Если никаких ограничений не требуется,
нужно указать array(0) .
Пример:
function Init()
{
return array(
/* Basic description */
"SID" => "simple",
"NAME" => "Доставка курьером",
"DESCRIPTION" => "",
"DESCRIPTION_INNER" =>
"Простой обработчик курьерской доставки. Для функционирования необходимо "
."наличие хотя бы одной группы местоположений. При настройке обработчика указывается "
."фиксированная стоимость доставки для каждой группы местоположений. Для того, чтобы "
."группа не участвовала в обработке, оставьте пустым поле стоимости для этой группы."
."<br />"
."<a href=\"/bitrix/admin/sale_location_group_admin.php?lang=ru\" target=\"_blank\">"
."Редактировать группы местоположений"
."</a>.",
"BASE_CURRENCY" => COption::GetOptionString("sale", "default_currency", "RUB"),
"HANDLER" => __FILE__,
/* Handler methods */
"DBGETSETTINGS" => array("CDeliveryMySimple", "GetSettings"),
"DBSETSETTINGS" => array("CDeliveryMySimple", "SetSettings"),
"GETCONFIG" => array("CDeliveryMySimple", "GetConfig"),
"COMPABILITY" => array("CDeliveryMySimple", "Compability"),
"CALCULATOR" => array("CDeliveryMySimple", "Calculate"),
/* List of delivery profiles */
"PROFILES" => array(
"simple" => array(
"TITLE" => "доставка",
"DESCRIPTION" => "Срок доставки до 3 дней",
"RESTRICTIONS_WEIGHT" => array(0),
"RESTRICTIONS_SUM" => array(0),
),
)
);
}
Параметры валидатора
Метод, заданный элементом GETCONFIG , должен возвращать массив
элементов вида:
array(
"CONFIG_GROUPS" => array(
"идентификатор_группы1" => "название_группы1",
"идентификатор_группы2" => "название_группы2",
/* ...................... */
),
"CONFIG" => array(
"идентфикатор_параметра1" => array(
"TITLE" = > "название_параметра1",
"TYPE" => "тип_параметра1",
"DEFAULT" => "значение_по_умолчанию_параметра1",
"GROUP" => "идентфикатор_группы_параметра1",
"VALUES" => array(
"значение1_параметра1" => "наименование_значения1_параметра1",
"значение2_параметра1" => "наименование_значения2_параметра1",
/* ....................... */
)
),
/* ........................ */
)
)
Группы параметров, описываемые в элементе массива с ключом
"CONFIG_GROUPS " отображаются в виде отдельных вкладок в форме
редактирования параметров обработчика, содержащих параметры, приписанные к этой
группе. Элемент массива с ключом "CONFIG " задает список параметров.
Тип параметра может принимать одно из следующих значений:
- STRING - поле для ввода текста
- PASSWORD - поле для ввода пароля
- CHECKBOX - элемент типа "флажок" со значением 'Y'
- RADIO - набор вариантов в виде радио-кнопок
- DROPDOWN - набор вариантов в виде выпадающего списка
- MULTISELECT - набор вариантов в виде списка со множественным
выбором
- RADIO - набор вариантов в виде радио-кнопок
Для типов параметра подразумевающий выбор из нескольких вариантов значений
(DROPDOWN, MULTISELECT и RADIO) список значений задается
элементом описательного массива с ключом "VALUES ". Для остальных
типов параметров этот элемент игнорируется.
Пример:
function GetConfig()
{
$arConfig = array(
"CONFIG_GROUPS" => array(
"all" => "Стоимость доставки",
),
"CONFIG" => array(),
);
// параметрами обработчика в данном случае являются значения стоимости доставки в различные группы местоположений.
// для этого сформируем список параметров на основе списка групп
$dbLocationGroups = CSaleLocationGroup::GetList();
while ($arLocationGroup = $dbLocationGroups->Fetch())
{
$arConfig["CONFIG"]["price_".$arLocationGroup["ID"]] = array(
"TYPE" => "STRING",
"DEFAULT" => "",
"TITLE" =>
"Стоимость доставки в группу "\" "
$arLocationGroup["NAME"]."\" "
(".COption::GetOptionString("sale", "default_currency", "RUB").')',
"GROUP" => "all",
);
}
return $arConfig;
}
Обработка параметров
Обработка параметров обработчика требует двух методов, задаваемых в описании
параметрами DBSETSETTINGS и DBGETSETTINGS . Первый из
них получает на вход массив значений параметров вида
"идентфикатор_параметра" => "значение_параметра" и
должен вернуть их строковое представление. Второй - совершить обратное
преобразование. Оба метода могут также совершать произвольные манипуляции со
значениями параметров.
Пример:
function SetSettings($arSettings)
{
// Проверим список значений стоимости. Пустые значения удалим из списка.
foreach ($arSettings as $key => $value)
{
if (strlen($value) > 0)
$arSettings[$key] = doubleval($value);
else
unset($arSettings[$key]);
}
// вернем значения в виде сериализованного массива.
// в случае более простого списка настроек можно применить более простые методы сериализации.
return serialize($arSettings);
}
function GetSettings($strSettings)
{
// вернем десериализованный массив настроек
return unserialize($strSettings);
}
Проверка совместимости
Проверка совместимости профилей обработчика с заказом осуществляется методом,
задаваемым в описании параметром "COMPABILITY ". Этот метод
принимает на вход 2 параметра - описательный массив заказа и массив настроек
обработчика. В качестве ответа метода ожидается массив, содержащий
идентификаторы подходящих для данного заказа профилей доставки. Проверка,
задаваемая значениями "RESTRICTIONS_WEIGHT " и
"RESTRICTIONS_SUM " в настройках профиля, производится вне
обработчика и здесь не требуется. Формат принимаемых на вход данных
следующий:
Первый параметр - информация о заказе - представляет собой массив со
следующими ключами:
Ключ |
Описание |
WEIGHT |
Суммарный вес заказа. |
PRICE |
Суммарная стоимость заказа. |
LOCATION_FROM |
ID местоположения магазина, настраиваемого в настройках модуля
"Интернет-магазин". |
LOCATION_TO |
ID местоположения, указываемого клиентом при оформлении
заказа. |
Второй параметр представляет собой значение массива, заданного элементом с
ключом "CONFIG " в списке настроек
обработчика, к каждому элементу которого добавлено значение параметра с ключом
"VALUE ".
В рассматриваемом нами примере единственная условие совместимости - это
наличие в настройках обработчика значения стоимости доставки хотя бы для одной
из групп местоположений, в которые входит местоположение, передаваемое в
заказе.
Пример:
// введем служебный метод, определяющий группу местоположения и возвращающий стоимость для этой группы.
function __GetLocationPrice($LOCATION_ID, $arConfig)
{
// получим список групп для переданного местоположения
$dbLocationGroups = CSaleLocationGroup::GetLocationList(array("LOCATION_ID" => $LOCATION_ID));
while ($arLocationGroup = $dbLocationGroups->Fetch())
{
if (
array_key_exists('price_'.$arLocationGroup["LOCATION_GROUP_ID"], $arConfig)
&&
strlen($arConfig['price_'.$arLocationGroup["LOCATION_GROUP_ID"]]["VALUE"] > 0)
)
{
// если есть непустая запись в массиве настроек для данной группы, вернем ее значение
return $arConfig['price_'.$arLocationGroup["LOCATION_GROUP_ID"]]["VALUE"];
}
}
// если не найдено подходящих записей, вернем false
return false;
}
// метод проверки совместимости в данном случае практически аналогичен рассчету стоимости
function Compability($arOrder, $arConfig)
{
// проверим наличие стоимости доставки
$price = CDeliveryMySimple::__GetLocationPrice($arOrder["LOCATION_TO"], $arConfig);
if ($price === false)
return array(); // если стоимость не найдено, вернем пустой массив - не подходит ни один профиль
else
return array('simple'); // в противном случае вернем массив, содержащий идентфиикатор единственного профиля доставки
}
Обработчик
Основной метод расчёта стоимости доставки получает на вход следующие
параметры:
- идентификатор профиля доставки;
- массив настроек обработчика доставки;
- описательный массив заказа;
- текущий шаг расчёта;
- временные данные, переданные с прошлого шага расчёта.
На выход обработчик должен дать стоимость доставки в валюте, задаваемой в
параметрах, либо массив следующей структуры:
Ключ |
Описание |
RESULT |
Идентификатор ответа. Возможные значения:
- "OK" - стоимость доставки успешно рассчитана;
- "ERROR" - в процессе расчёта произошла ошибка;
- "NEXT_STEP" - необходимо перейти на следующий шаг для
продолжения расчёта.
|
VALUE |
Значение стоимости доставки в валюте, задаваемой в параметрах.
(RESULT = 'OK' ) |
TRANSIT |
Длительность доставки в днях (RESULT = 'OK' ). Если
отсутствует, то длительность не выводится. |
periodFrom |
Строки доставки автоматизированных служб доставок. От указанного количества дней. Необходим для передачи сроков доставки в Яндекс.маркет. Используется при разработке собственных служб доставок. |
periodTo |
Строки доставки автоматизированных служб доставок. До указанного количества дней. Необходим для передачи сроков доставки в Яндекс.маркет. Используется при разработке собственных служб доставок. |
TEXT |
Текст ошибки или текст, сопровождающий переход на следующий шаг
(RESULT = {'ERROR'|'NEXT_STEP'} ). |
TEMP |
Строка, содержащая промежуточные данные, передаваемые следующему шагу
(RESULT = 'NEXT_STEP' ). |
В описываемом нами примере многошаговый процесс не подразумевается, потому,
расчёт осуществляется просто.
Пример:
function Calculate($profile, $arConfig, $arOrder, $STEP, $TEMP = false)
{
// служебный метод рассчета определён выше, нам достаточно переадресовать на выход возвращаемое им значение.
return array(
"RESULT" => "OK",
"VALUE" => CDeliveryMySimple::__GetLocationPrice($arOrder["LOCATION_TO"], $arConfig)
);
}
Интеграция обработчика
Путь к автоматически подключаемым файлам обработчиков устанавливается в настройках модуля "Интернет-магазин". Путь по умолчанию - /bitrix/php_interface/include/sale_delivery/ Такие файлы должны иметь префикс delivery_, в противном случае, они будут проигнорированы. Если система обнаружит файл, имеющее то же название, что и системный, то он будет подключаться вместо системного. Подключение автоматизированной доставки в файле производится установкой описательного метода в качестве обработчика события onSaleDeliveryHandlersBuildList .
Пример
Подытожив все вышесказанное, сформируем обработчик простой доставки. Класс
обработчика расположим в файле
/bitrix/php_interface/include/sale_delivery/delivery_mysimple.php
<?
// Листинг файла /bitrix/php_interface/include/sale_delivery/delivery_mysimple.php
CModule::IncludeModule("sale");
class CDeliveryMySimple
{
function Init()
{
return array(
/* Основное описание */
"SID" => "simple",
"NAME" => "Доставка курьером",
"DESCRIPTION" => "",
"DESCRIPTION_INNER" =>
"Простой обработчик курьерской доставки. Для функционирования необходимо "
."наличие хотя бы одной группы местоположений. При настройке обработчика указывается "
."фиксированная стоимость доставки для каждой группы местоположений. Для того, чтобы "
."группа не участвовала в обработке, оставьте пустым поле стоимости для этой группы."
."<br />"
."<a href=\"/bitrix/admin/sale_location_group_admin.php?lang=ru\" target=\"_blank\">"
."Редактировать группы местоположений"
."</a>.",
"BASE_CURRENCY" => COption::GetOptionString("sale", "default_currency", "RUB"),
"HANDLER" => __FILE__,
/* Методы обработчика */
"DBGETSETTINGS" => array("CDeliveryMySimple", "GetSettings"),
"DBSETSETTINGS" => array("CDeliveryMySimple", "SetSettings"),
"GETCONFIG" => array("CDeliveryMySimple", "GetConfig"),
"COMPABILITY" => array("CDeliveryMySimple", "Compability"),
"CALCULATOR" => array("CDeliveryMySimple", "Calculate"),
/* Список профилей доставки */
"PROFILES" => array(
"simple" => array(
"TITLE" => "доставка",
"DESCRIPTION" => "Срок доставки до 3 дней",
"RESTRICTIONS_WEIGHT" => array(0), // без ограничений
"RESTRICTIONS_SUM" => array(0), // без ограничений
),
)
);
}
// настройки обработчика
function GetConfig()
{
$arConfig = array(
"CONFIG_GROUPS" => array(
"all" => "Стоимость доставки",
),
"CONFIG" => array(),
);
// настройками обработчика в данном случае являются значения стоимости доставки в различные группы местоположений.
// для этого сформируем список настроек на основе списка групп
$dbLocationGroups = CSaleLocationGroup::GetList();
while ($arLocationGroup = $dbLocationGroups->Fetch())
{
$arConfig["CONFIG"]["price_".$arLocationGroup["ID"]] = array(
"TYPE" => "STRING",
"DEFAULT" => "",
"TITLE" =>
"Стоимость доставки в группу \""
$arLocationGroup["NAME"]."\" "
"(".COption::GetOptionString("sale", "default_currency", "RUB").')',
"GROUP" => "all",
);
}
return $arConfig;
}
// подготовка настроек для занесения в базу данных
function SetSettings($arSettings)
{
// Проверим список значений стоимости. Пустые значения удалим из списка.
foreach ($arSettings as $key => $value)
{
if (strlen($value) > 0)
$arSettings[$key] = doubleval($value);
else
unset($arSettings[$key]);
}
// вернем значения в виде сериализованного массива.
// в случае более простого списка настроек можно применить более простые методы сериализации.
return serialize($arSettings);
}
// подготовка настроек, полученных из базы данных
function GetSettings($strSettings)
{
// вернем десериализованный массив настроек
return unserialize($strSettings);
}
// введем служебный метод, определяющий группу местоположения и возвращающий стоимость для этой группы.
function __GetLocationPrice($LOCATION_ID, $arConfig)
{
// получим список групп для переданного местоположения
$dbLocationGroups = CSaleLocationGroup::GetLocationList(array("LOCATION_ID" => $LOCATION_ID));
while ($arLocationGroup = $dbLocationGroups->Fetch())
{
if (
array_key_exists('price_'.$arLocationGroup["LOCATION_GROUP_ID"], $arConfig)
&&
strlen($arConfig['price_'.$arLocationGroup["LOCATION_GROUP_ID"]]["VALUE"] > 0)
)
{
// если есть непустая запись в массиве настроек для данной группы, вернем ее значение
return $arConfig['price_'.$arLocationGroup["LOCATION_GROUP_ID"]]["VALUE"];
}
}
// если не найдено подходящих записей, вернем false
return false;
}
// метод проверки совместимости в данном случае практически аналогичен рассчету стоимости
function Compability($arOrder, $arConfig)
{
// проверим наличие стоимости доставки
$price = CDeliveryMySimple::__GetLocationPrice($arOrder["LOCATION_TO"], $arConfig);
if ($price === false)
return array(); // если стоимость не найдено, вернем пустой массив - не подходит ни один профиль
else
return array('simple'); // в противном случае вернем массив, содержащий идентфиикатор единственного профиля доставки
}
// собственно, рассчет стоимости
function Calculate($profile, $arConfig, $arOrder, $STEP, $TEMP = false)
{
// служебный метод рассчета определён выше, нам достаточно переадресовать на выход возвращаемое им значение.
return array(
"RESULT" => "OK",
"VALUE" => CDeliveryMySimple::__GetLocationPrice($arOrder["LOCATION_TO"], $arConfig)
);
}
}
// установим метод CDeliveryMySimple::Init в качестве обработчика события
AddEventHandler("sale", "onSaleDeliveryHandlersBuildList", array('CDeliveryMySimple', 'Init'));
?>
Post factum
Несколько советов в завершение:
- Если Ваш обработчик использует какие-либо ресурсоемкие вычисления, обращения к базе данных, запросы к удаленным серверам и т.д., то категорически рекомендуется использовать тот или иной вариант кеширования результата, реализованный таким образом, чтобы запоминались результаты хотя бы для заказа с данными параметрами. Это необходимо из-за того, что в процессе оформления и обработки заказа запрос к обработчику на расчёт стоимости заказа может происходить несколько раз. В поставляемых обработчиках используется механизм управляемого кеширования, настроенный с учётом специфики алгоритма вычисления стоимости конкретной службой доставки.
- Для кастомизации системного обработчика достаточно скопировать его файл (вместе с сопутствующими файлами, лежащими обычно в каталоге с тем же названием) в каталог /bitrix/php_interface/include/sale_deivery/ с сохранением имени. В этом случае он будет подключаться вместо системного.
См. также
AddEventHandler
|