# Qwelp Badges

## О модуле

Модуль `qwelp.badges` назначает текстовые бейджи товарам и торговым предложениям по условиям и ручному выбору. Он использует собственные таблицы, административный интерфейс, стили и публичный компонент. Зависимости: штатные `main`, `iblock`, `catalog`, `currency`. Модуль `sale` для фильтров не требуется.

Заявленный минимум — PHP 8.2 и `main` 23.0. База данных — MySQL или MariaDB. Поддержка других СУБД не заявлена. Требуются редакция с торговым каталогом и UTF-8. Установка полного пакета выполняется в `/bitrix/modules/qwelp.badges/`; исходники при разработке могут находиться в `/local/modules/qwelp.badges/`.

## Настройка

1. Установите модуль через административный список партнёрских решений. Откройте «Квэлп → Бейджи».
2. Создайте бейдж: внутреннее название, уникальный код строчными латинскими буквами, тексты RU/EN, сайты, места показа, период, приоритет и оформление. Меньшее число приоритета выводится раньше. Для одной группы взаимоисключения остаётся первый бейдж.
3. Создайте одно или несколько правил. Выберите каталог, сайт, бейдж и объект проверки. Соберите условия штатным деревом Битрикса с группами И/ИЛИ и отрицанием. Пустое дерево не означает «весь каталог»: для этого есть отдельный переключатель.
4. Используйте «Подходящие товары» у сохранённого правила и «Проверка товара». Список проверяется порциями по 200 записей; указанный счётчик относится к порции, а не ко всему каталогу.
5. Для исключения из правил откройте «Назначения» или вкладку «Бейджи» в штатной форме товара/SKU. Режимы: автоматически, показывать, скрывать.

У ручного назначения выбранного SKU приоритет выше наследования от товара. Ручной выбор заменяет результат условий, но сохраняет ограничения активности, сайта, периода, места показа, группы и общего количества бейджей. Несколько правил одного бейджа объединяются по ИЛИ. Выключенное наследование оставляет для SKU его собственные правила и назначения.

## Условия

Поддерживаются ID, название, символьный и внешний коды, дата создания, раздел с подразделами, доступность, общий остаток, свойства товара и предложений, типы цен с валютой и остатки по складам. Отбор цены использует запись выбранного типа и валюты для количества 1, без персональных скидок и пересчёта валюты. Учитываются права на просмотр товаров и цен.

Для строк доступны равенство и вхождение, для чисел и дат — сравнения, для списков — выбор значения. Множественное свойство совпадает, если хотя бы одно значение выполняет положительное сравнение; отрицательное сравнение требует отсутствия совпадений. Ноль считается заполненным значением. Файлы, HTML и неизвестные сложные пользовательские типы проверяются на заполненность. Для специфической структуры стороннего типа требуется дополнительный обработчик перед расширением списка операторов. Списки, привязки, даты и справочники directory имеют собственные элементы выбора.

Режимы правила:

| Режим | Поведение |
| --- | --- |
| Товар | Проверка данных родительского товара |
| Выбранное предложение | Проверка только переданного SKU; ID родителя не выбирает предложение автоматически |
| Хотя бы одно предложение | Достаточно одного активного доступного по правам SKU |
| Все предложения | Каждый активный доступный по правам SKU должен совпасть; пустой набор не совпадает |

Все условия группы проверяются для одного SKU. Свойства родителя доступны в контексте предложения. Поле отсутствующего или недоступного источника не превращается в совпадение при отрицании. Даты условий вводятся как `ГГГГ-ММ-ДД`; периоды бейджа используют часовой пояс PHP сервера.

## Подключение одного товара

```php
if (\Bitrix\Main\Loader::includeModule('qwelp.badges')) {
    echo \Qwelp\Badges\Api\BadgeManager::renderForEntity(
        $productOrOfferId,
        ['siteId' => SITE_ID, 'placement' => 'detail']
    );
}
```

