Кулинарная книга A1sCode · Часть 5

Fluent API

Fluent — это стиль, при котором каждый метод возвращает объект и позволяет вызывать следующий. Код читается как предложение: «создай документ, установи комментарий, добавь строки, проведи». Четыре обёртки: A1sDP_Docs, A1sDP_Catalogs, A1sDP_DS, A1sDP_AR.

4 обёртки только &НаСервере 9 рецептов входная точка — .On()
Концепция — как это работает

Анатомия цепочки

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

A1sDocs.On("ВыпускПродукцииУслуг", шапка) точка входа
.Set("Комментарий", "Корпус А") трансформатор
.AddRows("Продукция", ТЗКвартиры) трансформатор
.Post() терминатор → ссылка
A1sDP_Docs
обёртка документа
Вход: A1sDocs.On()
A1sDP_Catalogs
обёртка справочника
Вход: A1sCatalogs.On()
A1sDP_DS
обёртка структуры
Вход: A1sDS.On()
A1sDP_AR
обёртка массива
Вход: A1sAR.On()
⚠️
Только &НаСервере. Все четыре Fluent-обёртки работают исключительно на сервере — они создают объект обработки (Обработки.A1sDP_Docs.Создать()), который недоступен на клиенте. Если ваш код выполняется в &НаКлиентеНаСервере или на клиенте — используйте обычные функции.
ℹ️
Когда Fluent уместен, а когда нет. Fluent хорош когда операций много и они логически связаны — цепочка читается лучше, чем набор переменных. Когда операция одна (A1sDocs.Post(Dok)) — обычный вызов проще. Правило: если цепочка длиннее трёх методов — Fluent оправдан.
A1sDP_Docs — цепочки над документом
РЕЦЕПТ 1 · A1sDocs.On

Создать документ цепочкой

⚡ Когда применять: нужно создать документ с несколькими шагами заполнения в одном выражении

A1sDocs.On("ИмяДокумента", Header) создаёт документ и оборачивает в Fluent. Дальше — цепочка методов. Последний метод (.Post() или .Write()) записывает документ и возвращает ссылку, завершая цепочку.

✗ Обычный стиль
Dok = A1sDocs.Of("ВыпускПродукцииУслуг",
    A1sDS.Of("Дата", '20260201',
               "Организация", Орг));
A1sDocs.Set(Dok, "Комментарий", "А");
A1sDocs.AddRows(Dok, "Продукция", ТЗ);
Ссылка = A1sDocs.Post(Dok);
✓ Fluent стиль
Ссылка = A1sDocs.On(
        "ВыпускПродукцииУслуг",
        A1sDS.Of("Дата", '20260201',
                   "Организация", Орг))
    .Set("Комментарий", "А")
    .AddRows("Продукция", ТЗ)
    .Post();
A1sDocs.On — создать, заполнить, провести
// ── Базовая цепочка: создать → заполнить → провести ───────────────────────
Ссылка = A1sDocs.On("ВыпускПродукцииУслуг",
        A1sDS.Of(
            "Дата",        '20260201',
            "Организация", МояОрг,
            "Склад",       СкладГП))
    .Set("Комментарий", "Корпус А — февраль 2026")
    .AddRows("Продукция", ТЗКвартиры)
    .Post();

// ── Несколько ТЧ ─────────────────────────────────────────────────────────
Ссылка = A1sDocs.On("РеализацияТоваровУслуг",
        A1sDS.Of("Дата", ТекущаяДата(), "Контрагент", Контрагент))
    .Set("Договор",    Договор)
    .Set("Склад",     Склад)
    .AddRows("Товары",  ТЗТовары)
    .AddRows("Услуги",  ТЗУслуги)
    .Post();

// ── Write вместо Post — записать без проведения ───────────────────────────
Ссылка = A1sDocs.On("ВыпускПродукцииУслуг",
        A1sDS.Of("Дата", '20260201', "Организация", МояОрг))
    .AddRows("Продукция", ТЗКвартиры)
    .Write();  // черновик — не проводим

// ── Fluent с LoadRows (авторазрешение строк) ──────────────────────────────
Ссылка = A1sDocs.On("ВыпускПродукцииУслуг",
        A1sDS.Of("Дата", '20260201', "Организация", МояОрг))
    .LoadRows("Продукция", МассивСтрокИзJSON)  // строки → ссылки
    .Post();

РЕЦЕПТ 2 · A1sDocs.On

Обернуть существующий документ

⚡ Когда применять: документ уже в базе, нужно изменить и перепровести

Если передать в On() не строку, а ссылку или объект — обёртка открывает существующий документ. Потом применяете нужные изменения и перепроводите.

On(ссылка) — обернуть существующий + изменить
// ── Обернуть существующий и изменить ─────────────────────────────────────
A1sDocs.On(ДокСсылка)
    .Set("Комментарий", "Исправлено вручную")
    .Post(Истина);  // Force=Истина — перепровести даже если уже проведён

