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