В процессе разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией: пользователь накладывает фильтры в списке (например, через команду «Найти» или «Настроить список»), видит на экране три строки, нажимает «Печать», а в печатную форму выходят все данные справочника или документа. Разберем детально, почему так происходит, и как заставить программу печатать только то, что нужно.
Давайте проанализируем ситуацию. Когда мы открываем форму списка, перед нами объект ДинамическийСписок. Этот объект работает очень хитро: он не подгружает все данные сразу, а берет их из базы порциями. Когда пользователь применяет поиск (например, «Цех 62»), изменения происходят только внутри этого объекта на стороне клиента и сервера формы. Настройки поиска хранятся в свойстве КомпоновщикНастроек динамического списка.
В то же время код печати, который обычно размещается в Модуле менеджера, создает совершенно новый объект Запрос. Этот запрос обращается напрямую к таблицам базы данных (SQL). Он «ничего не знает» о том, что происходит в открытой форме у пользователя. Если в тексте запроса нет секции ГДЕ, он предсказуемо выберет все записи из таблицы. Наша задача — передать информацию о фильтрах из формы в процедуру печати.
Если пользователю нужно напечатать несколько конкретных строк, которые он выделил мышкой, мы можем передать их массив. Рассмотрим, как это реализовать. В модуле команды или формы мы получаем идентификаторы выделенных строк и передаем их в процедуру печати.
На стороне клиента в модуле команды это будет выглядеть так:
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
// ПараметрКоманды в списке — это массив ссылок на выделенные строки
Если ТипЗнч(ПараметрКоманды) = Тип("Массив") И ПараметрКоманды.Количество() > 0 Тогда
ТабДок = Новый ТабличныйДокумент;
ПечатьНаСервере(ТабДок, ПараметрКоманды);
ТабДок.Показать("Печать оборудования");
Иначе
Предупреждение("Пожалуйста, выделите строки для печати!");
КонецЕсли;
КонецПроцедуры
Теперь подкорректируем запрос в Модуле менеджера, чтобы он учитывал переданные ссылки:
Процедура Печать(ТабДок, МассивСсылок) Экспорт
Макет = Справочники.ЗаводскоеОборудование.ПолучитьМакет("Печать");
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗаводскоеОборудование.Наименование,
| ЗаводскоеОборудование.Инвен_N
|ИЗ
| Справочник.ЗаводскоеОборудование КАК ЗаводскоеОборудование
|ГДЕ
| ЗаводскоеОборудование.Ссылка В (&МассивСсылок)";
Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
// Далее идет стандартный вывод в ТабличныйДокумент...
КонецПроцедуры
Рассмотрим более сложную ситуацию: пользователь применил фильтр (например, через «Найти»), и мы хотим напечатать весь результат поиска, не заставляя его выделять строки вручную. Для этого нам нужно выгрузить настройки из ДинамическогоСписка. Выясним причину сложности: настройки поиска (когда мы просто вводим текст в строку поиска) не всегда попадают в обычный Отбор. Нам нужно использовать исполняемую схему компоновки.
Посмотрим на пример кода в форме списка, который позволит передать все настройки на сервер для генерации запроса:
&НаСервере
Функция СформироватьПечатьПоФильтру()
// Получаем схему и настройки, которые реально применяются в списке прямо сейчас
Схема = Элементы.Список.ПолучитьИсполняемуюСхемуКомпоновкиДанных();
Настройки = Элементы.Список.ПолучитьИсполняемыеНастройкиКомпоновкиДанных();
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
// Теперь мы можем либо вывести это в таблицу значений, либо сразу в ТабДок
// Если нужно использовать свой макет, выгружаем ссылки в массив
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ТаблицаРезультат = ПроцессорВывода.Вывести(ПроцессорКомпоновки);
МассивСсылок = ТаблицаРезультат.ВыгрузитьКолонку("Ссылка");
Возврат МассивСсылок;
КонецФункции
Важный момент: использование метода ПолучитьИсполняемыеНастройкиКомпоновкиДанных() критически важно, так как именно он учитывает пользовательский «Поиск», а не только жестко заданные отборы в настройках списка.
Если нам не требуется сложный художественный макет (с логотипами, рамками и особым оформлением), а нужно просто распечатать таблицу «как она есть на экране», воспользуемся встроенной функцией ВывестиСписок. Это самый быстрый путь, не требующий написания запросов вообще.
Проанализируем пример реализации:
&НаКлиенте
Процедура ПечатьСписка(Команда)
// Метод выводит содержимое элемента формы (таблицы) в табличный документ
ТабДок = Элементы.Список.ВывестиСписок();
ТабДок.Показать("Текущий список оборудования");
КонецПроцедуры
Этот метод автоматически учтет все фильтры, сортировки и даже порядок колонок, который пользователь настроил «под себя».
Разберем, почему попытки использовать ТекущиеДанные часто приводят к неудаче. Свойство Элементы.Список.ТекущиеДанные возвращает только одну строку — ту, на которой сейчас стоит курсор. Даже если на экране отфильтровано 3 строки, ТекущиеДанные не являются массивом. Итерация (цикл) по строкам динамического списка на клиенте невозможна, так как клиентская часть «не видит» все данные сразу, они подгружаются динамически с сервера.
Также стоит помнить, что в модуле менеджера Запрос.Параметры.Вставить("Ссылка", Ссылка) работает корректно только если вы печатаете один конкретный документ, передавая его ссылку. Для списков всегда используйте условие В (&МассивСсылок) или динамическое построение запроса через СКД.
Для правильной печати отфильтрованных данных выберите один из подходов:
Рассмотренные методы позволяют сделать работу пользователя комфортной, а печатные формы — точными и соответствующими ожиданиям.