Работа с элементами инфоблока, товаром, catalog.element и торговыми предложениями в Битрикс
Rus
Eng
Работа с элементами инфоблока, товаром, catalog.element и торговыми предложениями в Битрикс

Навигация по разделам:

Типы товаров

Товар – добавляется самый обычный простой товар, без каких-либо дополнительных возможностей. Это тот тип товара, который наиболее употребим, и используется в данный момент повсеместно.

Торговые предложения – Данный товар (как товар хранящий список предложений) не имеет остатков, не имеет цены и других атрибутов, которые есть у обычного товара. Этот товар не является товаром. По сути, он содержит список «торговых предложений», которые и являются товарами (предложениями).

Набор - это список привязанных к основному товару товаров, которые магазин хочет порекомендовать к покупке. В набор могут быть добавлены именно товары: торговые предложения и/или простые товары. Товар с торговыми предложениями добавить в него нельзя.

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

Работа с элементами инфоблоков

Добавление элемента инфоблока на сайт

//Инициализируем соответствующий модуль
CModule::IncludeModule("iblock");

//Массив со свойствами элемента инфоблока, где ключами массива служат id нужного свойства 
//(но можно использовать параметр CODE)
//Так же нужно помнить, что для списков и полей с привязкой к элементам или справочникам 
//в качестве значения мы указываем id элемента списка, справочника или объекта
$PROP = array(
    '342'=>'',
    '315'=>''
);

//Cоздаем объект класса для работы
$el = new CIBlockElement;

//Заполняем массив с данными
$arLoadProductArray = Array(
	"MODIFIED_BY"           => 1, 						  //указываем ID пользователя
	"IBLOCK_SECTION"     => $IBLOCK_SECTION_ID,          //для привязки ко многим разделам
	//"IBLOCK_SECTION_ID"     => $IBLOCK_SECTION_ID,     //для одиночного раздела
	"IBLOCK_ID"             => 20,
	"IBLOCK_TYPE"           => 'aspro_next_catalog',
	"PROPERTY_VALUES"       => $PROP,
	"NAME"                  => $NAME,
	"ACTIVE"                => "Y",
	"CODE"                  => $CODE,
	//"PREVIEW_TEXT"          => "текст для списка элементов",
	//"DETAIL_TEXT"           => "текст для детального просмотра",
	//"DETAIL_PICTURE"        => CFile::MakeFileArray($_SERVER["DOCUMENT_ROOT"]."/image.gif")
);

$res = $el->Add($arLoadProductArray);

if($res>0){
	//Успешно добавили
	//В $res хранится id добавленной записи
}else{
	//Добавить не удалось
	//Выводим сообщение с ошибкой
	echo $el->LAST_ERROR;
}

Превращаем элемент инфоблока в товар

/* Делаем добавленный товар простым */
$productFileds = array(
	"ID" => $res, //ID добавленного элемента инфоблока
	"VAT_ID" => 1, //выставляем тип ндс (задается в админке)
	"VAT_INCLUDED" => "Y", //НДС входит в стоимость
	"TYPE " => \Bitrix\Catalog\ProductTable::TYPE_PRODUCT //Тип товара
);

//Возможные значения типа товара:
//const TYPE_PRODUCT = 1;
//const TYPE_SET = 2;
//const TYPE_SKU = 3;
//const TYPE_OFFER = 4;
//const TYPE_FREE_OFFER = 5;
//const TYPE_EMPTY_SKU = 6;

if(CCatalogProduct::Add($productFileds)){
	//Элемент инфоблока превращен в товар
}else{
	//Произошла ошибка
}

Получение списка свойств элемента инфоблока с помощью D7 (начиная с версии 19.0.0)

$res = \Bitrix\Iblock\ElementTable::getList(array(
    "select" => array("ID", "*"),
    "filter" => array("IBLOCK_ID" => $IBLOCK_ID, "ID" => $ELEMENT_ID),
    "order"  => array("ID" => "ASC")
));

while ($arItem = $res->fetch()) {
    $propRes = \Bitrix\Iblock\ElementPropertyTable::getList(array(
        "select" => array("ID", "*"),
        "filter" => array("IBLOCK_ELEMENT_ID" => $arItem["ID"],),
        "order"  => array("ID" => "ASC")
    ));
	
    while($prop = $propRes->Fetch())
        $arItem["PROPERTIES"][$prop["IBLOCK_PROPERTY_ID"]] = $prop;
}

Битрикс получить ID элемента по его символьному коду

CIBlockFindTools::GetElementID($ELEMENT_ID, $ELEMENT_CODE, $SECTION_ID, $SECTION_CODE, $arFilter)
// $section_id - ID секции в которой лежит элемент
// $section_code - символьный код секции в которой лежит элемент
// $arFilter - массив дополнительных свойств для фильтрации

