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