При работе с отчетами в 1С часто возникает задача получить краткую статистику или «выжимку» из уже существующего сложного отчета. Ситуация осложняется, когда отчет формируется программно — а это, как известно, до сих пор актуальный подход к созданию печатных форм вручную — и в итоговом табличном документе одни и те же области (например, ОбластьШапка и ОбластьСтрока) повторяются многократно. Разберем, как правильно подойти к решению этой задачи, какие методы платформы использовать и как избежать типичных ошибок при манипуляции строками.
Прежде всего, проанализируем важный технический нюанс. Когда мы используем метод Вывести() для формирования отчета из макета, имя области, которое мы задали в конфигураторе, по умолчанию не сохраняется в результирующем документе как свойство объекта. В итоговой таблице мы видим просто набор строк. Если мы попытаемся обратиться к ТабДок.Области.ОбластьШапка, система либо вернет последнюю выведенную область с таким именем, либо вызовет ошибку, если имена не назначались при выводе явно.
Для решения задачи у нас есть два глобальных пути: изменить логику формирования отчета (превентивный метод) или обработать уже готовый результат (постобработка). Стоит отметить, что если бы отчет строился на СКД, то для изменения его структуры было бы удобнее использовать программную работу со схемой, но в данном случае мы рассматриваем манипуляции с уже готовым табличным документом. Рассмотрим оба варианта подробнее.
Проанализируем самый надежный и «чистый» с точки зрения архитектуры способ. Вместо того чтобы пытаться «резать» уже готовый документ, проще создать его сразу в нужном виде. Если оригинальный отчет трогать нельзя, мы можем продублировать его объект.
Пока Выборка.Следующий() Цикл
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
// Заполнение параметров
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
В этом блоке мы можем добавить условие, которое просто не будет выводить ненужные нам строки или шапки. Чтобы понять, какие данные и условия для фильтрации использовать, на этапе анализа бывает полезно выполнить исходный запрос в удобной консоли запросов. Это исключит необходимость в будущем «парсить» готовый документ и искать в нем данные.
Если же мы вынуждены работать с уже сформированным документом, нам необходимо найти координаты строк для удаления. Разберем, как использовать метод НайтиТекст() для поиска повторяющихся областей. Мы можем запустить цикл, который будет искать заголовки «ОбластьШапка» по всему документу.
Посмотрим на пример реализации такого поиска:
НайденнаяОбласть = Неопределено;
СтартоваяЯчейка = ТабДок.Область(1, 1);
Пока Истина Цикл
НайденнаяОбласть = ТабДок.НайтиТекст("ИскомыйЗаголовокШапки", СтартоваяЯчейка, ТабДок.Область(), Истина, Истина, Истина, Ложь);
Если НайденнаяОбласть = Неопределено Тогда
Прервать;
КонецЕсли;
// Сохраняем номер строки найденной шапки
НомерСтроки = НайденнаяОбласть.Верх;
// Логика пометки строки на удаление или обработка данных
// Перемещаем точку старта поиска ниже найденной области
СтартоваяЯчейка = ТабДок.Область(НомерСтроки + 1, 1);
КонецЦикла;
Важно помнить, что поиск по тексту чувствителен к изменениям в макете. Если завтра бухгалтер решит изменить заголовок в шапке, ваш программный код перестанет находить нужную область.
Выясним причину, по которой использование Расшифровка считается более надежным методом. Часто разработчики при выводе строк заполняют свойство Расшифровка ячейки уникальным идентификатором или специальной строкой-маркером (например, «Тип_Строки_Шапка»).
Рассмотрим, как проверить строки через расшифровку:
Для НомерСтроки = 1 По ТабДок.ВысотаТаблицы Цикл
ТекОбласть = ТабДок.Область(НомерСтроки, 1); // Проверяем первую колонку
Если ТекОбласть.Расшифровка = "НужнаяНамМетка" Тогда
// Мы нашли нужную строку
КонецЕсли;
КонецЦикла;
Теперь разберем самую частую ошибку начинающих программистов — удаление строк в цикле «сверху вниз». Проанализируем ситуацию: если вы удаляете строку №5, то бывшая строка №6 тут же становится строкой №5. Ваш счетчик цикла переходит к индексу 6, и в итоге вы пропускаете строку, которая только что сместилась вверх.
Правильное решение: всегда выполняйте удаление с конца документа к началу. Посмотрим на пример кода:
Высота = ТабДок.ВысотаТаблицы;
Для Счетчик = -Высота По -1 Цикл
ТекущийНомерСтроки = -Счетчик;
// Проверяем условие удаления для строки ТекущийНомерСтроки
Если НужноУдалитьСтроку(ТекущийНомерСтроки) Тогда
ТабДок.УдалитьОбласть(ТабДок.Область(ТекущийНомерСтроки, , ТекущийНомерСтроки, ), ТипСмещенияТабличногоДокумента.ПоВертикали);
КонецЕсли;
КонецЦикла;
Или более лаконичный вариант с использованием шага -1:
Для НомерСтроки = ТабДок.ВысотаТаблицы По 1 Шаг -1 Цикл
Если ОбнаруженПризнакУдаления(НомерСтроки) Тогда
ТабДок.УдалитьОбласть(ТабДок.Область(НомерСтроки, 1, НомерСтроки, ), ТипСмещенияТабличногоДокумента.ПоВертикали);
КонецЕсли;
КонецЦикла;
Вместо того чтобы «вырезать» лишнее, иногда проще «собрать» нужное. Этот метод особенно хорош, когда из огромного отчета нужно вытащить всего две-три таблицы. Проанализируем алгоритм:
ТабличныйДокумент.НайтиТекст).ПолучитьОбласть() для копирования фрагмента.
// Пример копирования блока со строки 10 по 20
НужныйБлок = ИсходныйТабДок.ПолучитьОбласть(10, , 20, );
НовыйТабДок.Вывести(НужныйБлок);
Этот способ работает значительно быстрее, чем массовое удаление строк по одной, так как 1С не приходится каждый раз пересчитывать структуру всего документа при удалении каждой строки.
В завершение разберем несколько советов, которые помогут сделать код надежнее:
УровеньГруппировкиСтрок(). Это позволит быстро определять, где заканчиваются детальные записи и начинаются итоги.Таким образом, мы рассмотрели различные подходы к манипуляции областями табличного документа. Выбор метода зависит от того, имеете ли вы доступ к исходному коду формирования отчета и насколько сложной является его структура.