Как по кнопке на управляемой форме заполнить документ на основании другого документа

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

Часто в процессе разработки возникает задача: перенести алгоритм заполнения документа, реализованный в стандартном событии ОбработкаЗаполнения модуля объекта, на кнопку формы. При этом начинающие разработчики нередко пытаются скопировать код из модуля объекта напрямую в обработчик команды формы и сталкиваются с ошибкой компиляции вида «Переменная не определена (ИмяТабличнойЧасти)». Разберем по шагам, почему возникает эта ошибка и как правильно реализовать заполнение документа по кнопке.

Выясним причину ошибки «Переменная не определена»

Проанализируем контекст выполнения кода в платформе 1С:Предприятие 8.3:

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

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

Вариант 1. Вызов стандартного механизма заполнения объекта (Рекомендуемый)

Рассмотрим правильный способ вызова логики ОбработкаЗаполнения из управляемой формы. В модуле объекта документа оставляем типовой обработчик заполнения. Посмотрим на пример кода в модуле объекта:


Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
	
	Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.уатЗаказГрузоотправителя") Тогда
		
		// Очищаем табличную часть перед заполнением
		Стоимость.Очистить();
		
		Для Каждого ТекСтрокаУслуги Из ДанныеЗаполнения.Услуги Цикл
			НоваяСтрока = Стоимость.Добавить();
			НоваяСтрока.Номенклатура       = ТекСтрокаУслуги.Номенклатура;
			НоваяСтрока.НоменклатураУслуги = ТекСтрокаУслуги.Номенклатура;
			НоваяСтрока.Количество         = ТекСтрокаУслуги.Количество;
			НоваяСтрока.Цена               = ТекСтрокаУслуги.Цена;
			НоваяСтрока.СтавкаНДС          = ТекСтрокаУслуги.СтавкаНДС;
			НоваяСтрока.Сумма              = ТекСтрокаУслуги.Сумма;
			НоваяСтрока.СуммаНДС           = ТекСтрокаУслуги.СуммаНДС;
		КонецЦикла;
		
	КонецЕсли;
	
КонецПроцедуры

Чтобы запустить этот код по кнопке на форме, преобразуем реквизит формы в прикладной объект с помощью РеквизитФормыВЗначение, вызовем платформенный метод Заполнить() и вернем измененные данные обратно в форму через ЗначениеВРеквизитФормы. Обратите внимание, что эти методы работают исключительно в контексте &НаСервере.

Разберем код модуля управляемой формы:


&НаКлиенте
Процедура КомандаЗаполнитьПоЗаказу(Команда)
	
	// В качестве параметра передаем ссылку на документ-основание
	// Например, реквизит документа или выбранное пользователем значение
	Если ЗначениеЗаполнено(Объект.ДокументОснование) Тогда
		ЗаполнитьНаСервере(Объект.ДокументОснование);
	Иначе
		ПоказатьПредупреждение(, "Не указан документ-основание для заполнения!");
	КонецЕсли;
	
КонецПроцедуры

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

Вариант 2. Прямое заполнение данных формы без создания объекта

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

Рассмотрим пример реализации прямого заполнения на сервере:


&НаКлиенте
Процедура ЗаполнитьТабличнуюЧасть(Команда)
	
	Если НЕ ЗначениеЗаполнено(Объект.ДокументОснование) Тогда
		ПоказатьПредупреждение(, "Выберите документ-основание!");
		Возврат;
	КонецЕсли;
	
	ЗаполнитьТабличнуюЧастьНаСервере(Объект.ДокументОснование);
	
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьТабличнуюЧастьНаСервере(СсылкаНаЗаказ)
	
	// Очищаем табличную часть формы через реквизит Объект
	Объект.Стоимость.Очистить();
	
	// Считываем строки документа-основания
	Для Каждого ТекСтрокаУслуги Из СсылкаНаЗаказ.Услуги Цикл
		НоваяСтрока = Объект.Стоимость.Добавить();
		НоваяСтрока.Номенклатура       = ТекСтрокаУслуги.Номенклатура;
		НоваяСтрока.НоменклатураУслуги = ТекСтрокаУслуги.Номенклатура;
		НоваяСтрока.Количество         = ТекСтрокаУслуги.Количество;
		НоваяСтрока.Цена               = ТекСтрокаУслуги.Цена;
		НоваяСтрока.СтавкаНДС          = ТекСтрокаУслуги.СтавкаНДС;
		НоваяСтрока.Сумма              = ТекСтрокаУслуги.Сумма;
		НоваяСтрока.СуммаНДС           = ТекСтрокаУслуги.СуммаНДС;
	КонецЦикла;
	
	Модифицированность = Истина;
	
КонецПроцедуры

Важные практические рекомендации

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