Как распечатать только выделенные строки табличной части документа в 1С:Предприятии 8.3 (Управляемые формы)?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом IT и автоматизация бизнеса
← На главную

При работе в 1С:Предприятии часто возникает необходимость распечатать не весь документ целиком, а лишь его часть, например, только те строки табличной части, которые пользователь выделил. Это особенно актуально для документов с большими табличными частями, таких как "Увольнение списком" в 1С:Зарплата и Управление Персоналом (ЗУП). Рассмотрим, как реализовать такую функциональность с помощью внешних печатных форм в управляемых приложениях на базе Библиотеки Стандартных Подсистем (БСП).

Общий принцип передачи данных для печати по выделенным строкам

Решение этой задачи в 1С требует понимания клиент-серверного взаимодействия, поскольку выделение строк происходит на клиенте, а формирование печатной формы (и обращение к базе данных) — обычно на сервере. Давайте разберем по шагам основной принцип, который мы будем использовать:

  1. Получение выделенных строк на клиенте: В пользовательском интерфейсе (на клиенте) мы должны определить, какие именно строки табличной части были выделены пользователем.
  2. Передача информации о выделенных строках на сервер: Поскольку печать выполняется на сервере, необходимо передать на сервер данные о выбранных строках. Обычно передаются их уникальные идентификаторы или индексы.
  3. Обработка данных на сервере: На сервере, получив информацию о выделенных строках, мы обращаемся к данным документа в базе, отбираем только необходимые строки и формируем на их основе печатную форму.
  4. Вывод печатной формы: Сформированный табличный документ отображается пользователю для предпросмотра и печати.

Получение выделенных строк на клиенте

Первый шаг – получить список выделенных пользователем строк табличной части. В управляемой форме это делается с помощью свойства ВыделенныеСтроки элемента формы, который представляет собой табличную часть. Это свойство возвращает массив идентификаторов строк (или индексов, если идентификаторы не используются).

Рассмотрим пример, как это можно сделать на клиенте:


&НаКлиенте
Процедура КомандаПечатьВыделенных(Команда)
    // Получаем массив выделенных строк из табличной части
    // Предполагается, что имя табличной части на форме - 'Сотрудники'
    МассивВыделенныхСтрок = ЭтаФорма.Элементы.Сотрудники.ВыделенныеСтроки; 

    // Проверяем, были ли выделены строки
    Если МассивВыделенныхСтрок.Количество() > 0 Тогда
        // Вызываем серверную процедуру для формирования печати
        // Передаем массив выделенных строк и другие необходимые параметры
        // например, ссылку на сам документ
        ПечатьВыделенныхНаСервере(Объект.Ссылка, МассивВыделенныхСтрок);
    Иначе
        ПоказатьПредупреждение(, "Пожалуйста, выделите строки для печати.");
    КонецЕсли;
КонецПроцедуры

В этом примере ЭтаФорма.Элементы.Сотрудники.ВыделенныеСтроки возвращает массив индексов или идентификаторов строк. Мы передаем этот массив вместе со ссылкой на документ в серверную процедуру ПечатьВыделенныхНаСервере.

Передача данных с клиента на сервер и обработка

Полученный на клиенте массив идентификаторов или индексов строк необходимо передать на сервер, где будет производиться основная логика формирования печатной формы. На сервере мы используем этот массив для отбора нужных данных из табличной части документа. Крайне важно применять метод НайтиПоИдентификатору() для получения строки табличной части, так как это более стабильный и надежный способ по сравнению с использованием индекса, особенно если табличная часть может динамически меняться.

Давайте посмотрим на пример серверной процедуры, которая получает массив выделенных строк и обрабатывает их:


