Как исправить ошибку Поле объекта не обнаружено и правильно настроить условия Если в 1С

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

При разработке или модификации печатных форм в 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда один и тот же программный код должен обрабатывать разные типы документов. Например, при печати УПД для «Реализации товаров и услуг» нам нужно получить ЗаказКлиента, а для «Корректировки реализации» — ДокументОснование. Если написать обращение «в лоб» через точку, система выдаст ошибку «Поле объекта не обнаружено», как только встретит документ, у которого нет такого реквизита.

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

Разбор синтаксических ошибок в конструкции Если

Проанализируем типичные ошибки, которые возникли в процессе обсуждения темы. Основная проблема была связана с неправильным использованием знаков препинания в условных операторах. В языке 1С точка с запятой ; является признаком окончания инструкции (оператора).

Важное правило: никогда не ставьте точку с запятой после ключевых слов Тогда, ИначеЕсли или Иначе. Это приводит к тому, что система считает оператор внутри условия пустым и выдает ошибку «Ожидается выражение».

Рассмотрим правильную структуру кода:


Если ЗначениеЗаполнено(Реквизит1) Тогда
    // Действие, если условие истинно
ИначеЕсли ЗначениеЗаполнено(Реквизит2) Тогда
    // Действие, если первое ложно, а второе истинно
Иначе
    // Действие во всех остальных случаях
КонецЕсли;

В сообщениях форума автор использовал ИначеЕсли;, что и вызывало синтаксическую ошибку. Также важно помнить, что каждое Если должно закрываться своим КонецЕсли;.

Проблема обращения к реквизитам разных документов

Выясним причину ошибки «Поле объекта не обнаружено». Когда мы пишем ДокументРеализация.ЗаказКлиента, платформа 1С пытается найти этот реквизит в метаданных конкретного документа. Если ДокументРеализация — это «Корректировка реализации», у которой в конфигураторе нет поля ЗаказКлиента, выполнение кода прервется с ошибкой еще до того, как сработает проверка на заполненность.

Рассмотрим, как правильно реализовать выбор нужного реквизита-основания в зависимости от его наличия в объекте. Нам нужно проверить, какой именно документ перед нами, или безопасно попытаться получить значение.

Вариант 1. Проверка через ЗначениеЗаполнено и типы ссылок

Посмотрим на пример кода, который позволяет переключаться между ЗаказКлиента и ДокументОснование, если мы заранее уверены в именах реквизитов:


ДокументРеализация = ДанныеПечати.Ссылка.ДокументыОснования[0].ДокументОснование;

// Проверяем наличие Заказа клиента через проверку типа или метаданные
// Но проще всего использовать логику: если это один тип документа, берем один реквизит, если другой - второй.
// В данном примере используем универсальный подход через проверку заполненности:

Попытка
    ДокументЗаказ = ДокументРеализация.ЗаказКлиента;
Исключение
    ДокументЗаказ = ДокументРеализация.ДокументОснование;
КонецПопытки;

Если НЕ ЗначениеЗаполнено(ДокументЗаказ) Тогда
    // Если оба варианта не сработали, возможно, нужно искать глубже
КонецЕсли;

Однако использование Попытка...Исключение — это не самый элегантный способ для бизнес-логики. Давайте разберем более профессиональный метод.

Вариант 2. Безопасное получение реквизитов (рекомендуемый)

Проанализируем ситуацию с точки зрения использования Библиотеки Стандартных Подсистем (БСП), которая есть почти во всех современных конфигурациях (ERP, УТ 11, КА, БП 3.0). В БСП есть отличная функция ОбщегоНазначения.ЗначениеРеквизитаОбъекта().

Преимущество этого метода: если реквизита не существует в метаданных документа, функция просто вернет Неопределено вместо того, чтобы вызвать критическую ошибку «Поле объекта не обнаружено».

Разберем по шагам, как переписать проблемный код из темы форума:


// Получаем ссылку на документ-основание
СсылкаОснование = ДанныеПечати.Ссылка.ДокументыОснования[0].ДокументОснование;

// Безопасно получаем значения реквизитов
Заказ = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаОснование, "ЗаказКлиента");
Если Заказ = Неопределено Тогда 
    // Если реквизита "ЗаказКлиента" нет, пробуем "ДокументОснование"
    Заказ = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СсылкаОснование, "ДокументОснование");
