Товары и каталог

Карточка товара, цена, варианты, остатки, тиры оптовых цен, продажа по заявке, управление каталогом, импорт CSV, массовые операции.

Товары и каталог

Каталог товаров живёт в текущей активной группе. Один товар может показываться сразу на нескольких сайтах и быть доступен нескольким агентам — это управляется правилами видимости.

Где создавать

/account/commerce → вкладка «Товары» → кнопка «Создать товар».

Поля карточки

ПолеОписание
НазваниеВидно покупателю и попадает в search_products LLM-tool.
SlugКороткое имя для URL /p/<slug>. Уникален в пределах группы. Заполняется автоматически из названия, можно править.
ОписаниеКраткий текст. LLM использует его при поиске и пересказе.
Подробное описание (long_description)Развёрнутый HTML-текст: преимущества, инструкция, история бренда. Отображается на странице товара как отдельная секция.
Характеристики (specs)Таблица пар «название — значение» (материал, вес, размер и т.д.). Рисуется таблицей под описанием, если секция включена.
Бейдж (badge)Короткая пометка в карточке: «Хит», «Новинка», «Акция». Плюс авто-бейдж скидки −N% появляется сам, когда задана comparePrice.
ЦенаВ рублях, хранится в копейках. Можно задать зачёркнутую цену (comparePrice) для отображения скидки.
ВалютаПо умолчанию RUB.
SKUОпциональный артикул для учёта.
ГалереяМассив картинок (url, alt). Первая используется как preview и og:image.
ВариантыРазмер / цвет / любой атрибут. Каждый вариант — со своим priceDelta к базе и собственным stock. Если массив пуст — товар без вариантов.
Остатки (stock)Целое число. Работает только при trackInventory=true. Декрементируется при paid, возвращается при cancel.
Учитывать остатки (trackInventory)Чек: если выключен — товар продаётся неограниченно (актуально для цифровых товаров).
ТегиМассив строк для AI-поиска и быстрых фильтров.
Требует доставки (requiresShipping)Если включено — в чекауте появляется блок адреса и способа доставки. Включает cash-on-delivery.
АктивенЕсли выключен — товар не виден в публичном каталоге и не находится через search_products.
Режим продажиbuy (оплата онлайн) или inquiry (по заявке — см. ниже).
54-ФЗ: paymentSubjectcommodity / service / job. Попадает в фискальный чек.
54-ФЗ: vatCode1 без НДС (по умолчанию, типично для УСН/самозанятых), 4 НДС 20% и т.д.

Страница товара /p/<slug>

Каждый товар получает публичную SSR-страницу по адресу /p/<slug>. Она наследует дизайн-систему проекта (--ds-* CSS-переменные), выглядит органично в стиле сайта и не требует отдельного шаблона.

Богатые секции рисуются, только если у товара есть данные под них и секция включена в настройках витрины:

  • Подробное описание (long_description) — sanitized-HTML с форматированием.
  • Таблица характеристик (specs).
  • Бейдж-лейбл + авто-бейдж скидки −N%.
  • Блок «Похожие товары» (авто-подбор по категориям/тегам).

SEO: Product JSON-LD, og:image, canonical. Товары попадают в sitemap.xml с корректным lastmod.

Клик по карточке в каталоге ведёт на эту страницу. В списке товаров кабинета — кнопка «Открыть на сайте».

Опт и количество

Настраивается в форме товара в блоке «Количество и оптовые цены».

Ограничения количества

ПараметрОписание
Минимум (minQuantity)Минимальное количество за заказ. По умолчанию 1.
Максимум (maxQuantity)Максимальное количество. Пусто = без ограничения.
Кратность (quantityStep)Шаг упаковки. Например, 6 — продаётся упаковками по 6 шт.
Единица измеренияПишется рядом с числом: «шт», «кг», «упак», «м» — до 20 символов.

Оптовые тиры цен

До 8 тиров формата «от N шт — цена за шт»:

От количестваЦена за шт
1 (базовая)1 500 ₽
51 350 ₽
201 100 ₽

На странице товара /p/<slug>:

  • Селектор количества −/+ (с учётом min/max/step).
  • Таблица оптовых диапазонов — активный тир подсвечен, у каждого тира бейдж экономии −X%.
  • Прогресс-бар «до скидки X% осталось Y ₽» (для скидок от суммы).
  • Динамическая сумма в кнопке «Купить» пересчитывается в реальном времени.

Тиры действуют и в quick-view модалке каталога.

Сервер всегда пересчитывает тиры сам (при создании черновика и при финализации заказа). Клиентской цене сервер не доверяет.

AI-агент видит опт-правила в ответе search_products и понимает ошибки типа «минимальный заказ — 5 шт».

Продажа «по заявке» (inquiry)

Для товаров, где оплата онлайн не нужна или невозможна: материалы на заказ, изделия под размер, B2B-позиции с договорной ценой.

Включение: в форме товара переключатель «Режим продажи» → «По заявке». В каталоге кабинета появляется бейдж «по заявке».

Флоу для покупателя:

  1. Клиент открывает страницу товара /p/<slug> или quick-view модалку.
  2. Выбирает количество (тиры применяются, сумма считается).
  3. Нажимает «Заказать» — открывается оверлей с формой: имя, телефон или email, комментарий.
  4. После отправки — лид попадает в CRM.

Что попадает в CRM (project_collection, source: product_inquiry):

  • Контакты покупателя (имя, email, телефон).
  • Снапшот выбора: название товара, количество, цена за единицу по тиру, итоговая сумма со скидкой корзины.
  • Геопривязка по IP.

