При разработке в среде «1С:Предприятие 8» программисты часто сталкиваются с ситуацией, когда код изменения документа отрабатывает без ошибок, но после открытия формы или проверки в базе данных значения реквизитов остаются пустыми или старыми. Особенно часто это проявляется в отраслевых решениях (например, от компании «Первый БИТ»), где логика работы объектов сильно перегружена дополнительными проверками.
В этой статье мы подробно разберем, как правильно записывать справочные данные в документ, и проанализируем основные причины, по которым эти данные могут «исчезать» в момент фиксации транзакции.
Для начала рассмотрим базовый программный шаблон, который использовал автор темы. Чтобы изменить существующий документ, нам необходимо получить его объект, заблокировать его от изменений другими пользователями, внести правки и записать.
Проанализируем пример кода:
КорДок = Документы.бит_д_ЗаказНаОтгрузку.НайтиПоНомеру(Результат.Номер, Результат.Дата);
Если Не КорДок.Пустая() Тогда
КорДокОбъект = КорДок.ПолучитьОбъект();
КорДокОбъект.Заблокировать();
// Поиск ссылки на справочник по наименованию
КорДокОбъект.ТранспортнаяКомпания = Справочники.Контрагенты.НайтиПоНаименованию(КомпанияР);
КорДокОбъект.Автомобиль = АвтомобильР;
КорДокОбъект.Водитель = ВодительР;
КорДокОбъект.ВремяПодачи = ВремяПодачи;
КорДокОбъект.Записать(РежимЗаписиДокумента.Запись);
КорДокОбъект.Разблокировать();
КонецЕсли;
На первый взгляд код выглядит корректно, однако именно здесь могут скрываться нюансы, связанные с типами данных и контекстом выполнения.
Это самая распространенная техническая причина. В 1С реквизиты документа имеют строго определенный тип, например, СправочникСсылка.Контрагенты. Если вы попытаетесь присвоить этому полю строку или СправочникОбъект, платформа не выдаст ошибку в момент присваивания, но при записи значение будет проигнорировано или очищено.
Разберем основные моменты проверки типов:
АвтомобильР или ВодительР содержат именно ссылку (Ref), а не весь объект справочника. Ссылку можно получить методом Ссылка у объекта или напрямую из запроса.НайтиПоНаименованию() возвращает пустую ссылку, если элемент не найден. Если в документе после записи «пусто», возможно, поиск просто не нашел нужную компанию.Если отладчик показывает, что значение в КорДокОбъект.Автомобиль заполнено непосредственно перед вызовом метода Записать(), но после него в базе данных значение пропадает — значит, срабатывает код внутри самого объекта.
Рассмотрим ситуацию подробнее. В конфигурациях БИТ часто реализована сложная бизнес-логика. В модуле документа в процедуре ПередЗаписью могут стоять проверки:
ТранспортнаяКомпания не совпадает с владельцем Автомобиля, код конфигурации может обнулять машину для соблюдения целостности данных.Для диагностики этого случая необходимо зайти в Модуль объекта документа и найти процедуру ПередЗаписью. Поставьте там точку останова и проследите за состоянием реквизитов объекта в процессе выполнения этой процедуры.
В современных конфигурациях 1С логика часто выносится за пределы модуля документа в специальные объекты — Подписки на события. Это позволяет разработчикам добавлять функционал, не меняя типовой код документа.
Проанализируем, как это влияет на запись:
Существует событие ПередЗаписью (уровня подписки), которое выполняется в той же транзакции, что и запись документа. Если в конфигурации есть подписка, фильтрующая данные вашего документа, она может модифицировать Источник (сам документ) прямо перед фиксацией в БД. Проверьте список подписок в дереве метаданных, фильтруя их по типу объекта ДокументОбъект.бит_д_ЗаказНаОтгрузку.
Как отметил автор в финальном сообщении темы, проблема может быть связана с «организацией работы формы». Если вы пытаетесь программно изменить документ, который в данный момент открыт у пользователя на экране, могут возникнуть коллизии:
ПриЗаписи или ПослеЗаписи), которые обновляют данные на основе экранных полей, игнорируя то, что было записано программно в фоновом режиме.Чтобы окончательно выяснить, где теряются данные, выполните следующие шаги:
Записать().
Сообщить("Значение перед записью: " + КорДокОбъект.Автомобиль);
КорДокОбъект.Записать(РежимЗаписиДокумента.Запись);
Записать(), используйте «Шаг внутрь» (F11), чтобы пройти по всей цепочке вызовов, включая подписки и модули объекта.Важный совет: При работе с отраслевыми решениями (БИТ, Рарус и др.) всегда проверяйте, нет ли специализированных программных интерфейсов (API) для изменения документов. Иногда вместо прямой записи объекта требуется вызывать экспортные процедуры из общих модулей, которые корректно заполняют все связанные регистры и проходят через контроли бизнес-логики.