Для гибкого размещения используйте компонент:

```php
$APPLICATION->IncludeComponent('qwelp:product.badges', '', [
    'ENTITY_ID' => $productOrOfferId,
    'SITE_ID' => SITE_ID,
    'PLACEMENT' => 'custom',
]);
```

Места показа: `card`, `detail`, `custom`. Язык по умолчанию — `LANGUAGE_ID`, его можно передать как `language`. Компонент поставляется с собственным шаблоном и не требует Bootstrap. Для тёмного варианта используется родительский `[data-theme="dark"]` или `.qb-badges--dark`.

## Пакетный вывод и смена SKU

Перед циклом карточек передайте все ID одним вызовом. Результат содержит массив бейджей для каждого ID, включая пустые массивы.

```php
if (\Bitrix\Main\Loader::includeModule('qwelp.badges')) {
    $badges = \Qwelp\Badges\Api\BadgeManager::getForEntities(
        $productAndOfferIds,
        ['siteId' => SITE_ID, 'placement' => 'card']
    );
    foreach ($products as $product) {
        echo \Qwelp\Badges\Api\BadgeManager::render($badges[$product['ID']] ?? []);
    }
}
```

При переключении SKU передавайте ID выбранного предложения. Можно заранее получить данные всех показанных SKU и менять содержимое отдельного контейнера без AJAX. Настройки мобильной видимости применяются CSS при ширине до 575,98 px. Произвольные CSS/HTML/JavaScript в настройках не исполняются; цвета и размеры валидируются, надписи экранируются.

## Кеш и Композит

Сервис загружает данные пакетами до 200 ID, выбирает только источники, используемые правилами, и кеширует результат с учётом сайта, языка, места, пользователя, групп и версии настроек. Для правил по предложениям может потребоваться загрузка всех активных SKU этих товаров. Скорость зависит от их количества и сложности правил; универсальное ограничение времени ответа не заявляется.

Если результат встраивается в кешируемый родительский компонент, зарегистрируйте зависимости в его `component_epilog.php`. ID инфоблоков сохраните в `templateData`, чтобы они были доступны и при попадании в кеш.

```php
if (\Bitrix\Main\Loader::includeModule('qwelp.badges')) {
    \Qwelp\Badges\Api\BadgeManager::registerCachedOutput(
        SITE_ID, [$catalogIblockId, $offersIblockId]
    );
}
```

Поставляемый компонент регистрирует свои зависимости сам. Изменения бейджей и назначений сбрасывают кеш модуля и зарегистрированный вывод. События каталога объединяют сбросы в конце запроса. Изменения через прямой SQL обходят события Битрикса и требуют явного сброса через `Invalidation::changed()` после операции.

Сроки ограничивают TTL результатов. Агент очищает зарегистрированные страницы по границам периодов с интервалом 60 секунд; для предсказуемого запуска нужен cron агентов Битрикса. Для уже готового HTML Композита задержка определяется запуском агента. Персональный вывод внутри общего HTML-кеша требует штатной динамической области Битрикса: кеш сервиса не заменяет её.

## Доступ и обслуживание

Права модуля: D — нет доступа, R — просмотр, W — изменение. Они задаются в стандартной вкладке «Доступ» настроек модулей. Ручное назначение дополнительно требует права редактирования соответствующего элемента. Рабочие параметры находятся внутри раздела Квэлп. Штатные формы Битрикса сохраняют штатное оформление.

Удаление предлагает сохранить таблицы либо удалить данные. Установщик проверяет владение файлами по хешам, не перезаписывает чужие файлы и локальные переопределения. Полная поставка не является средством обновления поверх другого содержимого установленного компонента: для обновлений нужен отдельный согласованный пакет обновления. При отказе preflight нельзя вручную обнулять реестр владения.

На многосайтовой установке общие артефакты размещаются в `/bitrix/`, настройки бейджей и ручные назначения привязаны к `SITE_ID`. Общая `/local/` не требуется.
