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

Справочники —
A1sCatalogs

Самый богатый модуль библиотеки. Закрывает весь жизненный цикл работы со справочниками: создание, поиск, массовые операции, upsert-синхронизация, иерархия. Ключевая идея — не писать запросы руками для типовых задач.

A1sCatalogs v2.1.0 12 рецептов ~50 функций зависит от A1sDS · A1sAR
Пять паттернов создания — выбрать правильный

Прежде чем писать код — выберите нужный паттерн. Ошибка в выборе приводит либо к дублям, либо к пропущенным обновлениям.

Ensure
Найти по имени. Если нет — создать с реквизитами.
Когда: загрузка из Excel/JSON впервые
EnsureUpdate
Найти. Если есть — обновить. Если нет — создать.
Когда: регулярная синхронизация (прайс, CRM)
EnsureBatch
Массово: для каждого имени из массива — Ensure.
Когда: нужен список ссылок по именам
EnsureByType
Определить справочник по типу реквизита из метаданных. Не хардкодить имя.
Когда: data-driven код, работающий с любым документом
EnsureGroup
Найти или создать группу (папку) в справочнике.
Когда: нужна структура групп до загрузки элементов
Of + Write
Создать новый элемент без проверки на существование.
Когда: точно нет дублей, нужна скорость
РЕЦЕПТ 1 · A1sCatalogs

Ensure — найти или создать

⚡ Когда применять: загружаете данные из Excel/JSON и не знаете, есть ли уже такой элемент в базе

Главный паттерн всей библиотеки. Ensure(Name, Description, Attrs) сначала ищет по наименованию. Нашёл — возвращает ссылку, ничего не трогает. Не нашёл — создаёт с переданными реквизитами и возвращает новую ссылку. Реквизиты Attrs применяются только при создании.

✗ Классика: поиск + создание вручную
Ссылка = Справочники.Номенклатура
    .НайтиПоНаименованию("Квартира 101", Истина);

Если НЕ ЗначениеЗаполнено(Ссылка) Тогда
    НовЭл = Справочники.Номенклатура
        .СоздатьЭлемент();
    НовЭл.Наименование = "Квартира 101";
    НовЭл.Родитель = ГрКвартиры;
    НовЭл.Записать();
    Ссылка = НовЭл.Ссылка;
КонецЕсли;
✓ A1sCode: одна строка
Ссылка = A1sCatalogs.Ensure(
    "Номенклатура",
    "Квартира 101",
    A1sDS.Of(
        "Родитель", ГрКвартиры));
Ensure — полный арсенал применений
// ── Базовый вариант: только наименование ──────────────────────────────────
Орг = A1sCatalogs.Ensure("Организации", "ООО Ромашка");

// ── С реквизитами: передаются только при СОЗДАНИИ, при нахождении — игнорируются
Кв101 = A1sCatalogs.Ensure(
    "Номенклатура",
    "Квартира 101",
    A1sDS.Of(
        "Родитель",          ГрКвартиры,
        "ВидНоменклатуры",   ВидКвартира,
        "ЕдиницаИзмерения",  ЕдШт,
        "Площадь",           42.5,
        "Этаж",              3));

// ── Контрагент с ИНН ──────────────────────────────────────────────────────
Покупатель = A1sCatalogs.Ensure(
    "Контрагенты",
    "ООО СтройГрупп",
    A1sDS.Of(
        "ИНН",  "7707083893",
        "КПП",  "770701001",
        "ВидКонтрагента", ВидЮрЛицо));

// ── Нечёткий поиск: ExactMatch = Ложь ────────────────────────────────────
// Найдёт "Квартира 101 (корпус А)" по подстроке "Квартира 101"
НечёткаяСсылка = A1sCatalogs.Ensure(
    "Номенклатура",
    "Квартира 101",
    Неопределено,  // без доп. реквизитов
    Ложь);         // ExactMatch = Ложь

// ── В цикле: загрузка массива из Excel ───────────────────────────────────
Для Каждого СтрЭксель Из ДанныеExcel Цикл
    Ссылка = A1sCatalogs.Ensure(
        "Номенклатура",
        СтрЭксель.Наименование,
        A1sDS.Of(
            "Родитель", ГрКвартиры,
            "Площадь", СтрЭксель.Площадь));
    Сообщить(СтрЭксель.Наименование + " → " + Ссылка);