// пример использования
$objFindTools = new CIBlockFindTools();
$elementID = $objFindTools->GetElementID(false, "super_element", false, "super_section", array("IBLOCK_ID" => 1));
// метод возвращает ID элемента, если найдет его, и 0, если элемент не будет найден.

Работа с торговым каталогом (цена\наличие на складах\остатки\резервы)

Получаем список типов цен с помощью d7

$rsPrices = \Bitrix\Catalog\GroupTable::getList();
while($arPrice = $rsPrices->fetch()){
    $PRICE_IDS[] = $arPrice['ID'];
}

Получаем цену и кол-во товара с помощью D7

$dbPrice = \Bitrix\Catalog\Model\Price::getList([
	"filter" => array(
		"PRODUCT_ID" => $id,
		"CATALOG_GROUP_ID" => 1
	)]);

if ($arPrice = $dbPrice->fetch()) {
	$price = $arPrice['PRICE'];
}

Добавляем или обновляем цену товара

$arFieldsPrice = Array(
	"PRODUCT_ID" => $ID,							//ID добавленного товара
	"CATALOG_GROUP_ID" => 1,						//ID типа цены
	"PRICE" => $item['price'],						//значение цены
	"CURRENCY" => !$currency ? "RUB" : $currency, 	// валюта
);

//Смотрим установлена ли цена адля данного товара
$dbPrice = \Bitrix\Catalog\Model\Price::getList([
	"filter" => array(
		"PRODUCT_ID" => $item['ID'],
		"CATALOG_GROUP_ID" => 1
	)
]);

if ($arPrice = $dbPrice->fetch()) {
	//Если цена установлена, то обновляем
	$result = \Bitrix\Catalog\Model\Price::update($arPrice["ID"], $arFieldsPrice);
	
	if ($result->isSuccess()){
		echo "Обновили цену у товара у элемента каталога " . $item['ID'] . " Цена " . $item['price'] . PHP_EOL;
	} else {
		echo "Ошибка обновления цены у товара у элемента каталога " . $item['ID'] . " Ошибка " . $result->getErrorMessages() . PHP_EOL;
	}
}else{
	//Если цены нет, то добавляем
	$result = \Bitrix\Catalog\Model\Price::add($arFieldsPrice);
	
	if ($result->isSuccess()){
		echo "Добавили цену у товара у элемента каталога " . $item['ID'] . " Цена " . $item['price'] . PHP_EOL;
	} else {
		echo "Ошибка добавления цены у товара у элемента каталога " . $item['ID'] . " Ошибка " . $result->getErrorMessages() . PHP_EOL;
	}
}

Добавляем к товару количество на складах

$arFields = Array(
	"PRODUCT_ID" => $id, 		//ID товара
	"STORE_ID"   => $storeId, 	//ID склада
	"AMOUNT"     => $amount,	//Количество
);

CCatalogStoreProduct::Add($arFields);

Более подробно о работе со складами вы можете почитать здесь Работа со складами и количеством товаров в Битрикс D7

Обновляем кол-во товара на складах

$rs = CCatalogStoreProduct::GetList(false, array(
	'PRODUCT_ID'=> $id, 		//ID товара
	'STORE_ID' => $storeId		//ID склада
));

while($ar_fields = $rs->GetNext())
{
	// Обновим значение остатка на складе из значения остатка количественного учёта
	$arFields = Array(
		"PRODUCT_ID" => $id, 		//ID товара
		"STORE_ID"   => $storeId, 	//ID склада
		"AMOUNT"     => $amount,	//Количество
	);

	CCatalogStoreProduct::Update($ar_fields['ID'], $arFields);

}

Обновление остатков товаров с помощью D7

$existProduct = \Bitrix\Catalog\Model\Product::getCacheItem($arFields['ID'],true);

if(!empty($existProduct)){
 \Bitrix\Catalog\Model\Product::update(intval($arFields['ID']),$arFields);
} else {
 \Bitrix\Catalog\Model\Product::add($arFields);
}

Добавляем или обновляем общее кол-во товара (параметр "Доступное кол-во")

CCatalogProduct::Update(
	$ID, //ID добавленного или обновляемого товара
	array(
		"QUANTITY" => $amount, //Кол-во товара
	)
)

Добавляем товар в резерв

$provider = new \Bitrix\Catalog\Product\CatalogProvider;
$resReserve = $provider->reserve(array(
    $productId => ["PRODUCT_ID" => $PRODUCT_ID,  "QUANTITY" => 10]
));

Снятие резерва

$provider = new \Bitrix\Catalog\Product\CatalogProvider;
$resReserve = $provider->reserve(array(
    $productId => ["PRODUCT_ID" => $PRODUCT_ID,  "QUANTITY" => -10 ]
));

