Как программно вызвать внешнюю обработку 1С 8.3 на управляемых формах из формы списка документов и передать текущий документ?

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

При работе в среде 1С:Предприятие 8.3 на управляемых формах часто возникает задача динамического вызова внешних обработок из форм списка документов. Мы, как разработчики, можем столкнуться с необходимостью выполнить специфические действия над выбранным в списке документом, используя при этом функционал, вынесенный во внешнюю обработку. Стандартный механизм «Дополнительные отчеты и обработки» не всегда подходит для реализации сложной кастомной логики или когда требуется максимально гибкий подход к вызову и передаче параметров.

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

Получение ссылки на текущий документ из формы списка

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

Мы должны убедиться, что пользователь выбрал какой-либо элемент в списке. Если выбор не сделан, свойство ТекущиеДанные будет иметь значение Неопределено. Все действия по обработке нажатия кнопки и вызову обработки обычно выполняются на клиенте, поэтому наш код будет использовать директиву &НаКлиенте.

Рассмотрим пример кода, который необходимо разместить в обработчике команды (процедуре, привязанной к кнопке на форме списка):


&НаКлиенте
Процедура МояКнопка(Команда)
    // Прежде всего, проверяем, выбран ли какой-либо элемент в списке
    Если Элементы.Список.ТекущиеДанные = Неопределено Тогда
        Сообщить("Выберите документ в списке для выполнения операции.", СтатусСообщения.Внимание);
        Возврат; // Выходим из процедуры, так как документ не выбран
    КонецЕсли;

    // Получаем ссылку на текущий выбранный документ
    // Свойство Ссылка доступно для элементов, отображаемых в списке
    СсылкаНаДокумент = Элементы.Список.ТекущиеДанные.Ссылка;

    // Далее мы будем использовать СсылкаНаДокумент для передачи во внешнюю обработку
    // ...
КонецПроцедуры

В этом фрагменте Элементы.Список — это обращение к таблице формы списка документов. Свойство ТекущиеДанные возвращает объект, который соответствует текущей строке данных (например, структуре данных или объекту типа СтрокаТаблицы), а из него мы уже извлекаем непосредственную ссылку на объект информационной базы с помощью свойства Ссылка. Это ключевой момент для получения контекста выбранного документа.

Вариант 1: Загрузка внешней обработки из файла

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

Пошаговое описание

  1. Мы уже получили СсылкаНаДокумент.
  2. Далее нам понадобится путь к файлу внешней обработки .epf. Этот путь может быть жестко задан (например, для локального использования), получен из настроек или выбран пользователем.
  3. Используем конструктор Новый ВнешняяОбработка(ИмяФайла) для создания объекта внешней обработки.
  4. С помощью метода ПолучитьФорму() получаем форму обработки.
  5. Передаем параметры в форму или объект обработки.
  6. Открываем форму обработки методом Открыть().

Пример кода для загрузки из файла

Расширим наш предыдущий пример:


