Недавно пришел к нам клиент и сказал: «Хочу при редактировании товара указывать скидку на этот товар, только чтобы применялась она исключительно для данного товара, причем была возможность вводить скидку как в процентах, так и фиксированную величину в рублях». Порывшись в скидках увидел, что к скидке можно привязывать товар, на который она будет дейсвовать. Однако, как обычно, процесс выбора товара не совсем удобен.
Немного подумав, родился следующий алгоритм:
Создаем два свойства у инфоблока FIXED_DISCOUNT и PERCENT_DISCOUNT. При срабатывании событий OnAfterIBlockElementAdd и OnAfterIBlockElementUpdate проверяем заполненность этих свойств. Если свойство скидки заполнено - создаем скидку( н.п. percent10 — если в PERCENT_DISCOUNT стоит значение 10) и в список товаров на которые действует эта скидка добавляем ID редактируемого элемента. Если же скидка percent10 уже существует, то просто дописываем товар к ней. Если поля со скидками оказываются пустыми надо проверить, к какой скидке принадлежит редактируемый товар и убрать его из списка. Важный момент! Необходимо проверять есть ли в списке товаров у скидки хотя бы 1 элемент, если нет — то скидку надо удалить, иначе она будет действовать на все товары.
Такой же подход и к фиксированной скидке. Ниже приведен исходный код для реализации ввода процентной скидки в форме редактирования товара. Помещаем его в init.php и не забываем создать свойство типа «строка» или «целое число» с кодом PERCENT_DISCOUNT.
P.S.
В обеих функциях желательно сделать обертку для каких инфоблоков выполнять это действие. Например так:
Была еще такая идея:
завести новый тип цены "Цена со скидкой" и при редактировании элемента пересчитывать "Базовую цену" с введенной скидкой и записывать ее в новый тип цены. Но такой вариант отпал по техническим причинам.
Немного подумав, родился следующий алгоритм:
Создаем два свойства у инфоблока FIXED_DISCOUNT и PERCENT_DISCOUNT. При срабатывании событий OnAfterIBlockElementAdd и OnAfterIBlockElementUpdate проверяем заполненность этих свойств. Если свойство скидки заполнено - создаем скидку( н.п. percent10 — если в PERCENT_DISCOUNT стоит значение 10) и в список товаров на которые действует эта скидка добавляем ID редактируемого элемента. Если же скидка percent10 уже существует, то просто дописываем товар к ней. Если поля со скидками оказываются пустыми надо проверить, к какой скидке принадлежит редактируемый товар и убрать его из списка. Важный момент! Необходимо проверять есть ли в списке товаров у скидки хотя бы 1 элемент, если нет — то скидку надо удалить, иначе она будет действовать на все товары.
Такой же подход и к фиксированной скидке. Ниже приведен исходный код для реализации ввода процентной скидки в форме редактирования товара. Помещаем его в init.php и не забываем создать свойство типа «строка» или «целое число» с кодом PERCENT_DISCOUNT.
AddEventHandler("iblock", "OnAfterIBlockElementUpdate", Array("CYDiscount", "SetDiscount"));
/* до сохранения элемента сбрасываем скидку, на случай если она изменилась */
AddEventHandler("iblock", "OnBeforeIBlockElementUpdate", Array("CYDiscount", "DropDiscount"));
class CYDiscount
{
function SetDiscount($arFields)
{
if(!CModule::IncludeModule('catalog'))
return;
/* Выбираем элемент который изменяется */
$obs = CIBlockElement::GetByID($arFields["ID"]);
if($res = $obs->GetNextElement())
{
/* Достаем свойства */
$props = $res->GetProperties();
$pdisc = $props["PERCENT_DISCOUNT"]["VALUE"];
/* Проверяем валидность введенной скидки */
if(!$pdisc || !intval($pdisc))
{
/* Удаляем скидку если скидка не целое число или пустое */
CYDiscount::DropDiscount($arFields);
return;
}
$discount = $pdisc;
/* Проверяем размер скидки, чтобы скидка была от 1 до 99 % включительно*/
if($discount == 0 || $discount == 100)
CYDiscount::DropDiscount($arFields);
}
else
return;
/* Выбираем скидку по имени, percent - это префикс для скидки, который использую я, допустим скидки 1% и 10 % будут именть имена percent1 и percent10 соответственно */
$dbProductDiscounts = CCatalogDiscount::GetList( array(), array( "ACTIVE" => "Y", "NAME"=>"percent".$discount) , false, false, array("ID"));
if($arProductDiscounts = $dbProductDiscounts->GetNext())
{
/* Выбираем все товары которые принадлежат данной скидке */
$res = CCatalogDiscount::GetDiscountProductsList( array() , array("DISCOUNT_ID"=>$arProductDiscounts["ID"]));
$ids = array();
/* Собираем новый массив ID товаров, которые уже были в скидке*/
while($el = $res->Fetch())
$ids[] = $el["PRODUCT_ID"];
/* и дописываем к нему ID редактируемого товара */
$ids[] = $arFields["ID"];
/* Обновляем скидку */
CCatalogDiscount::Update($arProductDiscounts["ID"], array("ACTIVE"=>"Y", "PRODUCT_IDS" => $ids));
}
else
{
/* если такой скидки не существует, создаем ее и привязываем к ней 1 товар */
CCatalogDiscount::Add(array("SITE_ID"=>"s1", "ACTIVE"=>"Y", "NAME"=>"percent".$discount, "VALUE_TYPE"=>"P", "VALUE"=>$discount, "CURRENCY"=>"RUB", "PRODUCT_IDS"=>array($arFields["ID"])));
}
}
function DropDiscount($arFields)
{
if(!CModule::IncludeModule('catalog'))
return;
/* Выбираем все скидки */
$dbProductDiscounts = CCatalogDiscount::GetList( array(), array( "ACTIVE" => "Y") , false, false, array("ID", "NAME"));
while($arProductDiscounts = $dbProductDiscounts->GetNext())
{
/* По префиксу проверяем наша ли это скидка */
if(substr_count($arProductDiscounts["NAME"], "percent") == 1)
{
$res = CCatalogDiscount::GetDiscountProductsList( array() , array("DISCOUNT_ID"=>$arProductDiscounts["ID"]));
$ids = array();
/* Заново группируем массив элементов этой скидки */
while($el = $res->Fetch())
$ids[] = $el["PRODUCT_ID"];
$idsn = array();
/* Удираем из массива элемент который редактируется */
for($i=0; $i < count($ids); $i++)
if($ids[$i]!=$arFields["ID"])
$idsn[] = $ids[$i];
/* проверяем, если в скидке нет элементов то удаляем ее, иначе - обновляем */
if(count($idsn)>0)
CCatalogDiscount::Update($arProductDiscounts["ID"], array("ACTIVE"=>"Y", "PRODUCT_IDS" => $idsn));
else CCatalogDiscount::Delete($arProductDiscounts["ID"]);
}
}
}
}
|
P.S.
В обеих функциях желательно сделать обертку для каких инфоблоков выполнять это действие. Например так:
if($arFields["IBLOCK_ID"] == 17 || $arFields["IBLOCK_ID"] == 18)
{
......
} |
Была еще такая идея:
завести новый тип цены "Цена со скидкой" и при редактировании элемента пересчитывать "Базовую цену" с введенной скидкой и записывать ее в новый тип цены. Но такой вариант отпал по техническим причинам.