Представим себе, что перед нами стоит следующая прикладная задача:
Есть правило работы с корзиной, применяющее 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 может привести к проблемам с производительностью. Эта проблема обычно возникает, когда товаров в правиле много. Для улучшения ситуации лучше использовать идею, описанную в этой статье:
https://dev.1c-bitrix.ru/community/blogs/vws/setup-discounts-problems-and-drop-performance.php
Если кратко: добавить в инфоблок с товарами свойство — идентификатор скидки и уже на основе его значения формировать правило работы с корзиной.