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