Итоги ИЕРАРХИЯ и ТОЛЬКО ИЕРАРХИЯ: проверить всё своё дерево9 против6строк

Учебные задачи

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

Где и как запускать

Полный серверный общий модуль УчебныйЯзык только нового собственного стенда УчебныеИерархическиеИтоги85 на 8.5.1.1343. BSL, запросы и транзакции здесь не исполнялись.

Подготовка

  1. В отдельной учебной базе 8.5.1.1343 создайте общий модуль УчебныйЯзык: Сервер=Истина, Глобальный=Ложь, ВызовСервера=Ложь, Привилегированный=Ложь. Клиентские и внешнее соединение отключены; ПовторноеИспользованиеВозвращаемыхЗначений=НеИспользовать.

  2. Вставьте весь приведённый текст в этот общий модуль. ВыполнитьПример — экспортная точка входа; остальные процедуры и функции располагаются рядом, а не внутри неё.

  3. В своей внешней учебной обработке создайте управляемую форму, команду Выполнить и кнопку. Клиентский обработчик Выполнить(Команда) вызывает свою процедуру ВыполнитьНаСервере(); она имеет директиву &НаСервереБезКонтекста и одну строку УчебныйЯзык.ВыполнитьПример();. Это серверный вызов общего модуля, а не разрешение клиенту прямо обращаться к серверной библиотеке.

  4. HTML только показывает BSL. Код в 1С не запускался; перечисленные результаты и отрицательные опыты проверяйте самостоятельно в собственном стенде.

  5. Создайте НОВУЮ отдельную пустую учебную базу, не копию приложения, на точной 8.5.1.1343. Конфигурация УчебныеИерархическиеИтоги85; совместимость отключена; единственный сеанс. Нет расширений базы/сеанса, подписок, общих реквизитов, документов, регистров, планов, последовательностей, фоновых заданий или внешних источников данных. Ошибки прав/схемы не являются ожидаемым результатом опыта.

  6. Справочники → УчебноеДерево85: Иерархический=Да; Вид иерархии=Иерархия групп и элементов; Ограничивать количество уровней=Нет; Владельцы пусты. Код только Строка, длина3; Автонумерация=Нет; Наименование длина20. Собственных реквизитов, табчастей и предопределённых элементов нет. Стандартные поля платформы остаются.

  7. Все объектные/менеджерские модули, формы, модули сеанса/приложения и обработчики вручную полностью пусты. Native МодульОбъекта и МодульМенеджера всегда Неопределено и не позволяют прочитать текст BSL: guard не выдаёт это значение за доказательство пустого модуля. Это обязательная проверка читателя в новом Конфигураторе; здесь Конфигуратор не запускался.

  8. Read-only guard проверяет минимальную схему, пустой ФиксированныйМассив предопределённых имён, пустые массивы трёх источников расширений БазаДанных/СеансАктивные/СеансОтключенные и отсутствие изменений метаданных расширениями. До действий запрещена чужая/вложенная транзакция и проверен Число0 собственных записей без их удаления.

  9. Основной код целиком заменяет свой серверный общий модуль УчебныйЯзык; все helpers расположены рядом с экспортной процедурой, не внутри неё. У модуля Сервер=Истина, Глобальный=Ложь, ВызовСервера=Ложь, Привилегированный=Ложь; клиентские/внешнее соединение отключены, повторное использование выключено. Для следующего урока замените модуль целиком, не объединяйте одноимённые экспортные точки.

  10. Новая собственная внешняя обработка УчебныйПускИерархическихИтогов85 → управляемая Форма → команда Выполнить и кнопка с одноимённым действием. Остальные модули пусты. Полный отдельный модуль формы:

    &НаКлиенте
    Процедура Выполнить(Команда)
    ВыполнитьНаСервере();
    Сообщить("Полные собственные проверки завершены; учебных записей не осталось");
    КонецПроцедуры

    &НаСервереБезКонтекста
    Процедура ВыполнитьНаСервере()
    УчебныйЯзык.ВыполнитьПример();
    КонецПроцедуры

  11. Будущий авторский BSL записывает ровно свои5узлов только внутри своей транзакции; не фиксирует её, не проводит/удаляет объекты. При успехе и ошибке обязательны собственный rollback и проверка завершения транзакции/отсутствия своих записей. Ничего заранее вручную не записывайте.

  12. Python моделирует только фиксированные входы, полные ожидания и нашу проверку состава/дерева. Direct HBK подтверждает нативный текст установленной версии, но ни он, ни focused/static tests не доказывают исполнение BSL/запросов/отката в 1С.

  13. Общий обязательный этап перед первым ручным запуском каждого урока: после ВСЕХ настроек метаданных, флагов общего модуля, вставки полного основного модуля и подготовки полного модуля своей формы сохраните свою конфигурацию. Завершите свой предыдущий учебный сеанс; активной транзакции и выполняющегося учебного опыта быть не должно. В Конфигураторе своего стенда выполните Конфигурация → Обновить конфигурацию базы данных (F7), подтвердите только изменения своей новой учебной конфигурации и дождитесь успешного завершения обновления. Затем запустите свежий учебный сеанс и только в нём нажимайте Выполнить. Здесь F7 означает только обновление конфигурации базы данных автором стенда ДО ручного запуска, никогда не аварийный опыт и не действие после пяти Записать внутри активной транзакции. Сохранение/обновление/1С здесь не выполнялись.

  14. Отдельный будущий ручной опыт «Контроль аварийного отката» выполняется только после обычного положительного опыта и подтверждённого Число0 в своей новой базе. Завершите положительный опыт и свой учебный сеанс до редактирования модуля. В Конфигураторе → Общие → Общие модули → УчебныйЯзык → Модуль временно вставьте ровно одну строку ВызватьИсключение "Учебная авария после пяти собственных записей"; сразу после строки ЛистЗ = СоздатьСвойУзел("201", "A-Z", ГруппаБ, Ложь, СвоиРодители); внутри Попытка экспортной ВыполнитьПример и до ОжиданияКаталога = Новый Массив. При будущем выполнении к этому месту завершатся ровно5собственных Записать; рабочие запросы/сверка каталога ещё не начнутся. Позиция строки BSL не означает обновление конфигурации во время опыта. Не вставляйте ошибку внутрь валидатора или его локального catch.

  15. Подготовка «Контроля аварийного отката» после временной вставки: сохраните свою конфигурацию и вне активной транзакции/до нового ручного запуска выполните Конфигурация → Обновить конфигурацию базы данных (F7). Дождитесь успешного обновления и запустите свежий учебный сеанс. Не обновляйте конфигурацию после пяти Записать или при остановленном в активной транзакции серверном коде: там исполняется уже подготовленная строка ВызватьИсключение, а не обновление конфигурации.

  16. «Контроль аварийного отката»: включите серверную отладку своей базы и поставьте останов в ПроверитьОтсутствиеСвоихЗаписей при вызове из аварийной очистки после ОтменитьТранзакцию, не на предварительный вызов до НачатьТранзакцию. После нажатия Выполнить продолжите исходную контролируемую ошибку через внешний Исключение. Здесь ТранзакцияАктивна() должна быть Булево Ложь; в собственной ПроверитьОтсутствиеСвоихЗаписей после Выполнить().Выгрузить() проверьте фактические Таблица.Количество()=1, одну колонку Количество и Таблица[0].Количество=Число0. Это actual readback нового собственного справочника вне транзакции, не обещание модели Python.

  17. «Контроль аварийного отката»: после завершения аварийной очистки вызов обязан закончиться ошибкой, а не сообщениями успешного опыта или launcher «Полные собственные проверки завершены». Если rollback/readback/Закрыть тоже отказали, фиксируйте фактическую диагностику и неподтверждённую очистку, не считайте контроль аварийного отката пройденным и не обновляйте конфигурацию при активном опыте. Завершите свой учебный сеанс до изменения модуля. Удалите только свою временную строку исключения из своего общего модуля, восстановите полный исходный положительный текст, сохраните конфигурацию и вне активной транзакции выполните Конфигурация → Обновить конфигурацию базы данных (F7). Дождитесь успешного обновления, затем запустите свежий учебный сеанс для отдельного повторения положительного опыта; ничего не удаляйте из базы. Контроль аварийного отката/отладчик/1С здесь не запускались.