&НаСервере
Процедура ПечатьВыделенныхНаСервере(СсылкаНаДокумент, МассивИдентификаторовСтрок)

    // Получаем сам объект документа по ссылке
    ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();

    // Создаем табличный документ для вывода
    ТабличныйДокумент = Новый ТабличныйДокумент;

    // Получаем макет печатной формы
    Макет = ДокументОбъект.ПолучитьМакет("МакетУвольнения"); // Замените на имя вашего макета

    // Области макета (пример)
    ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
    ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
    ОбластьСтрокаТаблицы = Макет.ПолучитьОбласть("СтрокаТаблицы");

    // Выводим заголовок
    ОбластьЗаголовок.Параметры.Заполнить(ДокументОбъект);
    ТабличныйДокумент.Вывести(ОбластьЗаголовок);

    // Выводим шапку таблицы
    ТабличныйДокумент.Вывести(ОбластьШапкаТаблицы);

    // Сортируем массив идентификаторов, если порядок важен
    // Это особенно полезно, если выводить строки в определенном порядке
    СписокДляСортировки = Новый СписокЗначений;
    СписокДляСортировки.ЗагрузитьЗначения(МассивИдентификаторовСтрок);
    СписокДляСортировки.СортироватьПоЗначению(НаправлениеСортировки.Возр); // Или Возр, в зависимости от нужного порядка
    МассивДляОбработки = СписокДляСортировки.ВыгрузитьЗначения();

    // Перебираем выделенные строки и выводим их
    Для Каждого ИдентификаторСтроки Из МассивДляОбработки Цикл
        // Находим строку табличной части по идентификатору
        // Используем НайтиПоИдентификатору() для надежности
        СтрокаТЧ = ДокументОбъект.Сотрудники.НайтиПоИдентификатору(ИдентификаторСтроки); // Замените 'Сотрудники' на имя вашей табличной части

        Если СтрокаТЧ <> Неопределено Тогда
            // Заполняем параметры области макета данными из текущей строки
            ОбластьСтрокаТаблицы.Параметры.Заполнить(СтрокаТЧ);
            ТабличныйДокумент.Вывести(ОбластьСтрокаТаблицы);
        КонецЕсли;
    КонецЦикла;

    // Показываем сформированный табличный документ
    ТабличныйДокумент.Показать();

КонецПроцедуры

Мы видим, что на сервере мы получаем объект документа, затем по каждому идентификатору строки из переданного массива находим соответствующую строку в табличной части с помощью ДокументОбъект.Сотрудники.НайтиПоИдентификатору(ИдентификаторСтроки) и выводим ее в табличный документ.

Иногда, вместо прямого получения объекта и его табличной части, можно использовать запросы к базе данных, особенно если табличная часть очень большая или требуется сложный отбор данных. В этом случае, массив идентификаторов/индексов передается в условие запроса, например, ГДЕ ТЧДокумента.НомерСтроки В (&МассивСтрок) И ТЧДокумента.Ссылка = &Ссылка.

Работа с внешними печатными формами и БСП

Если вы реализуете печать по выделенным строкам через внешнюю печатную форму, интегрированную по технологии БСП, есть свои особенности. В частности, при открытии формы печати через стандартные механизмы БСП, важно корректно заполнять структуру ПараметрыОткрытия и ПараметрыИсточника. Одна из распространенных ошибок, встречавшихся разработчикам, связана с параметром ДополнительнаяОбработкаСсылка.

Рассмотрим ситуацию, когда при открытии формы из внешней обработки возникает ошибка "Поле объекта не обнаружено (ДополнительнаяОбработкаСсылка)". Это обычно происходит из-за некорректной настройки ключевых параметров формы внешней обработки.

Пример ошибочного кода, который может вызвать такую проблему (фрагмент из клиентской процедуры внешней обработки):


&НаКлиенте
Процедура ВыполнитьОткрытиеПечатнойФормы(Команда)
    ВыполняемаяКоманда = Параметры;
    СтандартнаяОбработка = Истина;

    ПараметрыОткрытия = Новый Структура("ИсточникДанных, ПараметрыИсточника");
    // Здесь происходит ошибка, если ДополнительнаяОбработкаСсылка не является ключевым параметром формы
    ПараметрыОткрытия.ИсточникДанных = ВыполняемаяКоманда.ДополнительнаяОбработкаСсылка; 
    ПараметрыОткрытия.ПараметрыИсточника = Новый Структура("ИдентификаторКоманды, ОбъектыНазначения");
    ПараметрыОткрытия.ПараметрыИсточника.ИдентификаторКоманды = ВыполняемаяКоманда.ИдентификаторКоманды;

    // ... далее код передачи выделенных строк и открытия формы печати ...

    ОткрытьФорму("ОбщаяФорма.ПечатьДокументов", ПараметрыОткрытия);
