Создание правила корзины и купона при помощи api

В этой статье я расскажу, как в Битриксе создать правило корзины и купон к этому правилу при помощи API.

Допустим, есть следующая задача: пользователь нажимает на какую-нибудь кнопку на сайте и получает купон на случайную скидку с определенными товарами. Следовательно, при нажатии на эту кнопку, мы будем отправлять ajax запрос к файлу php, в котором будет создаваться правило для корзины со скидкой и купон к этому правилу.

Файл php в котором при помощи API Битрикса мы создаем правило и купон для этого правила:

<?require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");
use Bitrix\Sale\Internals;
CModule::IncludeModule("catalog");
CModule::IncludeModule("iblock");
CModule::IncludeModule("sale");

global $APPLICATION;


$unixStart = strtotime(date("d.m.Y H:i:s"));
$unixEnd = $unixStart+43200; //12 часов
$xcount = 0;
$discountValue = rand(1,10); //Размер случайной скидки от 1 до 10 процентов

$Actions["CLASS_ID"] = "CondGroup";
$Actions["DATA"]["All"] = "AND";
$Actions["CLASS_ID"] = "CondGroup";
$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";

$DbParentEl = CIBlockElement::GetList(array(),array("SECTION_ID"=>array(10,11)),false,false,array("ID")); 
while($ParentId = $DbParentEl->Fetch()){
	//Массив товаров к которым будет применяться скидка
	$Actions["CHILDREN"][0]["CHILDREN"][$xcount]["CLASS_ID"] = "CondIBElement"; 
	$Actions["CHILDREN"][0]["CHILDREN"][$xcount]["DATA"]["logic"] = "Equal";
	$Actions["CHILDREN"][0]["CHILDREN"][$xcount]["DATA"]["value"] = $ParentId["ID"];
	$xcount++;	
}

$Conditions["CLASS_ID"] = "CondGroup";
$Conditions["DATA"]["All"] = "AND";
$Conditions["DATA"]["True"] = "True";
$Conditions["CHILDREN"] = "";


//Массив для создания правила
$arFields = array(
	"LID"=>"s1",
	"NAME"=>$discountValue."% Скидки ".date("d.m.y"),
	"CURRENCY"=>"RUB",
	"ACTIVE"=>"Y",
	"USER_GROUPS"=>array(1),
	"ACTIVE_FROM"=>ConvertTimeStamp($unixStart, "FULL"),
	"ACTIVE_TO"=>ConvertTimeStamp($unixEnd, "FULL"),
	"CONDITIONS"=>$Conditions,
	'ACTIONS' => $Actions
	);
	
$ID = CSaleDiscount::Add($arFields); //Создаем правило корзины
$res = $ID>0;
if ($res) { 	
	$codeCoupon = CatalogGenerateCoupon(); //Генирация купона
    $fields["DISCOUNT_ID"] = $ID;
	$fields["COUPON"] = $codeCoupon;
	$fields["ACTIVE"] = "Y";
	$fields["TYPE"] = 2;
	$fields["MAX_USE"] = 0;
	$dd = Internals\DiscountCouponTable::add($fields); //Создаем купон для этого правила
	if (!$dd->isSuccess())
	{
		$err = $dd->getErrorMessages();
	}else{
		echo 'Купон на скидку: '.$codeCoupon;
	}
}else{
	$ex = $APPLICATION->GetException();  
	echo 'Ошибка: '.$ex->GetString();
}
?>

Теперь расскажу, что происходит переменные $unixStart и $unixEnd содержать значения даты начала активности и даты окончания активности, я поставил 12 часов от текущего времени. При помощи CIBlockElement::GetList мы выбираем товары, к которым будет применяться скидка.

Разберем массив $arFields который мы передаем при создании правила корзины. LID - это id вашего сайта, NAME - название правила, CURRENCY - валюта, USER_GROUPS - массив с id групп пользователей, для которых будет действовать это правило, ACTIVE_FROM и ACTIVE_TO - период действия правила. Наверняка вы уже заметили, что я много информации записал в массивы CONDITIONS и ACTIONS - это условия, которые будут применяться к нашему правилу. В ACTIONS мы записали товары, к которым будет применяться это правило. О том как наполнять эти массивы, я документации не нашел, поэтому нашел файл /bitrix/modules/sale/admin/delivery_edit.php и в этом файле распечатал данные, которые передаются в ACTIONS и CONDITIONS, если у вас условия будут отличаться от моих и сами вы не сможете правильно заполнить эти данные, то советую поступить также.

