При разработке бизнес-логики в 1С часто возникает необходимость автоматически приводить дату документа к началу дня (00:00:00) или к определенному времени при проведении. Программисты подписываются на событие ПередЗаписью и пишут стандартную проверку, однако при записи и оперативном проведении новых документов сталкиваются с проблемой: платформа 1С все равно подставляет текущее время или сдвигает отметку времени.
Рассмотрим подробно, почему платформа веде́т себя таким образом и какими способами можно гарантированно установить нужную дату и время документа.
Проанализируем работу платформы 1С при записи и проведении документов. Если для документа разрешено оперативное проведение и он записывается в режиме РежимЗаписиДокумента.Проведение с параметром РежимПроведенияДокумента.Оперативный, вступает в действие механизм оперативной отметки времени.
Посмотрим, что происходит на уровне платформы:
ПередЗаписью код подписки успешно меняет время на начало дня. Посмотрим на этот код:
Если Источник.Дата <> НачалоДня(Источник.Дата) Тогда
Источник.Дата = НачалоДня(Источник.Дата);
КонецЕсли;
Источник.Дата изменилось (например, стало 08.02.2018 00:00:00).ПолучитьОперативнуюОтметкуВремени()). Если в этой секунде уже есть документы, платформа может добавить +1 секунду или поставить время 23:59:59.Таким образом, даже если подписка на событие ПередЗаписью отработала корректно, сам механизм оперативного проведения платформы перекрывает установленное значение даты перед записью в базу данных.
Разберем наиболее эффективный способ решения проблемы через подписку на событие без изменения свойств метаданных документа.
В подписке на событие ПередЗаписью нам доступны не только свойства объекта, но и параметры записи, включая РежимПроведения. Если мы изменим режим проведения с оперативного на неоперативный непосредственно перед записью, платформа не будет подставлять оперативную отметку времени.
Рассмотрим пример кода в подписке на событие ПередЗаписью:
Процедура ИмяПодпискиПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
Если Отказ Тогда
Возврат;
КонецЕсли;
// Приводим дату к началу дня
Источник.Дата = НачалоДня(Источник.Дата);
// Если документ проводится, переводим режим в неоперативный
Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
РежимПроведения = РежимПроведенияДокумента.Неоперативный;
КонецЕсли;
КонецПроцедуры
Важно: этот способ отключает оперативную отметку времени для документа, благодаря чему переданная дата Источник.Дата сохраняется в базе данных в исходном виде.
Если бизнес-логика документа в целом не требует оперативного контроля остатков на текущую секунду, правильным решением будет отключение оперативного проведения на уровне конфигуратора.
Разберем шаги по настройке метаданных:
Запретить.После этого документ всегда будет проводиться в неоперативном режиме, и код смены даты в подписке ПередЗаписью будет отрабатывать без вмешательства алгоритмов платформы.
В некоторых случаях платформа может сдвигать время документа из-за настроек автоматической установки времени (режим автовремени). Чтобы исключить установку времени платформой при неоперативном проведении или обычной записи, убедимся, что режим автовремени отключен.
Для явного отключения сдвига времени в документе используется свойство ЗаполнениеДокументов.ЗаполнитьВремяДокумента или настройка РежимАвтоВремя.НеИспользовать при программной записи объекта.
Если проведение выполняется пользователем из формы документа, мы можем изменить режим проведения на сервере до запуска транзакции записи.
Рассмотрим пример кода в расширении формы документа в событии ПередЗаписьюНаСервере:
&НаСервере
Процедура Расш_ПередЗаписьюНаСервереПосле(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Устанавливаем дату объекта в начало дня
ТекущийОбъект.Дата = НачалоДня(ТекущийОбъект.Дата);
// Меняем режим проведения в параметрах записи
Если ПараметрыЗаписи.РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
ПараметрыЗаписи.РежимПроведения = РежимПроведенияДокумента.Неоперативный;
КонецЕсли;
КонецПроцедуры
Мы выяснили, что причиной изменения даты при проведении является встроенный механизм оперативного проведения платформы 1С. Для того чтобы дата документа в подписке на событие ПередЗаписью сохранялась на начало дня, необходимо либо перевести документ в неоперативный режим через параметр РежимПроведения, либо запретить оперативное проведение в свойствах метаданных документа.