В процессе разработки или поддержки конфигураций на платформе 1С:Предприятие 7.7 программисты часто сталкиваются с фатальной ошибкой: Значение не представляет агрегатный объект. Эта ситуация особенно коварна, когда код кажется абсолютно логичным, а в режиме отладчика проблема может магическим образом «исчезать». В данной статье мы подробно разберем причины возникновения этой ошибки на примере работы с платежными поручениями, проанализируем поведение системы и научимся писать отказоустойчивый код.
Для начала выясним, что именно сообщает нам система. Ошибка Значение не представляет агрегатный объект (ИмяРеквизита) означает, что программа пытается обратиться к атрибуту или методу через точку (например, Объект.Реквизит), но переменная, стоящая слева от точки, в данный момент не является объектом. В контексте 1С 7.7 под «агрегатным объектом» понимаются сложные типы данных: справочники, документы, списки значений, таблицы значений и другие.
Рассмотрим фрагмент кода, который вызвал проблему у автора темы:
Док = СоздатьОбъект("Документ.ПлатежноеПоручение");
// ... получение номера платежки из списка ...
Док.НайтиПоНомеру(НомерПлатежки);
Если Найти(Док.РасчетныйСчет.НомерIBAN, "AKBB") <> 0 Тогда
// выполнение действий
КонецЕсли;
В строке Док.РасчетныйСчет.НомерIBAN ошибка может возникнуть на двух этапах:
Док не был позиционирован на конкретном документе (поиск не удался).РасчетныйСчет у найденного документа пуст или содержит значение неверного типа (например, строку вместо ссылки на справочник).Главная причина, по которой метод НайтиПоНомеру может подвести разработчика, кроется в настройках метаданных документа. Если для документа в конфигураторе установлено свойство «Периодичность» (например, «Год»), то номера документов могут повторяться в разных периодах (годах).
Проанализируем ситуацию: если мы вызываем Док.НайтиПоНомеру(НомерПлатежки) без указания второго параметра (даты), система начинает искать документ с начала времен (с самой ранней записи в базе данных). Как только 1С находит любой документ с таким номером, поиск прекращается.
Если в базе данных за 2010 год существует «Платежное поручение №1» и в текущем 2024 году тоже есть «Платежное поручение №1», то без указания даты поиск «зацепится» за документ 2010 года. Скорее всего, в старом документе реквизит РасчетныйСчет не заполнен, либо структура справочника расчетных счетов тогда была иной (например, отсутствовало поле НомерIBAN). В результате при попытке обратиться к Док.РасчетныйСчет.НомерIBAN система выдает ошибку, так как РасчетныйСчет оказывается «пустым значением», которое не является агрегатным объектом.
Многих сбивает с толку тот факт, что при установке точки останова код начинает выполняться успешно. Проанализируем, почему это происходит. Существует несколько причин такого «эффекта наблюдателя» в 1С 7.7:
Чтобы избежать подобных ошибок, рассмотрим правильный алгоритм работы с документами. Нам необходимо добавить проверку результата поиска и проверку заполнения реквизитов.
Шаг 1: Использование даты в поиске. Если нумерация периодическая, всегда передавайте дату (или пустую дату текущего периода), чтобы ограничить область поиска.
Шаг 2: Проверка возвращаемого значения. Метод НайтиПоНомеру возвращает 1, если документ найден, и 0 в противном случае. Никогда не обращайтесь к атрибутам документа, не убедившись, что он найден.
Шаг 3: Проверка на пустое значение. Перед обращением к реквизитам через точку (цепочкой) проверяйте промежуточные звенья.
Посмотрим на пример правильного кода:
Док = СоздатьОбъект("Документ.ПлатежноеПоручение");
КонДата = РабочаяДата(); // или дата из контекста обработки
Пока а > 0 Цикл
// ... логика получения номера ...
// Передаем дату для корректного поиска в периоде
Если Док.НайтиПоНомеру(НомерПлатежки, КонДата) = 1 Тогда
// Проверяем, что расчетный счет выбран
Если ПустоеЗначение(Док.РасчетныйСчет) = 0 Тогда
// Теперь безопасно проверяем IBAN
Если Найти(Док.РасчетныйСчет.НомерIBAN, "AKBB") <> 0 Тогда
ЗагрузкаББ(Док);
СчББ = СчББ + 1;
// ... остальные проверки ...
КонецЕсли;
Иначе
Сообщить("У документа №" + Док.НомерДок + " не заполнен расчетный счет!");
КонецЕсли;
Иначе
Сообщить("Документ №" + НомерПлатежки + " не найден в периоде " + КонДата);
КонецЕсли;
а = а - 1;
КонецЦикла;
При работе с СписокЗначений и методом ПолучитьЗначение, как в примере автора, важно также следить за корректностью строки номера. Рассмотрим полезный совет из обсуждения: при извлечении номера из строки, где могут быть пробелы или дополнительные символы, используйте СокрЛП() и внимательно считайте позицию обрезки строки.
Выясним причину, по которой автор использовал конструкцию Лев(..., Найти(...)). Это часто делается для отделения номера от префикса или текстового описания. Однако стоит помнить, что в 1С 7.7 функция Найти вернет 0, если символ не найден, что может привести к ошибке в функции Лев.
Подведем итоги нашего анализа ситуации с агрегатными объектами:
НайтиПоНомеру(Номер, Дата) — это единственный надежный способ найти документ, если в конфигурации включена периодичность номеров.Если Объект.Найти... = 1 Тогда. Это золотое правило программирования в 1С 7.7.ПустоеЗначение() помогает предотвратить ошибки при обращении к вложенным реквизитам (через две и более точки).Соблюдение этих простых правил сделает ваш код стабильным, а работу программы — предсказуемой даже без использования отладчика.