Заполнить свойство инфоблока ценой из торгового каталога

Просмотров: 6308

Если вам по какой-то причине нужно скопировать цену товара в свойство этого же инфоблока. Например, для вывода старой цены в редакции Битрикс "Малый бизнес" (цена товара за минусом какого-то процента). Можно воспользоваться данной заметкой.

Итак: у нас есть инфоблок торгового каталога, в котором мы хотим заполнить свойство типа число (или строка) стоимостью элемента. В моем случае, код этого свойства "ATT_PRICE"

Единоразовое заполнение или по необходимости

Если нужно выполнить заполнение один раз или в ручную, по необходимости.

Создаем новую страничку на сайте (можно ограничить к ней доступ, только для администраторов) и вставляем туда такой код, подсказки по коду, прямо внутри:

CModule::IncludeModule('iblock');
CModule::IncludeModule('catalog');
CModule::IncludeModule('currency');

$IBLOCK_ID = 34; //Инфоблок с которым работаем

//Получаем ID всех элементов
$addProps = CIBlockElement::GetList (
	Array("ID" => "ASC"),
	Array("IBLOCK_ID" => $IBLOCK_ID),
		false,
		false,
		Array(
			'ID'
		)
);
while($ar_fields = $addProps->GetNext())
{
$arProductID =  $ar_fields['ID'];
//Узнаем цену элемента
    $rsPrices = CPrice::GetList(
        array(),
        array(
            "PRODUCT_ID" => $arProductID,
        )
    );
    while($arPrice = $rsPrices->Fetch())
    //Передаем цену в переменную
    {
       $PropPrice = $arPrice["PRICE"];
    }
    //Заполняем свойство с кодом "ATT_PRICE" ценой
    CIBlockElement::SetPropertyValuesEx(
        $arProductID,
        $IBLOCK_ID,
        array(
            "ATT_PRICE" => $PropPrice,
        )
    );
}

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

Далее, можете выполнять этот код в ручную или повесить выполнение на крон.

Постоянная работа скрипта. Обработчик в init.php

Если вам нужно, что бы свойство ATT_PRICE обновлялось постоянно, при каждом добавлении товаров и обновлении цен. Например, при обмене с 1С

Можете добавить обработчик в init.php. Код основан на томже, что приведен выше, в принципе выполняет теже самые действия по событиям обновления/добавления элементов

AddEventHandler("iblock", "OnAfterIBlockElementUpdate", "DoIBlockAfterSave");
AddEventHandler("iblock", "OnAfterIBlockElementAdd", "DoIBlockAfterSave");
AddEventHandler("catalog", "OnPriceAdd", "DoIBlockAfterSave");
AddEventHandler("catalog", "OnPriceUpdate", "DoIBlockAfterSave");

function DoIBlockAfterSave($arg1, $arg2 = false) {
    CModule::IncludeModule('iblock');
    CModule::IncludeModule('catalog');
    CModule::IncludeModule('currency');

    $IBLOCK_ID = 34;
    $ELEMENT_ID = null;

    if (is_array($arg2) && isset($arg2["PRODUCT_ID"]) && $arg2["PRODUCT_ID"] > 0) {
        $ELEMENT_ID = $arg2["PRODUCT_ID"];
    } elseif (is_array($arg1) && isset($arg1["ID"]) && $arg1["ID"] > 0) {
        $arElementFields = CIBlockElement::GetByID($arg1["ID"])->GetNext();
        if (in_array($arElementFields["IBLOCK_ID"], array($IBLOCK_ID))) {
            $ELEMENT_ID = $arg1["ID"];
        }
    }

    if ($ELEMENT_ID) {
        $arProductID = array($ELEMENT_ID);

        $rsProperty = CIBlockProperty::GetByID("PRICE", $IBLOCK_ID);
        if ($arProperty = $rsProperty->Fetch()) {
            $arPropCache[$IBLOCK_ID] = $arProperty["ID"];
        } else {
            // Обработка ситуации, если свойство PRICE не найдено
            return;
        }

        $rsPrices = CPrice::GetList(
            array(),
            array(
                "PRODUCT_ID" => $arProductID,
            )
        );

        $PropPrice = null;
        while ($arPrice = $rsPrices->Fetch()) {
            $PRICE = $arPrice["PRICE"];
            $PropPrice = $PRICE; // Если нужно агрегировать цены, изменить логику здесь
        }

        if ($PropPrice !== null) {
            CIBlockElement::SetPropertyValuesEx(
                $ELEMENT_ID,
                $IBLOCK_ID,
                array(
                    "ATT_PRICE" => $PropPrice,
                )
            );
        }
    }
}

Полезные дополнения:

Если хотите сконвертировать цену в другую валюту. Например: цена в каталоге указана в долларах, а в свойство должна попасть в рублях по курсу модуля валют.

Воспользуйтесь методом CCurrencyRates::ConvertCurrency в части получения цены товара

$strDefaultCurrency = CCurrency::GetBaseCurrency();
$arPrice["PRICE"] = CCurrencyRates::ConvertCurrency($arPrice["PRICE"], $arPrice["CURRENCY"], $strDefaultCurrency);
$PRICE = $arPrice["PRICE"];
$PropPrice = $PRICE;

Если нужно получить больше информации о свойстве ATT_PRICE. Например получить ее ID, проверить на заполненность итд. Воспользуйтесь методом CIBlockProperty::GetByID:

$rsProperty = CIBlockProperty::GetByID("ATT_PRICE", $IBLOCK_ID);
$arProperty = $rsProperty->Fetch();
$arPropCache[$IBLOCK_ID] = $arProperty["ID"];
Алексей 02.05.2024
Доброго дня.
Вдруг кому будет интересно.
Если у вас несколько типов цен, то чтобы брать верный - нужно добавить строку в код с ID типа цены:
Код
//Узнаем цену элемента
    $rsPrices = CPrice::GetList(
        array(),
        array(
            "PRODUCT_ID" => $arProductID,
            "CATALOG_GROUP_ID" => "9" // здесь ID вашего типа цены вместо 9
        )
    );
Иначе поле будет заполнятся ценой с самым большим ID по умолчанию.