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