При программном создании и заполнении документов разработчики часто сталкиваются с ситуацией: значение присвоено реквизиту формы через ПолучитьФорму() или контекст формы, затем вызывается метод Записать() у объекта документа, но при повторном открытии документа данные пропадают. Разберем подробно причины такого поведения платформы 1С и рассмотрим правильные варианты решения этой задачи.
Для понимания сути проблемы выясним причину, почему данные формы не попадают в базу данных при стандартном вызове метода записи объекта.
Проанализируем архитектуру платформы «1С:Предприятие». В ней четко разделены две сущности:
ДокументОбъект.Записать().Поэтому обращение к форме через ПолучитьФорму() с последующей записью ДокументОбъект не приводит к сохранению данных: форма и объект в памяти существуют раздельно, пока не сработает специальный механизм синхронизации данных.
Рассмотрим самый простой и архитектурно правильный способ. Если значение должно храниться в документе постоянно и использоваться в отчетах, движениях регистров или печатных формах, его необходимо сделать реквизитом самого объекта.
Разберем по шагам, как это реализовать:
НовыйДокумент = Документы.РеализацияТоваровУслуг.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДата();
НовыйДокумент.Организация = ВыбраннаяОрганизация;
НовыйДокумент.Контрагент = ВыбранныйКонтрагент;
// Заполняем реквизит объекта напрямую
НовыйДокумент.Комментарий = "Заполнено программно";
НовыйДокумент.СуммаВключаетНДС = Истина;
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
Если реквизит нельзя добавить в метаданные (например, типовая конфигурация находится на поддержке без возможности изменения структуры), выясним, как это значение сохраняется при интерактивной работе пользователя.
Посмотрим на типовые сценарии, куда разработчики конфигурации могли перенаправить данные формы:
ДополнительныеРеквизиты.ДополнительныеСвойства объекта: данные из реквизита формы перед записью помещаются в структуру Объект.ДополнительныеСвойства и обрабатываются в модуле объекта в событии ПередЗаписью.Проанализируем пример, когда реквизит формы на самом деле записывается в регистр сведений. В таком случае программный код должен сначала записать сам документ, а затем сформировать запись в регистре:
// 1. Создаем и записываем документ
НовыйДокумент = Документы.ЗаказПокупателя.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДата();
НовыйДокумент.Записать(РежимЗаписиДокумента.Запись);
// 2. Записываем данные в связанный регистр сведений
МенеджерЗаписи = РегистрыСведений.СтатусыДокументов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Документ = НовыйДокумент.Ссылка;
МенеджерЗаписи.Статус = Справочники.СтатусыЗаказов.Согласован;
МенеджерЗаписи.Период = ТекущаяДата();
МенеджерЗаписи.Записать(Истина);
Если форма отображает реквизит из состава подсистемы «Свойства» библиотеки стандартных подсистем, рассмотрим программное заполнение через штатное API БСП.
Посмотрим на пример заполнения дополнительного реквизита объекта без открытия экранных форм:
ДокОбъект = Документы.ЗаказКлиента.СоздатьДокумент();
ДокОбъект.Дата = ТекущаяДата();
ДокОбъект.Организация = СсылкаОрганизация;
// Добавляем значение в табличную часть дополнительных реквизитов
СтрокаРеквизита = ДокОбъект.ДополнительныеРеквизиты.Добавить();
СтрокаРеквизита.Свойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.НайтиПоНаименованию("НомерЗаказаНаСайте");
СтрокаРеквизита.Значение = "WEB-98745";
ДокОбъект.Записать(РежимЗаписиДокумента.Запись);
Если документ создается в обычном приложении, модуль формы содержит сложные невыделенные алгоритмы, а документ обязательно должен быть открыт или записан непосредственно через форму, разберем работу с методами формы.
Рассмотрим программное взаимодействие с обычной формой:
// Создаем объект документа
НовыйДокумент = Документы.ПоступлениеТоваровУслуг.СоздатьДокумент();
// Получаем форму документа
ФормаДокумента = НовыйДокумент.ПолучитьФорму("ФормаДокумента");
// Устанавливаем значение реквизита формы
ФормаДокумента.РеквизитФормыСтрока = "Значение реквизита";
// Вызываем экспортную процедуру пересчета или записи, если она предусмотрена разработчиком формы
ФормаДокумента.ЗаписатьВФорме();
Важно: Метод ЗаписатьВФорме() сохраняет данные формы и связанного с ней основного реквизита в обычном приложении. Однако в управляемом приложении такой подход недопустим: на стороне сервера контекст клиентских форм недоступен, а вся прикладная логика должна выполняться на уровне модулей менеджеров, модулей объектов или серверных процедур.
Подведем итог и выделим ключевые правила для надежной разработки:
ДокументОбъект), без обращения к методам ПолучитьФорму() и ОткрытьФорму().ПередЗаписью, ПриЗаписи, ПередЗаписьюНаСервере и вынести общую бизнес-логику в общий модуль или модуль менеджера документа для повторного использования.СохраняемыеДанные, однако он влияет только на контроль модифицированности формы при закрытии пользователем, но не сохраняет реквизит в базу сам по себе.