Как реализовать единственный документ в конце дня и правильно рассчитать его движения в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В учетных задачах на платформе 1С нередко возникает требование формировать специальный документ строго один раз в сутки — например, для ежедневного закрытия смены, фиксации суточных итогов или корректировки накопившихся остатков. При этом разработчики сталкиваются с двумя вопросами: как гарантировать единственность такого документа за выбранную дату и как обеспечить правильное позиционирование движений, чтобы они рассчитывались с учетом всех операций за день.

Разберем по шагам, как решить эти задачи чисто, надежно и с учетом архитектурных особенностей платформы 1С:Предприятие.

Проверка единственности документа за день

Для предотвращения создания дублирующих документов выполняется проверка на этапе записи или проведения объекта. Проанализируем типичную ошибку при передаче параметров в запрос и рассмотрим правильный вариант кода.

Частая ошибка — передача объекта Граница в параметры запроса при использовании оператора МЕЖДУ. Платформа выдаст синтаксическую ошибку о несовместимости типов, так как Граница предназначена для обращения к виртуальным таблицам регистров, а в обычном запросе к таблице документов используются стандартные значения типа Дата.

Посмотрим на корректный вариант проверки в обработчике ПередЗаписью модуля объекта:


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

Обратим внимание на ключевые детали этой реализации:

  1. Использование функций языка запросов НАЧАЛОПЕРИОДА(&ДатаДня, ДЕНЬ) и КОНЕЦПЕРИОДА(&ДатаДня, ДЕНЬ) позволяет передавать всего один параметр &ДатаДня, исключая человеческие ошибки при передаче нескольких дат.
  2. Условие КорректировкаЗадолженности.Ссылка <> &Ссылка обязательно для того, чтобы документ не находил сам себя при повторном перепроведении или редактировании.

Проблема позиции 23:59:59 и момента времени

Когда разработчики пытаются сделать документ самым последним за день, они обычно устанавливают его время на 23:59:59. Однако если другие документы системы также могут быть записаны на эту же секунду, возникает неопределенность.

В платформе 1С точность хранения времени ограничена одной секундой. Порядок документов в рамках одной секунды определяется внутренним свойством МоментВремени, где при одинаковой дате и времени сортировка выполняется по уникальному идентификатору Ссылка (GUID). Так как GUID генерируется недетерминированно относительно времени создания, невозможно стандартными средствами гарантировать, что один документ на 23:59:59 гарантированно окажется «позже» другого документа с тем же временем.

Чтобы избежать зависимости от случайного порядка ссылок, рассмотрим два правильных подхода к расчету суточных движений:

  1. Расчет итогов за день с исключением самого документа: При проведении корректирующего документа запрос рассчитывает обороты или остатки за весь текущий день, явно исключая движения текущего регистратора (условие Регистратор <> &Ссылка). При таком расчете абсолютно неважно, на какую секунду записан документ — он всегда соберет полные данные дня.
  2. Перенос даты на начало следующего дня: Если документ выполняет строго завершающую роль (например, закрытие периода или начисление итогов), его можно записывать на дату 00:00:00 следующих суток. Это гарантирует, что все операции закрываемого дня хронологически предшествуют корректирующему документу.

Надежность в многопользовательском режиме и автоматизация

Для построения отказоустойчивой системы стоит учитывать еще два важных аспекта:

1. Защита от параллельного создания (состояние гонки): Если два пользователя одновременно создают документ за один и тот же день, обычный проверочный запрос в обоих сеансах может вернуть пустой результат, что приведет к появлению дублей. Чтобы исключить параллельную запись, в транзакции перед проверкой устанавливается явная блокировка через объект БлокировкаДанных, либо контроль уникальности выносится на вспомогательный регистр сведений, где измерением является ДатаДня (с типом «Только дата»).

2. Автоматическое формирование: Для исключения человеческого фактора создание и проведение таких итоговых документов выносят в фоновое РегламентноеЗадание. Задание настраивается на ночной запуск (например, в 00:05:00), выбирает документы за прошедшие сутки и программно формирует итоговый документ с гарантированным заполнением данных.

← На главную