Или более кратко:

\Bitrix\Catalog\Product\CatalogProvider::ReserveProduct(array(
    $productId => ["PRODUCT_ID" => $PRODUCT_ID,  "QUANTITY" => -10 ]
))

Получаем measure и ratio товара на D7

\Bitrix\Catalog\ProductTable::getCurrentRatioWithMeasure($arResult['ID'])

Изменяем measure

\CCatalogProduct::Update(13194, array('MEASURE' => 6));

Изменяем ratio

$db_measure = CCatalogMeasureRatio::getList(array(), $arFilter = array('PRODUCT_ID' => 13194), false, false);
while ($ar_measure = $db_measure->Fetch()) {
    $new_measure = CCatalogMeasureRatio::update($ar_measure['ID'], array("RATIO" => 5));
}

Работа со свойствами товаров

Получаем значение отдельного свойства товара в Битрикс с помощью D7

class Product
{
    private $id;

    public function __construct($id)
    {
        if (empty($id)) {
            throw new \Bitrix\Main\ArgumentNullException('id');
        }
        $this->id = $id;
    }

    public function getFields()
    {
        return \Bitrix\Iblock\ElementTable::getById($this->id)->fetch();
    }

    public function getProperty($code)
    {
        $fields = $this->getFields();
        if ($fields) {
            $iblock = \Bitrix\Iblock\Iblock::wakeUp($fields['IBLOCK_ID']);
            $element = $iblock->getEntityDataClass()::getByPrimary($this->id, ['select' => [$code]])->fetchObject();
            $property = $element->__call('get', [$code]);
        }
        return $property ? $property->getValue() : null;
    }
}

Обновить свойство у элемента по коду свойства и ID элемента

\CIBlockElement::SetPropertyValuesEx(PRODUCT_ID, false, array('PROPERTY_CODE' => $NEW_PROPERTY_VALUE));

Очистить значение множественного свойства

\CIBlockElement::SetPropertyValuesEx(PRODUCT_ID, false, ['PROPERTY_CODE' => [0 => ["VALUE" => "" , "DESCRIPTION" => ""]]]);

Документация Концепция и архитектура

Получаем значение отдельного свойства товара или ТП (старый способ)

$arFilter = Array("IBLOCK_ID"=>$kitOffer['IBLOCK_ID'], "ID"=>$kitOffer['ID']);
$arSelect = Array("SORT");
$res = CIBlockElement::GetList(Array(), $arFilter,false,false,$arSelect);
if ($ob = $res->GetNextElement()){;
	$arFields = $ob->GetFields();
}

Получаем товары в Битрикс с помощью D7

//Фильтр стандартный, вы знаете как им пользоваться
$elementIterator = \Bitrix\Iblock\ElementTable::getList([
    'select' => [
        'ID',
    ],
    'filter' => [
        '=IBLOCK_ID' => 20,
        '!=ID' => array(1,2,3),//Массив ID товаров которые нужно пропустить
    ]
]);

$elems = $elementIterator->fetchAll();

foreach ($elems as $element) {
    // создаем объект класса для работы
    $obElement = new CIBlockElement();
	
    // обновляем элемент и делаем неактивным
    $obElement->Update($element['ID'], Array("ACTIVE" => 'N'));
}

Получаем все свойства элемента инфоблока

CIBlockElement::GetByID($arResult['ID'])->GetNextElement()->GetProperties()

Вывод всех свойств товара

CCatalogProduct::GetByIDEx($arElement['ID'])

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

Идем в файл result_modifier.php и добавляем в самый низ:

//==============================================//
// Показывать все свойства в DISPLAY_PROPERTIES //
//==============================================//
$arResult["DISPLAY_PROPERTIES"] = array();
foreach ($arResult["PROPERTIES"] as $pid => &$arProp)
{
    // Не выводим для просмотра свойства с сортировкой меньше 0 (они будут у нас служебными)
    if ($arProp["SORT"] < 0)
        continue;

    if((is_array($arProp["VALUE"]) && count($arProp["VALUE"])>0) ||
        (!is_array($arProp["VALUE"]) && strlen($arProp["VALUE"])>0))
    {
        $arResult["DISPLAY_PROPERTIES"][$pid] = CIBlockFormatProperties::GetDisplayValue($arResult, $arProp);
    }
}

Решение предложил Левый Иван с форума Битрикс

Получаем значения свойства товара типа список

$property_enums = CIBlockPropertyEnum::GetList(Array("DEF"=>"DESC", "SORT"=>"ASC"), Array("IBLOCK_ID"=>15, "CODE"=>"BREND_INTERNAL"));
while($enum_fields = $property_enums->GetNext()){
    echo $enum_fields["ID"]." - ".$enum_fields["VALUE"]."<br>";
}