КонецЦикла;
⚠️
Ensure в цикле с большим объёмом — антипаттерн. Если строк 500+, каждый вызов делает отдельный запрос к БД. Используйте EnsureBatch — он работает так же, но за один вызов. Подробнее в рецепте 3.

РЕЦЕПТ 2 · A1sCatalogs

EnsureGroup — создать структуру папок

⚡ Когда применять: перед загрузкой элементов нужно убедиться, что группы-контейнеры существуют

EnsureGroup(Name, Description, Parent?) — то же самое, что Ensure, но для групп. Ищет среди групп по наименованию, создаёт если не найдена. Вкладывать можно на любую глубину.

EnsureGroup — создание дерева групп
// ── Простая группа на верхнем уровне ─────────────────────────────────────
ГрКвартиры = A1sCatalogs.EnsureGroup(
    "Номенклатура",
    "Квартиры");

// ── Вложенная группа: корпус → этаж ──────────────────────────────────────
ГрКорпусА = A1sCatalogs.EnsureGroup(
    "Номенклатура",
    "Корпус А",
    ГрКвартиры);           // родитель — уже созданная группа

ГрЭтаж3 = A1sCatalogs.EnsureGroup(
    "Номенклатура",
    "Этаж 3",
    ГрКорпусА);

// ── Создать дерево за один раз: универсальная утилита ─────────────────────
// Паттерн: строим полное дерево групп перед массовой загрузкой
Дерево = A1sDS.Of(
    "Квартиры",        Неопределено,   // корень
    "Услуги",          Неопределено,
    "НомГруппы",       Неопределено);

Для Каждого КЗ Из Дерево Цикл
    КЗ.Значение = A1sCatalogs.EnsureGroup("Номенклатура", КЗ.Ключ);
КонецЦикла;
// Дерево.Квартиры → ссылка на группу "Квартиры"

// ── EnsureGroup для номенклатурных групп (документы) ─────────────────────
ГрПроживание  = A1sCatalogs.EnsureGroup("НоменклатурныеГруппы", "ПРОЖИВАНИЕ");
ГрПитание     = A1sCatalogs.EnsureGroup("НоменклатурныеГруппы", "ПИТАНИЕ");
ГрКоммунальные = A1sCatalogs.EnsureGroup("НоменклатурныеГруппы", "КОММУНАЛЬНЫЕ УСЛУГИ");

РЕЦЕПТ 3 · A1sCatalogs

EnsureBatch — массово, одной командой

⚡ Когда применять: нужны ссылки для списка имён — быстрее и чище, чем Ensure в цикле

EnsureBatch(Name, Descriptions, Attrs?) принимает массив наименований и возвращает массив ссылок в том же порядке. Для каждого — find-or-create. Общие реквизиты Attrs применяются ко всем новым элементам.

EnsureBatch — массовое find-or-create
// ── Простой вариант: только имена ─────────────────────────────────────────
Имена = A1sAR.Of(
    "Квартира 101", "Квартира 102",
    "Квартира 103", "Квартира 201");

Ссылки = A1sCatalogs.EnsureBatch("Номенклатура", Имена);
// Ссылки[0] → ссылка на "Квартира 101"
// Ссылки[1] → ссылка на "Квартира 102" и т.д.
// Порядок сохраняется!

// ── С общими реквизитами для всех создаваемых ────────────────────────────
Ссылки = A1sCatalogs.EnsureBatch(
    "Номенклатура",
    A1sAR.Of("Квартира 301", "Квартира 302", "Квартира 303"),
    A1sDS.Of(
        "Родитель",        ГрКвартиры,   // одинаково для всех
        "ВидНоменклатуры", ВидКвартира,
        "ЕдиницаИзмерения", ЕдШт));

// ── Практика: сразу назначить ссылки переменным ──────────────────────────
НомГруппы = A1sCatalogs.EnsureBatch(
    "НоменклатурныеГруппы",
    A1sAR.Of("ПРОЖИВАНИЕ", "ПИТАНИЕ", "ПРОЧИЕ УСЛУГИ"));

ГрПроживание  = НомГруппы[0];
ГрПитание     = НомГруппы[1];
ГрПрочие      = НомГруппы[2];

// ── EnsureBatch из столбца Excel ─────────────────────────────────────────
// ДанныеExcel — массив структур, колонка "Номенклатура" содержит имена
ИменаНом = Новый Массив;
Для Каждого Стр Из ДанныеExcel Цикл
    ИменаНом.Добавить(Стр.Номенклатура);
