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