Представим себе, что перед нами стоит следующая прикладная задача. Есть правило работы с корзиной, применяющее 10% скидку на определённые товары

Необходимо на уровне Bitrix API добавить в это правило еще несколько товаров. Данная задача актуальна, когда товаров много и вручную добавлять слишком трудозатратно.
Прежде чем приступить к решению задачи, стоит уточнить, что начиная с версии 16.6.0 модулей Информационные блоки, Торговый каталог и Интернет-магазин, доступны объединенные скидки каталога и магазина. Соответственно после конвертации правила работы с корзиной «переплыли» с CCatalogDiscount в CSaleDiscount. В новых же версиях Битрикс необходимо пользоваться классом CSaleDiscount.
Для решения задачи посмотрим, что там под капотом у нашего правила работы с корзиной (2 — это ID правила работы с корзиной):
CModule::IncludeModule('sale');
echo '<pre>';
print_r(CSaleDiscount::GetByID(2));
echo '</pre>';Результат:
Array
(
[ID] => 2
[XML_ID] =>
[LID] => s1
[SITE_ID] => s1
[NAME] => скидка 10%
[PRICE_FROM] =>
[PRICE_TO] =>
[CURRENCY] => RUB
[DISCOUNT_VALUE] => 0.00
[DISCOUNT_TYPE] => P
[ACTIVE] => Y
[SORT] => 100
[ACTIVE_FROM] =>
[ACTIVE_TO] =>
[TIMESTAMP_X] => 13.12.2018 10:45:20
[MODIFIED_BY] => 1
[DATE_CREATE] => 12.12.2018 17:23:30
[CREATED_BY] => 1
[PRIORITY] => 1
[LAST_DISCOUNT] => Y
[VERSION] => 3
[CONDITIONS] => a:3:{s:8:"CLASS_ID";s:9:"CondGroup";s:4:"DATA";a:2:{s:3:"All";s:3:"AND";s:4:"True";s:4:"True";}s:8:"CHILDREN";a:0:{}}
[UNPACK] => function($arOrder){return ((1 == 1)); };
[APPLICATION] => function (&$arOrder){$saleact_0_0=function($row){return ((isset($row['CATALOG']['PARENT_ID']) ? ((isset($row['CATALOG']['ID']) && ($row['CATALOG']['ID'] == 10 || $row['CATALOG']['ID'] == 18)) || ($row['CATALOG']['PARENT_ID'] == 10 || $row['CATALOG']['PARENT_ID'] == 18)) : (isset($row['CATALOG']['ID']) && ($row['CATALOG']['ID'] == 10 || $row['CATALOG']['ID'] == 18))));};\Bitrix\Sale\Discount\Actions::applyToBasket($arOrder, array (
'VALUE' => -10.0,
'UNIT' => 'P',
'LIMIT_VALUE' => 0,
), $saleact_0_0);};
[ACTIONS] => a:3:{s:8:"CLASS_ID";s:9:"CondGroup";s:4:"DATA";a:1:{s:3:"All";s:3:"AND";}s:8:"CHILDREN";a:1:{i:0;a:3:{s:8:"CLASS_ID";s:14:"ActSaleBsktGrp";s:4:"DATA";a:6:{s:4:"Type";s:8:"Discount";s:5:"Value";i:10;s:4:"Unit";s:4:"Perc";s:3:"Max";i:0;s:3:"All";s:3:"AND";s:4:"True";s:4:"True";}s:8:"CHILDREN";a:1:{i:0;a:2:{s:8:"CLASS_ID";s:13:"CondIBElement";s:4:"DATA";a:2:{s:5:"logic";s:5:"Equal";s:5:"value";a:2:{i:0;s:2:"18";i:1;s:2:"10";}}}}}}}
)Содержимое элемента массива с ключем «ACTIONS» — это сериализованный массив, содержащий параметры выполняемых действий правила работы с корзиной.
Посмотрим, что внутри:
CModule::IncludeModule('sale');
echo '<pre>';
print_r(unserialize(CSaleDiscount::GetByID(2)['ACTIONS']));
echo '</pre>';Результат:
Array
(
[CLASS_ID] => CondGroup
[DATA] => Array
(
[All] => AND
)
[CHILDREN] => Array
(
[0] => Array
(
[CLASS_ID] => ActSaleBsktGrp
[DATA] => Array
(
[Type] => Discount
[Value] => 10
[Unit] => Perc
[Max] => 0
[All] => AND
[True] => True
)
[CHILDREN] => Array
(
[0] => Array
(
[CLASS_ID] => CondIBElement
[DATA] => Array
(
[logic] => Equal
[value] => Array
(
[0] => 18
[1] => 10
)
)
)
)
)
)
)18 и 10 — это ID наших товаров, которые в данный момент времени присутствуют в правиле работы с корзиной.
Собственно код, добавляющий товар с ID = $item_id в правило работы с корзиной:
CModule::IncludeModule('sale');
//получим список товаров в правиле работы с корзиной:
$new_ids = [];
$new_ids = unserialize(CSaleDiscount::GetByID(2)['ACTIONS'])['CHILDREN'][0]['CHILDREN'][0]['DATA']['value'];
$new_ids[] = $item_id;
$new_ids = array_unique($new_ids);
//добавим в правило работы с корзиной:
$upd = [
'ACTIVE'=>'Y',
'ACTIONS'=>[
'CLASS_ID' => 'CondGroup',
'DATA' => ['All'=>'AND'],
'CHILDREN' =>[
[
'CLASS_ID'=>'ActSaleBsktGrp',
'DATA'=> [
'Type'=>'Discount',
'Value'=>10,
'Unit'=>'Perc',
'Max'=>0,
'All'=>'AND',
'True'=>'True'
],
'CHILDREN'=>[
[
'CLASS_ID'=>'CondIBElement',
'DATA'=>[
'logic'=>'Equal',
'value'=>$new_ids
]
]
]
]
]
]
];
CSaleDiscount::Update(2, $upd );p.s. Обращаю внимание, что создание правил работы с корзиной основанной на выборке товаров по ID может привести к проблемам с производительностью. Эта проблема обычно возникает, когда товаров в правиле много. Для улучшения ситуации лучше использовать идею, описанную в этой статье:
Если кратко: добавить в инфоблок с товарами свойство — идентификатор скидки и уже на основе его значения формировать правило работы с корзиной.