К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как в 1С программно заполнить форму документа

Разбираем способы программного заполнения формы документа в 1С: обработка заполнения, заполнение на основании, работа с реквизитами и табличными частями.

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

Главная ошибка начинающих разработчиков — путать заполнение объекта документа (данных в памяти и в базе) с заполнением элементов управляемой формы. Реквизит формы и реквизит документа — не одно и то же: форма лишь отображает данные объекта, и правильный подход почти всегда сводится к изменению данных объекта, а не элементов интерфейса. Ниже разобраны рабочие способы с примерами кода и указанием границ их применения.

Как устроена связь формы и объекта документа

Управляемая форма документа работает с реквизитом формы типа ДанныеФормыСтруктура, который обычно называется Объект. Этот реквизит содержит копию данных документа. Когда вы меняете значения внутри Объект.Реквизит на сервере, платформа сама синхронизирует отображение — элементы формы, связанные с этими данными, обновятся без дополнительных команд.

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

Заполнение через событие ОбработкаЗаполнения

Штатный механизм платформы — обработчик ОбработкаЗаполнения в модуле объекта документа. Он вызывается автоматически при создании документа с параметром заполнения: при вводе на основании, при копировании, при вызове из кода с указанием основания.

Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)

Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ЗаказКлиента") Тогда

Контрагент = ДанныеЗаполнения.Контрагент;

Договор = ДанныеЗаполнения.Договор;

Для Каждого СтрокаТовара Из ДанныеЗаполнения.Товары Цикл

НоваяСтрока = Товары.Добавить();

НоваяСтрока.Номенклатура = СтрокаТовара.Номенклатура;

НоваяСтрока.Количество = СтрокаТовара.Количество;

НоваяСтрока.Цена = СтрокаТовара.Цена;

КонецЦикла;

КонецЕсли;

КонецПроцедуры

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

Чтобы при программном создании документа сработал этот обработчик, передайте основание в метод Заполнить():

НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();

НовыйДокумент.Дата = ТекущаяДатаСеанса();

НовыйДокумент.Заполнить(ЗаказСсылка); // вызовет ОбработкаЗаполнения

НовыйДокумент.Записать();

Прямое присвоение реквизитов объекта

Когда документ создаётся из обработки, фонового задания или при обмене, чаще всего применяют прямое заполнение реквизитов объекта без всяких обработчиков. Это самый прозрачный способ: вы полностью контролируете каждое поле.

Док = Документы.ПриходныйОрдер.СоздатьДокумент();

Док.Дата = ТекущаяДатаСеанса();

Док.Организация = ПараметрыЗаполнения.Организация;

Док.Склад = ПараметрыЗаполнения.Склад;

Док.Ответственный = Пользователи.ТекущийПользователь();

СтрокаТЧ = Док.Товары.Добавить();

СтрокаТЧ.Номенклатура = ПараметрыЗаполнения.Номенклатура;

СтрокаТЧ.Количество = 10;

Док.Записать(РежимЗаписиДокумента.Проведение);

Обязательный минимум — дата документа. Без неё документ не запишется, а при попытке проведения платформа выдаст ошибку. Также проверяйте заполнение реквизитов с признаком «Проверка заполнения: выдавать ошибку» — платформа выполнит эту проверку при записи с проведением.

Заполнение из модуля формы

Если логика заполнения привязана к действию пользователя — например, кнопка «Заполнить по остаткам» в форме документа, — код размещают в модуле формы. Команда делится на клиентскую и серверную части, потому что изменение табличной части объекта безопаснее выполнять на сервере.

&НаКлиенте

Процедура ЗаполнитьПоОстаткам(Команда)

ЗаполнитьПоОстаткамНаСервере();

КонецПроцедуры

&НаСервере

Процедура ЗаполнитьПоОстаткамНаСервере()

Объект.Товары.Очистить();

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Остатки.Номенклатура КАК Номенклатура,

| Остатки.КоличествоОстаток КАК Количество

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК Остатки";

Запрос.УстановитьПараметр("Период", Объект.Дата);

Запрос.УстановитьПараметр("Склад", Объект.Склад);

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл

СтрокаТЧ = Объект.Товары.Добавить();

СтрокаТЧ.Номенклатура = Выборка.Номенклатура;

СтрокаТЧ.Количество = Выборка.Количество;

КонецЦикла;

КонецПроцедуры

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

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

Заполнение табличной части программно