КонецЦикла;
ИменаНом = A1sAR.RemoveDuplicates(ИменаНом);   // убрать дубли перед созданием
СсылкиНом = A1sCatalogs.EnsureBatch("Номенклатура", ИменаНом,
    A1sDS.Of("Родитель", ГрКвартиры));
💡
EnsureBatch vs Ensure в цикле. Оба делают find-or-create, но EnsureBatch удобнее читается и проще поддерживать. При 50+ записях разница в производительности несущественна (оба делают N запросов), но при 1000+ — уже имеет смысл разбивать на Chunk из Части 1.

РЕЦЕПТ 4 · A1sCatalogs new v2.1

EnsureByType — data-driven без хардкода

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

Суперсила библиотеки. EnsureByType(TypeValue, Description) получает тип реквизита из метаданных и сам определяет, в какой справочник нужно обратиться. Код не содержит строки "Номенклатура" или "Контрагенты" — он читает это из метаданных конфигурации.

✗ Хардкод: хрупко и негибко
// Имя справочника прибито гвоздями
Ном = A1sCatalogs.Ensure(
    "Номенклатура",  // ← строка
    СтрокаJSON.item);

// При смене документа — переписывать
✓ Data-driven: адаптируется сам
// Тип берётся из метаданных ТЧ
Тип = A1sDocs.TabAttrType(
    "ВыпускПродукцииУслуг",
    "Продукция", "Номенклатура");
Ном = A1sCatalogs.EnsureByType(
    Тип, СтрокаJSON.item);
EnsureByType — data-driven загрузчик
// ── Получить тип реквизита из метаданных ─────────────────────────────────
// A1sDocs.TabAttrType возвращает ОписаниеТипов реквизита ТЧ
ТипНоменклатуры = A1sDocs.TabAttrType(
    "ВыпускПродукцииУслуг",  // документ
    "Продукция",               // ТЧ
    "Номенклатура");            // реквизит
// ТипНоменклатуры содержит "СправочникСсылка.Номенклатура"
// EnsureByType сам это распарсит — мы не пишем "Номенклатура" в коде

// ── Теперь создаём ссылку, не зная имени справочника ─────────────────────
Ссылка = A1sCatalogs.EnsureByType(ТипНоменклатуры, "Квартира 101");

// ── Практика: универсальный загрузчик строк ТЧ ───────────────────────────
// Этот код работает с ЛЮБЫМ документом и ЛЮБОЙ ТЧ
// Не нужно переписывать при добавлении нового вида документа

ИмяДокумента = "ВыпускПродукцииУслуг";
ИмяТЧ        = "Продукция";

// Получаем схему ТЧ — имена и типы всех реквизитов
СхемаТЧ = A1sDocs.TabSchema(ИмяДокумента, ИмяТЧ);
// → массив структур: [{Имя:"Номенклатура", Тип:ОписаниеТипов, ЭтоСсылка:Истина}, ...]

Для Каждого СтрокаJSON Из ДанныеJSON Цикл
    СтрокаДляДока = Новый Структура;

    Для Каждого Поле Из СхемаТЧ Цикл
        Значение = СтрокаJSON[Поле.Имя];

        Если Поле.ЭтоСсылка И ТипЗнч(Значение) = Тип("Строка") Тогда
            // Строковое значение ссылочного поля → EnsureByType
            Значение = A1sCatalogs.EnsureByType(Поле.Тип, Значение);
        КонецЕсли;

        СтрокаДляДока.Вставить(Поле.Имя, Значение);
    КонецЦикла;

    A1sDocs.AddRow(Dok, ИмяТЧ, СтрокаДляДока);
КонецЦикла;
💡
Когда EnsureByType возвращает строку. Если тип реквизита не является справочником (например, число или дата), функция возвращает переданное значение как есть — без ошибки. Это позволяет безопасно передавать все поля без разбора типов вручную.

РЕЦЕПТ 5 · A1sCatalogs new v2.1

EnsureUpdate — upsert для регулярной синхронизации

⚡ Когда применять: данные приходят регулярно (каждую ночь, раз в час) и нужно обновлять существующие

В отличие от Ensure (который при нахождении ничего не делает), EnsureUpdate всегда обновляет реквизиты найденного элемента. Идеальный выбор для синхронизации прайс-листов, справочников из CRM, ГИС ЖКХ.