КонецПроцедуры

Причина ошибки и ее исправление:

Ошибка "Поле объекта не обнаружено (ДополнительнаяОбработкаСсылка)" в строке ПараметрыОткрытия.ИсточникДанных = ВыполняемаяКоманда.ДополнительнаяОбработкаСсылка; указывает на то, что в форме вашей внешней обработки (или отчета) параметр с именем ДополнительнаяОбработкаСсылка либо отсутствует, либо не помечен как "Ключевой". Для корректной работы механизмов БСП, служебные параметры, которые передаются из системы во внешнюю обработку (например, ссылка на саму обработку), должны быть объявлены в форме внешней обработки как ключевые параметры.

Для исправления необходимо:

  1. Открыть форму вашей внешней обработки в конфигураторе.
  2. Перейти на вкладку "Параметры формы".
  3. Убедиться, что существует параметр с именем ДополнительнаяОбработкаСсылка и типом СправочникСсылка.ДополнительныеОтчетыИОбработки.
  4. Самое важное: Установить для этого параметра флажок "Ключевой".

После этой настройки система сможет корректно передавать и получать этот параметр, и ошибка должна исчезнуть. Это критически важно для правильной передачи служебных параметров БСП.

Комплексные примеры реализации печати по выделенным строкам

Давайте сведем воедино полученные знания и рассмотрим несколько полных примеров реализации, которые были представлены в обсуждении.

Пример 1: Передача индексов строк из формы внешней обработки

Этот подход предполагает, что внешняя обработка сама имеет форму, в которой отображается табличная часть, и пользователь уже в этой форме выделяет строки. Тогда выделенные строки обрабатываются непосредственно в обработке.


// Модуль формы внешней обработки
&НаКлиенте
Процедура ПечатьВыделенныхМатериалов(Команда)
    МассивВыделенныхСтрок = Новый Массив;
    // Предполагаем, что имя табличной части на форме внешней обработки - 'ТабличнаяЧастьМатериалы'
    МассивВыделенныхСтрок = ЭтаФорма.Элементы.ТабличнаяЧастьМатериалы.ВыделенныеСтроки;

    Если МассивВыделенныхСтрок.Количество() > 0 Тогда
        // Рекомендуется сортировать индексы, т.к. они могут быть не по порядку
        СписокДляСортировкиЗначенийМассива = Новый СписокЗначений;
        СписокДляСортировкиЗначенийМассива.ЗагрузитьЗначения(МассивВыделенныхСтрок);
        // Сортируем по убыванию, чтобы при обходе, например, снизу вверх, 
        // не возникало проблем с удалением элементов из коллекции
        СписокДляСортировкиЗначенийМассива.СортироватьПоЗначению(НаправлениеСортировки.Возр); 
        МассивДляОбработки = СписокДляСортировкиЗначенийМассива.ВыгрузитьЗначения();

        // Вызываем серверную процедуру, передавая массив индексов строк
        Печать_Сервере(МассивДляОбработки); 
    Иначе
        ПоказатьПредупреждение(, "Пожалуйста, выделите строки для печати.");
    КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура Печать_Сервере(МассивДляОбработки)

    // Объект внешней обработки, если он содержит табличную часть для печати
    // В данном контексте 'Объект' относится к реквизиту формы типа 'ДополнительнаяОбработкаОбъект'
    // или к самому объекту обработки, если она реализует функционал
    // Предполагаем, что Объект.ТабличнаяЧастьМатериалы - это табличная часть, которую мы хотим печатать
    // и она уже заполнена данными для отображения в форме обработки
    
    Для Каждого СтрокаМассиваИндексовСтрок Из МассивДляОбработки Цикл
        // Здесь произошла небольшая путаница в исходном сообщении.
        // Если МассивДляОбработки содержит индексы, то метод Получить() подходит.
        // Если же (что чаще и надежнее) он содержит ИДЕНТИФИКАТОРЫ строк,
        // то нужно использовать НайтиПоИдентификатору().
        // В примере с форума, подразумевались индексы, но исправление на НайтиПоИдентификатору()
        // указывает на рекомендацию использовать идентификаторы.
        
        // Корректнее использовать НайтиПоИдентификатору(), если МассивДляОбработки содержит Идентификаторы.
        // Если МассивДляОбработки содержит индексы, то используем Получить().
        // Для табличных частей формы (не объекта), ВыделенныеСтроки обычно возвращают идентификаторы.
        // Поэтому используем НайтиПоИдентификатору.
        СтрокаТабличнойЧастиМатериаловПоИндексуВыделеннойСтроки = Объект.ТабличнаяЧастьМатериалы.НайтиПоИдентификатору(СтрокаМассиваИндексовСтрок);

        Если СтрокаТабличнойЧастиМатериаловПоИндексуВыделеннойСтроки <> Неопределено Тогда
            // Теперь у нас есть полная строка табличной части
            // Мы можем получить ее реквизиты, например:
            КоличествоМатериалов = СтрокаТабличнойЧастиМатериаловПоИндексуВыделеннойСтроки.Количество;
            НаименованиеМатериала = СтрокаТабличнойЧастиМатериаловПоИндексуВыделеннойСтроки.Материал;
            // ... и использовать их для формирования печатной формы
            // Например, заполнить области макета и вывести в ТабличныйДокумент
        КонецЕсли;
    КонецЦикла;
    // Здесь должен быть код формирования и вывода ТабличногоДокумента