Добавить новое значение в свойство типа список

$ibpenum = new CIBlockPropertyEnum;
if($PropID = $ibpenum->Add(Array('PROPERTY_ID'=>$PROPERTY_ID, 'VALUE'=>'New Enum 1')))
 echo 'New ID:'.$PropID;

или добавляем свойство на D7

\Bitrix\Main\Loader::includeModule('iblock');

$property = \CIBlockProperty::GetList(
    [],
    [
        'IBLOCK_ID' => $iblockId,  
        'CODE' => $code'
    ]
)->Fetch();

$ibpenum = new \CIBlockPropertyEnum();
$valueId = $ibpenum->Add([
    'PROPERTY_ID' => $property['ID'],
    'VALUE' => $newValueText,
    'XML_ID' => $newValueXmlId,
]);
if ((int) $valueId < 0) {
    throw new \Exception('Unable to add a value');
}

Удалить значение из свойства типа список

CIBlockPropertyEnum::Delete(ID);

или удаляем свойство на D7

if (! \Bitrix\Main\Loader::includeModule('iblock')) {
    throw new \Bitrix\Main\LoaderException('Unable to load IBLOCK module');
}

$property = \CIBlockProperty::GetList([], ['IBLOCK_ID' => $iblockId, 'CODE' => $propertyCode])->Fetch();
if (! $property) {
    throw new \Exception('No such property');
}

$query = \CIBlockPropertyEnum::GetList(
    [], 
    ["IBLOCK_ID" => $iblockId, "XML_ID" => 6, "PROPERTY_ID" => $property['ID']]
);

$value = $query->GetNext();
if (! $value) {
    throw new \Exception('No such value');
}

$delete = \CIBlockPropertyEnum::delete($value['ID']);
if (! $delete) {
    throw new \Exception('Error while deleting the property value');
}

Работа с наборами и комплектами

Получаем состав наборов и комплектов для родительского товара

$arProducts = CCatalogProductSet::GetList(
	array(), array( "TYPE" => array(1,2), "OWNER_ID" => $productID), false, false, array()
);

while($item = $arSets->Fetch() ){
	if($item["OWNER_ID"]!=$item["ITEM_ID"]  ){
		$arComplects[] = $item["ITEM_ID"];
	}
}

Получаем товары соседствующие с искомым в наборе или комплекте

\Bitrix\Main\Loader::includeModule('catalog');

$rItems = CCatalogProductSet::GetList(
	array(),
	array(
		array(
			'LOGIC' => 'OR',
			'TYPE' => CCatalogProductSet::TYPE_GROUP,
			'TYPE' => CCatalogProductSet::TYPE_SET
		),
		'ITEM_ID' => $arResult['ID']),
	false,
	false,
	array('SET_ID', 'OWNER_ID', 'ITEM_ID', 'TYPE')
);
while ($item = $rItems->Fetch()) {
	$arComplect[] = $item;
}

Получаем нужные свойства по массиву id торговых предложений

function getInform($arrOffersIDs){
	$arrProductsIDs = array();
	foreach($arrOffersIDs as $intElementID){
		$mxResult = CCatalogSku::GetProductInfo(
			$intElementID, 4
		);

		if (is_array($mxResult))
		{
			$arrProductsIDs[] = $mxResult["ID"];
		}

	}

	return  CCatalogSKU::getOffersList(
		$arrProductsIDs,
		$iblockID = 4,
		$skuFilter = array('ID'=>$arrOffersIDs),
		$fields = array('ID','NAME','DETAIL_PICTURE'),
		$propertyFilter = array() );

}
				
print_r(getInform(array(45,87,98)));

Получаем нужные свойства всех торговых предложений

function getInform($arrOffersIDs){
	$arrProductsIDs = array();
	foreach($arrOffersIDs as $intElementID){
		$mxResult = CCatalogSku::GetProductInfo(
			$intElementID, 
			4 //ID каталога с товаром
		);

		if (is_array($mxResult))
		{
			$arrProductsIDs[] = $mxResult["ID"];
		}
	}

	return  CCatalogSKU::getOffersList(
		$arrProductsIDs,
		$iblockID = 4, //ID каталога с товаром
		$skuFilter = array(),
		$fields = array('NAME','ID','DETAIL_PICTURE','PREVIEW_PICTURE', "DETAIL_PAGE_URL", "CML2_MANUFACTURER", "DETAIL_TEXT"),//Получаемые свойства
		$propertyFilter = array() );

}
print_r(getInform(array(45,87,98)));

Работа со скидками

Получаем скидки и правила работы с корзиной, которые были применены к товару

В файле result_modifier.php компонента sale.basket.basket получаем перечень примененных к товару скидок

