В учетных задачах на платформе 1С нередко возникает требование формировать специальный документ строго один раз в сутки — например, для ежедневного закрытия смены, фиксации суточных итогов или корректировки накопившихся остатков. При этом разработчики сталкиваются с двумя вопросами: как гарантировать единственность такого документа за выбранную дату и как обеспечить правильное позиционирование движений, чтобы они рассчитывались с учетом всех операций за день.
Разберем по шагам, как решить эти задачи чисто, надежно и с учетом архитектурных особенностей платформы 1С:Предприятие.
Для предотвращения создания дублирующих документов выполняется проверка на этапе записи или проведения объекта. Проанализируем типичную ошибку при передаче параметров в запрос и рассмотрим правильный вариант кода.
Частая ошибка — передача объекта Граница в параметры запроса при использовании оператора МЕЖДУ. Платформа выдаст синтаксическую ошибку о несовместимости типов, так как Граница предназначена для обращения к виртуальным таблицам регистров, а в обычном запросе к таблице документов используются стандартные значения типа Дата.
Посмотрим на корректный вариант проверки в обработчике ПередЗаписью модуля объекта:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Принудительно устанавливаем дату на конец дня
Дата = КонецДня(Дата);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| КорректировкаЗадолженности.Ссылка КАК Ссылка
|ИЗ
| Документ.КорректировкаЗадолженности КАК КорректировкаЗадолженности
|ГДЕ
| КорректировкаЗадолженности.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&ДатаДня, ДЕНЬ) И КОНЕЦПЕРИОДА(&ДатаДня, ДЕНЬ)
| И КорректировкаЗадолженности.Ссылка <> &Ссылка";
Запрос.УстановитьПараметр("ДатаДня", Дата);
Запрос.УстановитьПараметр("Ссылка", Ссылка);
Результат = Запрос.Выполнить();
Если НЕ Результат.Пустой() Тогда
Отказ = Истина;
ВызватьИсключение "Документ корректировки за дату " + Формат(Дата, "ДФ=dd.MM.yyyy") + " уже существует в базе!";
КонецЕсли;
КонецПроцедуры
Обратим внимание на ключевые детали этой реализации:
НАЧАЛОПЕРИОДА(&ДатаДня, ДЕНЬ) и КОНЕЦПЕРИОДА(&ДатаДня, ДЕНЬ) позволяет передавать всего один параметр &ДатаДня, исключая человеческие ошибки при передаче нескольких дат.КорректировкаЗадолженности.Ссылка <> &Ссылка обязательно для того, чтобы документ не находил сам себя при повторном перепроведении или редактировании.Когда разработчики пытаются сделать документ самым последним за день, они обычно устанавливают его время на 23:59:59. Однако если другие документы системы также могут быть записаны на эту же секунду, возникает неопределенность.
В платформе 1С точность хранения времени ограничена одной секундой. Порядок документов в рамках одной секунды определяется внутренним свойством МоментВремени, где при одинаковой дате и времени сортировка выполняется по уникальному идентификатору Ссылка (GUID). Так как GUID генерируется недетерминированно относительно времени создания, невозможно стандартными средствами гарантировать, что один документ на 23:59:59 гарантированно окажется «позже» другого документа с тем же временем.
Чтобы избежать зависимости от случайного порядка ссылок, рассмотрим два правильных подхода к расчету суточных движений:
Регистратор <> &Ссылка). При таком расчете абсолютно неважно, на какую секунду записан документ — он всегда соберет полные данные дня.00:00:00 следующих суток. Это гарантирует, что все операции закрываемого дня хронологически предшествуют корректирующему документу.Для построения отказоустойчивой системы стоит учитывать еще два важных аспекта:
1. Защита от параллельного создания (состояние гонки): Если два пользователя одновременно создают документ за один и тот же день, обычный проверочный запрос в обоих сеансах может вернуть пустой результат, что приведет к появлению дублей. Чтобы исключить параллельную запись, в транзакции перед проверкой устанавливается явная блокировка через объект БлокировкаДанных, либо контроль уникальности выносится на вспомогательный регистр сведений, где измерением является ДатаДня (с типом «Только дата»).
2. Автоматическое формирование: Для исключения человеческого фактора создание и проведение таких итоговых документов выносят в фоновое РегламентноеЗадание. Задание настраивается на ночной запуск (например, в 00:05:00), выбирает документы за прошедшие сутки и программно формирует итоговый документ с гарантированным заполнением данных.