КонецЕсли;

// Теперь работаем с результатом
Если ЗначениеЗаполнено(Заказ) Тогда
    ДокументЗаказ = Заказ;
    ТекстОснования = "Счет № " + ПрефиксацияОбъектовКлиентСервер.ПолучитьНомерНаПечать(ДокументЗаказ.Номер, Ложь, Истина) 
                     + " от " + Формат(ДокументЗаказ.Дата, "ДЛФ=DD");
Иначе
    // Логика, если основание не найдено
КонецЕсли;

Интеграция в существующий код с учетом доверенности

Теперь объединим все условия в один логический блок, который решит задачу автора темы. Нам нужно проверить наличие данных о доверенности и правильно сформировать строку основания, не допуская падения системы.


// 1. Сначала определим документ-основание (Реализация или Корректировка)
ДокументРеализация = ДанныеПечати.Ссылка.ДокументыОснования[0].ДокументОснование;

// 2. Определяем "Заказ", учитывая разную структуру документов
// Используем функцию ЕстьРеквизитОбъекта для проверки метаданных
МетаданныеОбъекта = ДокументРеализация.Метаданные();
Если МетаданныеОбъекта.Реквизиты.Найти("ЗаказКлиента") <> Неопределено Тогда
    ДокументЗаказ = ДокументРеализация.ЗаказКлиента;
ИначеЕсли МетаданныеОбъекта.Реквизиты.Найти("ДокументОснование") <> Неопределено Тогда
    ДокументЗаказ = ДокументРеализация.ДокументОснование;
Иначе
    ДокументЗаказ = Неопределено;
КонецЕсли;

// 3. Формируем текст на печать
Если ЗначениеЗаполнено(ДокументЗаказ) Тогда
    
    НомерДатаСчета = "Счет № " + ПрефиксацияОбъектовКлиентСервер.ПолучитьНомерНаПечать(ДокументЗаказ.Номер, Ложь, Истина) 
                     + " от " + Формат(ДокументЗаказ.Дата, "ДЛФ=DD");
    
    // Проверяем заполнение доверенности
    ДоверенностьЗаполнена = ЗначениеЗаполнено(ДанныеПечати.ДоверенностьНомер) 
                           И ЗначениеЗаполнено(ДанныеПечати.ДоверенностьДата) 
                           И (ЗначениеЗаполнено(ДанныеПечати.ДоверенностьВыдана) 
                           Или ЗначениеЗаполнено(ДанныеПечати.ДоверенностьЛицо));
    
    Если ДоверенностьЗаполнена Тогда
        
        ШаблонДоверенности = НСтр("ru = 'по доверенности №%1 от %2, выданной %3 %4'");
        ТекстДоверенности = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
                                ШаблонДоверенности, 
                                ДанныеПечати.ДоверенностьНомер, 
                                Формат(ДанныеПечати.ДоверенностьДата, "ДЛФ=DD"), 
                                ДанныеПечати.ДоверенностьВыдана, 
                                ДанныеПечати.ДоверенностьЛицо);
        
        ТекстОснования = НомерДатаСчета + "; " + ТекстДоверенности;
        
    Иначе
        // Если доверенность не заполнена, выводим только счет
        ТекстОснования = НомерДатаСчета;
    КонецЕсли;
    
КонецЕсли;

Подведем итоги

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

  1. Соблюдайте синтаксис условий: после Тогда, Иначе и ИначеЕсли не ставьте точку с запятой. Завершайте блок оператором КонецЕсли;.
  2. Проверяйте наличие реквизитов: перед тем как обратиться к полю через точку (Объект.Реквизит), убедитесь, что этот реквизит существует в данном типе документа.
  3. Используйте функции БСП: функции типа ОбщегоНазначения.ЗначениеРеквизитаОбъекта избавляют от необходимости писать сложные проверки и защищают от аварийного завершения программы.
  4. Унифицируйте поиск: если в разных документах нужные данные хранятся в полях с разными именами (например, ЗаказПокупателя и ЗаказКлиента), выносите логику поиска в отдельную переменную в начале процедуры.

Следуя этим рекомендациям, вы сможете создавать надежные механизмы печати, которые не «падают» при добавлении новых типов документов в цепочку оснований.

← На главную