Сумма в лиде совпадает с тем, что видел покупатель — считается сервером по тем же правилам, что и заказ.

Уведомления: email на адрес, указанный в настройках уведомлений проекта + push в кабинете.

Важно:

  • Работает без подключённого мерчант-аккаунта. Деньги онлайн не проводятся.
  • Стандартный чекаут (для buy-товаров) такие товары отклоняет — нельзя смешать в одну корзину.
  • AI-агент в режиме inquiry не создаёт заказ и не выставляет ссылку на оплату: вместо этого собирает контакты покупателя и сообщает, что менеджер свяжется.

Настройки витрины

/account/commerce → кнопка «Витрина» (диалог CommerceSettingsDialog).

Глобальные переключатели секций страниц товаров и услуг:

ПараметрЧто управляет
Подробное описаниеСекция long_description
ХарактеристикиТаблица specs
Похожие товарыБлок авто-подбора по категориям/тегам
Кол-во похожихЧисло карточек в блоке (1–12, по умолчанию 4)
Селектор количестваПоле −/+ на странице товара и в модалке
Оптовые ценыТаблица тиров с подсветкой активного
Прогресс скидкиПрогресс-бар «до скидки X% осталось Y ₽»

Секция рисуется, только если тумблер включён и у товара есть данные под неё.

Правила корзины группы

В том же диалоге настраиваются правила, применяемые к любому заказу в группе.

Минимальная сумма заказа (товарная часть, без доставки):

  • Если задана — заказы ниже порога отклоняются сервером.
  • На кнопке «Купить» показывается подсказка «не хватает N ₽».

Скидки от суммы корзины (до 6 порогов):

  • Формат: «от X ₽ — Y% скидки».
  • Применяются сервером при создании заказа; 54-ФЗ чек сходится копейка в копейку (скидка размазывается по юнит-ценам).
  • На странице товара → прогресс-бар «до скидки X% осталось Y ₽» (если включено).
  • В чекауте — строка «Скидка N%» и поле discount_amount / discount_percent на заказе.

Хранится в workspace.commerce_settings, контракт + дефолты — lib/commerceSettings.ts.

Категории

/account/commerce → вкладка «Категории».

  • Иерархия через self-FK (parentId): категория может иметь подкатегории.
  • Slug уникален в пределах группы.
  • Один товар через M2M (product_to_category) может быть в нескольких категориях. Например, «футболка» — в «Одежда» и в «Лето».
  • Категории общие для товаров и услуг: M2M service_to_category использует ту же таблицу. Полезно для смешанного каталога (косметология — товары + занятия в одной рубрике).

Видимость

По умолчанию товар виден везде в группе — на всех сайтах и у всех агентов. Если нужны исключения — заполните таблицы видимости:

  • Видимость по сайтам (product_site_visibility) — товар показывается только на выбранных сайтах.
  • Видимость по агентам (product_agent_visibility) — товар продаётся только указанными агентами.

Логика «пусто = виден всем» одинаковая для обеих таблиц. В карточке товара — бейдж «выборочно», если заданы конкретные сайты.

Управление каталогом

Inline-редактирование

Прямо в таблице/карточке — клик по цене или остатку переводит поле в режим редактирования. Изменение активности — переключатель без открытия формы. Всё с оптимистичным обновлением и откатом при ошибке.

Массовые операции

Выберите несколько товаров (чекбоксы) — появляется sticky-тулбар. Доступные действия:

  • Показать / скрыть (активен/неактивен).
  • Скрыть из продажи.
  • Добавить категорию.
  • Изменить цену на ±N% (двигает и comparePrice).
  • Добавить / убрать тег.

Бэкенд — POST /api/products/bulk с проверкой прав на каждый ID.

Импорт и экспорт CSV

Экспорт (GET /api/products/export): все товары группы в CSV с BOM для корректного открытия в Excel с кириллицей.

Импорт (ProductImportDialog + POST /api/products/import):

  • Клиентский CSV-парсер с авто-маппингом русских и английских заголовков.
  • Превью первых строк до фактической загрузки.
  • Режим create (только новые) или upsert (обновить по slug или SKU).
  • Построчный отчёт об ошибках после импорта.

Дублирование товара

POST /api/products/duplicate — копия со всеми полями, категориями и видимостью. Создаётся неактивной; slug и SKU авто-разводятся суффиксом, чтобы не конфликтовать.

Low-stock

  • Пилюля-фильтр «Заканчивается» в списке.
  • Бейдж «осталось N» (янтарный) в карточке и строке таблицы.
  • Per-товар порог low_stock_threshold (по умолчанию 5). API-фильтр lowStock сравнивает stock <= threshold.

AI-генерация карточки

POST /api/products/ai-generate: по названию генерируется описание, теги, SEO-описание, подбирается категория из уже существующих в группе. Расход токенов списывается с баланса owner'а (как генерация агента).

Поиск

Каталог индексируется через pg_trgm (GIN-индексы на name + description). Сортировки:

  • relevance — pg_trgm similarity (name ×2 + description);
  • price_asc / price_desc;
  • newest.

LLM-tool search_products бьёт по тому же индексу — скорость и качество одинаковы что в чате, что в UI.

Что хранится в БД

ТаблицаЧто
commerce_productКарточка товара (включая priceTiers jsonb, specs jsonb, salesMode, minQuantity, maxQuantity, quantityStep, unitLabel)
product_categoryКатегории (иерархия через parentId)
product_to_categoryM2M товар ↔ категория
product_site_visibilityВидимость по сайтам (пусто = везде)
product_agent_visibilityВидимость по агентам (пусто = всем)