Процедура ВыполнитьПример() Экспорт
    ПроверитьСвойИерархическийСтенд();
    Если ТранзакцияАктивна() Тогда
        ВызватьИсключение "Чужая или вложенная активная транзакция запрещена";
    КонецЕсли;
    ПроверитьОтсутствиеСвоихЗаписей();
    Менеджер = Неопределено;
    НачатьТранзакцию();
    Попытка
        Менеджер = Новый МенеджерВременныхТаблиц;
        ПустойРодитель = Справочники.УчебноеДерево85.ПустаяСсылка();
        СвоиРодители = Новый Массив;
        СвоиРодители.Добавить(ПустойРодитель);
        ПроверитьСвойВводУзла("001", "A", ПустойРодитель, Истина, СвоиРодители);
        ПроверитьСвойВводУзла("999", "12345678901234567890", ПустойРодитель, Истина, СвоиРодители);
        ПроверитьОтклонениеСвоегоУзла(Неопределено, "A", ПустойРодитель, Истина, СвоиРодители);
        ПроверитьОтклонениеСвоегоУзла("001", 7, ПустойРодитель, Истина, СвоиРодители);
        ПроверитьОтклонениеСвоегоУзла("01", "A", ПустойРодитель, Истина, СвоиРодители);
        ПроверитьОтклонениеСвоегоУзла("001", "", ПустойРодитель, Истина, СвоиРодители);
        ПроверитьОтклонениеСвоегоУзла("001", "A", Неопределено, Истина, СвоиРодители);
        ПроверитьОтклонениеСвоегоУзла("001", "A", ПустойРодитель, "Истина", СвоиРодители);
        ПроверитьОтклонениеСвоегоУзла("001", "A", ПустойРодитель, Ложь, СвоиРодители);
        ПроверитьОтказУровняПустойСсылки(ПустойРодитель);
        ГруппаА = СоздатьСвойУзел("100", "B-A", ПустойРодитель, Истина, СвоиРодители);
        СвоиРодители.Добавить(ГруппаА);
        ГруппаБ = СоздатьСвойУзел("200", "C-B", ПустойРодитель, Истина, СвоиРодители);
        СвоиРодители.Добавить(ГруппаБ);
        ЛистХ = СоздатьСвойУзел("101", "A-X", ГруппаА, Ложь, СвоиРодители);
        ЛистУ = СоздатьСвойУзел("102", "D-Y", ГруппаА, Ложь, СвоиРодители);
        ЛистЗ = СоздатьСвойУзел("201", "A-Z", ГруппаБ, Ложь, СвоиРодители);
        ОжиданияКаталога = Новый Массив;
        ОжиданияКаталога.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ГруппаА, "100", "B-A", ПустойРодитель, Истина));
        ОжиданияКаталога.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ЛистХ, "101", "A-X", ГруппаА, Ложь));
        ОжиданияКаталога.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ЛистУ, "102", "D-Y", ГруппаА, Ложь));
        ОжиданияКаталога.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ГруппаБ, "200", "C-B", ПустойРодитель, Истина));
        ОжиданияКаталога.Добавить(Новый Структура("Ссылка,Код,Наименование,Родитель,ЭтоГруппа", ЛистЗ, "201", "A-Z", ГруппаБ, Ложь));
        ПроверитьСвойКаталожныйСостав(ОжиданияКаталога);
        ПроверитьСвоеКоличество(0);
        ПроверитьСвоеКоличество(9999);
        ПроверитьОтклонениеСвоегоКоличества(Неопределено);
        ПроверитьОтклонениеСвоегоКоличества("2");
        ПроверитьОтклонениеСвоегоКоличества(-1);
        ПроверитьОтклонениеСвоегоКоличества(10000);
        ПроверитьОтклонениеСвоегоКоличества(2.5);
        СвоиЛисты = Новый Массив;
        СвоиЛисты.Добавить(ЛистХ);
        СвоиЛисты.Добавить(ЛистУ);
        СвоиЛисты.Добавить(ЛистЗ);
        ПроверитьОтклонениеСвоейДетали(Неопределено, 2, СвоиЛисты);
        ПроверитьОтклонениеСвоейДетали(ПустойРодитель, 2, СвоиЛисты);
        ПроверитьОтклонениеСвоейДетали(ГруппаА, 2, СвоиЛисты);
        Источник = Новый ТаблицаЗначений;
        Источник.Колонки.Добавить("Узел", Новый ОписаниеТипов("СправочникСсылка.УчебноеДерево85"));
        Источник.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(4, 0, ДопустимыйЗнак.Неотрицательный)));
        ПроверитьСвоюТипизированнуюКолонку(Источник, "Узел", Тип("СправочникСсылка.УчебноеДерево85"));
        ПроверитьСвойЧисловойКвалификатор(Источник);
        ОжиданияДеталей = Новый Массив;
        ПроверитьСвойВводДетали(ЛистХ, 2, СвоиЛисты);
        Строка = Источник.Добавить();
        Строка.Узел = ЛистХ;
        Строка.Количество = 2;
        ОжиданияДеталей.Добавить(Новый Структура("Узел,Количество", ЛистХ, 2));
        ПроверитьСвойВводДетали(ЛистХ, 3, СвоиЛисты);
        Строка = Источник.Добавить();
        Строка.Узел = ЛистХ;
        Строка.Количество = 3;
        ОжиданияДеталей.Добавить(Новый Структура("Узел,Количество", ЛистХ, 3));
        ПроверитьСвойВводДетали(ЛистУ, 7, СвоиЛисты);
        Строка = Источник.Добавить();
        Строка.Узел = ЛистУ;
        Строка.Количество = 7;
        ОжиданияДеталей.Добавить(Новый Структура("Узел,Количество", ЛистУ, 7));
        ПроверитьСвойВводДетали(ЛистЗ, 11, СвоиЛисты);
        Строка = Источник.Добавить();
        Строка.Узел = ЛистЗ;
        Строка.Количество = 11;
        ОжиданияДеталей.Добавить(Новый Структура("Узел,Количество", ЛистЗ, 11));
        ПоляДеталей = Новый Массив;
        ПоляДеталей.Добавить("Узел");
        ПоляДеталей.Добавить("Количество");
        ПроверитьСвоюПолнуюТаблицу(Источник, ОжиданияДеталей, ПоляДеталей, Ложь);
        Загрузка = Новый Запрос;
        Загрузка.МенеджерВременныхТаблиц = Менеджер;
        Загрузка.Текст = "ВЫБРАТЬ Ист.Узел КАК Узел, Ист.Количество КАК Количество ПОМЕСТИТЬ СвоиДетали ИЗ &Источник КАК Ист";
        Загрузка.УстановитьПараметр("Источник", Источник);
        Загрузка.Выполнить();
        ПроверитьСвойИсходникДеталей(Менеджер, Источник, ОжиданияДеталей);
        ПоляОбхода = Новый Массив;
        ПоляОбхода.Добавить("Узел");
        ПоляОбхода.Добавить("Количество");
        ПоляОбхода.Добавить("Вид");
        ПоляОбхода.Добавить("Группировка");
        ПоляОбхода.Добавить("Глубина");
        ПоляОбхода.Добавить("РодительВетки");
        ОжиданияОбхода = Новый Массив;
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ГруппаА, 12, ТипЗаписиЗапроса.ИтогПоИерархии, "Узлы", 0, ПустойРодитель));
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ЛистХ, 5, ТипЗаписиЗапроса.ИтогПоГруппировке, "Узлы", 1, ГруппаА));
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ЛистХ, 2, ТипЗаписиЗапроса.ДетальнаяЗапись, "", 2, ЛистХ));
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ЛистХ, 3, ТипЗаписиЗапроса.ДетальнаяЗапись, "", 2, ЛистХ));
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ЛистУ, 7, ТипЗаписиЗапроса.ИтогПоГруппировке, "Узлы", 1, ГруппаА));
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ЛистУ, 7, ТипЗаписиЗапроса.ДетальнаяЗапись, "", 2, ЛистУ));
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ГруппаБ, 11, ТипЗаписиЗапроса.ИтогПоИерархии, "Узлы", 0, ПустойРодитель));
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ЛистЗ, 11, ТипЗаписиЗапроса.ИтогПоГруппировке, "Узлы", 1, ГруппаБ));
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ЛистЗ, 11, ТипЗаписиЗапроса.ДетальнаяЗапись, "", 2, ЛистЗ));
        Запрос = Новый Запрос;
        Запрос.МенеджерВременныхТаблиц = Менеджер;
        Запрос.Текст = "ВЫБРАТЬ Дет.Узел КАК Узел, Дет.Количество КАК Количество
            |ИЗ СвоиДетали КАК Дет
            |ИТОГИ СУММА(Количество) ПО Узел ИЕРАРХИЯ КАК Узлы";
        Результат = Запрос.Выполнить();
        Если Результат.Колонки.Количество() <> 2 Или Результат.Колонки.Найти("Узел") = Неопределено
            Или Результат.Колонки.Найти("Количество") = Неопределено Тогда
            ВызватьИсключение "Нужны ровно две реальные колонки итогового результата";
        КонецЕсли;
        Обход = СоздатьТаблицуСвоегоОбхода();
        Группы = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией, "Узлы");
        СобратьСвойОбход(Группы, 0, ПустойРодитель, Ложь, Обход);
        ПроверитьСвоюПолнуюТаблицу(Обход, ОжиданияОбхода, ПоляОбхода, Ложь);
        ДетальнаяТаблица = Результат.Выгрузить(ОбходРезультатаЗапроса.Прямой);
        ПроверитьСвоюПолнуюТаблицу(ДетальнаяТаблица, ОжиданияДеталей, ПоляДеталей, Ложь);
        ПроверитьСвойИсходникДеталей(Менеджер, Источник, ОжиданияДеталей);
        ПроверитьСвойКаталожныйСостав(ОжиданияКаталога);
        Сообщить("ИЕРАРХИЯ: полный состав 9 строк; четыре детали сохранены отдельно");
        ОжиданияОбхода = Новый Массив;
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ГруппаА, 12, ТипЗаписиЗапроса.ИтогПоИерархии, "Узлы", 0, ПустойРодитель));
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ЛистХ, 2, ТипЗаписиЗапроса.ДетальнаяЗапись, "", 1, ГруппаА));
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ЛистХ, 3, ТипЗаписиЗапроса.ДетальнаяЗапись, "", 1, ГруппаА));
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ЛистУ, 7, ТипЗаписиЗапроса.ДетальнаяЗапись, "", 1, ГруппаА));
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ГруппаБ, 11, ТипЗаписиЗапроса.ИтогПоИерархии, "Узлы", 0, ПустойРодитель));
        ОжиданияОбхода.Добавить(Новый Структура("Узел,Количество,Вид,Группировка,Глубина,РодительВетки", ЛистЗ, 11, ТипЗаписиЗапроса.ДетальнаяЗапись, "", 1, ГруппаБ));
        Запрос = Новый Запрос;
        Запрос.МенеджерВременныхТаблиц = Менеджер;
        Запрос.Текст = "ВЫБРАТЬ Дет.Узел КАК Узел, Дет.Количество КАК Количество
            |ИЗ СвоиДетали КАК Дет
            |ИТОГИ СУММА(Количество) ПО Узел ТОЛЬКО ИЕРАРХИЯ КАК Узлы";
        Результат = Запрос.Выполнить();
        Если Результат.Колонки.Количество() <> 2 Или Результат.Колонки.Найти("Узел") = Неопределено
            Или Результат.Колонки.Найти("Количество") = Неопределено Тогда
            ВызватьИсключение "Нужны ровно две реальные колонки итогового результата";
        КонецЕсли;
        Обход = СоздатьТаблицуСвоегоОбхода();
        Группы = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией, "Узлы");
        СобратьСвойОбход(Группы, 0, ПустойРодитель, Истина, Обход);
        ПроверитьСвоюПолнуюТаблицу(Обход, ОжиданияОбхода, ПоляОбхода, Ложь);
        ДетальнаяТаблица = Результат.Выгрузить(ОбходРезультатаЗапроса.Прямой);
        ПроверитьСвоюПолнуюТаблицу(ДетальнаяТаблица, ОжиданияДеталей, ПоляДеталей, Ложь);
        ПроверитьСвойИсходникДеталей(Менеджер, Источник, ОжиданияДеталей);
        ПроверитьСвойКаталожныйСостав(ОжиданияКаталога);
        Сообщить("ТОЛЬКО ИЕРАРХИЯ: полный состав 6 строк; четыре детали сохранены отдельно");
        СуммаДеталей = 0;
        Для Каждого ДетальнаяСтрока Из ДетальнаяТаблица Цикл
            СуммаДеталей = СуммаДеталей + ДетальнаяСтрока.Количество;
        КонецЦикла;
        Если ТипЗнч(СуммаДеталей) <> Тип("Число") Или СуммаДеталей <> 23 Тогда
            ВызватьИсключение "Своя независимая сумма четырёх деталей должна быть Число23";
        КонецЕсли;
        Сообщить("Детали2+3+7+11=23; не суммировать повторно итоги разных уровней");
    Исключение
        ЗавершитьСвоюТранзакциюИВТ(Менеджер);
        ВызватьИсключение;
    КонецПопытки;
    ЗавершитьСвоюТранзакциюИВТ(Менеджер);
    Сообщить("Пять своих записей отменены; новый собственный справочник снова пуст");