КонецПроцедуры

В этом примере мы видим, как массив идентификаторов (или индексов) передается от клиента на сервер, где используется для получения полных данных строк табличной части. Метод НайтиПоИдентификатору() является предпочтительным, поскольку идентификаторы строк стабильны и не меняются при сортировке или удалении других строк, в отличие от индексов.

Пример 2: Получение выделенных строк из формы документа, открытой через ВПФ

Этот сценарий отличается тем, что печатная форма вызывается из формы документа, но для обработки информации о выделенных строках, внешняя печатная форма (ВПФ) сама открывает форму документа, чтобы получить доступ к его табличной части и ее выделенным строкам. Этот метод требует осторожности, так как повторное открытие формы может быть избыточным или нежелательным.


&НаКлиенте
Процедура Печать(ИдентификаторКоманды, МассивОбъектов) Экспорт
    Для Каждого СсылкаНаДокумент Из МассивОбъектов Цикл
        // Открываем форму самого документа в режиме просмотра
        // Параметр "Ключ" используется для открытия формы конкретного объекта
        ПараметрыФормы = Новый Структура("Ключ", СсылкаНаДокумент);
        Форма = ПолучитьФорму("Документ.ИзменениеПлановыхНачислений.Форма.ФормаДокумента", ПараметрыФормы);
        
        // Получаем выделенные строки из открытой формы документа
        // Предполагается, что табличная часть называется 'ПоказателиСотрудников'
        мВыделенныеСтроки = Форма.Элементы.ПоказателиСотрудников.ВыделенныеСтроки;
        
        // Если есть выделенные строки, передаем их на сервер для дальнейшей обработки
        Если мВыделенныеСтроки.Количество() > 0 Тогда
            // Серверный вызов для получения начислений сотрудников по выделенным строкам
            мСтруктураОкладов = НачисленияСотрудников(СсылкаНаДокумент, мВыделенныеСтроки); 
            
            // Здесь должна быть логика формирования печатной формы
            // например, ЗаполнитьДокументWord(СсылкаНаДокумент, мСтруктураОкладов);
            // или вывод в ТабличныйДокумент
        Иначе
            ПоказатьПредупреждение(, "В документе '" + СсылкаНаДокумент + "' не выделены строки для печати.");
        КонецЕсли;
        
    КонецЦикла;
КонецПроцедуры

