Перейти к содержанию

В торговом каталоге 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() || |#