КонецПроцедуры

Процедура ПроверитьСвойИерархическийСтенд()
    Если Метаданные.Справочники.Количество() <> 1 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
        ВызватьИсключение "Нужен только свой новый минимальный стенд";
    КонецЕсли;
    Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
        ВызватьИсключение "Метаданные своего сеанса не должны изменяться расширениями";
    КонецЕсли;
    ИсточникиРасширений = Новый Массив;
    ИсточникиРасширений.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
    ИсточникиРасширений.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
    ИсточникиРасширений.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
    Для Каждого ИсточникРасширений Из ИсточникиРасширений Цикл
        СписокРасширений = РасширенияКонфигурации.Получить(, ИсточникРасширений);
        Если ТипЗнч(СписокРасширений) <> Тип("Массив") Тогда
            ВызватьИсключение "Список расширений должен иметь native тип Массив";
        КонецЕсли;
        Если СписокРасширений.Количество() <> 0 Тогда
            ВызватьИсключение "В новом своём стенде не должно быть расширений базы или сеанса";
        КонецЕсли;
    КонецЦикла;
    МетаДерево = Метаданные.Справочники.Найти("УчебноеДерево85");
    Если МетаДерево = Неопределено Тогда
        ВызватьИсключение "Не найден свой справочник УчебноеДерево85";
    КонецЕсли;
    Свойства = Метаданные.СвойстваОбъектов;
    Если Не МетаДерево.Иерархический Или МетаДерево.ВидИерархии <> Свойства.ВидИерархии.ИерархияГруппИЭлементов
        Или МетаДерево.ОграничиватьКоличествоУровней Или МетаДерево.Владельцы.Количество() <> 0
        Или МетаДерево.ТипКода <> Свойства.ТипКодаСправочника.Строка Или МетаДерево.ДлинаКода <> 3
        Или МетаДерево.ДлинаНаименования <> 20 Или МетаДерево.Автонумерация
        Или МетаДерево.Реквизиты.Количество() <> 0 Или МетаДерево.ТабличныеЧасти.Количество() <> 0 Тогда
        ВызватьИсключение "Не совпала своя минимальная схема иерархии";
    КонецЕсли;
    Имена = МетаДерево.ПолучитьИменаПредопределенных();
    Если ТипЗнч(Имена) <> Тип("ФиксированныйМассив") Тогда
        ВызватьИсключение "Предопределённые имена должны иметь native тип ФиксированныйМассив";
    КонецЕсли;
    Если Имена.Количество() <> 0 Тогда
        ВызватьИсключение "В своём справочнике нет предопределённых имён";
    КонецЕсли;
