Меню

Установить цену товара из свойства инфоблока

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

На одном из проектов, нужно было единоразово заполнить цены товаров из свойства инфоблока. Сделать это можно через API, методами CPrice::Update и CPrice::Add.

Копируем цену из свойства используя D7

Итак: имеем инфоблок, в котором, у каждого элемента заполнено свойство типа срока и называется "Минимальная цена" c кодом "ATT_PRICE". Нам нужно заполнить этим свойством, базовую цену. По сути, скопировать значение этого свойства в цену элемента.

Cоздаем в корне сайта файл addprice.php и добавляем в него код:

require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");

use Bitrix\Catalog\Model\Price;
use Bitrix\Main\Loader;
use Bitrix\Iblock\ElementPropertyTable;
use Bitrix\Iblock\ElementTable;

Loader::includeModule('catalog');

$iblockId = 3; // Идентификатор инфоблока
$catalogGroupId = 1; // ID типа цены
$propertyId = 33; // ID свойства из которого копируем

$elements = ElementTable::getList([
    'filter' => ['IBLOCK_ID' => $iblockId],
    'select' => ['ID'],
]);

while ($element = $elements->fetch()) {
    $propertyValue = ElementPropertyTable::getList([
        'filter' => [
            'IBLOCK_ELEMENT_ID' => $element['ID'],
            'IBLOCK_PROPERTY_ID' => $propertyId,
        ],
        'select' => ['VALUE'],
    ])->fetch();

    if ($propertyValue) {
        $priceValue = $propertyValue['VALUE'];

        $priceData = [
            'PRODUCT_ID' => $element['ID'],
            'CATALOG_GROUP_ID' => $catalogGroupId,
            'PRICE' => $priceValue,
            'CURRENCY' => 'RUB',
        ];

        $existingPrice = Price::getList([
            'filter' => [
                'PRODUCT_ID' => $element['ID'],
                'CATALOG_GROUP_ID' => $catalogGroupId,
            ],
        ])->fetch();

        if ($existingPrice) {
            Price::update($existingPrice['ID'], $priceData);
        } else {
            Price::add($priceData);
        }
    }
}

require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/epilog_after.php");

Открываем в браузере и ждем выполнения. Этот код использует D7 и методы \Bitrix\Catalog\Model\Price::add и \Bitrix\Catalog\Model\Price::update, как рекомендовано в документации. Он также использует \Bitrix\Iblock\ElementTable для получения элементов инфоблока, что является более современным подходом.

Постоянное обновление цены из свойства. Cron задание.

Если нужно, что бы цена обновлялась из свойства постоянно. Например, каталог обновляется автоимпортом, каждую ночь и цена пишется именно в свойство, а не в нормальное поле. Можно создать скрипт обновления и запускать его по cron. В директории /bitrix/php_interface/include/ создаем файл cron_price_refresher.php и добавляем в него:

$_SERVER["DOCUMENT_ROOT"] = realpath(dirname(__FILE__)."/../../..");
$DOCUMENT_ROOT = $_SERVER["DOCUMENT_ROOT"];

require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");

@set_time_limit(0);
define("NO_KEEP_STATISTIC", true);
define("NOT_CHECK_PERMISSIONS", true);

use Bitrix\Catalog\Model\Price;
use Bitrix\Main\Loader;
use Bitrix\Iblock\ElementPropertyTable;
use Bitrix\Iblock\ElementTable;

Loader::includeModule('catalog');

$iblockId = 3; // Идентификатор инфоблока
$catalogGroupId = 1; // ID типа цены
$propertyId = 33; // ID свойства из которого копируем

$elements = ElementTable::getList([
    'filter' => ['IBLOCK_ID' => $iblockId],
    'select' => ['ID'],
]);

