Bitrix API правил работы с корзиной

Bitrix API правил работы с корзиной

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

Необходимо на уровне Bitrix API добавить в это правило еще несколько товаров. Данная задача актуальна, когда товаров много и вручную добавлять слишком трудозатратно.

Прежде чем приступить к решению задачи, стоит уточнить, что начиная с версии 16.6.0 модулей Информационные блокиТорговый каталог и Интернет-магазин, доступны объединенные скидки каталога и магазина. Соответственно после конвертации правила работы с корзиной «переплыли» с CCatalogDiscount в CSaleDiscount. В новых же версиях Битрикс необходимо пользоваться классом CSaleDiscount.

Для решения задачи посмотрим, что там под капотом у нашего правила работы с корзиной (2 — это ID правила работы с корзиной):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
CModule::IncludeModule('sale');
echo '<pre>';
print_r(CSaleDiscount::GetByID(2));
echo '</pre>';
CModule::IncludeModule('sale'); echo '<pre>'; print_r(CSaleDiscount::GetByID(2)); echo '</pre>';
CModule::IncludeModule('sale');
echo '<pre>';
print_r(CSaleDiscount::GetByID(2));
echo '</pre>';

Результат:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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";}}}}}}}
)
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";}}}}}}} )
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» — это сериализованный массив, содержащий параметры выполняемых действий правила работы с корзиной.

Посмотрим, что внутри:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
CModule::IncludeModule('sale');
echo '<pre>';
print_r(unserialize(CSaleDiscount::GetByID(2)['ACTIONS']));
echo '</pre>';
CModule::IncludeModule('sale'); echo '<pre>'; print_r(unserialize(CSaleDiscount::GetByID(2)['ACTIONS'])); echo '</pre>';
CModule::IncludeModule('sale');
echo '<pre>';
print_r(unserialize(CSaleDiscount::GetByID(2)['ACTIONS']));
echo '</pre>';

Результат:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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
)
)
)
)
)
)
)
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 ) ) ) ) ) ) )
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 в правило работы с корзиной:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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 );
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 );
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

Если кратко: добавить в инфоблок с товарами свойство — идентификатор скидки и уже на основе его значения формировать правило работы с корзиной.