EnsureUpdate — регулярная синхронизация
// ── Сценарий: прайс-лист от застройщика приходит раз в неделю ────────────
// Нужно: обновить цены существующих квартир, добавить новые

ПрайсЛист = /* ... массив структур из файла CSV ... */;

Счётчик = A1sDS.OfKeys("Обновлено, Создано, Ошибок", 0);

Для Каждого Позиция Из ПрайсЛист Цикл
    Попытка
        A1sCatalogs.EnsureUpdate(
            "Номенклатура",
            Позиция.Наименование,
            A1sDS.Of(
                "Цена",     Позиция.Цена,           // обновится всегда
                "Площадь",  Позиция.Площадь,
                "Статус",   Позиция.Статус,
                "Родитель", ГрКвартиры));            // для новых
        Счётчик.Обновлено = Счётчик.Обновлено + 1;
    Исключение
        Счётчик.Ошибок = Счётчик.Ошибок + 1;
        Сообщить("Ошибка: " + Позиция.Наименование + " — " + ОписаниеОшибки());
    КонецПопытки;
КонецЦикла;

Сообщить("Синхронизация завершена: обновлено " + Счётчик.Обновлено
    + ", ошибок: " + Счётчик.Ошибок);

// ── Разница между Ensure и EnsureUpdate ──────────────────────────────────
// Ensure:       нашёл "Квартира 101" → вернул ссылку, Цена НЕ изменилась
// EnsureUpdate: нашёл "Квартира 101" → обновил Цену = 3750000, вернул ссылку

// ── AutoResolve: автоматически разрешать строки в ссылки ─────────────────
A1sCatalogs.EnsureUpdate(
    "Номенклатура",
    "Квартира 101",
    A1sDS.Of(
        "ВидНоменклатуры", "Квартира"),  // строка → найдёт ссылку сам
    Истина,   // ExactMatch
    Истина);  // AutoResolve = Истина
Поиск
РЕЦЕПТ 6 · A1sCatalogs

ByName · ByAttr · ByCode — простой точечный поиск

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

Три функции для точечного поиска — каждая делает один запрос и возвращает одну ссылку. Если ничего не найдено — возвращается пустая ссылка (не ошибка).

ByName · ByCode · ByAttr · ByGUID · ByNameList
// ── ByName: найти по наименованию ────────────────────────────────────────
Ном = A1sCatalogs.ByName("Номенклатура", "Квартира 101");

// С родителем — ищет только в конкретной группе
Ном = A1sCatalogs.ByName("Номенклатура", "Квартира 101", ГрКорпусА);

// Нечёткий поиск (подстрока)
Ном = A1sCatalogs.ByName("Номенклатура", "Квартира 1", Неопределено, Ложь);

// ── ByCode: найти по коду ─────────────────────────────────────────────────
Валюта = A1sCatalogs.ByCode("Валюты", "840");   // USD
Ном    = A1sCatalogs.ByCode("Номенклатура", "000101");

// ── ByAttr: найти по любому реквизиту ────────────────────────────────────
Контрагент = A1sCatalogs.ByAttr("Контрагенты", "ИНН", "7707083893");
Сотрудник  = A1sCatalogs.ByAttr("Сотрудники",   "Табельный", "ТБ-0042");

// ── ByGUID: найти по GUID-строке (из внешней системы) ────────────────────
Элемент = A1sCatalogs.ByGUID("Номенклатура", "12345678-1234-5678-1234-567812345678");

// ── ByNameList: список имён через запятую → массив ссылок ─────────────────
Валюты = A1sCatalogs.ByNameList("Валюты", "USD,EUR,CNY");
// → [СправочникСсылка.Валюты, ...] — только найденные

// ── Проверить перед использованием ───────────────────────────────────────
Ном = A1sCatalogs.ByName("Номенклатура", "Квартира 999");
Если НЕ ЗначениеЗаполнено(Ном) Тогда
    Сообщить("Квартира 999 не найдена в справочнике");
КонецЕсли;

РЕЦЕПТ 7 · A1sCatalogs

PickByName · PickByAttr — массовый поиск одним запросом

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

PickByName и PickByAttr принимают массив значений и возвращают массив найденных ссылок. Не найденные элементы — пропускаются. Отличие от EnsureBatch — ничего не создаёт.

