Почему документы с одинаковым временем не видят движения друг друга при расчете остатков в 1С

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

При разработке механизмов проведения документов (например, взаимозачетов, списания партий или оплат аренды) разработчики нередко сталкиваются с ситуацией, когда два документа проведены на одну и ту же секунду (например, в 23:59:59), но один из них при запросе остатков не видит движения другого. Разберем по шагам, как устроена хронологическая шкала в платформе 1С:Предприятие, почему происходят подобные коллизии и как правильно использовать объекты МоментВремени и Граница.

Как платформа 1С упорядочивает документы во времени

Рассмотрим, как 1С определяет положение документов на временной оси. Точка на оси времени для любого документа состоит не только из даты и времени, но и из уникальной ссылки на сам документ.

  1. Разнесение по времени: если документы имеют разные даты или время хотя бы с разницей в одну секунду, их взаимное расположение очевидно: более поздний документ всегда видит движения более раннего.
  2. Одинаковое время (вплоть до секунды): если два документа записаны на одну секунду, платформа упорядочивает их по внутреннему уникальному идентификатору ссылки (GUID). Документ с меньшим бинарным представлением ссылки считается находящимся раньше, а с большим — позже. Этот порядок строго детерминирован, но случаен относительно бизнес-логики.
  3. Тип переданного параметра: поведение виртуальной таблицы регистра накопления напрямую зависит от того, что именно передано в качестве параметра периода — Дата, МоментВремени или Граница.

Разница между типами Дата, МоментВремени и Граница в запросах к остаткам

Проанализируем поведение виртуальной таблицы РегистрНакопления.ИмяРегистра.Остатки(&Период, ...) при различных типах значения в параметре &Период:

  1. Передана Дата: остатки рассчитываются строго на самое начало указанной секунды. Все движения, сделанные внутри этой же секунды (даже другими документами), в выборку не попадут.
  2. Передан МоментВремени: остатки рассчитываются на точку времени непосредственно перед движениями указанного документа. Движения документов, расположенных в той же секунде, но имеющих меньший GUID, будут учтены; движения документов с большим GUID учтены не будут.
  3. Передана Граница (ВидГраницы.Включая): остатки рассчитываются с учетом движений на указанную дату или движений конкретного документа.
  4. Передана Граница (ВидГраницы.Исключая): остатки рассчитываются без учета движений граничного момента или секунды.

Причина ошибки: создание МоментаВремени без регистратора

Посмотрим на типичную ошибку при формировании параметров запроса. Если конструктор вызывается следующим образом:


СтруктураПараметров.ГраницаОстатков = Новый МоментВремени(СтруктураПараметров.Период, СтруктураПараметров.Регистратор);

Если в переменную СтруктураПараметров.Регистратор попадает Неопределено, пустая ссылка или ссылка на еще не записанный в базу документ, платформа не может привязать момент времени к конкретной ссылке. В результате такой МоментВремени работает как обычная Дата.

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

Способы решения проблемы

Разберем основные методы решения данной задачи в кодовой базе.

Способ 1. Корректное получение МоментаВремени от объекта

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


// В обработке проведения ссылка уже доступна:
Запрос.УстановитьПараметр("Период", ЭтотОбъект.МоментВремени());

Если используется ссылка на документ:

Запрос.УстановитьПараметр("Период", СсылкаНаДокумент.МоментВремени());

Способ 2. Использование объекта Граница для включения движений

Если нам требуется получить остатки с включением всех движений на конец суток или с включением движений самого документа, используем объект Граница:


// Получение остатков на конец дня со всеми проведенными движениями:
ГраницаКонцаДня = Новый Граница(КонецДня(ДатаДокумента), ВидГраницы.Включая);
Запрос.УстановитьПараметр("Период", ГраницаКонцаДня);

// Получение остатков включая движения конкретного документа:
ГраницаДокумента = Новый Граница(СсылкаНаДокумент.МоментВремени(), ВидГраницы.Включая);
Запрос.УстановитьПараметр("Период", ГраницаДокумента);

Способ 3. Управление хронологией документов

Когда один документ логически зависит от другого в рамках одного дня, полагаться только на автоматическое распределение по GUID не следует. Рекомендуется применять следующие подходы:

  1. Разнесение по времени: устанавливать время зависимого документа хотя бы на 1 секунду позже основного (например, начисление в 23:59:58, а зачет/оплата в 23:59:59).
  2. Оперативное проведение: при оперативном проведении платформа автоматически назначает текущее время с миллисекундами, что гарантирует правильный порядок следования операций.
  3. Использование последовательностей: включение документов в последовательность гарантирует корректный хронологический пересчет итогов при перепроведении задним числом.
← На главную