В торговом каталоге API выбирают по задаче. Чтение, запись данных, карточка товара и складские операции работают через разные классы. Если перепутать их, цена не попадет в расчет. Остаток изменится без складского движения, элемент инфоблока не станет товаром, а события модуля не сработают.
Сначала определите, что меняется: карточка товара, товарные параметры, цена, складской остаток, скидка, купон, комплект, подписка или профиль обмена. Затем выберите, чем работать: ORM-таблицей, D7-моделью или классическим API. После записи проверьте данные через ORM-таблицу, например \Bitrix\Catalog\ProductTable или \Bitrix\Catalog\PriceTable.
Поля, связи и роли объектов описаны в статье Схема работы торгового каталога и основные объекты. В таблицах ниже для типовых задач указаны задача, основной метод и пояснение, почему подходит именно он.
Внимание
Перед операциями с товарами подключите модули iblock и catalog. Для купонов, корзины, заказа и расчета скидок может понадобиться модуль sale.
Как выбрать между ORM, D7-моделями и классическим API
Разделите задачу по ответственности. Чтение, запись и операции с внутренними правилами каталога решают разные группы классов.
Читайте через ORM-таблицы D7. Если нужно получить товары, цены, остатки, склады, типы цен или справочники, используйте классы вида \Bitrix\Catalog\*Table. Например, \Bitrix\Catalog\ProductTable::getList() или \Bitrix\Catalog\PriceTable::getList(). Эти классы подходят для выборок, фильтров, сортировки и проверки результата после записи.
Записывайте товарные данные через D7-модели. Если нужно создать, обновить или удалить товарные параметры, цену или НДС, используйте классы \Bitrix\Catalog\Model\Product, \Bitrix\Catalog\Model\Price, \Bitrix\Catalog\Model\Vat. Модели проверяют данные и возвращают объект результата. Он содержит ошибки валидации, которые можно обработать сразу.
Классическое API запускает правила каталога. С помощью классических методов регистрируют каталог, связывают торговые предложения, проводят складские документы, создают комплекты, скидки и профили обмена. В таких задачах нужно создать связи, пересчитать состояние или провести документ.
Например, карточку товара создают через API инфоблоков, товарные параметры и цену оформляют отдельными методами каталога, а складское движение проводят документом.
Не заменяйте API прямой записью в таблицы. Прямая запись может обойти проверки, события и пересчет доступности.
Товары и торговые предложения
Товар в каталоге состоит из карточки инфоблока и товарной записи. Карточка хранит контент, а товарная запись включает элемент в логику продажи: тип товара, остаток, доступность и другие параметры.
Для простого товара цена и остаток относятся к самому товару. Для товара с торговыми предложениями цена и остаток относятся к конкретному предложению. Родительская карточка хранит общее описание: например, название модели, изображения и свойства, общие для всех вариантов.
|
|| Задача | Метод | Пояснение ||
|| Создать инфоблок товаров | \CIBlock::Add() | Инфоблок хранит карточки товаров: названия, коды, свойства, разделы и изображения ||
|| Зарегистрировать инфоблок как каталог | \CCatalog::Add() | Регистрация подключает к инфоблоку цены, остатки, типы товаров и связь с торговыми предложениями ||
|| Шаг 1: создать карточку товара | \CIBlockElement::Add() | Карточка товара остается элементом инфоблока, поэтому контентные поля создают через API инфоблоков ||
|| Шаг 2: добавить товарные параметры | \Bitrix\Catalog\Model\Product::add() | Без товарной записи элемент останется карточкой и не станет товаром каталога ||
|| Создать родительский товар | \Bitrix\Catalog\Model\Product::add() с типом TYPE_SKU | Родительская карточка хранит общее описание товара, а цена и остаток относятся к торговым предложениям ||
|| Создать торговое предложение | \Bitrix\Catalog\Model\Product::add() с типом TYPE_OFFER | Торговое предложение хранит конкретный вариант товара, его цену и остаток ||
|| Создать услугу | \Bitrix\Catalog\Model\Product::add() с типом TYPE_SERVICE | Услуга продается как позиция каталога без складского остатка ||
|| Получить товарные параметры | \Bitrix\Catalog\ProductTable::getList() | ORM-таблица подходит для чтения типа товара, остатка и флага доступности без изменения данных ||
|| Обновить товарные параметры | \Bitrix\Catalog\Model\Product::update() | D7-модель меняет товарную запись и возвращает ошибки, если данные не прошли проверку ||
|| Получить торговые предложения товара | \CCatalogSKU::getOffersList() | Метод учитывает связь родительского товара с инфоблоком предложений и группирует варианты по товару ||
|| Получить предложения перед удалением товара | \CCatalogSKU::getOffersList() | Метод возвращает варианты товара, которые нужно обработать до удаления родительской карточки ||
|| Удалить карточку товара или предложения | \CIBlockElement::Delete() | Карточку предложения удаляют до родительского товара, чтобы не оставить варианты без товара ||
|#
Правило для торговых предложений: если у товара есть варианты, передавайте в PRODUCT_ID идентификатор предложения $offerId. Не используйте идентификатор родительского товара $productId для цены и остатка продаваемого варианта.
Базовые настройки: типы цен, НДС и единицы измерения
Подготовьте базовые настройки до массового создания товаров. Тип цены определяет, кто видит цену и может купить товар. НДС влияет на расчет налога. Единица измерения и коэффициент продажи задают, в каких количествах товар можно заказать.
|
|| Задача | Метод | Пояснение ||
|| Получить базовый тип цены | \Bitrix\Catalog\GroupTable::getBasePriceType() | Базовый тип цены нужен перед созданием первой цены товара ||
|| Создать тип цены | \CCatalogGroup::Add() | Классический метод сразу задает тип цены, языковые названия и права групп ||
|| Проверить права на тип цены | \Bitrix\Catalog\GroupAccessTable::getList() | Цена может существовать, но пользователь не увидит ее без прав на просмотр или покупку ||
|| Создать ставку НДС | \Bitrix\Catalog\Model\Vat::add() | D7-модель создает ставку с проверкой полей и возвращает ошибки в объекте результата ||
|| Назначить НДС товару | \Bitrix\Catalog\Model\Product::update() | НДС относится к товарной записи, поэтому его назначают через модель товара ||
|| Создать единицу измерения | \Bitrix\Catalog\MeasureTable::add() | Единицы измерения хранятся в справочнике каталога и затем назначаются товарам ||
|| Назначить единицу измерения товару | \Bitrix\Catalog\Model\Product::update() | Поле MEASURE находится в товарной записи, поэтому его меняют через модель товара ||
|| Добавить коэффициент продажи | \Bitrix\Catalog\MeasureRatioTable::add() | Метод создает шаг продажи для товара: например, покупать по одной штуке или упаковками ||
|| Обновить коэффициент продажи | \Bitrix\Catalog\MeasureRatioTable::update() | Метод меняет существующий шаг продажи, если коэффициент для товара уже задан ||
|#
Если пользователь видит товар, но не видит цену или не может купить по ней, проверьте не только товар и остаток. Часто причина в правах на тип цены.
Цены
Цена хранится отдельно от карточки товара и товарных параметров. Для одного товара можно хранить несколько цен: базовую, оптовую, цены в разных валютах и диапазонные цены для количества.
Перед обновлением цены найдите существующую запись по паре PRODUCT_ID и CATALOG_GROUP_ID. Если запись есть, обновите ее. Если записи нет, создайте новую. Такой порядок защищает от дублей цен.
|
|| Задача | Метод | Пояснение ||
|| Добавить цену товару | \Bitrix\Catalog\Model\Price::add() | Цена хранится отдельно от карточки и товарных параметров, поэтому ее создают отдельной моделью ||
|| Получить цены товара | \Bitrix\Catalog\PriceTable::getList() | ORM-таблица подходит для чтения всех цен товара по типам цен и валютам ||
|| Найти существующую цену перед изменением | \Bitrix\Catalog\Model\Price::getList() | Метод проверяет, есть ли цена для пары PRODUCT_ID и CATALOG_GROUP_ID ||
|| Обновить существующую цену | \Bitrix\Catalog\Model\Price::update() | Метод меняет найденную запись цены и не создает дубль для того же типа цены ||
|| Создать цену, если записи нет | \Bitrix\Catalog\Model\Price::add() | Метод создает новую цену, если для товара и типа цены еще нет записи ||
|| Создать диапазонную цену | \Bitrix\Catalog\Model\Price::add() с QUANTITY_FROM и QUANTITY_TO | Диапазонная цена нужна, когда стоимость зависит от количества товара ||
|| Получить цену для количества | \CCatalogProduct::GetNearestQuantityPrice() | Метод выбирает подходящую диапазонную цену для заданного количества ||
|| Рассчитать итоговую цену | \CCatalogProduct::GetOptimalPrice() | Метод учитывает права пользователя, скидки, купоны, диапазонные цены и сайт ||
|| Округлить цену по правилам типа цены | \Bitrix\Catalog\Product\Price::roundPrice() | Метод применяет правила округления, настроенные для типа цены ||
|#
Не храните рабочую цену только в свойстве инфоблока. Корзина, заказ, скидки и права на типы цен работают с ценами каталога.
Склады и остатки
Остаток можно менять двумя способами. Если складской учет выключен, общий остаток хранится в товарной записи. Если складской учет включен и товар реально движется между складами, работайте через складские документы.
|
|| Задача | Метод | Пояснение ||
|| Обновить общий остаток и доступность | \Bitrix\Catalog\Model\Product::update() | Подходит для общего остатка, если складской учет выключен и движение по складам не нужно фиксировать документом ||
|| Создать склад | \CCatalogStore::Add() | Склад нужен до записи складских остатков и оформления складских документов ||
|| Получить список складов | \Bitrix\Catalog\StoreTable::getList() | ORM-таблица помогает выбрать склад для остатка, документа или проверки данных ||
|| Создать поставщика | \CCatalogContractor::add() | Поставщик нужен для приходных документов и истории поступления товаров ||
|| Добавить начальный остаток при первичной загрузке | \CCatalogStoreProduct::Add() | Метод создает запись остатка для стартовой загрузки, а не для обычного движения товара ||
|| Обновить начальный остаток при первичной загрузке | \CCatalogStoreProduct::UpdateFromForm() | Метод меняет существующую запись остатка при служебной корректировке ||
|| Проверить остатки по складам | \Bitrix\Catalog\StoreProductTable::getList() | Таблица показывает остатки конкретного товара или предложения по складам ||
|| Создать складской документ | \CCatalogDocs::add() | Документ сохраняет причину движения товара: приход, списание, перемещение или возврат ||
|| Провести документ | \CCatalogDocs::conductDocument() | Только проведенный документ меняет складские остатки ||
|| Отменить проведение | \CCatalogDocs::cancellationDocument() | Отмена снимает влияние документа без удаления истории операции ||
|#
При рабочем складском учете не меняйте остатки прямой записью для сценариев с движением товара. Складской документ сохраняет саму операцию и меняет остатки после проведения.
Комплекты и наборы
Комплект продается как составной товар. Набор хранит рекомендации или связанные товары. Оба сценария работают через \CCatalogProductSet, но используют разные типы: TYPE_SET для комплекта и TYPE_GROUP для набора.
|
|| Задача | Метод | Пояснение ||
|| Создать товар-комплект | \Bitrix\Catalog\Model\Product::add() с типом \Bitrix\Catalog\ProductTable::TYPE_SET | Тип TYPE_SET сообщает каталогу, что товар продается как составной ||
|| Добавить состав комплекта | \CCatalogProductSet::add() с \CCatalogProductSet::TYPE_SET | Состав комплекта хранится отдельно от карточки товара и задается через \CCatalogProductSet ||
|| Получить состав комплекта | \CCatalogProductSet::getAllSetsByProduct() | Метод возвращает товары, которые входят в комплект ||
|| Изменить состав комплекта | \CCatalogProductSet::update() | Обновление заменяет состав на массив ITEMS, поэтому передавайте старые элементы заново, если они должны остаться ||
|| Создать набор рекомендаций | \CCatalogProductSet::add() с \CCatalogProductSet::TYPE_GROUP | Тип TYPE_GROUP описывает рекомендованные товары, а не состав продаваемого комплекта ||
|| Удалить комплект или набор | \CCatalogProductSet::delete() | Удаление убирает связь товаров из комплекта или набора ||
|#
Не путайте комплект и набор. Комплект участвует в продаже как составной товар, а набор описывает рекомендации.
Скидки, купоны и подписки
Цена хранит исходную стоимость. Скидка меняет итоговую стоимость при расчете. Купон включает условие для скидки, а подписка помогает оформить уведомление о поступлении товара.
|
|| Задача | Метод | Пояснение ||
|| Создать скидку на товар | \CCatalogDiscount::Add() | Скидка хранит правило изменения цены и участвует в расчете итоговой стоимости ||
|| Создать купон | \Bitrix\Catalog\DiscountCouponTable::add() | Купон создают отдельной записью и связывают со скидкой через DISCOUNT_ID ||
|| Включить купоны для скидки | \Bitrix\Catalog\DiscountTable::setUseCoupons() | Флаг включает расчет скидки только по купону ||
|| Добавить купон в расчет | \Bitrix\Sale\DiscountCouponsManager::add() | Менеджер купонов передает купон в расчет цены с учетом модуля sale ||
|| Получить список активных скидок | \CCatalogDiscount::GetDiscountByProduct() | Метод показывает, какие скидки подходят товару, группам пользователя, типу цены и сайту ||
|| Подписать пользователя на наличие товара | \Bitrix\Catalog\Product\SubscribeManager::addSubscribe() | Подписка привязана к товару или предложению и хранит контакт для уведомления о поступлении ||
|#
Не рассчитывайте скидку вручную. \CCatalogProduct::GetOptimalPrice() учитывает группы пользователя, купоны, диапазонные цены и сайт.
Импорт и экспорт
Импорт и экспорт работают через профили и PHP-шаблоны. Профиль отвечает за запуск, а шаблон выполняет обработку данных проекта.
|
|| Задача | Метод | Пояснение ||
|| Подготовить шаблон экспорта | PHP-шаблон экспорта | Шаблон описывает, какие данные выгружать и в каком формате ||
|| Создать профиль экспорта | \CCatalogExport::Add() | Профиль хранит настройки запуска экспорта и связывает их с шаблоном ||
|| Запустить экспорт по профилю | \CCatalogExport::PreGenerateExport() | Метод запускает профиль и подключает рабочий шаблон экспорта ||
|| Получить список профилей экспорта | \CCatalogExport::GetList() | Метод возвращает профили экспорта для программной проверки настроек ||
|| Получить профиль экспорта по идентификатору | \CCatalogExport::GetByID() | Метод возвращает настройки одного профиля экспорта ||
|| Обновить профиль экспорта | \CCatalogExport::Update() | Метод меняет настройки существующего профиля без ручной настройки в интерфейсе ||
|| Подготовить шаблон импорта | PHP-шаблон импорта | Шаблон описывает, как файл или внешний источник обновляет карточки, товарные параметры и цены ||
|| Создать профиль импорта | \CCatalogImport::Add() | Профиль хранит настройки запуска импорта и связывает их с шаблоном ||
|| Запустить импорт по профилю | \CCatalogImport::PreGenerateImport() | Метод запускает профиль и подключает рабочий шаблон импорта ||
|| Получить список профилей импорта | \CCatalogImport::GetList() | Метод возвращает профили импорта для программной проверки настроек ||
|| Получить профиль импорта по идентификатору | \CCatalogImport::GetByID() | Метод возвращает настройки одного профиля импорта ||
|| Обновить профиль импорта | \CCatalogImport::Update() | Метод меняет настройки существующего профиля импорта ||
|#
Внимание
Шаблон импорта или экспорта — это PHP-код проекта. Не передавайте в имя шаблона значения из запроса пользователя.
Типичные ошибки в коде каталога
Большинство ошибок в API каталога возникает не из-за синтаксиса, а из-за неверного уровня API. Метод может выполниться без явной ошибки, но данные окажутся не там, где их ждут корзина, складской учет или расчет скидок.
|
|| Ошибка | Почему возникает проблема | Как делать ||
|| Создать элемент инфоблока и не добавить товарные параметры | Элемент останется карточкой, но не станет товаром каталога | После создания карточки вызывайте \Bitrix\Catalog\Model\Product::add() ||
|| Добавить цену родительскому товару с торговыми предложениями | Покупатель выбирает предложение, а цена должна относиться к продаваемому варианту | Передавайте идентификатор предложения в PRODUCT_ID ||
|| Создать новую цену без проверки существующей | Для одной пары товар и тип цены может появиться дубль | Сначала ищите цену через \Bitrix\Catalog\Model\Price::getList() ||
|| Хранить рабочую цену в свойстве инфоблока | Корзина, заказы, скидки и права на типы цен читают цены каталога | Работайте с ценой через модель \Bitrix\Catalog\Model\Price ||
|| Менять складские остатки напрямую при рабочем складском учете | Система не сохранит движение товара в документе | Проводите изменение остатка через складской документ ||
|| Читать цены или остатки в цикле по списку товаров | Возникают лишние запросы к базе. На большом каталоге страница начнет работать медленнее | Соберите идентификаторы товаров в массив и сделайте одну выборку с фильтром по списку ||
|| Рассчитывать скидку вручную | Ручной расчет может пропустить права пользователя, купоны, диапазонные цены и настройки сайта | Используйте \CCatalogProduct::GetOptimalPrice() ||
|#
Сводная таблица устаревших методов
Старые методы могут встречаться в проектах, которые давно используют модуль catalog. При поддержке такого кода сначала проверьте текущий сценарий и риски замены. Для нового кода, новых примеров и автоматической генерации используйте классы из колонки Актуальная замена.
|
|| Задача | Устаревшие методы | Актуальная замена ||
|| Создать товарные параметры | \CCatalogProduct::Add() | \Bitrix\Catalog\Model\Product::add() ||
|| Обновить товарные параметры | \CCatalogProduct::Update() | \Bitrix\Catalog\Model\Product::update() ||
|| Удалить товарные параметры | \CCatalogProduct::Delete() | \Bitrix\Catalog\Model\Product::delete() ||
|| Создать цену | \CPrice::Add() | \Bitrix\Catalog\Model\Price::add() ||
|| Обновить цену | \CPrice::Update() | \Bitrix\Catalog\Model\Price::update() ||
|| Удалить цену | \CPrice::Delete() | \Bitrix\Catalog\Model\Price::delete() ||
|| Получить базовый тип цены | \CCatalogGroup::GetBaseGroup() | \Bitrix\Catalog\GroupTable::getBasePriceType() ||
|| Получить идентификатор базового типа цены | \CCatalogGroup::GetBaseGroupId() | \Bitrix\Catalog\GroupTable::getBasePriceTypeId() ||
|| Создать ставку НДС | \CCatalogVat::Add() | \Bitrix\Catalog\Model\Vat::add() ||
|| Обновить ставку НДС | \CCatalogVat::Update() | \Bitrix\Catalog\Model\Vat::update() ||
|| Удалить ставку НДС | \CCatalogVat::Delete() | \Bitrix\Catalog\Model\Vat::delete() ||
|| Создать единицу измерения | \CCatalogMeasure::add() | \Bitrix\Catalog\MeasureTable::add() ||
|| Обновить единицу измерения | \CCatalogMeasure::update() | \Bitrix\Catalog\MeasureTable::update() ||
|| Удалить единицу измерения | \CCatalogMeasure::delete() | \Bitrix\Catalog\MeasureTable::delete() ||
|| Передать купон в расчет скидки | \CCatalogDiscount::SetCoupon() | \Bitrix\Sale\DiscountCouponsManager::add() ||
|| Получить купоны для расчета | \CCatalogDiscount::GetCoupons() | \Bitrix\Sale\DiscountCouponsManager ||
|| Очистить купоны расчета | \CCatalogDiscount::ClearCoupon() | \Bitrix\Sale\DiscountCouponsManager ||
|| Определить инфоблок предложений по товару | \CCatalog::GetSkuInfoByProductID() | \CCatalogSKU::GetInfoByProductIBlock() ||
|| Определить связь предложений по свойству | \CCatalog::GetSkuInfoByPropID() | \CCatalogSKU::GetInfoByLinkProperty() ||
|| Получить расширенную информацию о каталоге | \CCatalog::GetByIDExt() | \CCatalogSKU::GetInfoByIBlock() ||
|#