КонецПроцедуры

Функция ПолностьюСовпадаетСвояСтрока(СтрокаТаблицы, Ожидаемая, Поля, Колонки)
    Для Каждого ИмяПоля Из Поля Цикл
        Если Не Ожидаемая.Свойство(ИмяПоля, Ожидание) Тогда
            ВызватьИсключение "Не найдено полное собственное ожидание поля " + ИмяПоля;
        КонецЕсли;
        Колонка = Колонки.Найти(ИмяПоля);
        Факт = СтрокаТаблицы.Получить(Колонки.Индекс(Колонка));
        Если ТипЗнч(Факт) <> ТипЗнч(Ожидание) Тогда
            Возврат Ложь;
        КонецЕсли;
        Если Факт <> Ожидание Тогда
            Возврат Ложь;
        КонецЕсли;
    КонецЦикла;
    Возврат Истина;
КонецФункции

Процедура ПроверитьСвоюПолнуюТаблицу(Таблица, Ожидания, Поля, Упорядоченный)
    Если ТипЗнч(Таблица) <> Тип("ТаблицаЗначений") Тогда
        ВызватьИсключение "Нужна своя ТаблицаЗначений";
    КонецЕсли;
    Если Таблица.Колонки.Количество() <> Поля.Количество() Или Таблица.Количество() <> Ожидания.Количество() Тогда
        ВызватьИсключение "Не совпали полные размеры своей таблицы";
    КонецЕсли;
    Для Каждого ИмяПоля Из Поля Цикл
        Если Таблица.Колонки.Найти(ИмяПоля) = Неопределено Тогда
            ВызватьИсключение "Не найдена своя колонка " + ИмяПоля;
        КонецЕсли;
    КонецЦикла;
    Использованные = Новый Массив;
    Если Ожидания.Количество() > 0 Тогда
        Для Индекс = 0 По Ожидания.Количество() - 1 Цикл
            Если Упорядоченный Тогда
                Если Не ПолностьюСовпадаетСвояСтрока(Таблица[Индекс], Ожидания[Индекс], Поля, Таблица.Колонки) Тогда
                    ВызватьИсключение "Не совпали все поля, типы или порядок своей строки";
                КонецЕсли;
            Иначе
                Найден = -1;
                Для Кандидат = 0 По Ожидания.Количество() - 1 Цикл
                    Если Использованные.Найти(Кандидат) = Неопределено Тогда
                        Если ПолностьюСовпадаетСвояСтрока(Таблица[Индекс], Ожидания[Кандидат], Поля, Таблица.Колонки) Тогда
                            Найден = Кандидат;
                            Прервать;
                        КонецЕсли;
                    КонецЕсли;
                КонецЦикла;
                Если Найден = -1 Тогда
                    ВызватьИсключение "Не совпал полный свой unordered состав с кратностями";
                КонецЕсли;
                Использованные.Добавить(Найден);
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
КонецПроцедуры

