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