Почему не заполняется реквизит документа при записи из управляемой формы и как это исправить

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

В процессе разработки в среде 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда программно измененный реквизит документа в модуле формы «отказывается» сохраняться в базе данных. Типичный сценарий: мы создаем связанный документ (например, «Поступление в кассу») в обработчике ПриЗаписиНаСервере основного документа и пытаемся записать ссылку на него в основной документ. Код выполняется без ошибок, документ создается, но поле на форме и в базе остается пустым.

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

Разбираем причину: Объект против ТекущийОбъект

Основная причина проблемы кроется в непонимании жизненного цикла записи управляемой формы. Разберем ситуацию поэтапно. Когда пользователь нажимает кнопку «Провести и закрыть» или «Записать», на сервере в модуле формы срабатывает процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи).

Проанализируем состав этой процедуры:

  1. Объект — это реквизит управляемой формы, имеющий тип ДанныеФормыСтруктура. Это «копия» данных для отображения в интерфейсе.
  2. ТекущийОбъект — это параметр процедуры, который имеет тип ДокументОбъект. Это тот самый экземпляр документа, который в данный момент находится внутри транзакции записи и будет физически записан в таблицы базы данных.

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

Исправляем заполнение основного реквизита

Рассмотрим правильный код для заполнения реквизита ссылки в основном документе. Вместо обращения к Объект.СозданныйДокПост, мы будем использовать ТекущийОбъект.СозданныйДокПост.


&НаСервере
Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    
    // Создаем новый документ
    ДокПостОтПодот = Документы.ПоступлениеВКассу.СоздатьДокумент();
    ДокПостОтПодот.Дата = ТекущийОбъект.Дата;
    ДокПостОтПодот.Организация = ТекущийОбъект.Организация;
    // ... заполнение остальных реквизитов ...

    Попытка
        // Пытаемся провести созданный документ
        ДокПостОтПодот.Записать(РежимЗаписиДокумента.Проведение);
        
        // КРИТИЧЕСКИ ВАЖНО: Пишем в ТекущийОбъект, а не в Объект!
        ТекущийОбъект.СозданныйДокПост = ДокПостОтПодот.Ссылка;
        
    Исключение
        // Если проведение не удалось, хотя бы просто записываем
        ДокПостОтПодот.Записать(РежимЗаписиДокумента.Запись);
        ТекущийОбъект.СозданныйДокПост = ДокПостОтПодот.Ссылка;
        
        ТекстСообщения = КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Не удалось провести документ: " + ТекстСообщения);
    КонецПопытки;

КонецПроцедуры

Работа с табличными частями внутри транзакции

Ситуация усложняется, когда нам нужно заполнить реквизиты в каждой строке табличной части. Проблема остается той же: если мы будем перебирать Объект.Расходы, изменения не сохранятся. Нам необходимо работать с коллекцией ТекущийОбъект.Расходы.

Проанализируем правильный алгоритм работы с табличной частью:


// Внутри процедуры ПриЗаписиНаСервере
Для Каждого СтрокаТЧ Из ТекущийОбъект.Расходы Цикл
    
    // Создаем связанный расходный документ
    НовыйРасход = Документы.РасходИзКассы.СоздатьДокумент();
    НовыйРасход.Дата = ТекущийОбъект.Дата;
    НовыйРасход.СуммаДокумента = СтрокаТЧ.Сумма;
    // ... заполнение данных ...

    Попытка
        НовыйРасход.Записать(РежимЗаписиДокумента.Запись);
        
        // Присваиваем ссылку строке табличной части ТЕКУЩЕГО ОБЪЕКТА
        СтрокаТЧ.СозданныйДокРасх = НовыйРасход.Ссылка;
    Исключение
        // Обработка ошибок записи
    КонецПопытки;
    
КонецЦикла;

Обратите внимание на использование НовыйРасход.Ссылка. Присваивание самого объекта НовыйРасход вместо его ссылки — это еще одна распространенная ошибка. Реквизит документа в базе данных имеет тип СправочникСсылка или ДокументСсылка, поэтому всегда явно указывайте свойство .Ссылка.

Где лучше размещать такой код?

Хотя мы выяснили, как заставить этот механизм работать в модуле формы, с точки зрения архитектуры 1С это решение не является оптимальным. Рассмотрим причины:

  1. Зависимость от интерфейса: Если вы создадите документ программно (через обмен данными или обработку), код в модуле формы не выполнится, и связанные документы не будут созданы. Для регулярной синхронизации баз в таких сценариях настраивают автоматический регулярный обмен данными по расписанию.
  2. Длинные транзакции: Создание и проведение других документов внутри транзакции записи основного документа значительно нагружает базу данных и может привести к блокировкам.

Рекомендация: Перенесите логику создания подчиненных документов в Модуль объекта основного документа, в обработчик ПриЗаписи. В модуле объекта нет разделения на Объект и ТекущийОбъект, вы работаете напрямую со свойствами через ключевое слово ЭтотОбъект.

Пошаговое резюме решения проблемы

Если вы все же решили оставить код в модуле формы, убедитесь, что вы выполнили следующие шаги:

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

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

← На главную