Процедура ПроверитьОтсутствиеСвоихЗаписей()
    Если ТранзакцияАктивна() Тогда
        ВызватьИсключение "Пустота своей базы проверяется вне транзакции";
    КонецЕсли;
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ КОЛИЧЕСТВО(*) КАК Количество ИЗ Справочник.УчебноеДерево85";
    Таблица = Запрос.Выполнить().Выгрузить();
    Если Таблица.Количество() <> 1 Или Таблица.Колонки.Количество() <> 1
        Или Таблица.Колонки.Найти("Количество") = Неопределено Тогда
        ВызватьИсключение "Не совпала полная форма собственного счётчика";
    КонецЕсли;
    Если ТипЗнч(Таблица[0].Количество) <> Тип("Число") Тогда
        ВызватьИсключение "Свой счётчик должен иметь тип Число";
    КонецЕсли;
    Если Таблица[0].Количество <> 0 Тогда
        ВызватьИсключение "Новая собственная база должна быть пустой; код ничего не удаляет";
    КонецЕсли;
КонецПроцедуры

Процедура ПроверитьСвойВводУзла(Код, Наименование, Родитель, ЭтоГруппа, СвоиРодители)
    Если ТипЗнч(Код) <> Тип("Строка") Или ТипЗнч(Наименование) <> Тип("Строка") Тогда
        ВызватьИсключение "Собственные код и наименование должны иметь тип Строка";
    КонецЕсли;
    Если СтрДлина(Код) <> 3 Или СтрДлина(Наименование) < 1 Или СтрДлина(Наименование) > 20 Тогда
        ВызватьИсключение "Собственный код имеет длину3, имя1..20";
    КонецЕсли;
    Если ТипЗнч(Родитель) <> Тип("СправочникСсылка.УчебноеДерево85") Или ТипЗнч(ЭтоГруппа) <> Тип("Булево")
        Или ТипЗнч(СвоиРодители) <> Тип("Массив") Тогда
        ВызватьИсключение "Не совпали собственные типы родителя, признака группы или списка родителей";
    КонецЕсли;
    Если СвоиРодители.Найти(Родитель) = Неопределено Тогда
        ВызватьИсключение "Родитель должен принадлежать данному собственному fixture";
    КонецЕсли;
    Пустой = Справочники.УчебноеДерево85.ПустаяСсылка();
    Если ЭтоГруппа И Родитель <> Пустой Тогда
        ВызватьИсключение "Наши две группы расположены только в корне";
    КонецЕсли;
    Если Не ЭтоГруппа И Родитель = Пустой Тогда
        ВызватьИсключение "Наши три элемента располагаются только в своих группах";
    КонецЕсли;
КонецПроцедуры

Процедура ПроверитьОтклонениеСвоегоУзла(Код, Наименование, Родитель, ЭтоГруппа, СвоиРодители)
    Отклонён = Ложь;
    Попытка
        ПроверитьСвойВводУзла(Код, Наименование, Родитель, ЭтоГруппа, СвоиРодители);
    Исключение
        Отклонён = Истина;
        Сообщить("Ручной опыт: свой неверный ввод узла отклонён. " + ОписаниеОшибки());
    КонецПопытки;
    Если Не Отклонён Тогда
        ВызватьИсключение "Ожидалось отклонение данного собственного ввода узла";
    КонецЕсли;
КонецПроцедуры

Функция СоздатьСвойУзел(Код, Наименование, Родитель, ЭтоГруппа, СвоиРодители)
    ПроверитьСвойВводУзла(Код, Наименование, Родитель, ЭтоГруппа, СвоиРодители);
    Если ЭтоГруппа Тогда
        Объект = Справочники.УчебноеДерево85.СоздатьГруппу();
    Иначе
        Объект = Справочники.УчебноеДерево85.СоздатьЭлемент();
    КонецЕсли;
    Если ТипЗнч(Объект.ЭтоГруппа) <> Тип("Булево") Или Объект.ЭтоГруппа <> ЭтоГруппа Тогда
        ВызватьИсключение "Native readonly ЭтоГруппа не совпало с выбранной фабрикой";
    КонецЕсли;
    Объект.Код = Код;
    Объект.Наименование = Наименование;
    Объект.Родитель = Родитель;
    Объект.Записать();
    Ссылка = Объект.Ссылка;
    Если ТипЗнч(Ссылка) <> Тип("СправочникСсылка.УчебноеДерево85") Тогда
        ВызватьИсключение "После записи нужна собственная ссылка узла";
    КонецЕсли;
    Если Ссылка = Справочники.УчебноеДерево85.ПустаяСсылка() Тогда
        ВызватьИсключение "Своя записанная ссылка не должна быть пустой";
    КонецЕсли;
    Возврат Ссылка;
КонецФункции

Процедура ПроверитьСвойКаталожныйСостав(Ожидания)
    Проверка = Новый Запрос;
    Проверка.Текст = "ВЫБРАТЬ Кат.Ссылка КАК Ссылка, Кат.Код КАК Код, Кат.Наименование КАК Наименование,
    |Кат.Родитель КАК Родитель, Кат.ЭтоГруппа КАК ЭтоГруппа
    |ИЗ Справочник.УчебноеДерево85 КАК Кат УПОРЯДОЧИТЬ ПО Кат.Код ВОЗР";
    Поля = Новый Массив;
    Поля.Добавить("Ссылка");
    Поля.Добавить("Код");
    Поля.Добавить("Наименование");
    Поля.Добавить("Родитель");
    Поля.Добавить("ЭтоГруппа");
    Таблица = Проверка.Выполнить().Выгрузить();
    ПроверитьСвоюПолнуюТаблицу(Таблица, Ожидания, Поля, Истина);
    Для Каждого Строка Из Таблица Цикл
        УровеньКаталога = Строка.Ссылка.Уровень();
        Если ТипЗнч(УровеньКаталога) <> Тип("Число") Тогда
            ВызватьИсключение "Native уровень своей непустой ссылки должен иметь тип Число";
        КонецЕсли;
        Если Строка.ЭтоГруппа Тогда
            Если УровеньКаталога <> 0 Тогда
                ВызватьИсключение "Своя группа без родителя должна иметь каталожный уровень0";
            КонецЕсли;
        Иначе
            Если УровеньКаталога <> 1 Тогда
                ВызватьИсключение "Свой лист под корневой группой должен иметь каталожный уровень1";
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Процедура ПроверитьОтказУровняПустойСсылки(Пустая)
    Отклонён = Ложь;
    Попытка
        Пустая.Уровень();
    Исключение
        Отклонён = Истина;
        Сообщить("Ручной native опыт: Уровень пустой ссылки вызвал исключение. " + ОписаниеОшибки());
    КонецПопытки;
    Если Не Отклонён Тогда
        ВызватьИсключение "По native вызов Уровень пустой ссылки должен вызвать исключение";
    КонецЕсли;