/** @var \Bitrix\Sale\BasketBase $basket */
$basket = (\Bitrix\Sale\Basket\Storage::getInstance(
    \Bitrix\Sale\Fuser::getId(),
    \Bitrix\Main\Context::getCurrent()->getSite()))
    ->getOrderableBasket();

$order = $basket->getOrder();
$discountApplyResults = $order->getDiscount()->getApplyResult(false);

Автогенерации правила работы с корзиной, добавление купона и его применение

Код генерации

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();
}

Код вызова

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 'Такого купона не существует';
}

Оригинал решения

Работа с налогами

Для установки галочки "НДС включен в цену" при добавлении товара воспользуемся событием OnProductAdd. Но не забываем, что событие устаревшее, чтобы оно работало - требуется включить "Включить поддержку устаревших событий" в настройках торгового каталога

AddEventHandler("catalog", "OnProductAdd", "OnProductAdd");
function OnProductAdd($ID, $FIELDS)
{   
	CCatalogProduct::Update($ID, ["VAT_INCLUDED"=>'Y']);
}

Для массового изменения значения "НДС включен в цену" можно выполнить sql запрос

UPDATE b_catalog_product SET VAT_INCLUDED = 'Y', VAT_ID='1' WHERE VAT_INCLUDED = 'N'

Работа с шаблоном

Изменение дополнительных полей торговых предложений в карточке товара "на лету" на примере PREVIEW_TEXT и DETAIL_TEXT

Идем в result_modifier.php и добавляем:

foreach ($arResult['OFFERS'] as $pid => &$arProp)
{
    $arResult['JS_OFFERS'][$pid]['PREVIEW_TEXT'] = $arProp['PREVIEW_TEXT'];//Добавляем в результирующий js массив предложения PREVIEW_TEXT
    $arResult['JS_OFFERS'][$pid]['DETAIL_TEXT'] = $arProp['DETAIL_TEXT'];//Добавляем так же DETAIL_TEXT
}

Для начала подготавливаем контейнеры куда будем выводить новую информацию в шаблоне template.php. В моем случае предполагается, что PREVIEW_TEXT будет грузиться в блок с классом offerShortDescription, DETAIL_TEXT в блок с классом offerFullDescription. Добавим блоки в требуемое место шаблона.

<div class="offerShortDescription"><?=$actualItem['PREVIEW_TEXT']?></div>
<div class="offerFullDescription"><?=$actualItem['DETAIL_TEXT']?></div>

Идем в файл script.js, ищем функцию changeInfo (~2463) и в после условия if (this.obSkuProps) (~2553) добавляем:

if(this.offers[index].PREVIEW_TEXT && this.offers[index].DETAIL_TEXT){
	$('.offerShortDescription').html(this.offers[index].PREVIEW_TEXT);
	$('.offerFullDescription').html(this.offers[index].DETAIL_TEXT);
}

Не забываем обработать случаи когда поля с описанием у торговых предложений не заполнены. Предлагаю это сделать вам самим. Лично я просто добавил через result_modifier.php в каждое торговое предложение дополнительные поля в описанием оригинального товара. Это не совсем красивое, но вполне рабочее решение.

Убираем смену слайда при наведении на превью в слайдере

Идем в script.js и комментируем данные строки (они встречаются дважды на ~552 и ~607)

BX.bind(this.product.slider.ITEMS[j], 'mouseenter', BX.delegate(this.onSliderControlHover, this));
BX.bind(this.product.slider.ITEMS[j], 'mouseleave', BX.delegate(this.onSliderControlLeave, this));

Решение применялось на редакции Бизнес v18.5.0

Меняем активное торговое предложение

Идем в файл \bitrix\components\bitrix\catalog.element\templates\.default\result_modifier.php

Ищем строку foreach ($arResult['OFFERS'] as $keyOffer => $arOffer) - где-то в районе 405 строки.

Там есть строка $intSelected = $keyOffer; - вот $intSelected это и есть порядковый(!) номер торгового предложения, выбранного по умолчанию. То есть, ключ элемента массива ТП, которые выводятся у конкретного товара.

Например, у меня была задача сделать активным по умолчанию предложение ID которого был в $_GET['TP_ID'].

В цикл foreach ($arResult['OFFERS'] as $keyOffer => $arOffer) вставляем:

if ($_GET['TP_ID']) {
   if ($arOffer['ID']==$_GET['TP_ID']) {
         $intSelected =$keyOffer;
   }
}  

Обмен с 1С

Костыль для пересчета остатков и кол-ва товаров при его обновлении из 1С

Будет полезен, если у вас не обновляются резервы при импорте из 1С, а в вашей редакции Битрикс нет кнопки очистить резервы

