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