При разработке систем на платформе 1С:Предприятие 8 часто возникает задача разделения оперативной даты документа (которая определяет момент отражения операции в учете) и реальной даты создания записи в базе данных. Это необходимо для контроля работы персонала, построения отчетов по KPI менеджеров или для интеграции с внешними системами. Разберем подробно, как реализовать этот механизм правильно, избежав типичных ошибок новичков.
Рассмотрим ситуацию: разработчик добавляет код заполнения даты в событие формы ПриСозданииНаСервере. На первый взгляд, это работает. Однако проанализируем риски. Документ может быть создан программно (например, через обмен данными, внешнюю обработку или фоновое задание). В этом случае форма документа вообще не открывается, и ваш реквизит ДатаСоздания останется пустым. Поэтому основную логику заполнения данных всегда следует выносить в модуль объекта.
Наиболее надежный метод фиксации момента появления документа в базе данных — это использование обработчика ПередЗаписью в модуле объекта. Этот метод гарантирует, что дата будет записана ровно один раз в момент самого первого сохранения документа.
Проанализируем пример кода, который необходимо разместить в модуле объекта:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Проверяем, является ли объект новым (еще не записанным в БД)
Если ЭтоНовый() Тогда
// Фиксируем дату именно в момент первой записи
ДатаСоздания = ТекущаяДатаСеанса();
КонецЕсли;
КонецПроцедуры
В данном примере мы используем метод ЭтоНовый(). Он возвращает Истина, если ссылка на документ еще не была сформирована в базе данных. Как только документ будет записан, при последующих изменениях условие ЭтоНовый() станет ложным, и дата создания не перезапишется.
Иногда требуется зафиксировать дату в тот момент, когда пользователь только нажал кнопку "Создать", еще до момента записи. Для этого используется процедура ОбработкаЗаполнения. Но здесь есть важный нюанс — копирование документов.
При стандартном копировании платформа копирует все реквизиты, включая вашу ДатуСоздания от старого документа. Чтобы в новом документе-копии появилась актуальная дата, необходимо использовать следующий подход в модуле объекта:
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
// Заполняем дату при обычном создании
ДатаСоздания = ТекущаяДатаСеанса();
КонецПроцедуры
Процедура ПриКопировании(ОбъектКопирования)
// При копировании обязательно обновляем дату на текущую
ДатаСоздания = ТекущаяДатаСеанса();
КонецПроцедуры
Важный момент: если вы используете и ОбработкаЗаполнения, и ПередЗаписью, следите за тем, чтобы логика не противоречила друг другу. Обычно достаточно одного из этих методов в зависимости от бизнес-задачи.
Рассмотрим разницу между этими функциями, так как это критично для распределенных систем.
ТекущаяДата() — возвращает время сервера, на котором выполняется код. Если сервер находится в Москве, а пользователь во Владивостоке, в документе будет московское время.ТекущаяДатаСеанса() — возвращает время с учетом часового пояса, установленного в настройках пользователя.
Для корректного отображения времени создания документа с точки зрения пользователя всегда используйте ТекущаяДатаСеанса().
В среде разработчиков иногда обсуждается возможность получения даты создания из уникального идентификатора ссылки (GUID). Проанализируем, почему это "моветон":
УстановитьСсылкуНового() дата в GUID может быть произвольной.
Вывод: создание отдельного реквизита ДатаСоздания с включенным индексированием — самый правильный путь.
Если вы добавили реквизит в уже работающую базу, у старых документов он будет пустым. Выясним, как это исправить. Простое заполнение датой из реквизита Дата может быть неточным, если документы вводились "задним числом".
Рассмотрим вариант использования Журнала регистрации. С помощью программного кода можно прочитать события добавления объектов:
Фильтр = Новый Структура;
Фильтр.Вставить("Данные", СсылкаНаОбъект);
Фильтр.Вставить("Событие", "_$Data$_.New"); // Событие создания
ТаблицаСобытий = Новый ТаблицаЗначений;
ВыгрузитьЖурналРегистрации(ТаблицаСобытий, Фильтр);
Если ТаблицаСобытий.Количество() > 0 Тогда
ДатаРеальногоСоздания = ТаблицаСобытий[0].Период;
КонецЕсли;
Этот метод позволяет ретроспективно восстановить реальную хронологию событий в базе данных и заполнить новый реквизит максимально достоверно.
Чтобы пользователь не мог изменить зафиксированную дату вручную на форме, выполните следующие действия:
Доступность = Ложь).Так мы обеспечим неизменность данных и доверие к отчетности, которая будет строиться на основе этого реквизита.