КонецПроцедуры

Процедура ПроверитьСвоюТипизированнуюКолонку(Таблица, Имя, НужныйТип)
    Колонка = Таблица.Колонки.Найти(Имя);
    Если Колонка = Неопределено Тогда
        ВызватьИсключение "Не найдена своя типизированная колонка " + Имя;
    КонецЕсли;
    Описание = Колонка.ТипЗначения;
    Если Описание.Типы().Количество() <> 1 Или Не Описание.СодержитТип(НужныйТип) Тогда
        ВызватьИсключение "В собственной колонке должен быть ровно заданный тип";
    КонецЕсли;
КонецПроцедуры

Процедура ПроверитьСвоеКоличество(Количество)
    Если ТипЗнч(Количество) <> Тип("Число") Тогда
        ВызватьИсключение "Собственное количество должно иметь тип Число";
    КонецЕсли;
    Если Количество < 0 Или Количество > 9999 Или Количество <> Цел(Количество) Тогда
        ВызватьИсключение "Собственное количество должно быть целым0..9999";
    КонецЕсли;
КонецПроцедуры

Процедура ПроверитьОтклонениеСвоегоКоличества(Количество)
    Отклонён = Ложь;
    Попытка
        ПроверитьСвоеКоличество(Количество);
    Исключение
        Отклонён = Истина;
        Сообщить("Ручной опыт: своё неверное количество отклонено. " + ОписаниеОшибки());
    КонецПопытки;
    Если Не Отклонён Тогда
        ВызватьИсключение "Ожидалось отклонение данного собственного количества";
    КонецЕсли;
КонецПроцедуры

Процедура ПроверитьСвойЧисловойКвалификатор(Таблица)
    ПроверитьСвоюТипизированнуюКолонку(Таблица, "Количество", Тип("Число"));
    Квалификатор = Таблица.Колонки.Найти("Количество").ТипЗначения.КвалификаторыЧисла;
    Если Квалификатор.Разрядность <> 4 Или Квалификатор.РазрядностьДробнойЧасти <> 0
        Или Квалификатор.ДопустимыйЗнак <> ДопустимыйЗнак.Неотрицательный Тогда
        ВызватьИсключение "Количество должно иметь собственный Число(4,0), неотрицательный";
    КонецЕсли;
КонецПроцедуры

Процедура ПроверитьСвойВводДетали(Узел, Количество, СвоиЛисты)
    Если ТипЗнч(Узел) <> Тип("СправочникСсылка.УчебноеДерево85") Или ТипЗнч(СвоиЛисты) <> Тип("Массив") Тогда
        ВызватьИсключение "Детали нужны своя ссылка и свой список листов";
    КонецЕсли;
    Если СвоиЛисты.Найти(Узел) = Неопределено Тогда
        ВызватьИсключение "Деталь относится только к одному из трёх настоящих своих листов";
    КонецЕсли;
    ПроверитьСвоеКоличество(Количество);
КонецПроцедуры

Процедура ПроверитьОтклонениеСвоейДетали(Узел, Количество, СвоиЛисты)
    Отклонён = Ложь;
    Попытка
        ПроверитьСвойВводДетали(Узел, Количество, СвоиЛисты);
    Исключение
        Отклонён = Истина;
        Сообщить("Ручной опыт: своя неверная деталь отклонена. " + ОписаниеОшибки());
    КонецПопытки;
    Если Не Отклонён Тогда
        ВызватьИсключение "Ожидалось отклонение данной собственной детали";
    КонецЕсли;
КонецПроцедуры

Функция СоздатьТаблицуСвоегоОбхода()
    Таблица = Новый ТаблицаЗначений;
    Таблица.Колонки.Добавить("Узел", Новый ОписаниеТипов("СправочникСсылка.УчебноеДерево85"));
    Таблица.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(4, 0, ДопустимыйЗнак.Неотрицательный)));
    Таблица.Колонки.Добавить("Вид", Новый ОписаниеТипов("ТипЗаписиЗапроса"));
    Таблица.Колонки.Добавить("Группировка", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20, ДопустимаяДлина.Переменная)));
    Таблица.Колонки.Добавить("Глубина", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(2, 0, ДопустимыйЗнак.Неотрицательный)));
    Таблица.Колонки.Добавить("РодительВетки", Новый ОписаниеТипов("СправочникСсылка.УчебноеДерево85"));
    Возврат Таблица;
КонецФункции

