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

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

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

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

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

Стандартный интерфейс для внешних обработок заполнения ТЧ

Прежде всего, давайте вспомним, как обычно подключаются внешние обработки заполнения табличных частей. Для того чтобы обработка могла быть подключена к документу как стандартный механизм заполнения ТЧ, она должна содержать экспортную процедуру в своем модуле объекта:


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

После этой инициализации обработка может получить доступ к объекту документа и его табличной части для программного заполнения. Но как после этого запускать логику на форме документа?

Решение 1: Использование механизма оповещений (ОбработкаОповещения)

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

  1. Во внешней обработке:

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

    
    // В модуле объекта внешней обработки, после заполнения ТЧ на сервере
    // ... код заполнения табличной части ...
            
    // Оповещаем форму документа о завершении работы
    // "ИмяСобытия" - произвольная строка, по которой форма будет идентифицировать событие
    // "РезультатЗаполнения" - данные, которые мы хотим передать форме (например, количество добавленных строк, статус)
    // "ЭтаФорма" - можно передать текущую форму обработки, если она есть и нужно вернуть ей контекст
    Оповестить("ЗаполнениеТЧЗавершено", РезультатЗаполнения);
    
  2. На форме документа:

    На форме документа нам необходимо "подписаться" на это оповещение. Это делается в событии ПриСозданииНаСервере или ПриОткрытии формы документа.

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

    Использование оповещений является наиболее гибким, так как позволяет внешней обработке быть "независимой" от конкретной формы, а форма сама решает, как реагировать на оповещения.

Решение 2: Вынесение общей логики в отдельную процедуру

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

  1. В модуле формы документа:

    Создадим экспортную процедуру, которая содержит общую логику.

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

    Внешняя обработка, после заполнения ТЧ, может вызвать эту экспортную процедуру через объект формы документа, который был передан при инициализации.

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

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

Решение 3: Прямое выполнение серверного кода и обновление данных формы

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

  1. Внешняя обработка (Клиент):

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

    
    // В модуле формы внешней обработки (на клиенте)
    // ... получение параметров для заполнения ...
            
    // Вызываем серверную функцию для заполнения ТЧ
    ЗаполнитьТабличнуюЧастьНаСервере(ЭтаФорма.ОбъектДокумента, ПараметрыЗаполнения);
            
    // После возврата с сервера, если нужно обновить отображение данных на форме документа,
    // но форма документа управляется отдельным контекстом,
    // потребуется оповещение или прямое обновление формы документа.
    // Если же объект ДокументФорма был передан как ссылка на форму,
    // то обновление можно выполнить через нее.
    // Например: ДокументФорма.Объект.Прочитать(); ДокументФорма.ОбновитьОтображениеДанных();
    
  2. Внешняя обработка (Сервер):

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

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

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

    
    // В модуле формы документа (на клиенте), если внешняя обработка запускала эту функцию
    // или в модуле формы обработки, если она имеет доступ к форме документа
    // Если объект документа передавался как ссылка на реквизит формы,
    // то достаточно просто обновить данные формы.
            
    // Для обновления отображения табличной части
    ЭтаФорма.Элементы.Товары.Обновить(); 
            
    // Для полного обновления всех данных формы (перечитывает объект с сервера)
    // Если нужно полностью перечитать объект после серверных изменений
    ЭтаФорма.Прочитать();
    

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

Решение 4: Создание формы обработки с диалогом

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

  1. Форма внешней обработки:

    Создаем форму в обработке, на которой размещаем поля для ввода параметров (например, период, источник данных, флажки настроек).

  2. Действия пользователя:

    Пользователь открывает форму этой внешней обработки, вводит необходимые параметры и нажимает кнопку "Заполнить".

  3. Заполнение ТЧ:

    По нажатию кнопки "Заполнить" в обработке выполняется клиентский код, который вызывает серверную функцию этой же обработки. В эту серверную функцию передаются собранные на форме параметры и сам объект документа, который был передан при инициализации обработки.

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

    После успешного выполнения серверной операции, форма документа будет обновлена, показывая новые данные в табличной части.

Общие рекомендации и важные моменты

Таким образом, хотя событие ОбработкаВыбора не срабатывает автоматически при программном заполнении ТЧ, платформа 1С:Предприятие 8.3 предоставляет мощные механизмы для организации взаимодействия между внешней обработкой и формой документа, позволяя нам реализовать любую необходимую логику после завершения операции заполнения.

← На главную