При разработке отчетов типа «Прайс-лист» в системе 1С:Предприятие 7.7 программисты часто сталкиваются с необходимостью очистки данных от лишних заголовков. Если в иерархическом справочнике Номенклатура есть группы, которые не содержат товаров (или содержат только другие пустые группы), выводить их в печатную форму нецелесообразно. Рассмотрим детально один из классических, «витиеватых» способов решения этой задачи с использованием таблицы значений.
Проанализируем ситуацию: на входе мы имеем объект типа ТаблицаЗначений (переменная ТабЗнач), в которой уже содержатся данные. Важно понимать, что в эту таблицу предварительно выгружены как сами элементы (товары), так и их родительские группы. Для корректной работы данного алгоритма таблица должна быть отсортирована по иерархии (наименованию или коду с учетом родителя).
Рассмотрим код, вызвавший вопросы:
Поз = ТабЗнач.КоличествоСтрок();
Удалить2 = 1;
Удалить1 = 1;
Пока Поз > 0 Цикл
ТабЗнач.ПолучитьСтрокуПоНомеру(Поз);
Если ТабЗнач.Товар.ЭтоГруппа()=0 Тогда
Удалить2 = 0;
Удалить1 = 0;
Иначе
Если (ТабЗнач.Товар.Уровень() = 2) Тогда
Если Удалить2 = 1 Тогда
ТабЗнач.УдалитьСтроку();
Иначе
Удалить2 = 1;
КонецЕсли
ИначеЕсли (ТабЗнач.Товар.Уровень() = 1) Тогда
Если Удалить1 = 1 Тогда
ТабЗнач.УдалитьСтроку();
Иначе
Удалить1 = 1;
КонецЕсли;
КонецЕсли
КонецЕсли;
Поз = Поз - 1;
КонецЦикла;
Первое, на что стоит обратить внимание — это использование обратного цикла (от КоличествоСтрок() до 1). Выясним причину такого подхода. В платформе 1С 7.7 (как и в более поздних версиях) при вызове метода УдалитьСтроку() индексы всех последующих строк уменьшаются на единицу. Если бы мы использовали прямой цикл (от 1 до N), то после удаления строки 5, бывшая строка 6 стала бы 5-й, и при переходе к следующему шагу итерации (к индексу 6) мы бы просто пропустили этот элемент. Движение с конца таблицы позволяет избежать этой проблемы: удаление текущей строки никак не влияет на порядковые номера тех строк, которые нам еще только предстоит обработать.
Проанализируем переменные Удалить1 и Удалить2. Они выполняют роль индикаторов «пустоты» соответствующих уровней иерархии. Разберем по шагам, как они взаимодействуют с данными:
ЭтоГруппа() возвращает 0), это означает, что мы нашли конечный элемент. Программа тут же сбрасывает оба флага в 0. Этим мы помечаем, что текущая ветка иерархии (родители 1-го и 2-го уровней) содержит полезные данные и их удалять нельзя.Уровень() равен 2, проверяется значение Удалить2. Если оно осталось равным 1 (с момента начала цикла или с момента обработки предыдущей группы), значит, ниже по списку не было встречено ни одного товара, относящегося к этой группе. Группа удаляется. Если же флаг был сброшен в 0 товаром, группа сохраняется, но флаг Удалить2 снова взводится в 1 для проверки следующей группы того же уровня, расположенной выше в таблице.Выясним причину, по которой этот код может не сработать в произвольной таблице. Данный алгоритм опирается на иерархический порядок строк. В правильно отсортированной ТЗ для отчета товары всегда следуют сразу за своей группой (при прямом обходе) или предшествуют ей (при обратном обходе). Если перемешать товары из разных групп или расположить их до заголовков в прямой последовательности, флаги будут сбрасываться некорректно, и программа удалит нужные разделы или оставит пустые.
Проанализируем ситуацию, описанную автором темы: справочник имеет 5 уровней, а код обрабатывает только 1-й и 2-й. Это важный нюанс. Данная реализация является упрощенной. Она предполагает, что основная структура прайс-листа строится только на двух верхних уровнях, а всё, что находится глубже (3, 4 и 5 уровни), либо считается «товарами» в широком смысле, либо их наличие/отсутствие не критично для визуального отображения заголовков. Если требуется очистка всех уровней, алгоритм должен быть расширен соответствующими проверками для Уровень() = 3, Уровень() = 4 и так далее, с добавлением соответствующих переменных-флагов.
Несмотря на то что данный код выполняет свою задачу, его можно назвать «хрупким» из-за жесткой привязки к номерам уровней. Рассмотрим, как можно улучшить или заменить подобную логику в современных условиях сопровождения систем на базе 7.7:
Удалить1, Удалить2 можно использовать массив или список значений, размер которого соответствует максимальной глубине справочника. Это позволит обрабатывать любое количество уровней без переписывания условий Если...ИначеЕсли.ПринадлежитГруппе() или строить запрос таким образом, чтобы пустые ветки не попадали в результат выборки изначально.КоличествоЭлементов, заполнить её при обходе справочника (суммируя количество товаров вверх по родителям) и затем удалить все строки-группы, где это количество равно нулю.Таким образом, мы выяснили, что «загадочный код» — это специализированный механизм пост-обработки таблицы значений, предназначенный для визуальной оптимизации иерархических отчетов. Он эффективно решает задачу удаления пустых разделов при условии соблюдения иерархической сортировки данных.