Главная » Интернет-магазин » Каталог » CCatalogProduct и CPrice — цена и остаток товара в Битрикс

CCatalogProduct и CPrice — цена и остаток товара в Битрикс

Схема изменения цены и остатка товара через CPrice и CCatalogProduct в модуле Каталог Битрикс

Цена и торговые параметры товара в модуле "Каталог" хранятся отдельно от самого элемента инфоблока — в собственных таблицах, с которыми работают классы CCatalogProduct и CPrice. Разберём, как читать и менять цену и остаток программно, не через админку.

Почему цена — это не свойство элемента

Товар в 1С-Битрикс — это элемент инфоблока, а его торговые параметры (цена, остаток на складе, вес, единица измерения) хранятся в отдельных таблицах модуля catalog, привязанных к тому же ID элемента. Поэтому смена цены не делается через CIBlockElement::Update — для этого есть отдельные классы.

Чтение цены товара

<?php

use Bitrix\Main\Loader;

Loader::includeModule('catalog');

$priceResult = CPrice::GetList(
    [],
    ['PRODUCT_ID' => $productId, 'CATALOG_GROUP_ID' => 1] // базовая группа цен
);

$price = $priceResult->Fetch();

echo $price['PRICE'] . ' ' . $price['CURRENCY'];

CATALOG_GROUP_ID — тип цены (базовая, оптовая, розничная и так далее), настроенных в разделе МагазинНастройкиТипы цен. У товара может быть несколько записей цены — по одной на каждый настроенный тип.

Нужна помощь с Битрикс?





    Установка новой цены

    <?php
    
    $existingPrice = CPrice::GetList(
        [],
        ['PRODUCT_ID' => $productId, 'CATALOG_GROUP_ID' => 1]
    )->Fetch();
    
    if ($existingPrice) {
        CPrice::Update($existingPrice['ID'], ['PRICE' => 1990]);
    } else {
        CPrice::Add([
            'PRODUCT_ID' => $productId,
            'CATALOG_GROUP_ID' => 1,
            'PRICE' => 1990,
            'CURRENCY' => 'RUB',
        ]);
    }

    Обязательная проверка на существующую запись перед добавлением — CPrice::Add не заменяет значение автоматически, а создаёт новую запись, из-за чего у товара может появиться несколько цен одного типа, если проверку пропустить.

    Остаток товара через CCatalogProduct

    <?php
    
    CCatalogProduct::Update($productId, [
        'QUANTITY' => 42,
        'QUANTITY_TRACE' => 'Y', // включён учёт остатков
    ]);
    
    $product = CCatalogProduct::GetByID($productId);
    echo $product['QUANTITY'];

    CCatalogProduct отвечает за параметры, не связанные с ценой напрямую: остаток на складе, признак товара/услуги, и другие торговые настройки. Если учёт остатков включён (QUANTITY_TRACE = 'Y'), товар с нулевым остатком считается недоступным для заказа в зависимости от общих настроек каталога.

    Массовое изменение цен через агента

    <?php
    
    function updatePricesForCategory(int $sectionId, float $percent): string
    {
        Loader::includeModule('iblock');
        Loader::includeModule('catalog');
    
        $result = CIBlockElement::GetList(
            [], ['SECTION_ID' => $sectionId, 'ACTIVE' => 'Y'], false, false, ['ID']
        );
    
        while ($el = $result->GetNext()) {
            $price = CPrice::GetList([], ['PRODUCT_ID' => $el['ID'], 'CATALOG_GROUP_ID' => 1])->Fetch();
    
            if ($price) {
                $newPrice = round($price['PRICE'] * (1 + $percent / 100), 2);
                CPrice::Update($price['ID'], ['PRICE' => $newPrice]);
            }
        }
    
        return 'updatePricesForCategory(' . $sectionId . ', ' . $percent . ');';
    }

    Массовую переоценку удобно запускать агентом — функция возвращает саму себя строкой, что нужно только если планируется повторный запуск по расписанию; для разового пересчёта достаточно вызвать функцию напрямую в консоли или обработчике события.

    Работа с валютой

    Значение PRICE в CPrice хранится строго в валюте, указанной в поле CURRENCY той же записи. Конвертация между валютами при выводе цены на сайте выполняется модулем currency по текущему курсу и не меняет само хранимое значение — стоит избегать ручного пересчёта цены на лету в обход штатного механизма валют, чтобы не рассинхронизировать отображаемую и хранимую цену.

    Частые ошибки

    • CPrice::Add без проверки существующей записи. У товара появляется несколько цен одного типа вместо обновления существующей.
    • Попытка изменить цену через CIBlockElement::Update. Цена не хранится в элементе инфоблока — метод её просто не увидит.
    • Не подключён модуль catalog перед вызовом классов. Классы CPrice и CCatalogProduct недоступны без явного Loader::includeModule.
    • Ручной пересчёт валюты в обход модуля currency. Хранимая и отображаемая цена расходятся при изменении курса.

    Итог

    Цена и остаток товара — отдельная сущность от элемента инфоблока, за которую отвечают CPrice и CCatalogProduct модуля "Каталог". Перед изменением цены через CPrice::Add нужно проверить, нет ли уже записи для этого товара и типа цены, иначе вместо обновления появится дубликат.

    Нужна помощь с Битрикс?

    Исправим ошибку, доработаем сайт, ускорим Битрикс или поможем разобраться с проблемой.

    Услуги
    База знаний