//При начале импорта из 1С устанавливаем сессионную переменную
AddEventHandler(
      'catalog',
      'OnBeforeCatalogImport1C',
      function ()
      {
         $_SESSION["1C_UPDATE"] = true;
      }
);

//При обновлении товара проверяем, что установлена сесионная переменная и видоизменяем данные
AddEventHandler(
      'catalog',
      'OnProductUpdate',
      function ($id, $arFields)
      {
        if (isset($_SESSION["1C_UPDATE"]) && $_SESSION["1C_UPDATE"])
        {
           $_SESSION["1C_UPDATE"] = false; // борьба с зацикливанием, чтобы сам себя не вызывал. Так как при вызове CCatalogProduct::Update будет опять срабатывать OnProductUpdat
           CCatalogProduct::Update(
            $id, 
            array(
				'QUANTITY' => $arFields['QUANTITY'] + $add /*новое количество товаров*/,
				'QUANTITY_RESERVE' => $arFields['QUANTITY_RESERVE'] + $add /*новое количество зарезервированных товаров*/
			)
         );
           $_SESSION["1C_UPDATE"] = true;
        }
      }
);
   
//При окончании импорта из 1С устанавливаем сессионную переменную
AddEventHandler(
      'catalog',
      'OnSuccessCatalogImport1C',
      function ()
      {
         $_SESSION["1C_UPDATE"] = false;
      }
);

Дополнительные решения возникающих проблем при обмене описываю здесь Битрикс: обмен с 1С

Сложная ORM выборка для получения всех необходимых данных товара

Достаточно часто возникает задача ускорить тот или иной компонент, вывести товары "как в каталоге" или получить все необходимые данные по элементу товара. Сделать это можно как с помощью обычных компонентов, так и с помощью ORM.

Делюсь примером ORM запроса сложного случая. На сайте клиента плевая выборка из 20 товаров на базе catalog.section существенно грузила систему и отрабатывала в среднем за 1.5с. Объединив все выборки в один запрос смог ускорить выбор до 0.4-0.5с без кеширования, а с кешированием результатов до 0.1с

Данный ORM запрос выводит:

- обычные товары и товары с ТП.

- запрос получает несколько типов цен, включая базовую

- запрос получает товары из раздела включая подразделы

- запрос сортирует товары в случайном RAND порядке

- запрос корректно генерирует URL

- в данном запросе свойства товара хранятся в общей таблице (важно)

- запрос суммирует все значения остатков на складах