Табличная часть — это коллекция строк, и работа с ней сводится к трём операциям: очистка, добавление строк, заполнение полей строки. Типичные приёмы:

  • Объект.Товары.Очистить() — удалить все строки перед заполнением;
  • Объект.Товары.Добавить() — добавить строку и получить на неё ссылку для заполнения полей;
  • Объект.Товары.Загрузить(ТаблицаЗначений) — массовая загрузка из заранее подготовленной таблицы значений с совпадающими именами колонок;
  • ЗаполнитьЗначенияСвойств(СтрокаТЧ, СтрокаИсточника) — копирование одноимённых полей из строки другой табличной части без перечисления каждого поля.

Метод Загрузить() быстрее цикла с добавлением строк и удобен при заполнении из результата запроса: Объект.Товары.Загрузить(Запрос.Выполнить().Выгрузить()). Ограничение — имена колонок результата запроса должны совпадать с именами реквизитов табличной части, иначе лишние колонки будут проигнорированы, а недостающие поля останутся пустыми.

Типичные ошибки
01
Присваивать значения полям ввода формы вместо реквизитов объекта — данные не сохранятся при записи
02
Забыть установить Дату документа — запись завершится ошибкой
03
Очищать табличную часть без подтверждения пользователя — данные, введённые вручную, будут потеряны
04
Вызывать серверные процедуры заполнения в цикле с клиента — резкое падение производительности из-за множества серверных вызовов
05
Не проверять тип ДанныеЗаполнения в ОбработкаЗаполнения — обработчик упадёт при вводе на основании непредусмотренного объекта

Как выбрать способ заполнения

Маршрут решения

Как выбрать действие

Документ создаётся на основании другого объектаРеализуйте логику в ОбработкаЗаполнения модуля объекта и вызывайте Заполнить(Основание)
Документ создаётся из обработки, обмена или регламентного заданияИспользуйте СоздатьДокумент() и прямое присвоение реквизитов
Заполнение инициирует пользователь кнопкой в формеРазместите код в модуле формы: клиентская команда + серверная процедура, меняющая данные Объекта
Нужно переиспользовать сложную логику заполненияВынесите её в экспортную процедуру модуля объекта и вызывайте через ДанныеФормыВЗначение из формы

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

Проверка результата

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

Контрольные точки

Как проверить результат

Запись документа
Норма

Записать() выполняется без исключений, документ открывается в форме

Тревожный признак

Ошибка проверки заполнения или исключение при записи

Табличная часть
Норма

Количество строк и итоговые суммы совпадают с источником

Тревожный признак

Строки дублируются или часть полей пуста

Движения по регистрам
Норма

После проведения движения соответствуют данным документа

Тревожный признак

Движения отсутствуют или содержат неверные измерения

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

Итог

Что важно запомнить

Заполняйте данные объекта, а не элементы формы. Для ввода на основании используйте ОбработкаЗаполнения и метод Заполнить(), для создания из кода — прямое присвоение реквизитов, для кнопок в форме — серверные процедуры модуля формы. Всегда устанавливайте дату, проверяйте обязательные реквизиты и тестируйте массовое создание документов на копии базы.

Часто задаваемые вопросы

Почему изменения в форме не сохраняются после записи?

Чаще всего значения присваивались элементам формы (полям ввода), а не реквизитам объекта. При записи платформа берёт данные из реквизита Объект, а не из элементов. Проверьте, что код меняет именно Объект.ИмяРеквизита.

Можно ли заполнить документ, не открывая его форму?

Да, и это предпочтительный способ для автоматизации. Используйте СоздатьДокумент(), заполните реквизиты и табличные части, затем вызовите Записать(). Форма при этом вообще не создаётся, что работает быстрее и не требует интерактивного сеанса.

Как заполнить документ при вводе на основании нескольких разных документов?

В ОбработкаЗаполнения проверяйте тип параметра ДанныеЗаполнения через ТипЗнч() и для каждого поддерживаемого типа пишите свою ветку заполнения. Если тип не распознан, оставьте стандартную обработку включённой.

Чем Загрузить() отличается от добавления строк в цикле?

Загрузить() переносит всю таблицу значений за один вызов и работает быстрее, но требует совпадения имён колонок с реквизитами табличной части и не позволяет обработать каждую строку индивидуально. Цикл с Добавить() гибче, когда нужны вычисления или проверки для каждой строки.

Как вызвать процедуру заполнения из модуля объекта, находясь в форме?

Получите объект через ДокументОбъект = РеквизитФормыВЗначение("Объект"), вызовите его экспортную процедуру, затем верните данные через ЗначениеВРеквизитФормы(ДокументОбъект, "Объект"). Без обратного преобразования изменения не попадут в форму.

Безопасно ли программно проводить документы сразу после заполнения?

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