// ── Заменить всю ТЧ существующего документа ──────────────────────────────
A1sDocs.On(ДокСсылка)
    .ClearRows("Продукция")       // очистить старые строки
    .AddRows("Продукция", НоваяТЗ) // загрузить новые
    .Post(Истина);

// ── On с Header: обернуть и сразу изменить несколько реквизитов шапки ────
A1sDocs.On(ДокСсылка,
    A1sDS.Of(
        "Комментарий",   "Откорректировано",
        "Ответственный", НовыйОтвет))
    .Post(Истина);

// ── Передать объект если он уже открыт ───────────────────────────────────
ДокОбъект = A1sDocs.GetObject(ДокСсылка); // открыт ранее
A1sDocs.On(ДокОбъект)           // обёртка без лишнего GetObject
    .LoadRows("Продукция", НовыеДанные)
    .Post(Истина);

РЕЦЕПТ 3 · A1sDocs.On — полная шпаргалка методов

Все методы A1sDP_Docs

Метод Сигнатура Что делает Тип
Шапка
.Set .Set(Key, Value) Установить один реквизит шапки → this
.FillHeader .FillHeader(Structure) Заполнить несколько реквизитов шапки из структуры → this
Табличные части
.AddRow .AddRow(TabName, RowData) Добавить строку из структуры (ссылки готовы) → this
.AddRows .AddRows(TabName, Source, Map?) Добавить из ТЗ или массива структур → this
.LoadRows .LoadRows(TabName, Rows[]) Добавить с авторазрешением строк → ссылок → this
.ClearRows .ClearRows(TabName) Очистить ТЧ → this
.SetRows .SetRows(TabName, Source) ClearRows + AddRows в одном → this
Терминаторы
.Post .Post(Force?) Записать и провести → DocumentRef → ссылка
.Write .Write() Записать без проведения → DocumentRef → ссылка
.Unpost .Unpost() Отменить проведение → DocumentRef → ссылка
.Value .Value() Получить объект документа без записи → объект
.Ref .Ref() Получить ссылку (только если уже записан) → ссылка
A1sDP_Catalogs — цепочки над справочником
РЕЦЕПТ 4 · A1sCatalogs.On

Создать элемент справочника шаг за шагом

⚡ Когда применять: много реквизитов или часть из них условная

A1sCatalogs.On("ИмяСправочника") создаёт новый незаписанный элемент и оборачивает в Fluent. Метод .Write() записывает и возвращает ссылку.

A1sCatalogs.On — создать элемент справочника
// ── Создать новую номенклатуру ────────────────────────────────────────────
НомСсылка = A1sCatalogs.On("Номенклатура")
    .Set("Наименование",      "Квартира 401")
    .Set("Родитель",          ГрКвартиры)
    .Set("ВидНоменклатуры",  ВидКвартира)
    .Set("ЕдиницаИзмерения", ЕдШт)
    .Set("Площадь",          48.5)
    .Set("Этаж",             5)
    .Write();

// ── Передать начальные реквизиты сразу в On() ─────────────────────────────
КонтрСсылка = A1sCatalogs.On("Контрагенты",
        A1sDS.Of("Наименование", "ООО Ромашка", "ИНН", "7707083893"))
    .Set("КПП",             "770701001")
    .Set("ВидКонтрагента", ВидЮрЛицо)
    .Write();

// ── Создать элемент с ТЧ (например, у справочника есть ТЧ «Контакты») ────
Ссылка = A1sCatalogs.On("Контрагенты")
    .Set("Наименование", "ООО Ромашка")
    .AddRow("Контакты",
        A1sDS.Of("Вид", "Email", "Значение", "[email protected]"))
    .AddRow("Контакты",
        A1sDS.Of("Вид", "Телефон", "Значение", "+7 495 000-00-00"))
    .Write();

РЕЦЕПТ 5 · A1sCatalogs.On — методы и обёртка существующего

Обернуть существующий элемент + полная шпаргалка

On(ссылка) — обернуть существующий элемент справочника
// ── Обернуть существующий и изменить один реквизит ───────────────────────
A1sCatalogs.On(НомСсылка)
    .Set("Цена", 3750000)
    .Write();

// ── Обернуть с немедленным Set в On() ────────────────────────────────────
A1sCatalogs.On(НомСсылка,
        A1sDS.Of("Цена", 3750000, "Статус", СтатусАктив))
    .Write();

// ── Заменить ТЧ существующего ─────────────────────────────────────────────
A1sCatalogs.On(КонтрСсылка)
    .ClearRows("Контакты")
    .AddRows("Контакты", НовыеКонтакты)
    .Write();