$IBLOCK_ID = 29;

    //Свойства в общей таблице
    $entityPropsSingle   = \Bitrix\Main\Entity\Base::compileEntity(
        'PROPS_COMMON',
        [
            'IBLOCK_ELEMENT_ID'     => ['data_type' => 'integer'],
            'IBLOCK_PROPERTY_ID'    => ['data_type' => 'integer'],
            'VALUE'                 => ['data_type' => 'string'] // там ещё есть столбцы типа VALUE_TYPE, VALUE_ENUM, VALUE_NUM, DESCRIPTION, но они нам тут не нужны, поэтому опускаем
        ],
        [
            'table_name'            => 'b_iblock_element_property', // общая таблица со свойствами
        ]
    );

    /*Получаем 20 случайных товаров в разделе, включая вложенные*/
    $elements = \Bitrix\Iblock\ElementTable::getList([
        'filter' => [
            'SECTION.ID' => $arResult['SECTION']['PATH'][0]['ID'], // Раздел, в котором ищем включая подразделы.
            '==LINK.ADDITIONAL_PROPERTY_ID' => NULL, // Основная привязка элементов к группам.
            'ACTIVE' => 'Y', // Активные элементы.
            '!=ID' => [$arResult['ID']], //Исключаем из выборки ненужный элемент
            '>base_price.PRICE' => 0, // Исключаем товары с нулевой базовой ценой
            '=PROPS_335.IBLOCK_PROPERTY_ID' => 335, // id свойства артикул
            '=PRODUCT.AVAILABLE' => 'Y', // Доступный к покупке
            //'>PRODUCT.QUANTITY' => 0, // Есть остатки
            //'!=PRODUCT.TYPE' => 1, // Товар с ТП
        ],
        'select' => [
            'ID',
            'NAME',
            'IBLOCK_ID', //Элемент построения урл
            'IBLOCK_SECTION_ID', //Элемент построения урл
            'CODE', //Элемент построения урл
            "QUANTITY" => "PRODUCT.QUANTITY", //Количество товаров
            //'QUANTITY_STORE', //Кол-во на складах
            "TYPE" => "PRODUCT.TYPE", //Тип товара
            'DETAIL_PAGE_URL' => 'IBLOCK.DETAIL_PAGE_URL', //маска урл
            "PRICE_7" => "base_price.PRICE", //базовая цена
            "PRICE_8" => "prop_PRICE_8.PRICE", //оптовая цена
            'ART_NUMBER' => 'PROPS_335.VALUE', //Свойство Артикула с ID 335
            'AVAILABLE' => 'PRODUCT.AVAILABLE', //Доступность
        ],
        'order' => ['RAND' => 'ASC'],
        //'group' => [ 'ID' ], //Группировка недоступна при указанной сортировке
        'limit' => 20,
        'runtime' => [
            //Получаем элемента раздела
            'LINK' => [
                'data_type' => \Bitrix\Iblock\SectionElementTable::class,
                'reference' => [
                    '=this.ID' => 'ref.IBLOCK_ELEMENT_ID',
                ],
                'join_type' => 'inner',
            ],
            //Получаем родительский раздел
            'PARENT' => [
                'data_type' => \Bitrix\Iblock\SectionTable::class,
                'reference' => [
                    '=this.LINK.IBLOCK_SECTION_ID' => 'ref.ID',
                ],
                'join_type' => 'inner',
            ],
            //Подключаем таблицу товара
            'PRODUCT' => [
                'data_type' => \Bitrix\Catalog\ProductTable::class,
                'reference' => [
                    '=this.ID' => 'ref.ID',
                ],
                'join_type' => 'left'
            ],
            //Подключаем таблицу разделов
            'SECTION' => [
                'data_type' => \Bitrix\Iblock\SectionTable::class,
                'reference' => [
                    '=this.PARENT.IBLOCK_ID' => 'ref.IBLOCK_ID',
                    '<=ref.LEFT_MARGIN' => 'this.PARENT.LEFT_MARGIN',
                    '>=ref.RIGHT_MARGIN' => 'this.PARENT.RIGHT_MARGIN',
                ],
                'join_type' => 'inner',
            ],
            //Получаем значение базовой цены с ID 7
            'base_price' => [
                'data_type' => '\Bitrix\Catalog\PriceTable',
                'reference' => [
                    '=this.ID' => 'ref.PRODUCT_ID'
                ],
                'join_type' => 'inner'
            ],
            //Получаем значение оптовой цены с ID 8
            'prop_PRICE_8' => [
                'data_type' => '\Bitrix\Catalog\PriceTable',
                'reference' => [
                    '=this.ID' => 'ref.PRODUCT_ID'
                ],
                'join_type' => 'inner'
            ],
            //Получаем значение свойства 335 (Артикул)
            'PROPS_335' => [
                'data_type' => $entityPropsSingle->getDataClass(),
                'reference' => [
                    '=this.ID' => 'ref.IBLOCK_ELEMENT_ID'
                ],
                'join_type' => 'inner'
            ],
            //Подключаем таблицу складов
            /*'STORE' => [
                'data_type' => \Bitrix\Catalog\StoreProductTable::class,
                'reference' => [
                    '=this.ID' => 'ref.PRODUCT_ID'
                ],
                'join_type' => 'inner'
            ],
            //Суммируем остатки на всех доступных складах
            'QUANTITY_STORE' => [
                'data_type' => 'integer',
                'expression' => ['sum(%s)', 'STORE.AMOUNT']
            ],*/
            //Определяем кастомный порядок сортировку "Случайный"
            'RAND'=>array('data_type' => 'float', 'expression' => array('RAND()')),
        ],
        'cache' => array( // Кеш запроса. Сброс можно сделать методом \Bitrix\Iblock\ElementTable::getEntity()->cleanCache();
            'ttl' => 86400, // Время жизни кеша сутки
            'cache_joins' => true // Кешировать ли выборки с JOIN
        ),
    ]);

    $elements = $elements->fetchAll();

    foreach ($elements as &$element){
        $element['DETAIL_PAGE_URL'] = \CIBlock::ReplaceDetailUrl($element['DETAIL_PAGE_URL'], $element, false, 'E');
        $element['HAVE_OFFERS'] = $element['TYPE'] != 1 ? true : false;
        $element['QUANTITY'] = $element['QUANTITY'] > $element['QUANTITY_STORE'] ? $element['QUANTITY'] : $element['QUANTITY_STORE'];

    }

Для свойств в отдельной таблице можно воспользоваться другой декларацией entityPropsSingle

//Свойства в отдельной таблице
$entityPropsSingle = \Bitrix\Main\Entity\Base::compileEntity(
    'PROPS_SINGLE_IB29',
    [
        'IBLOCK_ELEMENT_ID' => ['data_type' => 'integer'],
        'PROPERTY_335' => ['data_type' => 'integer'],
    ],
    [
        'table_name' => 'b_iblock_element_prop_s29',
    ]
);

Где свойство хранится в инфоблоке с ID 29, а само свойство имеет ID 335

Проверка на детальную страницу в header

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