После создания правила, проверяем нет ли ошибки и если ошибки нет, то создаем купон к этому правилу. Массив $fields содержит данные для создания купона. DISCOUNT_ID - id правила работы с коризной, COUPON - код купона, TYPE - тип купона, в данном случае "на один заказ" (1 - на одну позицию заказа, 4 - многоразовый)

Таким образом у нас получилось создать правило работы с корзиной и купон к этому правилу при помощи api.

Также, если вас не устраивает стандартный функционал и вам необходимо самим написать код, который будет применять купон, то используйте это:

<?require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");

use Bitrix\Main\Loader;
use Bitrix\Sale\DiscountCouponsManager;

CModule::IncludeModule("sale");

$check = DiscountCouponsManager::isExist($_POST['coupon']);

if($check["ID"]>0){
	DiscountCouponsManager::add($_POST['coupon']); 	
	echo "ok";
}else{
	echo 'Такого купона не существует';
}

?>
Комменатрии
Михаил 20.06.2019 10:00:45
Пытаюсь применить после создания правила работы с корзиной и купона, все это к заказу, вообще никак не получается. Что делаю не так? $codeCoupon = CatalogGenerateCoupon(); //Генирация купона $fields["DISCOUNT_ID"] = $ID; $fields["COUPON"] = $codeCoupon; $fields["ACTIVE"] = "Y"; $fields["TYPE"] = 2; $fields["MAX_USE"] = 0; $dd = InternalsDiscountCouponTable::add($fields); //Создаем купон для этого правила if (!$dd->isSuccess()){ $err = $dd->getErrorMessages(); }else{ $res = $dd->getId(); BitrixSaleDiscountCouponsManager::init( BitrixSaleDiscountCouponsManager::MODE_ORDER, [ "userId" => $order->getUserId(), "orderId" => $order->getId() ] ); SaleDiscountCouponsManager::add($codeCoupon); $discount = $order->getDiscount(); BitrixSaleDiscountCouponsManager::clearApply(true); BitrixSaleDiscountCouponsManager::useSavedCouponsForApply(true); $discount->setOrderRefresh(true); $discount->setApplyResult($calcResults); if (!($basket = $order->getBasket())) { throw new BitrixMainObjectNotFoundException('Entity "Basket" not found'); } $basket->refreshData(array('PRICE', 'COUPONS')); $discount->calculate(); $order->save();
Ответить
Станислав 20.06.2019 10:24:41
Михаил, я копирнул ваш код к себе в редактор, смотрите я не нашел закрывающего знака } для else, но скорее всего это вы просто сюда не вставили. У вас сумма заказа меняется, когда вы применяете после создания корзины и купона? Просто, я когда делал данный пример, мне важно было просто менять цену в заказе и она менялась, но при этом информации о купоне в админке я не видел.
Ответить
юзверь 26.07.2019 09:06:07
правило корзины создается, но не работает.
Ответить
Станислав 26.07.2019 09:11:32
юзверь, У вас в принципе не работают правила корзины? Если вручную создаете, через админку, оно работает?
Ответить
юзверь 26.07.2019 09:13:30
Станислав, ошибку нашел. добавлял товар, но надо было предложение, т.к. в корзину падает именно оно. Товар в чистом виде (без опций) в корзину не падает вообще.
Ответить
Ольга 12.10.2019 13:36:18
Добрый день! Применяю Ваш код, получаю: "Ошибка: Действия, заданные для правила, некорректны. Правило не может быть сохранено." С чем это может быть связано? Это не может быть связано с тем, что у нас редакция Малый бизнес? Или причина в чем-то другом?
Ответить
Ольга 12.10.2019 14:13:34
Заработало после добавления $Actions["CHILDREN"][0]["DATA"]["Max"] = "10"; $Actions["CHILDREN"][0]["DATA"]["True"] = "True";
Ответить
Dmitriy 03.12.2019 23:15:27
Спасибо за ваш код! Идеально :) P.S. короткий код выглядит так: use BitrixSaleInternals; if (CModule::IncludeModule("catalog")
Ответить
Дмитрий 13.08.2020 13:35:11
Как сделать так чтобы это правило после добавления появилось в админке? \Bitrix\Sale\Internals\DiscountGroupTable::updateByDiscount() не помогает
Ответить
Дмитрий 13.08.2020 13:51:22
Через какое-то время появились, странно
Ответить
Добавить комментарий