while ($element = $elements->fetch()) {
    $propertyValue = ElementPropertyTable::getList([
        'filter' => [
            'IBLOCK_ELEMENT_ID' => $element['ID'],
            'IBLOCK_PROPERTY_ID' => $propertyId,
        ],
        'select' => ['VALUE'],
    ])->fetch();

    if ($propertyValue) {
        $priceValue = $propertyValue['VALUE'];

        $priceData = [
            'PRODUCT_ID' => $element['ID'],
            'CATALOG_GROUP_ID' => $catalogGroupId,
            'PRICE' => $priceValue,
            'CURRENCY' => 'RUB',
        ];

        $existingPrice = Price::getList([
            'filter' => [
                'PRODUCT_ID' => $element['ID'],
                'CATALOG_GROUP_ID' => $catalogGroupId,
            ],
        ])->fetch();

        if ($existingPrice) {
            Price::update($existingPrice['ID'], $priceData);
        } else {
            Price::add($priceData);
        }
    }
}

require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/epilog_after.php");

Здесь мы, подключили ядро битрикс, без шаблона и отключили статистику с проверкой прав. Добавляем выполнение этого кода в cron задания (в примере, каждое утро в 7 часов). Это /usr/bin/php81/bin/php -f - путь к интерпритатору php, на вашем окружении может отличаться


0 7 * * * /usr/bin/php81/bin/php -f /ПУТЬ_ДО_САЙТА_НА_СЕРВЕРЕ/bitrix/php_interface/include/cron_price_refresher.php

PS: Понятное дело, можно добавить обработчик с событиями обновления добавления элементов в init.php - но это не всегда подходит. Обновление цен с параллельной загрузкой каталога- ресурсоемкая процедура. На больших каталогах, потребуется либо мощный, дорогой сервер.

Guest 01.11.2021
А если в обратном порядке, базовую цену поместить в свойство.
Михаил Базаров 01.11.2021
Цитата
Guest написал:
А если в обратном порядке, базовую цену поместить в свойство.
С помощью метода CPrice::GetByID получить цену товара
С помощью CIBlockElement::Update и CIBlockElement::SetPropertyValues установить значение нужному свойству
Anton 07.09.2022
Добрый день, Михаил!
Подскажите, на сайте товар уже заполнен проставлены цены и есть товар новый, который только залился, тут цена в собственном поле хранится. Когда пытаюсь воспользоваться вашим примером цена из свойства кастомного записывается в поле с Ценой, но начинают создаваться дубли товара, во всем каталоге.
Ainur 26.10.2023
Надо использовать D7, класс \Bitrix\Catalog\PriceTable
Максим 07.08.2024
Добрый день!

А как выбрать элементы только в определенном разделе инфоблока?
Михаил Базаров 07.08.2024
В фильтр перебора элементов добавить 'IBLOCK_SECTION_ID' => 'ID нужного раздела'
Максим 07.08.2024
 Я так попробовал сделать выбирает только элементы указанного раздела, а у  меня родительский раздел и в нем подразделы и элементы, как быть в такой ситуации?

И еще вопрос у вас используется ElementTable::getList в документации Битрикса я так и не нашел упоминание такого метода. Может я не умею пользоваться... Как вы находите описание  этих методов?
Михаил Базаров 07.08.2024
Получи старым методом, у него есть параметр "INCLUDE_SUBSECTIONS" => "Y" позволит получить элементы из всех вложенных разделов, раздела 'IBLOCK_SECTION_ID' => 'ID нужного раздела'. А D7 методы в основном в исходниках находятся, приходиться туда лазить в их поиске.

Стоимость и сроки разработки сайтов и приложений

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

Интернет магазин: разработка с нуля от 400 000 руб.
от 5-ти недель

Cоздание интернет-магазина на 1С-Битрикс. Разработка с нуля, оптимизация кода под конкретный проект и требования. Реализация любого функционала без ограничений готовых решений.

Интернет-магазин на готовом решении от 100 000 руб.
от 7-ми дней

Готовое решение — вариант для тех, кто не хочет тратить много средств на индивидуальный проект, и не имеет серьезных требований к сайту. Запускается на одном из 200-та (на ваш выбор) готовых решений.

Мобильное приложение от 400 000 руб.
от 1-го месяца

Разработка кроссплатформенного мобильного приложения, которое не уступает нативным решениям как в производительности, так и пользовательском опыте. Публикуется в AppStore, GooglePlay и RuStore

Опросник на разработку. После ознакомления, задам уточняющие вопросы и оценю проект по стоимости и срокам разработки.