PickByName · PickByCode · PickByAttr · PickPredefined
// ── PickByName: массив имён → массив ссылок (только найденные) ───────────
НомГруппы = A1sCatalogs.PickByName(
    "НоменклатурныеГруппы",
    A1sAR.Of("ПРОЖИВАНИЕ", "ПИТАНИЕ", "ПРОЧИЕ УСЛУГИ"));
// → [СсылкаПроживание, СсылкаПитание, СсылкаПрочие]
// Если "ПРОЧИЕ УСЛУГИ" нет в базе — в массиве будет только 2 элемента

// ── PickByCode: массив кодов → массив ссылок ─────────────────────────────
Товары = A1sCatalogs.PickByCode(
    "Номенклатура",
    A1sAR.Of("000101", "000102", "000103"));

// ── PickByAttr: по значениям произвольного реквизита ─────────────────────
Контрагенты = A1sCatalogs.PickByAttr(
    "Контрагенты", "ИНН",
    A1sAR.Of("7701234567", "7707654321", "7709999999"));

// ── PickPredefined: предопределённые элементы по именам ──────────────────
ВидыНом = A1sCatalogs.PickPredefined(
    "ВидыНоменклатуры",
    A1sAR.Of("Товар", "Услуга", "Работа"));
// Обращается к Справочники.ВидыНоменклатуры.Товар и т.д.

// ── Практика: быстро получить нужные ссылки перед циклом загрузки ─────────
// Вместо: внутри цикла каждый раз искать ЕдиницаИзмерения...
ЕдИзмерения = A1sCatalogs.PickByName(
    "КлассификаторЕдиницИзмерения",
    A1sAR.Of("шт", "м2", "м3", "усл"));
// ЕдИзмерения[0] → шт, [1] → м2, [2] → м3, [3] → усл
// Теперь используем в цикле без лишних запросов

РЕЦЕПТ 8 · A1sCatalogs

Refs · Count · Exists — запросы без написания запросов

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

Три функции для произвольных запросов к справочникам. Вы передаёте только условие WHERE и параметры — функция строит и выполняет запрос сама.

Refs · Count · Exists · TopLevelItems · AllInGroup · AllByOwner
// ── Refs: массив ссылок с условием ───────────────────────────────────────
АктивныеКвартиры = A1sCatalogs.Refs(
    "Номенклатура",
    "НЕ ПометкаУдаления И Родитель = &Группа И Статус = &Статус",
    A1sDS.Of("Группа", ГрКвартиры, "Статус", СтатусАктив),
    "Наименование");              // OrderBy — сортировка

// Без параметров — все элементы справочника
ВсяНоменклатура = A1sCatalogs.Refs("Номенклатура");

// ── Count: подсчёт элементов ──────────────────────────────────────────────
КолвоКвартир = A1sCatalogs.Count(
    "Номенклатура",
    "Родитель = &Гр И НЕ ПометкаУдаления",
    A1sDS.Of("Гр", ГрКвартиры));
Сообщить("Квартир в группе: " + КолвоКвартир);

// ── Exists: есть ли хоть один? ────────────────────────────────────────────
ЕстьСпецПредложения = A1sCatalogs.Exists(
    "Номенклатура",
    "СпецПредложение = Истина И НЕ ПометкаУдаления");

Если НЕ ЕстьСпецПредложения Тогда
    Сообщить("Нет активных спецпредложений");
КонецЕсли;

// ── TopLevelItems: элементы верхнего уровня ───────────────────────────────
ВерхнийУровень = A1sCatalogs.TopLevelItems("Номенклатура");               // с группами
ТолькоЭлементы = A1sCatalogs.TopLevelItems("Номенклатура", Ложь);         // без групп

// ── AllInGroup: все элементы в группе ────────────────────────────────────
КвартирыКорпусА = A1sCatalogs.AllInGroup("Номенклатура", ГрКорпусА);       // с вложенными
ТолькоПрямые    = A1sCatalogs.AllInGroup("Номенклатура", ГрКорпусА, Ложь); // только прямые

// ── AllByOwner: подчинённый справочник по владельцу ───────────────────────
ДоговорыКонтрагента = A1sCatalogs.AllByOwner("ДоговорыКонтрагентов", КонтрагентСсылка);
ℹ️
Условие WHERE без слова «ГДЕ». Передаёте только само условие: "Родитель = &Гр", не "ГДЕ Родитель = &Гр". Слово ГДЕ функция добавит сама. Параметры запроса — через A1sDS.Of.
Изменение элементов
РЕЦЕПТ 9 · A1sCatalogs