Процедура СобратьСвойОбход(Выборка, Глубина, РодительВетки, ТолькоИерархия, Таблица)
    Если ТипЗнч(Выборка) <> Тип("ВыборкаИзРезультатаЗапроса") Тогда
        ВызватьИсключение "Нужна настоящая native выборка результата";
    КонецЕсли;
    Если Глубина > 2 Или (ТолькоИерархия И Глубина > 1) Тогда
        ВызватьИсключение "Свой обход вышел за полную ожидаемую структуру";
    КонецЕсли;
    Пока Выборка.Следующий() Цикл
        Узел = Выборка.Узел;
        Количество = Выборка.Количество;
        Вид = Выборка.ТипЗаписи();
        Группировка = Выборка.Группировка();
        УровеньВыборки = Выборка.Уровень();
        Если ТипЗнч(Узел) <> Тип("СправочникСсылка.УчебноеДерево85") Или ТипЗнч(Количество) <> Тип("Число")
            Или ТипЗнч(Вид) <> Тип("ТипЗаписиЗапроса") Или ТипЗнч(Группировка) <> Тип("Строка")
            Или ТипЗнч(УровеньВыборки) <> Тип("Число") Тогда
            ВызватьИсключение "Не совпали все native типы реальной строки обхода";
        КонецЕсли;
        Если Вид <> ТипЗаписиЗапроса.ДетальнаяЗапись И Вид <> ТипЗаписиЗапроса.ИтогПоГруппировке
            И Вид <> ТипЗаписиЗапроса.ИтогПоИерархии Тогда
            ВызватьИсключение "В своём опыте нет других видов строк или ОБЩИЕ";
        КонецЕсли;
        Если ТолькоИерархия И Вид = ТипЗаписиЗапроса.ИтогПоГруппировке Тогда
            ВызватьИсключение "ТОЛЬКО ИЕРАРХИЯ не должна добавлять контрольную точку листа";
        КонецЕсли;
        ЗаписьОбхода = Таблица.Добавить();
        ЗаписьОбхода.Узел = Узел;
        ЗаписьОбхода.Количество = Количество;
        ЗаписьОбхода.Вид = Вид;
        ЗаписьОбхода.Группировка = Группировка;
        ЗаписьОбхода.Глубина = Глубина;
        ЗаписьОбхода.РодительВетки = РодительВетки;
        Сообщить("Собственная структурная глубина=" + Строка(Глубина) + "; фактический native Уровень="
            + Строка(УровеньВыборки) + "; тип native уровня=" + Строка(ТипЗнч(УровеньВыборки)));
        Если Вид = ТипЗаписиЗапроса.ИтогПоИерархии Тогда
            Если ТолькоИерархия Тогда
                Дети = Выборка.Выбрать(ОбходРезультатаЗапроса.Прямой, "");
            Иначе
                Дети = Выборка.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией, "Узлы");
            КонецЕсли;
            СобратьСвойОбход(Дети, Глубина + 1, Узел, ТолькоИерархия, Таблица);
        ИначеЕсли Вид = ТипЗаписиЗапроса.ИтогПоГруппировке Тогда
            Детали = Выборка.Выбрать(ОбходРезультатаЗапроса.Прямой, "");
            СобратьСвойОбход(Детали, Глубина + 1, Узел, ТолькоИерархия, Таблица);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Процедура ПроверитьСвойИсходникДеталей(Менеджер, Источник, Ожидания)
    ПроверитьСвоюТипизированнуюКолонку(Источник, "Узел", Тип("СправочникСсылка.УчебноеДерево85"));
    ПроверитьСвойЧисловойКвалификатор(Источник);
    Поля = Новый Массив;
    Поля.Добавить("Узел");
    Поля.Добавить("Количество");
    ПроверитьСвоюПолнуюТаблицу(Источник, Ожидания, Поля, Ложь);
    Проверка = Новый Запрос;
    Проверка.МенеджерВременныхТаблиц = Менеджер;
    Проверка.Текст = "ВЫБРАТЬ Дет.Узел КАК Узел, Дет.Количество КАК Количество ИЗ СвоиДетали КАК Дет";
    ПроверитьСвоюПолнуюТаблицу(Проверка.Выполнить().Выгрузить(), Ожидания, Поля, Ложь);
КонецПроцедуры

Процедура ЗавершитьСвоюТранзакциюИВТ(Менеджер)
    ОшибкаЗакрытия = "";
    Если Менеджер <> Неопределено Тогда
        Попытка
            Менеджер.Закрыть();
        Исключение
            ОшибкаЗакрытия = ОписаниеОшибки();
        КонецПопытки;
    КонецЕсли;
    Если ТранзакцияАктивна() Тогда
        ОтменитьТранзакцию();
    КонецЕсли;
    ПроверитьОтсутствиеСвоихЗаписей();
    Если ОшибкаЗакрытия <> "" Тогда
        ВызватьИсключение "Своя транзакция отменена, но закрытие ВТ завершилось ошибкой: " + ОшибкаЗакрытия;
    КонецЕсли;
КонецПроцедуры
УчебныйПускИерархическихИтогов85.Форма

Собственная новая внешняя обработка УчебныйПускИерархическихИтогов85 → управляемая Форма → Модуль

Полный отдельный клиентский/серверный модуль формы; серверная процедура без контекста вызывает свой серверный общий модуль. Не смешивать с основным модулем.

&НаКлиенте
Процедура Выполнить(Команда)
    ВыполнитьНаСервере();
    Сообщить("Полные собственные проверки завершены; учебных записей не осталось");
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ВыполнитьНаСервере()
    УчебныйЯзык.ВыполнитьПример();
КонецПроцедуры

Разбор по шагам

  1. Подготовить только новый собственный стенд и полный серверный модуль. Guard до действий сверяет минимальную схему и native metadata-enum вида иерархии.

  2. Проверить конфигурационные предопределённые имена как пустой ФиксированныйМассив. Read-only список расширений проверяется для всех3native источников, не только базы; изменения метаданных расширениями не допускаются.

  3. Пустые модули/формы и единственный сеанс — обязательная ручная подготовка. Native-свойства модулей всегда Неопределено: нельзя на основании этого обещать отсутствие обработчиков.

  4. До действий запретить активную чужую/вложенную транзакцию и непустой собственный источник без очистки. После обеих ветвей проверить отсутствие своих записей вне транзакции; полный запуск дан отдельно от общего модуля.

  5. Создать ровно те же5настоящих узлов A/B/X/Y/Z в своей транзакции. Проверить полные5полей и отдельно каталожные уровни0/1 до запросов; неверные поля/пустой Уровень проверяются изолированно.

  6. Задать единственный ссылочный тип колонки Узел и Число(4,0), неотрицательный, колонки Количество. До присвоения проверять свои непустые листовые ссылки и количества. Границы0/9999 принимаются; отсутствующее/строковое/отрицательное/слишком большое/дробное количество, пустая ссылка и группа отклоняются собственными валидаторами.

  7. Полный вход: (X,2),(X,3),(Y,7),(Z,11). Две детали X не сливаются в одну. Отдельный загрузочный запрос ПОМЕСТИТЬ использует только прямые колонки внешней таблицы; ИТОГИ/соединения/разыменование запрещены native именно при такой загрузке.

  8. Сравнить полный исходник памяти и ВТ до/между/после запросов, без обещания порядка. В итоговых запросах нет УПОРЯДОЧИТЬ ПО: порядок соседей/деталей не выводится из UUID.

  9. Первый запрос ИТОГИ СУММА(Количество) ПО Узел ИЕРАРХИЯ КАК Узлы добавляет группы A12/B11 и контрольные точки X5/Y7/Z11. Четыре исходные детали остаются отдельными строками: полный состав9=2H+3G+4D.

  10. Результат.Выбрать(ПоГруппировкамСИерархией,"Узлы") получает native выборку корневых иерархических итогов. Только в обычном режиме ИЕРАРХИЯ у записи ИтогПоИерархии вызывается Выборка.Выбрать(ПоГруппировкамСИерархией,"Узлы") к собственным контрольным точкам листов; у их фактической ИтогПоГруппировке вызывается Выбрать(Прямой,"") к деталям. Узлы — точный КАК-псевдоним контрольной точки, сверяемый по actual Группировка().

  11. Каждая фактическая строка даёт ссылку Узел, Число Количество, enum ТипЗаписиЗапроса и строковое имя Группировка. Собираются также наша структурная Глубина и РодительВетки; по ним проверяется настоящее вложение, не плоская сумма или COUNT.

  12. Наши уровни структуры0/1/2 у первого результата означают группа→контрольнаяточка→деталь. Уровень() native выборки отдельно проверяется как Число и выводится фактически; не обещается абсолютный старт0, которого его страница не фиксирует.

  13. Во втором запросе ТОЛЬКО ИЕРАРХИЯ исчезают именно контрольные точки X5/Y7/Z11. Явный Булево-параметр ТолькоИерархия передаётся из выполняемого режима запроса, не вычисляется из ожиданий или отсутствия строк. У фактической корневой ИтогПоИерархии вызывается Выборка.Выбрать(ОбходРезультатаЗапроса.Прямой, ""): native Select557 требует пустое имя группировки для деталей текущей записи. В нашем bounded двухуровневом fixture под группой нет промежуточных групп, поэтому читаются её actual детальные записи, а не обещается переход к деталям по alias-групповому обходу.

  14. Полный ожидаемый состав второго actual обхода6: A12 с X2/X3/Y7 и B11 с Z11. ТипЗаписи(), Группировка(), типы узла/числа/native Уровень() читаются фактически; ДетальнаяЗапись с пустой группировкой, собственная глубина1 и РодительВетки=текущая actual группа A/B должны пройти полный typed multiset. Ошибочный тип/группировка/родитель/глубина или отсутствующая деталь вызывают отказ, не сообщение успеха.

  15. Полный unordered multiset всех6полей сравнивает9 и6строк с независимыми ожиданиями, включая enum, имя группировки, кратность, глубину и родителя. Прямая выгрузка каждого результата отдельно должна вернуть все4детали.

  16. Независимая BSL сумма деталей2+3+7+11=23 — наше явное правило проверки. Итоги A12/B11 и листовые суммы нельзя складывать ещё раз с деталями: это разные уровни одной совокупности.

  17. До отката повторно проверить все5исходных узлов, их уровни и все4детали памяти/ВТ. Завершение закрывает приватный менеджер и отменяет свою транзакцию на обеих ветвях; даже ошибка Закрыть не подменяется успехом и не пропускает попытку rollback.

  18. Выполнение в 1С не проверялось. Python — только модель собственных фиксированных данных и проверок полного состава, не заменяет будущий ручной BSL опыт.

  19. Отдельно в будущем выполнить «Контроль аварийного отката» по точной подготовке: контролируемая ошибка после5своих Записать и до рабочей проверки каталога/запросов должна пройти внешний catch, свой rollback и actual Число0readback. Проверить Булево Ложь активности транзакции и отсутствие сообщения успеха; затем вне опыта убрать только свою временную строку, восстановить обычный модуль, сохранить/обновить свою конфигурацию и запустить свежий учебный сеанс. Встроенные локальные negative-validator catches этот аварийный путь не проверяют.

