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