Update · UpdateAll — обновить реквизиты

⚡ Когда применять: нужно обновить один или несколько реквизитов у существующих элементов

Update принимает ссылку и структуру полей — открывает объект, заполняет, записывает. UpdateAll делает то же самое для массива. Оба возвращают {Success, Failed}.

Update · UpdateAll — изменение реквизитов
// ── Update: один элемент, несколько реквизитов ────────────────────────────
A1sCatalogs.Update(
    НомСсылка,
    A1sDS.Of(
        "Цена",     3750000,
        "Статус",   СтатусАктив,
        "Площадь",  42.5));

// Старый стиль — одно поле (обратная совместимость)
A1sCatalogs.Update(НомСсылка, "Цена", 3750000);

// Без немедленной записи (DoWrite=Ложь) — для пакетных операций
A1sCatalogs.Update(НомСсылка, A1sDS.Of("Цена", 4000000), Ложь);

// ── UpdateAll: массив элементов, одинаковые изменения ─────────────────────
ВсеКвартирыКорпусА = A1sCatalogs.AllInGroup("Номенклатура", ГрКорпусА);

Итог = A1sCatalogs.UpdateAll(
    ВсеКвартирыКорпусА,
    A1sDS.Of(
        "Статус",            СтатусСдан,
        "ДатаСдачи",        ТекущаяДата(),
        "ЭтапСтроительства", ЭтапСдан));

Сообщить("Обновлено: "   + Итог.Success.Количество());
Сообщить("С ошибками: " + Итог.Failed.Количество());

// ── Старый стиль UpdateAll — одно поле для всего массива ─────────────────
A1sCatalogs.UpdateAll(СписокЭлементов, "Ответственный", НовыйОтветственный);

РЕЦЕПТ 10 · A1sCatalogs

Move · MarkForDeletion — перемещение и удаление

⚡ Когда применять: реструктуризация групп, массовая пометка устаревшей номенклатуры
Move · MoveBatch · MarkForDeletion · MarkForDeletionBatch
// ── Move: переместить элемент в другую группу ─────────────────────────────
A1sCatalogs.Move(НомСсылка, НоваяГруппа);

// ── MoveBatch: переместить массив элементов в одну группу ────────────────
КвартирыЭтаж3 = A1sCatalogs.Refs(
    "Номенклатура",
    "Этаж = 3 И Родитель = &Гр",
    A1sDS.Of("Гр", ГрКорпусА));

Итог = A1sCatalogs.MoveBatch(КвартирыЭтаж3, ГрЭтаж3КорпусА);
Сообщить("Перемещено: " + Итог.Success.Количество());

// ── MarkForDeletion: пометить один элемент ────────────────────────────────
A1sCatalogs.MarkForDeletion(УстаревшаяНом);               // пометить
A1sCatalogs.MarkForDeletion(УстаревшаяНом, Ложь);          // снять пометку

// ── MarkForDeletionBatch: пометить массив ──────────────────────────────────
УстаревшиеКвартиры = A1sCatalogs.Refs(
    "Номенклатура",
    "Статус = &С И Год < &Г",
    A1sDS.Of("С", СтатусАрхив, "Г", 2020));

Итог = A1sCatalogs.MarkForDeletionBatch(УстаревшиеКвартиры);
Сообщить("Помечено на удаление: " + Итог.Success.Количество()
    + ", ошибок: "             + Итог.Failed.Количество());
Иерархия
РЕЦЕПТ 11 · A1sCatalogs

Parent · Children · Level · Path — навигация по дереву

⚡ Когда применять: нужно найти родителя, получить всех потомков, построить хлебные крошки
Parent · Children · Level · Path · HasChildren · IsGroup
// ── Parent: родительская группа ───────────────────────────────────────────
Группа = A1sCatalogs.Parent(НомСсылка);
Сообщить("Группа: " + Группа);

// ── Children: прямые дочерние элементы ───────────────────────────────────
ПрямыеДети    = A1sCatalogs.Children(ГрКорпусА);              // Recursive=Ложь
ВсеПотомки    = A1sCatalogs.Children(ГрКорпусА, Истина);    // все вложенные

Сообщить("Прямых: " + ПрямыеДети.Количество()
    + ", всего: " + ВсеПотомки.Количество());

// ── Level: уровень в иерархии (0 = корень) ───────────────────────────────
Уровень = A1sCatalogs.Level(НомСсылка);
// Квартиры (0) → Корпус А (1) → Этаж 3 (2) → Квартира 301 (3)

// ── Path: полный путь через разделитель ──────────────────────────────────
Путь = A1sCatalogs.Path(НомСсылка);                        // "Квартиры / Корпус А / Квартира 101"
ПутьСтрелка = A1sCatalogs.Path(НомСсылка, " → ");          // свой разделитель
ПутьСлэш    = A1sCatalogs.Path(НомСсылка, "/");             // "Квартиры/Корпус А/..."

// ── HasChildren · IsGroup ─────────────────────────────────────────────────
Если A1sCatalogs.IsGroup(Ссылка) Тогда
    Сообщить("Это группа");
    Если A1sCatalogs.HasChildren(Ссылка) Тогда
        Сообщить("В ней есть элементы");
    КонецЕсли;
КонецЕсли;

РЕЦЕПТ 12 · A1sCatalogs

Details · IsEmpty · IsGroup — диагностика и проверки

⚡ Когда применять: нужно получить несколько реквизитов за один вызов, проверить тип ссылки
Details · IsEmpty · IsGroup · IsCatalog · IsRef
// ── Details: получить реквизиты одним вызовом без GetObject() ────────────
Инфо = A1sCatalogs.Details(НомСсылка);
// → { Type:"Номенклатура", Code:"000101", Description:"Квартира 101",
//      IsFolder:Ложь, DeletionMark:Ложь, Parent:СсылкаГруппы }

Сообщить(Инфо.Description + " (код: " + Инфо.Code + ")");
Сообщить("Помечен на удаление: " + Инфо.DeletionMark);

// С дополнительными реквизитами
Инфо = A1sCatalogs.Details(НомСсылка, "Площадь, Этаж, Цена, Статус");
Сообщить("Площадь: " + Инфо.Площадь + " м², этаж: " + Инфо.Этаж);

// ── IsEmpty: пустая ли ссылка ─────────────────────────────────────────────
Если A1sCatalogs.IsEmpty("Номенклатура", НомСсылка) Тогда
    Сообщить("Пустая ссылка!");
КонецЕсли;

// ── Проверки типа значения ────────────────────────────────────────────────
Если A1sCatalogs.IsCatalog(НекоеЗначение) Тогда   // является ли справочником
    Сообщить("Это справочник: " + НекоеЗначение.Метаданные().Имя);
КонецЕсли;

Если A1sCatalogs.IsRef(НекоеЗначение) Тогда      // ссылка (не объект)
ИначеЕсли A1sCatalogs.IsObject(НекоеЗначение) Тогда  // объект
КонецЕсли;

// GetObject / GetRef: явное приведение типа ───────────────────────────────
Объект  = A1sCatalogs.GetObject(НомСсылка);   // ссылка → объект
Ссылка  = A1sCatalogs.GetRef(НомОбъект);      // объект → ссылка
💡
Details vs GetObject. Details делает один лёгкий запрос через свойства ссылки — это быстрее, чем открывать объект. Используйте его когда нужно просто «прочитать» несколько полей без изменения.
Справочник функций

A1sCatalogs — все экспортируемые функции