Метод Сигнатура Что делает Тип
.Set .Set(Key, Value) Установить реквизит → this
.FillAttrs .FillAttrs(Structure) Заполнить несколько реквизитов из структуры → this
.AddRow .AddRow(TabName, RowData) Добавить строку в ТЧ → this
.AddRows .AddRows(TabName, Source) Добавить из ТЗ или массива структур → this
.ClearRows .ClearRows(TabName) Очистить ТЧ → this
.Write .Write() Записать → CatalogRef → ссылка
.Value .Value() Получить объект без записи → объект
.Ref .Ref() Получить ссылку (только если уже записан) → ссылка
A1sDP_DS — цепочки над структурой
РЕЦЕПТ 6 · A1sDS.On

Построить структуру с условиями

⚡ Когда применять: структура формируется динамически — часть полей добавляется по условию

A1sDS.On() — пустая структура. A1sDS.On(СуществующаяСтруктура) — трансформация. Терминатор .Value() возвращает обычную структуру. .ToFixed() — фиксированную.

A1sDS.On — построить структуру шаг за шагом
// ── Простая сборка структуры ──────────────────────────────────────────────
Шапка = A1sDS.On()
    .Set("Организация", МояОрг)
    .Set("Дата",        ТекущаяДата())
    .Set("Склад",       СкладГП)
    .Value();
// → обычная Структура {Организация, Дата, Склад}

// ── SetIf: добавить поле только при выполнении условия ────────────────────
Фильтр = A1sDS.On()
    .Set("Организация", МояОрг)
    .SetIf("Склад",        Склад,        ЗначениеЗаполнено(Склад))
    .SetIf("Контрагент",   Контрагент,   ЗначениеЗаполнено(Контрагент))
    .SetIf("ПремиумКлиент", Истина,       ЕстьПодписка)
    .Value();

// ── SetMany: добавить несколько ключей из структуры ───────────────────────
Параметры = A1sDS.On()
    .Set("Версия", "2.1.0")
    .SetMany(A1sDS.Of("Хост", "prod-server", "Порт", 8080))
    .Value();

// ── ToFixed: неизменяемая структура-константа ─────────────────────────────
Константы = A1sDS.On()
    .Set("MaxRetries",  3)
    .Set("TimeoutSec",  30)
    .Set("BatchSize",   100)
    .ToFixed();
// Константы.MaxRetries = 5 → ОШИБКА: ФиксированнаяСтруктура нельзя изменить

РЕЦЕПТ 7 · A1sDS.On

Трансформировать данные из API

⚡ Когда применять: получили большой ответ API — нужно убрать лишнее, переименовать, применить умолчания
On(существующая) — Omit + Rename + Defaults
// ── Очистить ответ API: убрать служебные поля, переименовать ──────────────
ОтветAPI = A1sDS.Of(
    "first_name", "Иван",    "last_name",  "Петров",
    "email",      "[email protected]",  "token",      "eyJ...",
    "_internal", 42,        "role",       "admin");

ПубличныйПрофиль = A1sDS.On(ОтветAPI)
    .Omit("token, _internal")            // убрать чувствительное
    .Rename(A1sDS.Of(
        "first_name", "Имя",
        "last_name",  "Фамилия",
        "email",      "Email",
        "role",       "Роль"))
    .Value();
// → { Имя: "Иван", Фамилия: "Петров", Email: "[email protected]", Роль: "admin" }

// ── Defaults: применить умолчания к пользовательским настройкам ──────────
НастройкиПользователя = A1sDS.Of("Хост", "prod-server"); // только хост

ИтоговаяКонфигурация = A1sDS.On(НастройкиПользователя)
    .Defaults(A1sDS.Of(
        "Хост",          "localhost",  // перезапишется "prod-server"
        "Порт",          8080,         // добавится
        "Таймаут",       30,           // добавится
        "SSL",           Ложь,         // добавится
        "ПулСоединений", 10))          // добавится
    .Value();
// → { Хост: "prod-server", Порт: 8080, Таймаут: 30, SSL: Ложь, ПулСоединений: 10 }

// ── Слить данные из нескольких источников ────────────────────────────────
БазовыеДанные    = /* из БД */;
КэшДанные       = /* из кэша */;
СессионныеДанные = /* из сессии */;

ПолныеДанные = A1sDS.On(БазовыеДанные)
    .Merge(КэшДанные)             // перезапишет совпадающие ключи
    .Merge(СессионныеДанные)       // высший приоритет
    .Set("ДатаЗагрузки", ТекущаяДата())
    .Omit("ВнутренниеДанные")
    .Value();

РЕЦЕПТ 8 · A1sDS.On — полная шпаргалка методов

Все методы A1sDP_DS

