Перейти к содержимому

Как применить скидку к товару битрикс api

  • автор:

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

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

Заметки айтишника

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

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

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

CModule::IncludeModule('sale'); echo '
'; print_r(CSaleDiscount::GetByID(2)); echo '

';

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:"CHILDREN";a:0:<>> [UNPACK] => function($arOrder); [APPLICATION] => function (&$arOrder);\Bitrix\Sale\Discount\Actions::applyToBasket($arOrder, array ( 'VALUE' => -10.0, 'UNIT' => 'P', 'LIMIT_VALUE' => 0, ), $saleact_0_0);>; [ACTIONS] => a:3:s:8:"CHILDREN";a:1:s:8:"CHILDREN";a:1:>>>>>> )

Содержимое элемента массива с ключем «ACTIONS» — это сериализованный массив, содержащий параметры выполняемых действий правила работы с корзиной.

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

CModule::IncludeModule('sale'); echo '
'; print_r(unserialize(CSaleDiscount::GetByID(2)['ACTIONS'])); echo '

';

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 наших товаров, которые в данный момент времени присутствуют в правиле работы с корзиной.

Собственно код, добавляющий товар с в правило работы с корзиной:

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

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

  • ← Пример скрипта импорта данных из csv файла в инфоблок Битрикс
  • Заготовка собственного компонента фильтра в Битрикс →

Как вывести все товары со скидкой в 1С-битрикс (catalog.section)

На одном проекте потребовалось вывести на определенной странице все товары со скидкой, проставленной в Правилах работой с корзиной.

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

Погуляв по форумам в поисках готового решения не нашел ничего подходящего для меня, пришлось делать всё ручками с нуля 🙂

Сразу скажу, что не претендую на звание лучшего решения данного вопроса, но для моей задачи этого вполне хватило. Если будут какие-либо предложения по улучшению логики работы, буду только рад.

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

Почему не используем метод «на лету» — из-за потенциальных проблем с производительностью такого способа.

Итак, что делаем:

Заводим для нашего основного инфоблока свойство типа Список (можно и простую строку, у меня просто оно уже было). Ставим там одно единственное возможное значение (у меня это «yes»). У меня свойство имеет код SPECIALOFFER.

Далее в какой-нибудь служебной папочке добавляем скрипт следующего содержания, где меняем входные параметры на свои, а именно: код инфоблока, значение свойства, сам код свойства (если у вас он другой)

require_once($_SERVER['DOCUMENT_ROOT'] . "/bitrix/modules/main/include/prolog_before.php"); CModule::IncludeModule("iblock"); CModule::IncludeModule("catalog"); // меняем под себя эти значения $iblock_id = 10; // основной инфоблок $idPropSale = 22; // ID значения свойства отвечающего за Акцию $oldPropsSale = $arNewSale = array(); // перебираем все активные элементы нашего инфоблока $resItem = CIBlockElement::GetList( array("ID"=>"asc"), array( "ACTIVE"=>"Y", "IBLOCK_ID"=>$iblock_id), false, false, array("ID", "IBLOCK_ID", "PROPERTY_SPECIALOFFER") ); while($arItem = $resItem->Fetch()) < // запишем текущее значение свойства скидки $oldPropsSale[$arItem["ID"]] = $arItem["PROPERTY_SPECIALOFFER_VALUE"]; // смотрим есть ли у нашего товара SKU $offersExist = CCatalogSKU::getExistOffers($arItem["ID"], $arItem["IBLOCK_ID"]); // для товаров с SKU if($offersExist[$arItem["ID"]] == 1) < // получим все SKU $resSku = CCatalogSKU::getOffersList( $arItem["ID"], $arItem["IBLOCK_ID"], array("ACTIVE"=>"Y") // дополнительный фильтр предложений. по умолчанию пуст. ); // Если нашли SKU if(!empty($resSku[$arItem["ID"]])) < // Перебираем их foreach($resSku[$arItem["ID"]] as $sku) < // смотрим есть ли для текущего предложения скидка $arDiscounts = CCatalogDiscount::GetDiscountByProduct($sku["ID"], array(2), "N", 1, SITE_ID);// ID, группа пользователей, пр.подписки, Группа цены, сайт // если нашлась скидка if(!empty($arDiscounts)) < // ставим для родителя флаг наличия скидки $arNewSale[$sku["PARENT_ID"]] = "Y"; // если нашли останавливаем цикл break; >> > > else // для простых товаров < // смотрим есть ли для текущего предложения скидка $arDiscounts = CCatalogDiscount::GetDiscountByProduct($arItem["ID"], array(2), "N", 1, SITE_ID);// ID, группа пользователей, пр.подписки, Группа цены, сайт // если нашлась скидка if(!empty($arDiscounts)) < // ставим для родителя флаг наличия скидки $arNewSale[$arItem["ID"]] = "Y"; >> > // теперь проставляем свойство где нужно foreach($arNewSale as $prodId => $propVal) < // ставим значение только если оно уже не установлено if($oldPropsSale[$prodId] != "yes" && $propVal == "Y") < //echo "Значение для товара $prodId добавлено \r\n"; CIBlockElement::SetPropertyValuesEx($prodId, $iblock_id, array("SPECIALOFFER" =>$idPropSale)); > > // теперь очистим устаревшие значения свойства Акция foreach($oldPropsSale as $prodId => $propVal) < // ставим значение только если оно уже не установлено if($oldPropsSale[$prodId] == "yes" && $arNewSale[$prodId] != "Y") < //echo "Значение у товара $prodId удалено \r\n"; CIBlockElement::SetPropertyValuesEx($prodId, $iblock_id, array("SPECIALOFFER" =>false)); > >