Функция Сигнатура Что делает
Проверки типа
IsCatalog IsCatalog(Value) → Bool Является ли справочником (ссылка или объект)
IsRef IsRef(Value) → Bool Является ли ссылкой справочника
IsObject IsObject(Value) → Bool Является ли объектом справочника
GetObject GetObject(Value) → CatalogObject Привести к объекту
GetRef GetRef(Value) → CatalogRef Привести к ссылке
Manager Manager(Name) → CatalogManager Менеджер справочника по имени
Empty Empty(Name) → CatalogRef Пустая ссылка
Создание
Of Of(Name, Attrs?) → CatalogObject Создать новый элемент с реквизитами (не записан)
CreateGroup CreateGroup(Name, Desc, Parent?, Attrs?) Создать группу (не записана)
Copy Copy(ItemRef, Overrides?) → CatalogObject Скопировать элемент с перекрытием реквизитов
Find-or-create
Ensure Ensure(Name, Desc, Attrs?, Exact?) Найти по имени или создать
EnsureByCode EnsureByCode(Name, Code, Attrs?) Найти по коду или создать
EnsureGroup EnsureGroup(Name, Desc, Parent?) Найти или создать группу
EnsureBatch EnsureBatch(Name, Names[], Attrs?) Массово find-or-create по массиву имён
EnsureByTypev2.1 EnsureByType(TypeValue, Desc, Attrs?) Find-or-create по типу из метаданных реквизита
EnsureUpdatev2.1 EnsureUpdate(Name, Desc, Attrs?, Exact?, AutoResolve?) Upsert: найти и обновить или создать
Data mapping
MapRowv2.1 MapRow(SourceData, Scheme?) Трансформировать структуру: строки → ссылки по схеме
PickFromDocumentv2.1 PickFromDocument(DocRef, TabName, Field) Уникальные ссылки из ТЧ документа
Реквизиты и ТЧ
FillAttrs FillAttrs(Item, Data) Заполнить реквизиты из структуры
FillAttrsAuto FillAttrsAuto(Item, Data) Заполнить с авторазрешением строк в ссылки
Set Set(Item, Key, Value) Установить один реквизит
AddRow AddRow(Item, TabName, RowData) Добавить строку в ТЧ
AddRowAuto AddRowAuto(Item, TabName, RawData) Добавить строку с авторазрешением ссылок
AddRows AddRows(Item, TabName, Source, Mapping?) Загрузить строки из ТЗ или массива структур
ExportRows ExportRows(Item, TabName, Cols?) Выгрузить ТЧ в ТаблицуЗначений
Запись и удаление
Write Write(Item) → CatalogRef Записать элемент
Update Update(Ref, Fields|Name, Val?, Write?) Обновить реквизит(ы) и записать
UpdateAll UpdateAll(Items[], Fields|Name, Val?) Обновить массив → {Success, Failed}
MarkForDeletion MarkForDeletion(Ref, Mark?) Пометить / снять пометку удаления
MarkForDeletionBatch MarkForDeletionBatch(Items[], Mark?) Массовая пометка → {Success, Failed}
Move Move(Ref, NewParent, Write?) Переместить в другую группу
MoveBatch MoveBatch(Items[], NewParent) Переместить массив → {Success, Failed}
Поиск
ByName ByName(Name, Desc, Parent?, Exact?) По наименованию
ByCode ByCode(Name, Code) По коду
ByAttr ByAttr(Name, AttrName, Value) По реквизиту
ByGUID ByGUID(Name, GUIDStr) По GUID
ByNameList ByNameList(Name, "a,b,c", Sep?) Список имён через разделитель → массив
PickByName PickByName(Name, Names[]) Массив имён → массив найденных ссылок
PickByCode PickByCode(Name, Codes[]) Массив кодов → массив ссылок
PickByAttr PickByAttr(Name, AttrName, Values[]) Массив значений реквизита → массив ссылок
PickPredefined PickPredefined(Name, Names[]) Предопределённые по именам
Refs Refs(Name, Where?, Params?, Order?) Произвольное WHERE → массив ссылок
Count Count(Name, Where?, Params?) → Num Количество с условием
Exists Exists(Name, Where?, Params?) → Bool Проверить наличие с условием
TopLevelItems TopLevelItems(Name, Groups?) Элементы верхнего уровня
AllInGroup AllInGroup(Name, GroupRef, Nested?) Все элементы в группе
AllByOwner AllByOwner(Name, OwnerRef) Подчинённый справочник по владельцу
Иерархия
Parent Parent(Ref) → CatalogRef Родительская группа
Children Children(Ref, Recursive?) Дочерние элементы
Level Level(Ref) → Num Уровень вложенности (0 = корень)
Path Path(Ref, Sep=" / ") → String Полный путь через разделитель
HasChildren HasChildren(Ref) → Bool Есть ли дочерние элементы
Валидация
IsGroup IsGroup(Ref) → Bool Является ли группой
IsEmpty IsEmpty(Name, Value) → Bool Пустая ли ссылка
IsCodeUnique IsCodeUnique(Name, Code, Exclude?) Уникален ли код
Details Details(Ref, ExtraAttrs?) → Structure Реквизиты элемента без GetObject
On On(Name) → Fluent Fluent-обёртка A1sDP_Catalogs
SelfTest SelfTest() → Bool Самотест модуля