Персональные скидки пользователя через правила работы с корзиной Bitrix

Была поставлена задача сделать персональные скидки пользователя, которые должны были автоматически рассчитываться сайтом по некоторым правилам от 5 до 90% с шагом в 1%.
Группировка по уровню скидки, мягко говоря, была бы не удобной, т.к. было бы 85 групп, которыми пришлось бы оперировать.
Тогда для каждого пользователя будет создано правило с привязкой к пользователю через CSaleDiscount.
Однако, в документации к методам https://dev.1c-bitrix.ru/api_help/sale/classes/csalediscount/csalediscount__add.php информация, как всегда, в полном объеме, особенно скудно описана часть CONDITIONS и ACTIONS.
Более подробное описание есть в https://dev.1c-bitrix.ru/api_help/catalog/classes/ccatalogdiscount/ccatalogdiscount_add.php , но нет структуры и логики процесса.
Как и другие разработчики системы рекомендовали, для понимания логики правил корзины лучше всего создать типовое правило и изучить его:

Так, к примеру,

<?
CModule::IncludeModule('sale');
echo '<pre>';
print_r(unserialize(CSaleDiscount::GetByID(1)['CONDITIONS']));
echo '</pre>';
?>

выведет всю начинку CONDITIONS:

Array
(
    [CLASS_ID] => CondGroup
    [DATA] => Array
        (
            [All] => AND
            [True] => True
        )

    [CHILDREN] => Array
        (
            [0] => Array
                (
                    [CLASS_ID] => CondMainUserId
                    [DATA] => Array
                        (
                            [Type] => CondIBIBlock
                            [Value] => Equal
                            [Unit] => 1
                        )

                )

        )

)

А [‘ACTIONS’]

<?
CModule::IncludeModule('sale');
echo '<pre>';
print_r(unserialize(CSaleDiscount::GetByID(1)['ACTIONS']));
echo '</pre>';
?>

покажет ACTIONS для правила с кодом 1 (GetByID(1)):

Array
(
    [CLASS_ID] => CondGroup
    [DATA] => Array
        (
            [All] => AND
        )

    [CHILDREN] => Array
        (
            [0] => Array
                (
                    [CLASS_ID] => ActSaleBsktGrp
                    [DATA] => Array
                        (
                            [Type] => Discount
                            [Value] => 5
                            [Unit] => Perc
                            [All] => OR
                            [True] => True
                        )

                    [CHILDREN] => Array
                        (
                            [0] => Array
                                (
                                    [CLASS_ID] => CondIBIBlock
                                    [DATA] => Array
                                        (
                                            [logic] => Equal
                                            [value] => 2
                                        )

                                )

                        )

                )

        )

)

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

CModule::IncludeModule("sale");
global $USER;
$discountValue = calcDisc(); //Функция для определения значения скидки

$Actions["CLASS_ID"] = "CondGroup";
$Actions["DATA"]["All"] = "AND";
$Actions["CHILDREN"][0]["CLASS_ID"] = "ActSaleBsktGrp";
$Actions["CHILDREN"][0]["DATA"]["Type"] = "Discount";
$Actions["CHILDREN"][0]["DATA"]["Value"] = $discountValue;
$Actions["CHILDREN"][0]["DATA"]["Unit"] = "Perc";
$Actions["CHILDREN"][0]["DATA"]["All"] = "OR";
$Actions["CHILDREN"][0]["DATA"]["True"] = "True";
$Actions["CHILDREN"][0]["CHILDREN"][0]["CLASS_ID"]="CondIBIBlock";
$Actions["CHILDREN"][0]["CHILDREN"][0]["DATA"]["logic"]="Equal";
$Actions["CHILDREN"][0]["CHILDREN"][0]["DATA"]["value"]="2";//на все, что лежит в ИБ=2

$Conditions["CLASS_ID"] = "CondGroup";
$Conditions["DATA"]["All"] = "AND";
$Conditions["DATA"]["True"] = "True";
$Conditions["CHILDREN"][0]["CLASS_ID"] = "CondMainUserId";
$Conditions["CHILDREN"][0]["DATA"]["Type"] = "CondIBIBlock";
$Conditions["CHILDREN"][0]["DATA"]["Value"] = "Equal";
$Conditions["CHILDREN"][0]["DATA"]["Unit"] =$USER->GetID();//привязка к текущему юзеру


$arFields = array(
"LID"=>"s1",
"NAME"=>$discountValue."% персональная скидка от ".date("d.m.y"),
"CURRENCY"=>"RUB",
"ACTIVE"=>"Y",
"USER_GROUPS"=>array(2),
"ACTIVE_FROM"=>ConvertTimeStamp(time(), "FULL"),
"CONDITIONS"=>$Conditions,
'ACTIONS' => $Actions,
"DISCOUNT_TYPE" => "P",
"LAST_LEVEL_DISCOUNT" => "Y",
"LAST_DISCOUNT" => "Y",
);

$rsUser = CUser::GetByID($USER->GetID());
$arUser = $rsUser->Fetch();
if (intval($arUser["UF_BASKETRULE"])){
CSaleDiscount::Update($arUser["UF_BASKETRULE"],$arFields);
}else{
$ID = CSaleDiscount::Add($arFields);
if(IntVal($ID) > 0) {
\Bitrix\Sale\Internals\DiscountGroupTable::updateByDiscount($ID, [2], "Y", true);
$user = new CUser;
$arFields = array(
"UF_BASKETRULE" => $ID
);
$ID = $user->Update($USER->GetID(),$arFields);
}
}

Дальше хотелось бы отдельно остановится на последней части кода. Поскольку скидка будет обновляться, то каждый раз методом add ее добавлять не стоит, но нужно обновлять правило, а обновить мы можем только по ID правила, а как получить правила, где участвует пользователь, я не знаю. Есть GetList, но его использование с выборкой CONDITIONS так и осталось черным ящиком (и не старался понять, если честно). Было принято решение в пользовательском поле просто хранить ID правила для текущего пользователя, тогда если $arUser[«UF_BASKETRULE»], то обновляем, иначе создаем и запоминаем ID правила для пользователя.

Профит. Все работает )

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *