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