&НаСервере
Функция НачисленияСотрудников(СсылкаНаДокумент, мВыделенныеСтроки)
    мСтруктураОкладов = Новый Массив; // Массив для сбора данных по сотрудникам

    // Получаем сам объект документа
    ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();

    // Отбираем только выделенных сотрудников из табличной части документа
    мВыделенныеСотрудники = Новый Массив;
    Для Каждого ИдентификаторСтроки Из мВыделенныеСтроки Цикл
        // Предполагается, что табличная часть документа называется 'Сотрудники'
        // и содержит реквизит 'Сотрудник' типа СправочникСсылка.Сотрудники
        СтрокаТЧДокумента = ДокументОбъект.Сотрудники.НайтиПоИдентификатору(ИдентификаторСтроки);
        Если СтрокаТЧДокумента <> Неопределено Тогда
            мВыделенныеСотрудники.Добавить(СтрокаТЧДокумента.Сотрудник);
        КонецЕсли;
    КонецЦикла;

    // Далее можно выполнять запросы или перебирать эти мВыделенныеСотрудники
    // Например, получить плановые начисления для каждого сотрудника
    Для Каждого СотрудникСсылка Из мВыделенныеСотрудники Цикл
        // ... Логика получения данных по сотруднику ...
        // И заполнение мСтруктураОкладов
    КонецЦикла;

    Возврат мСтруктураОкладов;
КонецФункции

Этот подход позволяет получить доступ к выделенным строкам непосредственно из формы документа, но требует аккуратного управления жизненным циклом открываемой формы, чтобы не создавать лишние объекты в памяти и не замедлять работу пользователя.

Альтернативные подходы и рекомендации

Помимо рассмотренных вариантов, существуют и другие способы решить задачу печати по выделенным строкам, а также общие рекомендации, которые помогут вам в разработке.

Альтернативные методы:

  1. Добавление булевого реквизита "Печатать": Мы можем модифицировать конфигурацию, добавив в табличную часть документа булевый реквизит, например, Печатать. Пользователь будет вручную отмечать галочками нужные строки, а внешняя печатная форма будет отбирать строки по этому признаку. Этот метод требует изменения конфигурации документа, но предлагает простую и понятную механику для пользователя.
  2. Выделение на предпросмотре: Если требования не слишком строгие, пользователь может выделить нужные строки уже в окне предварительного просмотра печатной формы и затем в настройках принтера указать печать выделенной области. Это наименее гибкое и не программное решение, но может подойти для разовых случаев.
  3. Использование временных таблиц: Для сложных отчетов или при необходимости агрегировать данные выделенных строк, мы можем на сервере сформировать временную таблицу, заполнить ее данными выбранных строк и затем использовать эту временную таблицу в запросе для макета печати.

Важные рекомендации:

  1. Используйте идентификаторы строк вместо индексов: Как мы уже выяснили, идентификаторы строк (получаемые, например, через ВыделенныеСтроки и используемые с НайтиПоИдентификатору()) более стабильны, чем индексы, которые могут измениться при различных манипуляциях с табличной частью.
  2. Сортируйте индексы/идентификаторы: Если порядок вывода строк важен, всегда сортируйте массив идентификаторов или индексов перед обработкой на сервере. Это гарантирует предсказуемый результат.
  3. Проверяйте наличие выделенных строк: Всегда включайте проверку МассивВыделенныхСтрок.Количество() > 0, чтобы избежать ошибок, если пользователь не выделил ни одной строки.
  4. Информируйте пользователя: Если выбрана только одна строка или не выбрано ни одной, предоставляйте пользователю соответствующую обратную связь, чтобы он понимал, что будет напечатано (или почему ничего не напечатано).
  5. Будьте осторожны с модификацией типовых структур: При передаче дополнительных параметров в типовые процедуры печати БСП, будьте внимательны. Добавление своих данных в стандартные структуры может непреднамеренно нарушить работу других типовых печатных форм. Внешние печатные формы обычно имеют свои собственные механизмы для передачи дополнительных параметров, которые следует использовать.
  6. Обращайтесь к документации БСП: Для глубокого понимания работы с внешними обработками и печатными формами в рамках БСП, мы рекомендуем изучать документацию и демонстрационные конфигурации, разработанные 1С.

Реализация печати по выделенным строкам в 1С:Предприятии 8.3 — это типовая задача, требующая внимательности к деталям клиент-серверного взаимодействия и особенностям работы с БСП. Следуя изложенным принципам и примерам, вы сможете успешно решить эту задачу и предоставить пользователям удобный инструмент для выборочной печати данных.

← На главную