Недавно пришел к нам клиент и сказал: «Хочу при редактировании товара указывать скидку на этот товар, только чтобы применялась она исключительно для данного товара, причем была возможность вводить скидку как в процентах, так и фиксированную величину в рублях». Порывшись в скидках увидел, что к скидке можно привязывать товар, на который она будет дейсвовать. Однако, как обычно, процесс выбора товара не совсем удобен.
Немного подумав, родился следующий алгоритм:
Создаем два свойства у инфоблока 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) { ...... } |
Была еще такая идея:
завести новый тип цены "Цена со скидкой" и при редактировании элемента пересчитывать "Базовую цену" с введенной скидкой и записывать ее в новый тип цены. Но такой вариант отпал по техническим причинам.