При работе в 1С:Предприятии часто возникает необходимость распечатать не весь документ целиком, а лишь его часть, например, только те строки табличной части, которые пользователь выделил. Это особенно актуально для документов с большими табличными частями, таких как "Увольнение списком" в 1С:Зарплата и Управление Персоналом (ЗУП). Рассмотрим, как реализовать такую функциональность с помощью внешних печатных форм в управляемых приложениях на базе Библиотеки Стандартных Подсистем (БСП).
Решение этой задачи в 1С требует понимания клиент-серверного взаимодействия, поскольку выделение строк происходит на клиенте, а формирование печатной формы (и обращение к базе данных) — обычно на сервере. Давайте разберем по шагам основной принцип, который мы будем использовать:
Первый шаг – получить список выделенных пользователем строк табличной части. В управляемой форме это делается с помощью свойства ВыделенныеСтроки элемента формы, который представляет собой табличную часть. Это свойство возвращает массив идентификаторов строк (или индексов, если идентификаторы не используются).
Рассмотрим пример, как это можно сделать на клиенте:
&НаКлиенте
Процедура КомандаПечатьВыделенных(Команда)
// Получаем массив выделенных строк из табличной части
// Предполагается, что имя табличной части на форме - 'Сотрудники'
МассивВыделенныхСтрок = ЭтаФорма.Элементы.Сотрудники.ВыделенныеСтроки;
// Проверяем, были ли выделены строки
Если МассивВыделенныхСтрок.Количество() > 0 Тогда
// Вызываем серверную процедуру для формирования печати
// Передаем массив выделенных строк и другие необходимые параметры
// например, ссылку на сам документ
ПечатьВыделенныхНаСервере(Объект.Ссылка, МассивВыделенныхСтрок);
Иначе
ПоказатьПредупреждение(, "Пожалуйста, выделите строки для печати.");
КонецЕсли;
КонецПроцедуры
В этом примере ЭтаФорма.Элементы.Сотрудники.ВыделенныеСтроки возвращает массив индексов или идентификаторов строк. Мы передаем этот массив вместе со ссылкой на документ в серверную процедуру ПечатьВыделенныхНаСервере.
Полученный на клиенте массив идентификаторов или индексов строк необходимо передать на сервер, где будет производиться основная логика формирования печатной формы. На сервере мы используем этот массив для отбора нужных данных из табличной части документа. Крайне важно применять метод НайтиПоИдентификатору() для получения строки табличной части, так как это более стабильный и надежный способ по сравнению с использованием индекса, особенно если табличная часть может динамически меняться.
Давайте посмотрим на пример серверной процедуры, которая получает массив выделенных строк и обрабатывает их:
&НаСервере
Процедура ПечатьВыделенныхНаСервере(СсылкаНаДокумент, МассивИдентификаторовСтрок)
// Получаем сам объект документа по ссылке
ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
// Создаем табличный документ для вывода
ТабличныйДокумент = Новый ТабличныйДокумент;
// Получаем макет печатной формы
Макет = ДокументОбъект.ПолучитьМакет("МакетУвольнения"); // Замените на имя вашего макета
// Области макета (пример)
ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
ОбластьСтрокаТаблицы = Макет.ПолучитьОбласть("СтрокаТаблицы");
// Выводим заголовок
ОбластьЗаголовок.Параметры.Заполнить(ДокументОбъект);
ТабличныйДокумент.Вывести(ОбластьЗаголовок);
// Выводим шапку таблицы
ТабличныйДокумент.Вывести(ОбластьШапкаТаблицы);
// Сортируем массив идентификаторов, если порядок важен
// Это особенно полезно, если выводить строки в определенном порядке
СписокДляСортировки = Новый СписокЗначений;
СписокДляСортировки.ЗагрузитьЗначения(МассивИдентификаторовСтрок);
СписокДляСортировки.СортироватьПоЗначению(НаправлениеСортировки.Возр); // Или Возр, в зависимости от нужного порядка
МассивДляОбработки = СписокДляСортировки.ВыгрузитьЗначения();
// Перебираем выделенные строки и выводим их
Для Каждого ИдентификаторСтроки Из МассивДляОбработки Цикл
// Находим строку табличной части по идентификатору
// Используем НайтиПоИдентификатору() для надежности
СтрокаТЧ = ДокументОбъект.Сотрудники.НайтиПоИдентификатору(ИдентификаторСтроки); // Замените 'Сотрудники' на имя вашей табличной части
Если СтрокаТЧ <> Неопределено Тогда
// Заполняем параметры области макета данными из текущей строки
ОбластьСтрокаТаблицы.Параметры.Заполнить(СтрокаТЧ);
ТабличныйДокумент.Вывести(ОбластьСтрокаТаблицы);
КонецЕсли;
КонецЦикла;
// Показываем сформированный табличный документ
ТабличныйДокумент.Показать();
КонецПроцедуры
Мы видим, что на сервере мы получаем объект документа, затем по каждому идентификатору строки из переданного массива находим соответствующую строку в табличной части с помощью ДокументОбъект.Сотрудники.НайтиПоИдентификатору(ИдентификаторСтроки) и выводим ее в табличный документ.
Иногда, вместо прямого получения объекта и его табличной части, можно использовать запросы к базе данных, особенно если табличная часть очень большая или требуется сложный отбор данных. В этом случае, массив идентификаторов/индексов передается в условие запроса, например, ГДЕ ТЧДокумента.НомерСтроки В (&МассивСтрок) И ТЧДокумента.Ссылка = &Ссылка.
Если вы реализуете печать по выделенным строкам через внешнюю печатную форму, интегрированную по технологии БСП, есть свои особенности. В частности, при открытии формы печати через стандартные механизмы БСП, важно корректно заполнять структуру ПараметрыОткрытия и ПараметрыИсточника. Одна из распространенных ошибок, встречавшихся разработчикам, связана с параметром ДополнительнаяОбработкаСсылка.
Рассмотрим ситуацию, когда при открытии формы из внешней обработки возникает ошибка "Поле объекта не обнаружено (ДополнительнаяОбработкаСсылка)". Это обычно происходит из-за некорректной настройки ключевых параметров формы внешней обработки.
Пример ошибочного кода, который может вызвать такую проблему (фрагмент из клиентской процедуры внешней обработки):
&НаКлиенте
Процедура ВыполнитьОткрытиеПечатнойФормы(Команда)
ВыполняемаяКоманда = Параметры;
СтандартнаяОбработка = Истина;
ПараметрыОткрытия = Новый Структура("ИсточникДанных, ПараметрыИсточника");
// Здесь происходит ошибка, если ДополнительнаяОбработкаСсылка не является ключевым параметром формы
ПараметрыОткрытия.ИсточникДанных = ВыполняемаяКоманда.ДополнительнаяОбработкаСсылка;
ПараметрыОткрытия.ПараметрыИсточника = Новый Структура("ИдентификаторКоманды, ОбъектыНазначения");
ПараметрыОткрытия.ПараметрыИсточника.ИдентификаторКоманды = ВыполняемаяКоманда.ИдентификаторКоманды;
// ... далее код передачи выделенных строк и открытия формы печати ...
ОткрытьФорму("ОбщаяФорма.ПечатьДокументов", ПараметрыОткрытия);
КонецПроцедуры
Причина ошибки и ее исправление:
Ошибка "Поле объекта не обнаружено (ДополнительнаяОбработкаСсылка)" в строке ПараметрыОткрытия.ИсточникДанных = ВыполняемаяКоманда.ДополнительнаяОбработкаСсылка; указывает на то, что в форме вашей внешней обработки (или отчета) параметр с именем ДополнительнаяОбработкаСсылка либо отсутствует, либо не помечен как "Ключевой". Для корректной работы механизмов БСП, служебные параметры, которые передаются из системы во внешнюю обработку (например, ссылка на саму обработку), должны быть объявлены в форме внешней обработки как ключевые параметры.
Для исправления необходимо:
ДополнительнаяОбработкаСсылка и типом СправочникСсылка.ДополнительныеОтчетыИОбработки.После этой настройки система сможет корректно передавать и получать этот параметр, и ошибка должна исчезнуть. Это критически важно для правильной передачи служебных параметров БСП.
Давайте сведем воедино полученные знания и рассмотрим несколько полных примеров реализации, которые были представлены в обсуждении.
Этот подход предполагает, что внешняя обработка сама имеет форму, в которой отображается табличная часть, и пользователь уже в этой форме выделяет строки. Тогда выделенные строки обрабатываются непосредственно в обработке.
// Модуль формы внешней обработки
&НаКлиенте
Процедура ПечатьВыделенныхМатериалов(Команда)
МассивВыделенныхСтрок = Новый Массив;
// Предполагаем, что имя табличной части на форме внешней обработки - 'ТабличнаяЧастьМатериалы'
МассивВыделенныхСтрок = ЭтаФорма.Элементы.ТабличнаяЧастьМатериалы.ВыделенныеСтроки;
Если МассивВыделенныхСтрок.Количество() > 0 Тогда
// Рекомендуется сортировать индексы, т.к. они могут быть не по порядку
СписокДляСортировкиЗначенийМассива = Новый СписокЗначений;
СписокДляСортировкиЗначенийМассива.ЗагрузитьЗначения(МассивВыделенныхСтрок);
// Сортируем по убыванию, чтобы при обходе, например, снизу вверх,
// не возникало проблем с удалением элементов из коллекции
СписокДляСортировкиЗначенийМассива.СортироватьПоЗначению(НаправлениеСортировки.Возр);
МассивДляОбработки = СписокДляСортировкиЗначенийМассива.ВыгрузитьЗначения();
// Вызываем серверную процедуру, передавая массив индексов строк
Печать_Сервере(МассивДляОбработки);
Иначе
ПоказатьПредупреждение(, "Пожалуйста, выделите строки для печати.");
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура Печать_Сервере(МассивДляОбработки)
// Объект внешней обработки, если он содержит табличную часть для печати
// В данном контексте 'Объект' относится к реквизиту формы типа 'ДополнительнаяОбработкаОбъект'
// или к самому объекту обработки, если она реализует функционал
// Предполагаем, что Объект.ТабличнаяЧастьМатериалы - это табличная часть, которую мы хотим печатать
// и она уже заполнена данными для отображения в форме обработки
Для Каждого СтрокаМассиваИндексовСтрок Из МассивДляОбработки Цикл
// Здесь произошла небольшая путаница в исходном сообщении.
// Если МассивДляОбработки содержит индексы, то метод Получить() подходит.
// Если же (что чаще и надежнее) он содержит ИДЕНТИФИКАТОРЫ строк,
// то нужно использовать НайтиПоИдентификатору().
// В примере с форума, подразумевались индексы, но исправление на НайтиПоИдентификатору()
// указывает на рекомендацию использовать идентификаторы.
// Корректнее использовать НайтиПоИдентификатору(), если МассивДляОбработки содержит Идентификаторы.
// Если МассивДляОбработки содержит индексы, то используем Получить().
// Для табличных частей формы (не объекта), ВыделенныеСтроки обычно возвращают идентификаторы.
// Поэтому используем НайтиПоИдентификатору.
СтрокаТабличнойЧастиМатериаловПоИндексуВыделеннойСтроки = Объект.ТабличнаяЧастьМатериалы.НайтиПоИдентификатору(СтрокаМассиваИндексовСтрок);
Если СтрокаТабличнойЧастиМатериаловПоИндексуВыделеннойСтроки <> Неопределено Тогда
// Теперь у нас есть полная строка табличной части
// Мы можем получить ее реквизиты, например:
КоличествоМатериалов = СтрокаТабличнойЧастиМатериаловПоИндексуВыделеннойСтроки.Количество;
НаименованиеМатериала = СтрокаТабличнойЧастиМатериаловПоИндексуВыделеннойСтроки.Материал;
// ... и использовать их для формирования печатной формы
// Например, заполнить области макета и вывести в ТабличныйДокумент
КонецЕсли;
КонецЦикла;
// Здесь должен быть код формирования и вывода ТабличногоДокумента
КонецПроцедуры
В этом примере мы видим, как массив идентификаторов (или индексов) передается от клиента на сервер, где используется для получения полных данных строк табличной части. Метод НайтиПоИдентификатору() является предпочтительным, поскольку идентификаторы строк стабильны и не меняются при сортировке или удалении других строк, в отличие от индексов.
Этот сценарий отличается тем, что печатная форма вызывается из формы документа, но для обработки информации о выделенных строках, внешняя печатная форма (ВПФ) сама открывает форму документа, чтобы получить доступ к его табличной части и ее выделенным строкам. Этот метод требует осторожности, так как повторное открытие формы может быть избыточным или нежелательным.
&НаКлиенте
Процедура Печать(ИдентификаторКоманды, МассивОбъектов) Экспорт
Для Каждого СсылкаНаДокумент Из МассивОбъектов Цикл
// Открываем форму самого документа в режиме просмотра
// Параметр "Ключ" используется для открытия формы конкретного объекта
ПараметрыФормы = Новый Структура("Ключ", СсылкаНаДокумент);
Форма = ПолучитьФорму("Документ.ИзменениеПлановыхНачислений.Форма.ФормаДокумента", ПараметрыФормы);
// Получаем выделенные строки из открытой формы документа
// Предполагается, что табличная часть называется 'ПоказателиСотрудников'
мВыделенныеСтроки = Форма.Элементы.ПоказателиСотрудников.ВыделенныеСтроки;
// Если есть выделенные строки, передаем их на сервер для дальнейшей обработки
Если мВыделенныеСтроки.Количество() > 0 Тогда
// Серверный вызов для получения начислений сотрудников по выделенным строкам
мСтруктураОкладов = НачисленияСотрудников(СсылкаНаДокумент, мВыделенныеСтроки);
// Здесь должна быть логика формирования печатной формы
// например, ЗаполнитьДокументWord(СсылкаНаДокумент, мСтруктураОкладов);
// или вывод в ТабличныйДокумент
Иначе
ПоказатьПредупреждение(, "В документе '" + СсылкаНаДокумент + "' не выделены строки для печати.");
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаСервере
Функция НачисленияСотрудников(СсылкаНаДокумент, мВыделенныеСтроки)
мСтруктураОкладов = Новый Массив; // Массив для сбора данных по сотрудникам
// Получаем сам объект документа
ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
// Отбираем только выделенных сотрудников из табличной части документа
мВыделенныеСотрудники = Новый Массив;
Для Каждого ИдентификаторСтроки Из мВыделенныеСтроки Цикл
// Предполагается, что табличная часть документа называется 'Сотрудники'
// и содержит реквизит 'Сотрудник' типа СправочникСсылка.Сотрудники
СтрокаТЧДокумента = ДокументОбъект.Сотрудники.НайтиПоИдентификатору(ИдентификаторСтроки);
Если СтрокаТЧДокумента <> Неопределено Тогда
мВыделенныеСотрудники.Добавить(СтрокаТЧДокумента.Сотрудник);
КонецЕсли;
КонецЦикла;
// Далее можно выполнять запросы или перебирать эти мВыделенныеСотрудники
// Например, получить плановые начисления для каждого сотрудника
Для Каждого СотрудникСсылка Из мВыделенныеСотрудники Цикл
// ... Логика получения данных по сотруднику ...
// И заполнение мСтруктураОкладов
КонецЦикла;
Возврат мСтруктураОкладов;
КонецФункции
Этот подход позволяет получить доступ к выделенным строкам непосредственно из формы документа, но требует аккуратного управления жизненным циклом открываемой формы, чтобы не создавать лишние объекты в памяти и не замедлять работу пользователя.
Помимо рассмотренных вариантов, существуют и другие способы решить задачу печати по выделенным строкам, а также общие рекомендации, которые помогут вам в разработке.
Печатать. Пользователь будет вручную отмечать галочками нужные строки, а внешняя печатная форма будет отбирать строки по этому признаку. Этот метод требует изменения конфигурации документа, но предлагает простую и понятную механику для пользователя.ВыделенныеСтроки и используемые с НайтиПоИдентификатору()) более стабильны, чем индексы, которые могут измениться при различных манипуляциях с табличной частью.МассивВыделенныхСтрок.Количество() > 0, чтобы избежать ошибок, если пользователь не выделил ни одной строки.Реализация печати по выделенным строкам в 1С:Предприятии 8.3 — это типовая задача, требующая внимательности к деталям клиент-серверного взаимодействия и особенностям работы с БСП. Следуя изложенным принципам и примерам, вы сможете успешно решить эту задачу и предоставить пользователям удобный инструмент для выборочной печати данных.