# Таблицы вариантов

Таблицы вариантов — это таблицы, в которых хранятся комбинации значений атрибутов и связанные с ними объекты.

Пользователь определяет набор атрибутов, которые являются [универсальными характеристиками](https://help.globalerp.ru/books/BtkDocumentation/SNAPSHOT/html/060_%D1%83%D0%BD%D0%B8%D0%B2%D0%B5%D1%80%D1%81%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B5_%D1%85%D0%B0%D1%80%D0%B0%D0%BA%D1%82%D0%B5%D1%80%D0%B8%D1%81%D1%82%D0%B8%D0%BA%D0%B8.html), заполняет таблицу конкретными значениями и использует её для поиска нужных записей по заданным условиям. Результатом поиска будет являться объект из этой же таблицы.

Это позволяет настраивать поведение системы через данные, а не через код: вместо жёстко прописанной логики или проектных справочников используется единый стандартизированный инструмент.

Таблицы вариантов используются в сценариях, где требуется:
- выбор значения по комбинации параметров (например, цена по материалу и толщине);
- определение правила обработки на основе набора признаков;
- замена проектных справочников и классов, создаваемых под конкретные задачи.

Таблицы создаются и редактируются через пользовательский интерфейс, заполняются вручную или массово из Excel / буфера обмена. Поиск значений осуществляется через системные API-методы, доступные в процедурах описания отношений (JEXL).

## Описание интерфейса функционала

Таблицы вариантов доступны в приложении `Настройка системы > Сущности > Таблицы вариантов`. Тут содержится список всех созданных таблиц. 

При открытии карточки отображаются следующие элементы:

![1](../img/1.png)

**Поле «Код»** — задаётся системное имя таблицы вариантов (уникальный мнемокод).  
**Поле «Наименование»** — отображается человекочитаемое название таблицы.  
**Поле «Состояние»** — выбирается одно из трёх значений: **Аннулирована**, **Формируется**, **Действует**. От состояния зависит, может ли таблица использоваться в логике системы.

**Закладка «Настройка атрибутов»** — содержит список атрибутов, участвующих в таблице. Для каждого атрибута доступны два флага:
- **«Входит в ключ поиска»** — определяет, будет ли атрибут участвовать в поиске объектов;  
- **«Обязателен для ввода»** — запрещает сохранение объекта, если значение атрибута не задано.  
  ```{note}
  Если установлен флаг **«Входит в ключ поиска»**, флаг **«Обязателен для ввода»** устанавливается автоматически и недоступен для редактирования.
  ```
**Закладка «Объекты»** — отображает значения атрибутов. Можно задать не только конкретные значения, но и интервалы.

**Создание таблицы вариантов**

Таблица вариантов создается только через интерфейс системы, для создания необходимо:
1. Указать **Код**, **Наименование** и выбрать **Состояние**.
2. На закладке **«Атрибуты»** добавить универсальные характеристики и настроить флаги.
3. На закладке **«Объекты»** заполнить варианты вручную или загрузить из Excel / буфера обмена.

## Ключевые возможности

- **Поддержка диапазонов при поиске** — позволяет задавать не только точные значения, но и интервалы (например, толщина от 1.5 до 2.5 мм).
- **Массовая загрузка из Excel и буфера обмена** — упрощает заполнение таблиц с большим числом вариантов.
- **Контроль уникальности по составному ключу** — исключает дублирование правил, обеспечивая стабильность подстановок.
- **Настройка логики без кода** — бизнес-правила задаются через таблицы, без правок в коде.

## Архитектура

Функционал реализован на трёх классах:
```
Btk_Variant // Заголовок таблицы
├── Btk_VariantAttr // Атрибуты таблицы 
└── Btk_VariantObj // Объекты (варианты) таблицы 
```

**Ключевые атрибуты**

**Btk_Variant** — основная запись, описывающая саму таблицу вариантов.  
Содержит:
- **sCode** — уникальное системное имя (мнемокод), по которому таблица идентифицируется в коде;
- **sCaption** — человекочитаемое название;
- **idState** — состояние (**Аннулирована**, **Формируется**, **Действует**), определяющее, может ли таблица использоваться в логике системы.

**Btk_VariantAttr** — записи, описывающие, какие атрибуты участвуют в таблице. Каждая запись ссылается на универсальную характеристику и указывает:
  - входит ли атрибут в ключ поиска — только такие атрибуты можно использовать в условиях поиска;
  - является ли обязательным — если да, значение должно быть заполнено при создании объекта;
  - порядок отображения (**nOrder**) — определяет последовательность колонок в интерфейсе.

**Btk_VariantObj** — конкретные варианты (строки таблицы).  
Содержит:
  - **jAttrs** — значения всех атрибутов в формате JSON вида `{«код_характеристики»: gid_значения}`;
  - **sKeyAttrs** — служебный поисковый ключ, автоматически формируемый из значений атрибутов, отмеченных как **«Входит в ключ поиска»**.  
  Используется для:
    - быстрого поиска нужного объекта;
    - гарантии отсутствия дублирующихся комбинаций (уникальность контролируется по этому полю).

## Логика поиска объектов

Поиск объектов в таблицах вариантов реализован через код — через пакет **Btk_VariantPkg.scala**.  
Все операции выполняются с помощью специального билдера условий, который:
- создаётся по идентификатору таблицы вариантов;
- позволяет задать критерии поиска;
- передаётся в методы поиска.

### Основные шаги

1. Создайте билдер условий по идентификатору таблицы вариантов.
2. Добавьте в билдер условия поиска (одно или несколько).
3. Вызвовите метод поиска, передав в него готовый билдер.

**Пример создания билдера и вызова методов:**  
```scala
//создание билдера
val builder = new VariantExpBuilderImpl(Btk_VariantApi().findByMnemoCode("test"))
//добавление условий
builder.addEquals("bBoolAttr", 0.nr)
  .addEqualsTruncDate("dDateAttr", NDate.now())
  .addInInterval("nNumberAttr", NNumber.fromAny(0), NNumber.fromAny(25))
  .addInList("nAnotherNumberAttr", Array(4.nr, 9.nr, 3.nr))
//поиск объектов
Btk_VariantPkg().getObjects(builder)
```

### Условия поиска в билдере
Все условия задаются через методы билдера **VariantExpBuilderImpl**. Атрибут указывается по системному имени (коду универсальной характеристики).

- **addEquals(sAttr, value)** — точное совпадение значения. Поддерживает интервалы и множественные значения: объект находится, если **value** входит в значение атрибута (например, число попадает в интервал).
- **addInInterval(sAttr, start, end)** — поиск по числовому диапазону. Объект подходит, если хотя бы одно его значение атрибута лежит в интервале [start, end].
- **addInList(sAttr, values)** — проверка вхождения в список, массив. Объект подходит, если хотя бы одно его значение содержится в переданном массиве.
- **addContains(sAttr, text)** — поиск в тексте. Поиск фрагмента внутри текстового значения атрибута.
- **addEqualsTruncDate(sAttr, date)** — сравнение дат без учёта времени. Используется, когда значение содержит дату и время, но сравнивается только дата.

## Примеры использования

Функционал используется в процедурах описания отношений (JEXL) для подстановки значений на основе комбинаций признаков.

- **Подбор цены** по комбинации «материал + толщина»:
  - таблица вариантов содержит атрибуты **UC_Material**, **UC_Thickness**, **UC_Price**;
  - **UC_Material** и **UC_Thickness** — ключевые;
  - при вызове API с ключом **{UC_Material: "сталь", UC_Thickness: "2.0"}** система находит соответствующий объект в таблице и возвращает значение **UC_Price** из этой записи.

## Ограничения

- При переносе объектов между средами **обязателен пересчёт `sKeyAttrs`**, так как `gid` значений универсальных характеристик могут отличаться;
- Порядок столбцов в Excel **должен совпадать** с порядком атрибутов (`nOrder`) — сопоставление по заголовкам не поддерживается;
- Уникальность записей контролируется только по **непустому ключу** (`sKeyAttrs`). Записи с пустым или частично заполненным ключом могут дублироваться.