Bitrix - выводим доставку в зависимости от свойств товара, добавленного в корзину
Обратился ко мне заказчик с таким вопросом. В каталоге у товаров присутствовало свойство, в котором хранилась стоимость доставки. Судя по всему, стоимость доставки для различных товаров была разной, а может так было удобней добавлять товары - я не особо вникал в данный вопрос. Была поставлена задача, а значит - будем делать то, что просят.

Суть задачи:

Есть товары со свойством равным 0.

Если в корзине присутствует хотя бы один товар с данным свойством - доставка бесплатная для всего заказа.

Однако для некоторых товаров доставка платная и она тоже будет отображаться по умолчанию на шаге оформления заказа.То есть, покупатель сможет выбирать между платной и бесплатной доставкой, что глупо, не так ли? Поэтому необходимо вариант с платной доставкой скрывать

Мы все с вами помним - ведь помним же ))), что для любой службы доставки можно настроить ограничения -  учебный курс. Мы создадим собственное ограничение, которое и будем использовать. Итак, приступим. Стоп! Кофе налить...

Вот теперь погнали! )

В файле init.php подключим собственный класс ограничения, используя событие onSaleDeliveryRestrictionsClassNamesBuildLis:

$eventManager = \Bitrix\Main\EventManager::getInstance();
$eventManager->addEventHandler(
'sale',
'onSaleDeliveryRestrictionsClassNamesBuildList',
'functionDeliveryRestrictions'
);

function functionDeliveryRestrictions()
{
return new \Bitrix\Main\EventResult(
\Bitrix\Main\EventResult::SUCCESS,
array(
'\InCartPropCodeDeliveryRestriction' => '/bitrix/php_interface/include/InCartPropCodeDeliveryRestriction.php',
)
);
}

В папке include создаём файл InCartPropCodeDeliveryRestriction.php. Заготовка выглядит так:

<?php
use Bitrix\Sale\Delivery\DeliveryLocationTable,
Bitrix\Sale\Internals\CollectableEntity,
Bitrix\Sale\Shipment;

class InCartPropCodeDeliveryRestriction extends \Bitrix\Sale\Delivery\Restrictions\Base
{
public static function getClassTitle()
{
}

public static function getClassDescription()
{
}

public static function check($arData, array $restrictionParams, $deliveryId = 0)
{
}

protected static function extractParams(CollectableEntity $shipment)
{
}

public static function getParamsStructure($deliveryId = 0)
{
}
}

Функции getClassTitle() и getClassDescription() отвечают за заголовок и описание ограничения соответственно.

Заполним:

public static function getClassTitle()
{
return 'По наличию в корзине товара с определённым свойством';
}

public static function getClassDescription()
{
return 'Работает для типов свойств: список, число, строка, привязка к элементу, файл (по имени файла).
<br><br>Множественные свойства НЕ учитываются! Только одиночные значения.
<br><br>Сравнение производится по корневому товару. Не по ТП!!!
';
}

getParamsStructure - параметры ограничения, которые мы задаём в админке при добавлении этого ограничения к службе доставки:

public static function getParamsStructure($deliveryId = 0)
{
return array(
"PARAM_CODE" => array(
'TYPE' => 'STRING',
'LABEL' => 'Символьный код свойства',
),
"PARAM_IF" => array(
"TYPE" => "ENUM",
'MULTIPLE' => 'N',
"OPTIONS" => array(
'==' => 'Равно',
'!=' => 'Не равно',
'>' => 'Больше',
'<' => 'Меньше',
'>=' => 'Больше, либо равно',
'<=' => 'Меньше, либо равно',
),
"LABEL" => 'Условие',
),
"PARAM_VALUE" => array(
'TYPE' => 'STRING',
'LABEL' => 'Значение свойства',
),
"PARAM_ACTION" => array(
"TYPE" => "ENUM",
'MULTIPLE' => 'N',
"OPTIONS" => array(
'Y' => 'Отображать доставку',
'N' => 'Скрывать доставку',
),
"LABEL" => 'Действие',
),
);
}


extractParams - подготовит данные для проверки ограничения функцией check. В нашем случае мы получим товары в корзине. Проверим ТП это или нет и получим массив с минимальной информацией о элементе инфоблока:

protected static function extractParams(CollectableEntity $shipment)
{
$mxResult = false;
// Получаем товары в корзине:
foreach ($shipment->getShipmentItemCollection() as $shipmentItem) {
/** @var \Bitrix\Sale\BasketItem $basketItem - запись в корзине*/
$basketItem = $shipmentItem->getBasketItem();
$productId = $basketItem->getProductId(); // Получим id товара

// Если товар ТП - получим данные элемента ИБ по ID ТП, в противном случае - по текущему ID
$tpInfo = CCatalogSku::GetProductInfo(
$productId
);
if (is_array($tpInfo))
{
$mxResult[] = $tpInfo;
} else {
$mxResult[] = \CIBlockElement::GetByID($productId)->Fetch();
}
}

return $mxResult;
}

check - выполним все необходимые проверки и отобразим, либо скроем доставку:

public static function check($arData, array $restrictionParams, $deliveryId = 0)
{
/* для корректной работы, нам нужно инвертировать значение стартового параметра $restrictionParams['PARAM_ACTION']
Если он выставлен в настроках на Y - то выставить N и наоборот*/
$visibleDelivery = (($restrictionParams['PARAM_ACTION'] == 'Y') ? 'N' : 'Y');

foreach ($arData as $data) {
$arDC_prop = \CIBlockElement::GetProperty($data['IBLOCK_ID'], $data['ID'], array('sort' => 'asc'), Array('CODE'=>$restrictionParams['PARAM_CODE']))->Fetch();

// Что будем использовать - VALUE, VALUE_ENUM, и тд
switch ($arDC_prop['PROPERTY_TYPE']) {
case 'F': // для фото из свойств
$arFile = CFile::GetFileArray($arDC_prop['VALUE']);
$value = $arFile['FILE_NAME'];
break;
case 'L': // для списков
$value = $arDC_prop['VALUE_ENUM'];
break;
case 'N': // для поля "число"
$value = $arDC_prop['VALUE'];
break;
default:
$value = $arDC_prop['VALUE'];
}

// Погнали проверять и сравнивать с настройками ограничения
if($restrictionParams['PARAM_IF'] == '=='){
if($value == $restrictionParams['PARAM_VALUE']){
$visibleDelivery = $restrictionParams['PARAM_ACTION'];
break;
}
}
if($restrictionParams['PARAM_IF'] == '!='){
if($value != $restrictionParams['PARAM_VALUE']){
$visibleDelivery = $restrictionParams['PARAM_ACTION'];
break;
}
}
if($restrictionParams['PARAM_IF'] == '>'){
if($value > $restrictionParams['PARAM_VALUE']){
$visibleDelivery = $restrictionParams['PARAM_ACTION'];
break;
}
}
if($restrictionParams['PARAM_IF'] == '<'){
if($value < $restrictionParams['PARAM_VALUE']){
$visibleDelivery = $restrictionParams['PARAM_ACTION'];
break;
}
}
if($restrictionParams['PARAM_IF'] == '>='){
if($value >= $restrictionParams['PARAM_VALUE']){
$visibleDelivery = $restrictionParams['PARAM_ACTION'];
break;
}
}
if($restrictionParams['PARAM_IF'] == '<='){
if($value <= $restrictionParams['PARAM_VALUE']){
$visibleDelivery = $restrictionParams['PARAM_ACTION'];
break;
}
}

}
if($visibleDelivery == 'N'){
return false;
}
return true;
}
В принципе - всё. Более подробно всё разжевал MR.CAPPUCCINO у себя в блоге.

На выходе, в админке, мы получили дополнительное ограничение для служб доставки. Можем применить только для того, чтобы показывать определённый вид доставки при определённом значении свойства товара. Можем наоборот - скрывать. Условий заложено достаточно. При необходимости, можно доработать как угодно. Предусмотреть иные проверки, различные условия. Результат - ниже:

результат - ограничение для служб доставки Bitrix


Стоимость интеграции данного решения на ваш сайт - 1000 руб

Возможны любые доработки под ваши требования.

Пишите, спрашивайте.