При программном создании элементов в справочнике Контрагенты в типовой конфигурации "1С:Бухгалтерия государственного учреждения" (БГУ) разработчики часто сталкиваются с ошибкой на этапе записи объекта. Система сообщает: {Справочник.Контрагенты.МодульОбъекта(57)}: Значение не является значением объектного типа (Пустая). Эта ошибка возникает в обработчике события ПередЗаписью и прерывает создание элемента.
В этой статье мы подробно разберем, почему возникает эта ошибка, проанализируем механизм работы справочника контрагентов в БГУ и предоставим пошаговый алгоритм с примерами кода для корректного создания элементов.
Рассмотрим типичный код, который приводит к ошибке:
СК = Справочники.Контрагенты.СоздатьЭлемент();
СК.Наименование = "Петров";
Ск.Родитель = "Студенты"; // Некорректное присвоение, нужно передавать ссылку
Ск.ЮридическоеФизическоеЛицо = Справочники.ТипыКонтрагентов.НайтиПоНаименованию("7 - Физическое лицо"); // Некорректное присвоение типа
ск.Записать(); // Здесь возникает ошибка
Ошибка происходит из-за внутренней логики конфигурации БГУ. Давайте заглянем в модуль объекта справочника Контрагенты, в процедуру ПередЗаписью, которая выполняется непосредственно перед сохранением данных в базу:
Процедура ПередЗаписью(Отказ)
// ... пропущена часть кода ...
Если НЕ ЭтоГруппа Тогда
// ... пропущена часть кода ...
// Если контрагент был скопирован, а ЮрФизЛицо очищено, то нужно очистить ИНН и КПП.
// Если контрагент не новый, а ЮрФизЛицо не существует в базе, то ИНН и КПП нужно очистить.
Если (ЭтоНовый И ЮридическоеФизическоеЛицо.Пустая)
ИЛИ (НЕ ЭтоНовый И НЕ ОбщегоНазначения.СсылкаСуществует(ЮридическоеФизическоеЛицо)) Тогда
ИНН = "";
КПП = "";
КонтактнаяИнформация.Очистить;
КППИстория.Очистить;
КонецЕсли;
КонецЕсли;
// ...
КонецПроцедуры
Ключевая строка здесь: Если (ЭтоНовый И ЮридическоеФизическоеЛицо.Пустая). Система проверяет, что если создается новый элемент (ЭтоНовый = Истина), то его реквизит ЮридическоеФизическоеЛицо не должен быть пустым. В нашем первоначальном коде мы не заполнили этот реквизит корректным значением, поэтому проверка не проходит, и система генерирует ошибку.
Важный момент: реквизит ЮридическоеФизическоеЛицо — это не просто строка или перечисление. Это реквизит с составным типом данных, который должен содержать ссылку на элемент другого справочника: либо СправочникСсылка.ФизическиеЛица, либо СправочникСсылка.ЮридическиеЛица. По сути, контрагент в БГУ — это бизнес-сущность, которая всегда опирается на конкретное физическое или юридическое лицо, уже зарегистрированное в системе.
Чтобы избежать ошибки, необходимо соблюдать строгую последовательность действий. Нельзя создать контрагента "в вакууме". Сначала нужно убедиться, что в базе данных существует соответствующее ему физическое (или юридическое) лицо.
Разберем правильный алгоритм по шагам.
ФизическиеЛица или ЮридическиеЛица. Если элемент уже существует, его нужно найти. Если нет — создать.
СоздатьЭлемент().
Наименование, ВидКонтрагента и, самое главное, ЮридическоеФизическоеЛицо.
Записать().
Рассмотрим, как реализовать этот алгоритм на практике. Допустим, нам нужно создать контрагента для нового физического лица "Петров Иван Сергеевич", которого еще нет в базе.
// Шаг 1: Создаем новое физическое лицо, так как его еще нет в базе
НовоеФизЛицо = Справочники.ФизическиеЛица.СоздатьЭлемент();
НовоеФизЛицо.Наименование = "Петров Иван Сергеевич";
// Здесь необходимо заполнить и другие важные реквизиты физлица, если они известны
// Например, ИНН, СНИЛС, паспортные данные и т.д.
НовоеФизЛицо.Записать();
// Получаем ссылку на только что созданный элемент
СсылкаНаФизЛицо = НовоеФизЛицо.Ссылка;
// Шаг 2: Создаем контрагента
НовыйКонтрагент = Справочники.Контрагенты.СоздатьЭлемент();
// Шаг 3: Заполняем реквизиты контрагента
НовыйКонтрагент.Наименование = "Петров Иван Сергеевич";
// Ищем родительскую группу. Если не найдена, Родитель останется пустым.
НовыйКонтрагент.Родитель = Справочники.Контрагенты.НайтиПоНаименованию("Студенты");
НовыйКонтрагент.ВидКонтрагента = Перечисления.ЮрФизЛицо.ФизЛицо;
// КЛЮЧЕВОЙ ШАГ: Присваиваем ссылку на созданное физлицо
НовыйКонтрагент.ЮридическоеФизическоеЛицо = СсылкаНаФизЛицо;
// Также может потребоваться заполнить ТипКонтрагента (зависит от настроек учета)
// ТипКонтрагентаСсылка = Справочники.ТипыКонтрагентов.НайтиПоКоду("7");
// Если ТипКонтрагентаСсылка.Пустая() = Ложь Тогда
// НовыйКонтрагент.ТипКонтрагента = ТипКонтрагентаСсылка;
// КонецЕсли;
// Шаг 4: Записываем контрагента
Попытка
НовыйКонтрагент.Записать();
Сообщить("Контрагент 'Петров Иван Сергеевич' успешно создан!");
Исключение
Сообщить("Не удалось записать контрагента. Описание ошибки: " + ОписаниеОшибки());
КонецПопытки;
В этом примере мы сначала гарантированно создаем запись в справочнике ФизическиеЛица, получаем на нее ссылку и только потом используем эту ссылку для заполнения обязательного реквизита ЮридическоеФизическоеЛицо у нового контрагента. Такой подход полностью соответствует логике системы и позволяет избежать ошибки.
Если вы создаете обработку для загрузки данных из внешнего файла (например, Excel), правильная последовательность действий становится еще важнее. Не стоит пытаться создать физлицо и контрагента одновременно в одной транзакции без четкого разделения.
Рекомендуемый подход — двухэтапная загрузка:
Прочитайте файл и для каждой строки сначала создайте/обновите запись в справочнике ФизическиеЛица (или ЮридическиеЛица). На этом этапе важно реализовать проверку на дубли, например, по ИНН, СНИЛС или комбинации ФИО и даты рождения. Сохраняйте созданные ссылки (например, в Соответствие или ТаблицуЗначений), чтобы не искать их повторно.
После того, как все физические/юридические лица созданы, пройдитесь по данным еще раз и создавайте контрагентов. Для заполнения реквизита ЮридическоеФизическоеЛицо используйте ссылки, полученные на первом этапе. Этот подход гарантирует, что к моменту создания контрагента все связанные данные уже существуют в базе.
Такое разделение делает код более надежным, читаемым и позволяет избежать ошибок целостности данных.