Оглавление
Стандартный набор ограничений службы доставки
Из коробки 1С Битрикс «Управление сайтом» предоставляет следующий набор ограничений:- Исключить по местоположению
- По весу
- По группам пользователей
- По категории товара
- По товарам
- По максимальному размеру
- По максимальным размерам
- По общей стоимости товаров
- По платёжным системам
- По публичной части
- По типу плательщика
Список не маленький и в 90% случаев его будет достаточно для корректной настройки использования службы доставки. Например можно ограничить работу штатного курьера по определённым городам или увязать доставку с определённой платёжной системой. Но если у вас стоит специфическая задача, вы можете создать и зарегистрировать собственный класс ограничений.
Собственный класс ограничений
Для реализации ограничения, вам необходимо унаследовать свой класс от базового классаBitrix\Sale\Delivery\Restrictions\Base
системы. Однако вы так же можете наследоваться от существующих классов ограничений из папки /bitrix/modules/sale/lib/delivery/restrictions/
. И так, минимальный набор методов класса ограничений выглядит так:
namespace Lib\Restrictions;
use \Bitrix\Sale\Delivery\Restrictions\Base;
use \Bitrix\Sale\Internals\CollectableEntity;
use \Bitrix\Sale\Shipment;
/**
* Ограничние по свойство товара
*/
class ProductPropertyXRestriction extends Base
{
/**
* Название ограничения
* @return string
*/
public static function getClassTitle()
{
return 'ограничение по свойству товара';
}
/**
* Описание ограничения
* @return string
*/
public static function getClassDescription()
{
return 'Если у товара задано свойство «X», вы не можете использовать эту службу доставки';
}
/**
* Метод получения необходимых для проверки ограничения данных
* @param Bitrix\Sale\Shipment $shipment
* @return null
*/
protected static function extractParams(CollectableEntity $shipment)
{
return null;
}
/**
* Массив параметров ограничения, на его основе строиться форма в админке
* @param $deliveryId
* @return array
*/
public static function getParamsStructure($deliveryId = 0)
{
return [];
}
/**
* Основная функция проверки наступления условия ограничения
* @param $shipmentParams
* @param array $restrictionParams
* @param $deliveryId
* @return bool
*/
public static function check($shipmentParams, array $restrictionParams, $deliveryId = 0)
{
return true;
}
}
В качестве примера, сделаем проверку на наличие у товара корзины, какого-нибудь свойства, например свойство типа "Хрупкий товар", допустим хрупкий товар можно возить только курьером компании.Создадим свойства инфоблока с торговыми предложениями. В качестве примера я взял стандартный интернет-магазин который можно развернуть при установке системы.
Свойство типа "Список" имеет одно значение "Да" с мнемоническим кодом "Y".
Запомним код свойства
DELICATE_PRODUCT
, оно потребуется для проверки товаров. Давайте сразу же проставим одному из товаров это свойство. Перейдём к торговым предложениям, выведем свойство в список, чтобы не пришлось проваливаться в каждое ТП отдельно.Жмём на шестерёнку в верхнем правом углу списка. Перейдём к настройкам, найдём наше свойство, переместим его в правую колонку и сохраним настройки списка.
Теперь свойство доступно в списке и можно отредактировать его прямо отсуюда.
Подготовка выполнена, давайте займёмся классом ограничения.
Подключение и использование
Чтобы ваше ограничение стало доступно в админке, необходимо повесить обработчик на событие инициализации списка ограничений службы доставки onSaleDeliveryRestrictionsClassNamesBuildList.Пример сткруты файлов и папок отвечающих за подключение собственных классов я приводил в этой статье раздел «Подготовка init.php и пространства имён». В целом можно воспользоваться такой же схемой. Т.е. собственные классы в папке
/local/php_interface/lib/
с пространством имён lib
, а так же файл init.php
с подключением констант, файла автозагрузки классов и обработчика событий:
<?php
//Константы
require dirname(__FILE__) . '/constants.php';
//Автозагрузка классов
require dirname(__FILE__) . '/autoload.php';
//Обработка событий
require dirname(__FILE__) . '/event_handler.php';
/**
* обёртка для print_r() и var_dump()
* @param $val - значение
* @param string $name - заголовок
* @param bool $mode - использовать var_dump() или print_r()
* @param bool $die - использовать die() после вывода
*/
function print_p($val, $name = 'Содержимое переменной', $mode = false, $die = false){
global $USER;
if($USER->IsAdmin()){
echo '<pre>'.(!empty($name) ? $name.': ' : ''); if($mode) { var_dump($val); } else { print_r($val); } echo '</pre>';
if($die) die;
}
}
Функцию print_p()
я часто использую для отладки, поэтому оставлю её тут по умолчанию.Получаем такую структуру папки local:
Файл constants.php
Тут пока путь к корню папки с пользовательскими классами
<?
//Папка с пользовательскими классами
define('APP_CLASS_FOLDER', '/local/Lib/');
Файл autoload.php
Тут битриксовая «автозагрузка» классов
<?
use Bitrix\Main\Loader;
//Автозагрузка наших классов
Loader::registerAutoLoadClasses(null, [
'Lib\Restrictions\ProductPropertyXRestriction' => APP_CLASS_FOLDER . 'Restrictions/ProductPropertyXRestriction.php'
]);
Файл event_handler.php
Для подключения своего ограничения в событииonSaleDeliveryRestrictionsClassNamesBuildList
нужно вызвать функцию которая вернёт объект \Bitrix\Main\EventResult
<?
use Bitrix\Main;
$eventManager = Main\EventManager::getInstance();
$eventManager->addEventHandler(
'sale',
'onSaleDeliveryRestrictionsClassNamesBuildList',
'ProductPropertyXDeliveryRestriction'
);
function ProductPropertyXDeliveryRestriction()
{
return new \Bitrix\Main\EventResult(
\Bitrix\Main\EventResult::SUCCESS,
[
'Lib\Restrictions\ProductPropertyXRestriction' => APP_CLASS_FOLDER . 'Restrictions/ProductPropertyXRestriction.php',
]
);
}
Если всё сделано верно и с путями нигде не напутали, то в настройках любой службы доставки появиться наше ограничение.Пока оно бесполезно. Чтобы оно полноценно заработало, нужно доделать несколько методов.
Проверка основного условия
Для проверки нам потребуется создать вспомогательный методgetDelicateProductId()
который вернёт массив идентификаторов всех торговых предложений, имеющих флаг "Хрупкий товар", он потребуется для проверки содержимого корзины. А так же дополним методы getParamsStructure()
, extractParams()
и главный метод check()
.
<?php
namespace Lib\Restrictions;
use \Bitrix\Sale\Delivery\Restrictions\Base;
use \Bitrix\Sale\Internals\CollectableEntity;
use \Bitrix\Sale\Shipment;
/**
* Ограничние по свойство товара
*/
class ProductPropertyXRestriction extends Base
{
/**
* Название ограничения
* @return string
*/
public static function getClassTitle()
{
return 'ограничение по свойству товара';
}
/**
* Описание ограничения
* @return string
*/
public static function getClassDescription()
{
return 'Если у товара задано свойство «X», вы не можете использовать эту службу доставки';
}
/**
* Метод получаения необходимых для проверкм ограничения данных
* в данном случае мы получаем флаг, имеются ли в корзине товары с отмеченным флагом "Хрупкий товар"
* @param Bitrix\Sale\Shipment $shipment
* @return null
*/
protected static function extractParams(CollectableEntity $entity)
{
if ($entity instanceof Shipment)
{
$basketHasDelicateProducts = false;
$aeDelicateProductId = self::getDelicateProductId();
$collection = $entity->getCollection();
$order = $collection->getOrder();
$basket = $order->getBasket();
foreach ($basket as $basketItem) {
if(in_array($basketItem->getProductId(), $aeDelicateProductId)){
$basketHasDelicateProducts = true;
}
}
return $basketHasDelicateProducts;
} else {
return -1;
}
return 0;
}
/**
* Массив параметров ограничения, на его основе строиться форма в админке
* @param $deliveryId
* @return array
*/
public static function getParamsStructure($deliveryId = 0)
{
return [
'HAS_DELICATE' => [
'TYPE' => 'Y/N',
'DEFAULT' => 'Y',
'LABEL' => 'Запретить службу доставки для хрупких товаров'
],
];
}
/**
* Основная функция проверки наступления условия ограничения
* @param $shipmentParams - результат extractParams()
* @param array $restrictionParams - значение параметра описанного в getParamsStructure()
* @param $deliveryId
* @return bool
*/
public static function check($shipmentParams, array $restrictionParams, $deliveryId = 0)
{
$result = true;
//Стоит флаг "Запретить службу доставки для хрупких товаров" и в корзине есть хрупкий товар (параметр $shipmentParams)
if($restrictionParams['HAS_DELICATE']=='Y' && $shipmentParams == true){
//Службу доставки использовать нельзя
$result = false;
}
//Стоит флаг "Запретить службу доставки для хрупких товаров" и в корзине НЕТ хрупких товаров
if($restrictionParams['HAS_DELICATE']=='Y' && $shipmentParams == false){
//Службу доставки использовать можно
$result = true;
}
return $result;
}
/**
* Получим массив, всех торговых предложений относящихся к хрупким товарам
* @return array
*/
private static function getDelicateProductId()
{
$delicateProductId = [];
$arFilter = ['IBLOCK_ID'=>IB_CATALOG_SKU, '!PROPERTY_DELICATE_PRODUCT'=>false];
$res = \CIBlockElement::GetList(['ID'=>'ASC'], $arFilter, false, false, ['ID']);
while($ob = $res->GetNextElement()){
$arFields = $ob->GetFields();
$delicateProductId[] = $arFields['ID'];
}
return $delicateProductId;
}
}
Обратите внимание в методе
getDelicateProductId()
добавлена константа IB_CATALOG_SKU
заранее заведённая в файле local/php_interface/constants.php
. В getParamsStructure()
возвращаем массив описывающий тип свойства и возможные значения параметра. Этот параметр будет доступен при редактировании ограничения в службе доставки.Далее проверив корзину и получив параметры ограничения, выполняем финальную проверку в методе
check()
. Я добавил комментарии в код, чтобы вам было проще сориентироваться. Я настроил ограничение для Почты России. Теперь при такой корзине (без хрупких товаров) нам доступны все методы доставки.Добавим в корзину товар, для которого мы проставили флаг "Хрупкий товар". Теперь нам доступен только курье и самовывоз.
Наше ограничение работает! Через
extractParams()
и объект класса Shipment
можно дотянуться до множества параметров корзины и заказа, а используя вспомогательные методы такие как getDelicateProductId()
можно получить дополнительные данные не относящиеся напрямую к заказу, например узнать группу пользователя и т.д. Параметров кстати может быть множество, они описываются как элементы массива в getParamsStructure()
.Создавайте свои ограничения доставки, улучшайте пользовательский опыт клиента и логистику сайта. Удачи!.