Перенос кода из модуля формы в модуль объекта — это классическая задача, с которой сталкивается каждый разработчик 1С при рефакторинге или необходимости автоматизировать действия (например, при копировании документа). Однако механическое копирование текста процедуры приводит к ошибкам компиляции, таким как Переменная не определена (Этаформа) или Поле объекта не обнаружено (ЭлементыФормы). Проанализируем причины этих ошибок и разберем правильный подход к трансформации кода.
Прежде всего, разберем ситуацию: почему старый код перестал работать? В 1С существует четкое разделение на интерфейсную логику (модуль формы) и прикладную логику данных (модуль объекта).
ЭтаФорма, ЭлементыФормы (в обычном приложении) или ЭтаФорма.Элементы (в управляемом). Здесь мы знаем, куда наведен курсор пользователя (ТекущаяСтрока).Проанализируем исходный код автора. В нем вызывается ПолучитьФорму() и ОткрытьМодально(). В модуле объекта это недопустимо. Если ваша задача — записать данные в регистр сведений при копировании документа, вам не нужно открывать форму набора записей. Вам нужно записать эти данные программно.
Вместо открытия формы для редактирования, мы должны создать набор записей, заполнить его измерения и ресурсы, а затем вызвать метод Записать(). Рассмотрим, как это должно выглядеть в модуле объекта:
// В модуле объекта (например, в процедуре ПриКопировании)
НаборЗаписей = РегистрыСведений.NKE_Спецификация.СоздатьНаборЗаписей();
// Вместо установки отбора в элементах формы, устанавливаем отбор в наборе
НаборЗаписей.Отбор.Документ.Установить(ЭтотОбъект.Ссылка);
// Если документ еще не записан (а при копировании Ссылка обычно пустая),
// то запись в регистр сведений, связанный с этим документом,
// обычно переносится в процедуру ПриЗаписи или выполняется после записи.
В модуле формы мы часто используем ЭлементыФормы.Товары.ТекущиеДанные. В модуле объекта понятия «текущая строка» нет, так как нет пользователя, который бы ее выбрал. Рассмотрим ситуацию, когда нужно рассчитать суммы для всей табличной части. Для этого мы используем цикл Для Каждого.
Проанализируем пример трансформации расчета сумм:
// БЫЛО (в модуле формы):
СтрокаТабличнойЧасти = ЭлементыФормы.Товары.ТекущиеДанные;
ОбработкаТабличныхЧастей.РассчитатьСуммуТабЧасти(СтрокаТабличнойЧасти, ЭтотОбъект);
// СТАЛО (в модуле объекта):
Для Каждого СтрокаТабличнойЧасти Из Товары Цикл
// Вызываем экспортную процедуру общего модуля для каждой строки
ОбработкаТабличныхЧастей.РассчитатьСуммуТабЧасти(СтрокаТабличнойЧасти, ЭтотОбъект);
ОбработкаТабличныхЧастей.РассчитатьСуммуНДСТабЧасти(СтрокаТабличнойЧасти, ЭтотОбъект);
КонецЦикла;
Автор столкнулся с ошибкой Поле объекта не обнаружено (КлючСтроки). Выясним причину: в типовых конфигурациях (таких как УПП или КА) КлючСтроки — это специальный реквизит табличной части, используемый для связи строк документа с записями в регистрах сведений или накопления.
Если вы переносите логику в новый документ (например, из «Заказа покупателя» во «Внутренний заказ»), необходимо проверить следующее:
КлючСтроки с типом Число.ТекущаяСтрока.КлючСтроки, всегда будет выдавать ошибку.Рассмотрим подробнее процедуру ПриКопировании(ОбъектКопирования). В этот момент ЭтотОбъект — это новый документ (дубликат), а ОбъектКопирования — это исходный документ, из которого берутся данные.
Если нужно скопировать записи регистра сведений, связанные с документом, алгоритм будет следующим:
Документ = ОбъектКопирования.Ссылка.Важный нюанс: поскольку у нового объекта при копировании еще нет ссылки (ЭтотОбъект.Ссылка.Пустая() = Истина), вы не сможете записать записи в регистр, если ссылка является обязательным измерением. В этом случае правильнее будет:
ПриКопировании сохранить данные во временную структуру (ДополнительныеСвойства).ПриЗаписи, когда ссылка уже гарантированно получена.Подведем итоги нашего анализа. Чтобы успешно перенести процедуру в модуль документа, придерживайтесь следующих правил:
Во-первых, заменяйте любые обращения к ЭтаФорма и ЭлементыФормы на прямые обращения к реквизитам документа (например, просто Товары вместо ЭлементыФормы.Товары).
Во-вторых, исключайте любые методы интерактивного взаимодействия: ОткрытьФорму, Вопрос, Предупреждение. В модуле объекта они вызовут ошибку при работе в фоновом задании или на сервере.
В-третьих, если код должен работать со строкой табличной части, передавайте эту строку в процедуру как параметр, а не пытайтесь получить её через «текущие данные» интерфейса.
В-четвертых, всегда проверяйте наличие необходимых реквизитов в метаданных документа, если используете такие поля, как КлючСтроки или НомерСтроки.
Используя этот структурный подход, вы сможете перенести любую бизнес-логику из экранных форм в программные модули, обеспечив стабильную работу системы в любых режимах.