public static function checkIsDetail() {
	global $APPLICATION;

	$IBLOCK_ID = 24;

	if(!\CModule::IncludeModule("iblock")) return false;
	$url = $APPLICATION->GetCurPage();

	$code = array_pop(array_filter(explode( '/',  $url)));
	$rsSections = \CIBlockSection::GetList([], ['IBLOCK_ID' => $IBLOCK_ID, '=CODE' => $code]);

	return ($rsSections->Fetch() !== false);
}

$is_section_page = self::checkIsDetail();

if(\CSite::InDir('/catalog/') && $APPLICATION->GetCurPage() !== '/catalog/' && $is_section_page){
	//Мы на детальной странице каталога
}

Получить все элементы из раздела и вложенных подразделов

$SECTION_ID = 5;
$IBLOCK_ID = 8;

$section = \Bitrix\Iblock\SectionTable::getByPrimary($SECTION_ID, [
    'filter' => ['IBLOCK_ID' => $IBLOCK_ID],
    'select' => ['LEFT_MARGIN', 'RIGHT_MARGIN'],
])->fetch();

$arItems = \Bitrix\Iblock\ElementTable::getList([
    'select' => ['ID', 'NAME', 'IBLOCK_ID'],
    'filter' => [
        'IBLOCK_ID' => $IBLOCK_ID,
        '>=IBLOCK_SECTION.LEFT_MARGIN' => $section['LEFT_MARGIN'],
        '<=IBLOCK_SECTION.RIGHT_MARGIN' => $section['RIGHT_MARGIN'],
    ],
]);

или так

$SECTION_ID = 5;
$IBLOCK_ID = 8;

$SECTION_IDS = getSubsections($SECTION_ID, $IBLOCK_ID);

function getSubsections(int $SECTION_ID, int $IBLOCK_ID): array
{
    $SECTION_IDS = [];
    $connection = \Bitrix\Main\Application::getConnection();
    $sql = sprintf('SELECT cs.ID FROM %1$s AS ps
                        INNER JOIN %1$s AS cs 
                        ON ps.LEFT_MARGIN <= cs.LEFT_MARGIN AND ps.RIGHT_MARGIN >= cs.RIGHT_MARGIN AND ps.IBLOCK_ID = cs.IBLOCK_ID
                        WHERE ps.ID = %2$d AND ps.IBLOCK_ID = %3$d',
        \Bitrix\Iblock\SectionTable::getTableName(),
        $SECTION_ID,
        $IBLOCK_ID
    );
    $result = $connection->query($sql);
    while ($section = $result->fetch()) {
        $SECTION_IDS[] = $section['ID'];
    }
    return $SECTION_IDS;
}

$arItems = \Bitrix\Iblock\ElementTable::getList([
    'select' => ['ID', 'NAME', 'IBLOCK_ID'],
    'filter' => [
        'IBLOCK_ID' => $IBLOCK_ID,
        'IBLOCK_SECTION_ID' => $SECTION_IDS,
    ],
]);

 

Стоит ознакомиться:

Комментарии

Комментариев еще нет, Вы можете стать первым кто его оставит

Оставьте комментарий

На сайте используется система премодерирования комментариев, поэтому ваше сообщение будет опубликовано лишь после одобрения модератором

Вы отвечаете на комментарий пользователя

Отправить

ОБРАТНАЯ СВЯЗЬ

Напишите мне

Вы разрабатываете новый сервис, вносите доработки в существующий и хотите лучше чем у конкурентов? Вы обратились по адресу. Предлагаю вам комплексную разработку сайтов студийного уровня. У меня вы можете заказать дизайн, верстку, програмированние, разработку нетрадиционного функционала, реализацию связи между CMS, CRM и Data Analitics, а так же все остальное касаемое сайтов, кроме продвижения.

Обращайтесь, я всегда проконсультирую по всем вопросам и помогу подобрать наиболее эффективное решение для Вашего бизнеса. Я занимаюсь созданием сайтов в Новосибирске и в других регионах России, также работаю со странами СНГ. Вы останетесь довольны нашим сотрудничеством

Во время отправки произошла ошибка, пожалуйста попробуйте еще раз через некоторое время
Сообщение отправлено успешно

Телефоны

+7(993) 007-18-96

Email

info@tichiy.ru

Адрес

Россия, г. Москва

Отправляя форму Вы автоматически подтверждаете, что ознакомились и принимаете Политику конфиденциальности сайта

Написать мне
Отправить
Отправляя форму Вы автоматически подтверждаете, что ознакомились и принимаете Политику конфиденциальности сайта
Отправка успешна!
Thank you for your feedback. I will answer you within the next working hours
Отправка не удалась
Во время отправки запроса произошла ошибка. Пожалуйста, подождите и попробуйте снова через некоторое время или свяжитесь со мной