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