&НаКлиенте
Процедура МояКнопка(Команда)
    Если Элементы.Список.ТекущиеДанные = Неопределено Тогда
        Сообщить("Выберите документ в списке для выполнения операции.", СтатусСообщения.Внимание);
        Возврат;
    КонецЕсли;

    СсылкаНаДокумент = Элементы.Список.ТекущиеДанные.Ссылка;

    // Определяем путь к файлу внешней обработки.
    // В реальной системе этот путь может быть переменным или храниться в настройках.
    ИмяФайлаОбработки = "C:\МоиОбработки\МояВнешняяОбработка.epf"; // Пример пути на клиенте
    
    // Прежде чем пытаться открыть файл, убедимся, что он существует.
    // Проверка существования файла на клиенте напрямую возможна, но для универсальности
    // или если файл находится на сервере, потребуется серверный вызов.
    // Если обработка запускается в веб-клиенте, этот подход потребует загрузки файла на клиент,
    // что реализуется через серверные вызовы.
    Если Не ФайлСуществуетНаКлиенте(ИмяФайлаОбработки) Тогда // Предполагаем наличие такой клиентской функции
        Сообщить("Файл обработки не найден по указанному пути: " + ИмяФайлаОбработки, СтатусСообщения.Ошибка);
        Возврат;
    КонецЕсли;

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

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

        // Открываем форму внешней обработки
        Форма.Открыть();

    Исключение
        Сообщить("Ошибка при открытии внешней обработки: " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
    КонецПопытки;
КонецПроцедуры

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

Важные моменты:

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

Вариант 2: Загрузка внешней обработки из зарегистрированных дополнительных обработок

Если ваша внешняя обработка уже зарегистрирована в информационной базе через стандартный механизм «Дополнительные отчеты и обработки» (справочник ДополнительныеОтчетыИОбработки), мы можем использовать этот факт для ее получения. Этот подход более централизован, облегчает администрирование и обновление обработок, а также позволяет управлять правами доступа через систему 1С.

Пошаговое описание

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

Пример кода для получения из зарегистрированных обработок

Этот вариант потребует вызова серверной функции для получения объекта обработки.


&НаКлиенте
Процедура МояКнопка(Команда)
    Если Элементы.Список.ТекущиеДанные = Неопределено Тогда
        Сообщить("Выберите документ в списке для выполнения операции.", СтатусСообщения.Внимание);
        Возврат;
    КонецЕсли;

    СсылкаНаДокумент = Элементы.Список.ТекущиеДанные.Ссылка;

    // Получаем объект внешней обработки с сервера.
    // 'МояВнешняяОбработка' - это наименование, под которым обработка зарегистрирована
    // в справочнике ДополнительныеОтчетыИОбработки.
    ОбработкаОбъект = ПолучитьОбъектДополнительнойОбработкиНаСервере("МояВнешняяОбработка");

    Если ОбработкаОбъект = Неопределено Тогда
        Сообщить("Дополнительная обработка 'МояВнешняяОбработка' не найдена или не удалось получить ее объект.", СтатусСообщения.Ошибка);
        Возврат;
    КонецЕсли;

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

        // Открываем форму
        Форма.Открыть();

    Исключение
        Сообщить("Ошибка при открытии формы дополнительной обработки: " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
    КонецПопытки;
КонецПроцедуры

&НаСервере
Функция ПолучитьОбъектДополнительнойОбработкиНаСервере(ИмяОбработки)
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ ПЕРВЫЕ 1
    |    ДополнительныеОтчетыИОбработки.Объект,
    |    ДополнительныеОтчетыИОбработки.Файл
    |ИЗ
    |    РегистрСведений.ДополнительныеОтчетыИОбработки КАК ДополнительныеОтчетыИОбработки
    |ГДЕ
    |    ДополнительныеОтчетыИОбработки.Наименование = &Наименование
    |    И ДополнительныеОтчетыИОбработки.ВидОбработки = &ВидОбработки";
    
    Запрос.УстановитьПараметр("Наименование", ИмяОбработки);
    // ВидОбработки может быть 'ДополнительнаяОбработка' или 'ДополнительныйОтчет'
    Запрос.УстановитьПараметр("ВидОбработки", ПредопределенноеЗначение("Перечисление.ВидыДополнительныхОтчетовИОбработок.ДополнительнаяОбработка"));

    Выборка = Запрос.Выполнить().Выбрать();
    Если Выборка.Следующий() Тогда
        // Обычно объект внешней обработки хранится в поле "Объект" или "Файл"
        // поля "Объект" типа СправочникСсылка.ДополнительныеОтчетыИОбработки. Это ссылка на сам элемент справочника
        // в этом элементе справочника уже хранится двоичные данные обработки
        // Если это макет, получаем его так:
        // Возврат Выборка.Объект.ПолучитьМакет("Макет"); 
        
        // Более универсальный подход: если обработка хранится как двоичные данные
        // в реквизите "Файл" типа ХранилищеЗначения
        Если НЕ Выборка.Файл.Пустая() Тогда
            ДвоичныеДанные = Выборка.Файл.Получить();
            Возврат Новый ВнешняяОбработка(ДвоичныеДанные);
        Иначе
            Сообщить("Двоичные данные обработки отсутствуют в справочнике.", СтатусСообщения.Предупреждение);
            Возврат Неопределено;
        КонецЕсли;
    Иначе
        Возврат Неопределено;
    КонецЕсли;
КонецФункции

Нюансы получения объекта обработки:

  1. В зависимости от конфигурации и способа регистрации, объект обработки может храниться по-разному. В стандартных конфигурациях 1С ДополнительныеОтчетыИОбработки часто имеют реквизит Файл типа ХранилищеЗначения. Из него мы получаем двоичные данные и передаем их в конструктор Новый ВнешняяОбработка().
  2. Также возможно, что сама обработка хранится как макет внутри элемента справочника. В этом случае мы бы использовали СправочникОбъект.ПолучитьМакет("ИмяМакета"). Всегда исследуйте структуру справочника в вашей конкретной конфигурации.

Подходы к передаче параметров во внешнюю обработку

Когда мы открываем форму внешней обработки, нам необходимо передать в нее контекст — ссылку на документ. Мы рассмотрели два основных способа: присвоение реквизиту формы или реквизиту объекта обработки. Давайте разберем их подробнее и посмотрим на другие возможности.

  1. Присвоение реквизиту формы (наиболее часто используемый)

    Если у вашей формы внешней обработки есть реквизит с именем, например, Документ (тип ДокументСсылка.<ИмяДокумента> или Произвольный), вы можете присвоить ему значение до открытия формы.

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

    В самой форме обработки в обработчике события ПриСозданииНаСервере или ПриОткрытии (если реквизит формы уже доступен на клиенте) вы сможете получить это значение.

    
    &НаСервере
    Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
        Если ЗначениеЗаполнено(Документ) Тогда // Документ - это реквизит формы
            // Используем Документ для дальнейшей работы
            Сообщить("Ссылка на документ получена: " + Документ);
        КонецЕсли;
    КонецПроцедуры
    
  2. Присвоение реквизиту объекта обработки

    Каждая форма управляемого приложения имеет свойство Объект, которое является ссылкой на основной объект данных формы (если он есть). Для внешней обработки это будет ссылка на сам объект ВнешняяОбработка. Если вы определили реквизит в модуле объекта внешней обработки, то можете присвоить его через это свойство:

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

    В модуле объекта внешней обработки (не в модуле формы!) вы должны иметь соответствующий реквизит. Код в самой обработке будет обращаться к нему через ЭтотОбъект.Документ.

    Примечание: Если у формы нет основного объекта (например, она создана без указания основного реквизита), то свойство Объект будет Неопределено. Для внешних обработок обычно Объект ссылается на экземпляр ВнешняяОбработкаОбъект.

  3. Через параметры открытия формы

    Хотя в данном сценарии мы используем Форма.Открыть() без явных параметров, существует стандартный механизм передачи параметров через метод ОткрытьФорму() глобального контекста. Если бы мы открывали форму не напрямую через ПолучитьФорму() объекта обработки, а через глобальный метод, это было бы так:

    
    ПараметрыОткрытия = Новый Структура("ДокументСсылка", СсылкаНаДокумент);
    ОткрытьФорму("ВнешняяОбработка.<ИмяФормы>", ПараметрыОткрытия);
    

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

    Внутри формы обработки эти параметры доступны через свойство Параметры:

    
    &НаКлиенте
    Процедура ПриОткрытии(Отказ)
        Если Параметры.Свойство("ДокументСсылка") Тогда
            МойДокумент = Параметры.ДокументСсылка;
            // Дальнейшая работа с МойДокумент
        КонецЕсли;
    КонецПроцедуры
    
  4. Вызов метода объекта обработки

    Если вам не нужно открывать форму, а просто выполнить какой-либо код в обработке, вы можете вызвать ее метод напрямую после создания объекта:

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

    В этом случае во внешней обработке должен быть экспортный метод с таким именем:

    
    Процедура ВыполнитьДействиеСДокументом(Ссылка) Экспорт
        // Здесь реализуем логику работы с документом
        Сообщить("Выполняю действие с документом: " + Ссылка);
        // ...
    КонецПроцедуры
    

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

Логика выполнения внутри внешней обработки

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

  1. В обработчике события ПриОткрытии формы

    Если обработка должна автоматически выполнить действия при своем появлении на экране, мы размещаем код в процедуре ПриОткрытии формы. Здесь мы можем получить переданные параметры и сразу начать работу.

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

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

  2. По кнопке на форме обработки

    Если пользователь должен сначала просмотреть данные, возможно, ввести дополнительные параметры, а затем инициировать действие, логика должна быть привязана к обработчику команды кнопки на форме обработки. Здесь также потребуются клиент-серверные взаимодействия.

    
    &НаКлиенте
    Процедура ВыполнитьДействие(Команда)
        // Документ - это реквизит формы, заполненный при открытии
        Если ЗначениеЗаполнено(Документ) Тогда
            Сообщить("Начинаю выполнение действия для документа: " + Документ);
            ВыполнитьДействиеСервер(Документ);
        Иначе
            Сообщить("Ссылка на документ не определена.", СтатусСообщения.Ошибка);
        КонецЕсли;
    КонецПроцедуры
    
    &НаСервере
    Процедура ВыполнитьДействиеСервер(СсылкаДокумента)
        Попытка
            // Здесь сложная серверная логика...
            ДокументОбъект = СсылкаДокумента.ПолучитьОбъект();
            Если ДокументОбъект <> Неопределено Тогда
                ДокументОбъект.ДополнительныеСвойства.Вставить("ДатаОбработки", ТекущаяДата());
                ДокументОбъект.Записать();
                СообщитьНаКлиенте("Действие для документа " + ДокументОбъект + " успешно завершено.");
            КонецЕсли;
        Исключение
            СообщитьНаКлиенте("Произошла ошибка при выполнении действия: " + ОписаниеОшибки(), СтатусСообщения.Ошибка);
        КонецПопытки;
    КонецПроцедуры
    

Рекомендации и лучшие практики

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

Мы проанализировали различные аспекты динамического вызова внешних обработок в 1С 8.3 на управляемых формах. Теперь вы имеете представление о том, как получить ссылку на текущий документ, как загрузить обработку из файла или из зарегистрированных данных, и как эффективно передавать в нее параметры для выполнения необходимой логики. Эти знания позволят вам создавать более гибкие и мощные инструменты для автоматизации бизнес-процессов.

← На главную