Как проверить результат

  1. Первый полный состав9: A12H; X5G→X2D/X3D; Y7G→Y7D; B11H; Z11G→Z11D. Типы всех6полей и реальные родители ветвей совпадают.

  2. Второй полный состав6: A12H→X2D/X3D/Y7D; B11H→Z11D. ИтогПоГруппировке отсутствует; две детали X и каждое число сохранены.

  3. Обе прямые выгрузки возвращают4исходные строки с типами СправочникСсылка.УчебноеДерево85/Число. Их сумма23, а native уровни показаны отдельно от нашей глубины.

  4. Полные исходники5узлов/4деталей совпадают до/после. Менеджер закрывается, своя транзакция отменяется, своих записей после обеих ветвей нет.

  5. Контроль аварийного отката — отдельная будущая ручная проверка внешнего аварийного пути после5Записать: ТранзакцияАктивна()=Булево Ложь, actual собственный COUNT=Число0, исходная ошибка при успешной очистке и никаких сообщений успеха. Ошибка самой очистки означает неподтверждённый контроль аварийного отката, не успех; временная строка затем убрана только из своего модуля вне опыта, конфигурация сохранена/обновлена до запуска свежего учебного сеанса.

Ожидаемый результат

Настоящие итоги по иерархии показаны полным вложенным native обходом, без выдуманного порядка ссылок и без повторного сложения ресурсов разных уровней.

На что обратить внимание

  1. Native модули объекта/менеджера всегда Неопределено, поэтому guard не может доказать пустой BSL текст. Пустота проверяется вручную в новом Конфигураторе; расширения не отключаются/не удаляются кодом.

  2. Будущие собственные записи нужны только для реальной иерархии первых двух уроков. Здесь база/конфигурация/1С не исполнялись и не менялись; успешное создание/откат не заявляются.

  3. Python моделирует только фиксированные данные, наши ожидания и проверки. Статические тесты/direct native не являются runtime доказательством.

  4. Привязка примера только к реально применённой теме; базовые источники/агрегаты/параметры не добавляются повторно ради счётчика. ДЛЯ ИЗМЕНЕНИЯ, РАЗРЕШЕННЫЕ и РазмерХранимыхДанных разобраны в самостоятельных уроках с собственными сеансами, правами и данными. Этот урок не заменяет их отдельные задачи. Комментарии и общая грамматика также разобраны отдельно.

  5. Ограничение диагностики: аварийная очистка вызывается до ВызватьИсключение без аргументов. Если её собственные ОтменитьТранзакцию, Закрыть менеджера ВТ или readback тоже вызывают исключение, исходная диагностика может быть заменена ошибкой очистки; сохранение исходной диагностики не обещается. Для RU/EN транзакции/записей нет, но ограничение относится к ЗакрытьСвоиВТБезЗаписей и проверке пустоты. При таком сбое фактически закрытые ВТ/откат/пустота требуют отдельной проверки, сообщение успеха не допускается. Здесь аварийные операции и диагностика не проверены runtime.

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

  7. Собственная структурная глубина — аргумент нашего обхода, не обещанный абсолютный native Уровень(). Нативный метод документирует Число и отсчёт от начальной выборки; его фактическое значение выведено отдельно.

  8. Без ORDER BY весь состав/родители проверяются независимо от sibling/detail порядка. Из plain сортировки ссылок нельзя вывести порядок итогов.

  9. ТОЛЬКО ИЕРАРХИЯ исключает контрольные итоги листов, но не исходные детали. Перечисление содержит разные значения ИтогПоИерархии/ИтогПоГруппировке/ДетальнаяЗапись.

  10. Bounded fixture имеет ровно2уровня каталога: две корневые группы и три листа непосредственно под ними. OnlyHierarchy ветвь сознательно выбирает Прямой,"" из текущей actual корневой группы, без промежуточных групп. Это не универсальный collector произвольной, смешанной или многоуровневой иерархии. Native ByGroupsWithHierarchy сам по себе не обещает получение деталей по псевдониму Узлы после удаления контрольных точек; runtime этого маршрута не заявляется.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.