В процессе разработки в среде 1С:Предприятие программисты часто сталкиваются с ситуацией, когда стандартный код, успешно работающий в других местах, внезапно выдает ошибку: «Поле объекта не обнаружено». Особенно странно это выглядит, когда ошибка указывает на глобальную коллекцию, такую как Документы, Справочники или РегистрыСведений. В этой статье мы подробно разберем, почему это происходит, проанализируем конкретный пример из практики работы с конфигурацией «Зарплата и управление персоналом 3.1» и выясним, как правильно организовывать программное создание документов, чтобы избежать подобных конфликтов.
Первое, что нам необходимо понять — это то, как платформа 1С ищет идентификаторы в коде. Когда вы пишете слово Документы, система запускает поиск этого имени по определенной иерархии. Проанализируем этот порядок:
В рассматриваемой ситуации программист создал в своем документе (или обработке) табличную часть и назвал её Документы. С этого момента внутри модуля данного объекта слово Документы перестало означать «коллекцию всех типов документов системы» и стало означать «эту конкретную таблицу». Естественно, у табличной части нет свойства ДоходВНатуральнойФорме, что и приводило к падению системы с ошибкой.
Рассмотрим фрагмент кода, в котором возникла ошибка. Программист пытался автоматизировать создание документов ДоходВНатуральнойФорме на основании данных из своей таблицы. Посмотрим на структуру процедуры:
&НаСервере
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// ... (подготовительные запросы к базе данных)
Для Каждого ЭлементКВО Из МассивКВО Цикл
// ... (логика подбора данных)
Если докДоход = Неопределено Тогда
// ОШИБКА ПРОИСХОДИТ ЗДЕСЬ:
докДоход = Документы.ДоходВНатуральнойФорме.СоздатьДокумент();
докДоход.Дата = СтрокаКВО.Дата;
докДоход.Начисление = СтрокаКВО.НачислениеШаблон;
// ... (заполнение остальных реквизитов)
КонецЕсли;
// В конце процедуры мы видим причину конфликта:
Если докДоход <> Неопределено Тогда
докДоход.Записать(РежимЗаписиДокумента.Проведение);
нСтрокаРегистрации = ЭтотОбъект.Документы.Добавить(); // Обращение к табличной части
нСтрокаРегистрации.Документ = докДоход;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Как мы видим, в коде используется ЭтотОбъект.Документы. Наличие реквизита с именем Документы полностью блокирует доступ к глобальному менеджеру из модуля этого объекта. Это типичная ловушка: синтакс-помощник может продолжать подсказывать правильные имена типов документов через точку, так как он ориентируется на метаданные в целом, но в момент исполнения кода платформа выбирает локальный контекст.
Выясним, какие варианты исправления ситуации существуют, если вы уже столкнулись с такой проблемой.
Это самый правильный и надежный метод. Если вы создаете собственный объект (обработку или новый документ), старайтесь не давать реквизитам имена, совпадающие с глобальными коллекциями или ключевыми словами языка (Документы, Справочники, Запрос, Выполнить и т.д.). Например, табличную часть можно назвать СозданныеДокументы или СписокДокументов. Это снимет конфликт имен раз и навсегда.
Если по каким-то причинам переименовать реквизит невозможно (например, это типовой объект или расширение, где изменение имени приведет к потере данных), следует вынести логику создания документов в Общий модуль. Рассмотрим, почему это помогает:
Документы всегда будет указывать на глобальную коллекцию метаданных.В некоторых случаях (хотя это считается менее «чистым» стилем программирования) можно попытаться обратиться к метаданным в обход прямого имени. Однако для коллекции Документы в 1С нет альтернативного глобального синонима, кроме как использование функций, возвращающих менеджеры по строковому имени типа. Например, использование функций БСП или методов типа Документы["ДоходВНатуральнойФорме"]. Но если имя Документы перекрыто табличной частью, даже такой синтаксис внутри модуля может не сработать, так как 1С будет пытаться найти индекс в таблице.
Помимо исправления ошибки с именованием, при программном создании документов в ЗУП 3.1 важно учитывать особенности бизнес-логики этой конфигурации. Проанализируем, что еще необходимо добавить в код для корректной работы:
1. Заполнение обязательных полей. Документ ДоходВНатуральнойФорме требует обязательного указания не только сотрудника и суммы, но и Начисления, МесяцаНачисления, а также Организации. Без этих полей документ не проведется.
2. Расчет НДФЛ. В приведенном примере кода расчет НДФЛ делается вручную: НоваяСтрока.НДФЛ = СтрокаКВО.Сумма * 0.13;. Мы должны понимать, что это упрощение. В реальной базе ЗУП налоги могут зависеть от статуса нерезидента, применения вычетов и прогрессивной шкалы (15%). Правильнее использовать программный вызов процедур расчета из модулей ЗУП, например:
// Пример вызова типового расчета (условно)
КадровыйУчет.ЗаполнитьОрганизациюПоСотруднику(докДоход);
ДоходыВНатуральнойФормеСобытия.РассчитатьДокумент(докДоход);
3. Проверка прав доступа. Если ошибка «Поле объекта не обнаружено» сохраняется даже после проверки имен, стоит убедиться, что у пользователя, под которым запускается код, есть права на Просмотр и Интерактивное добавление для данного типа документа. Хотя RLS обычно выдает другую ошибку («Нарушение прав доступа»), отсутствие прав в некоторых контекстах может приводить к тому, что менеджер объекта просто не включается в коллекцию для данного сеанса.
Подведем итоги нашего анализа. Ошибка «Поле объекта не обнаружено» при обращении к Документы — это явный признак того, что в вашем текущем программном контексте появилось что-то другое с таким же именем. Всегда проверяйте состав реквизитов объекта, в модуле которого вы пишете код. Соблюдение стандартов именования 1С (избегание использования имен глобальных коллекций для локальных переменных) позволит вам избежать подобных трудностей и сделает ваш код более читаемым и надежным.