Всё, теперь нам только остается добавить фильтрацию по нашему свойству где это необходимо.

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

Надеюсь кому-нибудь будет полезно.

Битрикс выводим оптимальную цену со скидкой

Как известно, цена в товарах битрикса хранится не в свойствах, а в полях каталога. Цену необходимо выводить динамически, т.к. могут появиться скидки.

Вывести цену со скидкой и старую цену в Битриксе

Для начала посмотрим на такой код:

GetUserGroupArray(), $renewal ); if (!$arPrice || count($arPrice) GetUserGroupArray())) < $quantity = $nearestQuantity; $arPrice = CCatalogProduct::GetOptimalPrice($productID, $quantity, $USER->GetUserGroupArray(), $renewal); > > //print_r($arPrice);

Получаем массив со следующими ключами:

array( "PRICE" => массив параметров цены, из которой была получена минимальная. Устарел, не используется с версии 15.0.2 (необходимо использовать ключ RESULT_PRICE). Содержит ключи "ID" - ID ценового предложения, "CATALOG_GROUP_ID" - ID типа цены, "PRICE" - величина исходной цены, "CURRENCY" - валюта исходной цены, "ELEMENT_IBLOCK_ID" - ID инфоблока товара, которому принадлежит ценовое предложение, "VAT_INCLUDED" - включен ли НДС в цену (Y/N), "VAT_RATE" - величина ставки НДС в процентах, "DISCOUNT_PRICE" => минимальная цена в базовой_валюте, "DISCOUNT" => самая первая скидка из DISCOUNT_LIST. Устарел, не используется с версии 12.5.0, "DISCOUNT_LIST" => список скидок, примененных к товару. Инкрементный массив, скидки идут в порядке применения. Каждая запись описывает скидку, >array( "ID" => ID скидки "TYPE" => тип (накопительная или нет), "SITE_ID" => сайт, "ACTIVE" => активность, "ACTIVE_FROM", "ACTIVE_TO" => даты активности скидки, "RENEWAL" => применяется к товару или к продлению подписки, "NAME" =>название, "SORT" => сортировка, "MAX_DISCOUNT" => максимальная величина скидки в валюте, "VALUE_TYPE" => процентная, абсолютная скидка либо фиксированная цена, "VALUE" => величина скидки, "CURRENCY" => валюта скидки, "PRIORITY" => приоритет, "LAST_DISCOUNT" => прекратить или нет применения скидок, "COUPON" => купон (если есть), "COUPON_ONE_TIME" => тип купона, "COUPON_ACTIVE" => активность купона, "MODULE_ID" => модуль, к которому относится скидка "HANDLERS" => массив модулей, требуемых для условий скидки ) "PRODUCT_ID" => ID товара, "RESULT_PRICE" => array( "PRICE_TYPE_ID" => ID типа цены "BASE_PRICE" => исходная цена "DISCOUNT_PRICE" => цена со скидкой "CURRENCY" => валюта результата "DISCOUNT" => величина скидки "PERCENT" => процент скидки "VAT_RATE" => величина ставки НДС в процентах "VAT_INCLUDED" => включен ли НДС в цену (Y/N) (в магазин всегда отдаются цены с включенным НДС) ) )

“DISCOUNT_PRICE” – содержит минимальную цену, именно это нам и нужно. Остальные параметры вы можете использовать для своих условий.
$productID – id товара
$quantity – количество
$renewal – пропускаем этот параметр

Таким образом, передав правильные параметры по API битрикса, можно узнать всю необходимую информацию по ценам и по скидкам. Конечно, при условии, что элемент инфоблока является товаров.

CCatalogDiscount

С версии 12.0.0 в связи с изменением логики работы модуля считаются устаревшими следующие методы:

  • GetDiscountIBlockList
  • GetDiscountSectionsList
  • GetDiscountProductsList

До выхода версии 12.0.0 все вышеперечисленные методы являлись служебными и позволяли получить явно заданные привязки скидки к инфоблоку, разделу, элементу. То есть данные, которые можно было увидеть в форме редактирования скидки.

Использование этих методов для получения ID элементов, на которые могла подействовать скидка, было и является некорректным. Например, для скидки, у которой задано ограничение на раздел, вызов GetDiscountProductsList вернет пустой массив.

С выходом 12.0 эти методы оставлены лишь для сохранения совместимости. Они могут вернуть привязки лишь к тем инфоблокам, разделам, элементам, которые явно заданы в ограничениях. Т.е. если скидка действует на название элемента, все перечисленные методы вернут пустые массивы.

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

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