Метод Сигнатура Что делает Тип
Трансформаторы
.Set .Set(Key, Value) Установить / перезаписать ключ → this
.SetIf .SetIf(Key, Value, Condition) Установить ключ только если условие истинно → this
.SetMany .SetMany(Structure) Установить несколько ключей из структуры → this
.Remove .Remove(Key) Удалить ключ → this
.Pick .Pick("K1,K2") Оставить только указанные ключи → this
.Omit .Omit("K1,K2") Исключить указанные ключи → this
.Merge .Merge(Structure) Слить структуру (источник перезаписывает) → this
.Defaults .Defaults(Structure) Применить дефолты (не перезаписывает существующие) → this
.Rename .Rename(MapStruct) Переименовать ключи по карте → this
.DeepCopy .DeepCopy() Глубокое копирование текущей структуры → this
.Clear .Clear() Очистить структуру → this
.Transform .Transform(Key, "expr") Преобразовать значение выражением → this
Терминаторы
.Value .Value() → Structure Получить структуру → структура
.ToFixed .ToFixed() → FixedStructure Получить фиксированную структуру → фикс.
.Get .Get(Key) → Arbitrary Получить значение по ключу → значение
.Keys .Keys() → Array Получить массив ключей → массив
.Values .Values() → Array Получить массив значений → массив
.HasKey .HasKey(Key) → Bool Проверить наличие ключа → булево
.IsEmpty .IsEmpty() → Bool Структура пустая? → булево
.Count .Count() → Num Количество ключей → число
.ToJSON .ToJSON() → String Сериализовать в JSON → строка
A1sDP_AR — цепочки над массивом
РЕЦЕПТ 9 · A1sAR.On

Цепочки над массивом + шпаргалка методов

⚡ Когда применять: нужно собрать, очистить, трансформировать массив в одном выражении

A1sAR.On() — пустой массив. A1sAR.On(МассивИсточник) — обёртка существующего. Терминатор .Value() возвращает обычный массив.

A1sAR.On — цепочки над массивом
// ── Построить массив шаг за шагом ─────────────────────────────────────────
Результат = A1sAR.On()
    .Add(1).Add(2).Add(3).Add(2).Add(1)
    .RemoveDuplicates()
    .Sort()
    .Value();
// → [1, 2, 3]

// ── Трансформация существующего массива ───────────────────────────────────
СырыеДанные = A1sAR.Of(Ном1, Неопределено, Ном2, Ном1, Неопределено, Ном3);

ЧистыйСписок = A1sAR.On(СырыеДанные)
    .PickFilled()            // убрать Неопределено и пустые
    .RemoveDuplicates()      // убрать дубли
    .Value();
// → [Ном1, Ном2, Ном3]

// ── Объединить и обработать ───────────────────────────────────────────────
ВсяНоменклатура = A1sAR.On(НомДок1)
    .Concatenate(НомДок2)
    .Concatenate(НомДок3)
    .RemoveDuplicates()
    .Reverse()
    .Value();

// ── Построить список условно ──────────────────────────────────────────────
Действия = A1sAR.On()
    .Add("Проведение")
    .AddIf("Отправить уведомление", НужноУведомление)
    .AddIf("Обновить склад",       ЕстьДвижениеТМЦ)
    .AddIf("Печать документа",    НужнаПечать)
    .Value();
Сообщить("Будут выполнены: " + A1sAR.Join(Действия, ", "));
Метод Сигнатура Что делает Тип
Трансформаторы
.Add .Add(Value) Добавить элемент → this
.AddIf .AddIf(Value, Condition) Добавить по условию → this
.Concatenate .Concatenate(Array) Объединить с другим массивом → this
.RemoveDuplicates .RemoveDuplicates() Убрать дубликаты → this
.PickFilled .PickFilled() Оставить только заполненные → this
.PickRefs .PickRefs() Оставить только ссылки → this
.Sort .Sort() Сортировать → this
.Reverse .Reverse() Обратить порядок → this
.Flatten .Flatten() Схлопнуть массив массивов → this
Терминаторы
.Value .Value() → Array Получить массив → массив
.First .First() → Arbitrary Первый элемент → значение
.Last .Last() → Arbitrary Последний элемент → значение
.Count .Count() → Num Количество элементов → число
.IsEmpty .IsEmpty() → Bool Массив пустой? → булево
.Contains .Contains(Value) → Bool Содержит ли элемент → булево
.Join .Join(Sep) → String Склеить через разделитель → строка
.ToJSON .ToJSON() → String Сериализовать в JSON → строка
💡
Когда Fluent выигрывает у обычного кода — таблица сравнения:

A1sDS.On выигрывает у A1sDS.Of когда нужен SetIf или цепочка трансформаций (Omit + Rename + Defaults).
A1sDocs.On выигрывает у обычных вызовов когда операций 3+ и они логически связаны.
A1sAR.On выигрывает когда нужно собрать массив условно с AddIf.
Во всех остальных случаях — обычные функции проще и быстрее читаются.