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

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

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

Различие контекстов исполнения: Форма vs Объект

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

  1. Модуль формы работает в контексте отображения. Здесь доступны такие объекты, как ЭтаФорма, ЭлементыФормы (в обычном приложении) или ЭтаФорма.Элементы (в управляемом). Здесь мы знаем, куда наведен курсор пользователя (ТекущаяСтрока).
  2. Модуль объекта работает непосредственно с данными в базе или оперативной памяти. Когда исполняется код в модуле объекта, никакой формы может не существовать вовсе (например, при программном создании документа или выполнении регламентного задания). Поэтому обращение к визуальным элементам здесь запрещено.

Шаг 1. Избавляемся от интерфейсных методов

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

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


// В модуле объекта (например, в процедуре ПриКопировании)
НаборЗаписей = РегистрыСведений.NKE_Спецификация.СоздатьНаборЗаписей();

// Вместо установки отбора в элементах формы, устанавливаем отбор в наборе
НаборЗаписей.Отбор.Документ.Установить(ЭтотОбъект.Ссылка);

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

Шаг 2. Замена «ТекущейСтроки» на перебор коллекции

В модуле формы мы часто используем ЭлементыФормы.Товары.ТекущиеДанные. В модуле объекта понятия «текущая строка» нет, так как нет пользователя, который бы ее выбрал. Рассмотрим ситуацию, когда нужно рассчитать суммы для всей табличной части. Для этого мы используем цикл Для Каждого.

Проанализируем пример трансформации расчета сумм:


// БЫЛО (в модуле формы):
СтрокаТабличнойЧасти = ЭлементыФормы.Товары.ТекущиеДанные;
ОбработкаТабличныхЧастей.РассчитатьСуммуТабЧасти(СтрокаТабличнойЧасти, ЭтотОбъект);

// СТАЛО (в модуле объекта):
Для Каждого СтрокаТабличнойЧасти Из Товары Цикл
    // Вызываем экспортную процедуру общего модуля для каждой строки
    ОбработкаТабличныхЧастей.РассчитатьСуммуТабЧасти(СтрокаТабличнойЧасти, ЭтотОбъект);
    ОбработкаТабличныхЧастей.РассчитатьСуммуНДСТабЧасти(СтрокаТабличнойЧасти, ЭтотОбъект);
КонецЦикла;

Шаг 3. Решение проблемы с Ключом Строки

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

Если вы переносите логику в новый документ (например, из «Заказа покупателя» во «Внутренний заказ»), необходимо проверить следующее:

  1. Откройте конфигуратор и найдите ваш документ.
  2. Перейдите в список реквизитов табличной части (например, «Товары»).
  3. Убедитесь, что там создан реквизит КлючСтроки с типом Число.
  4. Если его нет — добавьте. Без этого реквизита код, обращающийся к ТекущаяСтрока.КлючСтроки, всегда будет выдавать ошибку.

Шаг 4. Работа с данными при копировании

Рассмотрим подробнее процедуру ПриКопировании(ОбъектКопирования). В этот момент ЭтотОбъект — это новый документ (дубликат), а ОбъектКопирования — это исходный документ, из которого берутся данные.

Если нужно скопировать записи регистра сведений, связанные с документом, алгоритм будет следующим:

  1. Прочитать записи из регистра по отбору Документ = ОбъектКопирования.Ссылка.
  2. Выгрузить их в таблицу значений.
  3. В каждой строке таблицы заменить старую ссылку на новую (хотя при копировании ссылка нового объекта еще не сформирована в БД, что является отдельной сложностью).
  4. Записать данные.

Важный нюанс: поскольку у нового объекта при копировании еще нет ссылки (ЭтотОбъект.Ссылка.Пустая() = Истина), вы не сможете записать записи в регистр, если ссылка является обязательным измерением. В этом случае правильнее будет:

Итоговые рекомендации

Подведем итоги нашего анализа. Чтобы успешно перенести процедуру в модуль документа, придерживайтесь следующих правил:

Во-первых, заменяйте любые обращения к ЭтаФорма и ЭлементыФормы на прямые обращения к реквизитам документа (например, просто Товары вместо ЭлементыФормы.Товары).

Во-вторых, исключайте любые методы интерактивного взаимодействия: ОткрытьФорму, Вопрос, Предупреждение. В модуле объекта они вызовут ошибку при работе в фоновом задании или на сервере.

В-третьих, если код должен работать со строкой табличной части, передавайте эту строку в процедуру как параметр, а не пытайтесь получить её через «текущие данные» интерфейса.

В-четвертых, всегда проверяйте наличие необходимых реквизитов в метаданных документа, если используете такие поля, как КлючСтроки или НомерСтроки.

Используя этот структурный подход, вы сможете перенести любую бизнес-логику из экранных форм в программные модули, обеспечив стабильную работу системы в любых режимах.

← На главную