Как управлять порядком записей в регистре накопления внутри одной секунды

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

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

В рамках этой статьи мы разберем, как именно 1С упорядочивает записи внутри одной секунды, почему это происходит и какие существуют методы управления этой последовательностью.

Почему порядок записей внутри секунды кажется произвольным?

Разберем ситуацию, описанную в теме. Когда мы указываем Период движения, мы оперируем типом данных Дата, точность которого ограничена одной секундой. Если два документа имеют одинаковый Период, платформа 1С применяет внутренние правила сортировки, чтобы выстроить их в таблицу. Рассмотрим, как это выглядит на уровне СУБД (SQL):

  1. Период: Первичная сортировка идет по дате и времени.
  2. Тип регистратора (Recorder_TYPE): Это внутренний идентификатор метаданных документа. Если «Сторно» делается документом другого вида, он может всегда оказываться выше основного документа просто потому, что его внутренний ID в конфигурации меньше.
  3. Ссылка регистратора (Recorder_RRef): Если типы документов одинаковы, система сравнивает их уникальные идентификаторы (GUID).

Таким образом, если вы создали новый вид документа для корректировок, его «вес» в системе может быть меньше, чем у основного документа, и он будет всегда вставать перед ним в рамках одной секунды. Это и создает проблему «сторно раньше основного движения».

Решение 1: Использование объекта МоментВремени и Граница

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

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


// Создаем границу, включающую движения конкретного документа
ГраницаКонца = Новый Граница(ДокументСсылка.МоментВремени(), ВидГраницы.Включая);

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Остатки.РесурсОстаток
    |ИЗ
    |   РегистрНакопления.МойРегистр.Остатки(&ГраницаКонца, ) КАК Остатки";

Запрос.УстановитьПараметр("ГраницаКонца", ГраницаКонца);
Результат = Запрос.Выполнить();

Важный нюанс: Использование ВидГраницы.Включая гарантирует, что система учтет движения документа-регистратора, даже если в ту же секунду есть другие записи. Это позволяет «отсечь» лишние движения, которые физически записаны в ту же секунду, но по логике должны следовать позже.

Решение 2: Программное смещение времени

Рассмотрим самый простой с практической точки зрения метод — разнесение документов по времени. Если вы программно формируете документ-сторно, логично установить ему время на секунду позже основного. Однако, как справедливо заметил автор темы, при массовых операциях в 23:59:59 мы можем быстро «упереться» в конец дня.

Для документов, которые должны быть последними в дне, рекомендуется использовать метод УстановитьВремя():


// Установка времени документа в самый конец текущего дня
ДокументОбъект.УстановитьВремя(РежимАвтоВремя.Последним);
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);

Механизм РежимАвтоВремя.Последним заставляет платформу искать самое позднее время среди существующих документов и записывать новый документ после них. В пределах одной секунды это также влияет на логику формирования ссылок в некоторых версиях платформы, но не гарантирует 100% порядка для разных типов документов.

Решение 3: Дополнительный реквизит для точной сортировки

Выясним, как добиться гарантированной хронологии, если стандартных средств недостаточно. Вы можете добавить в регистр накопления дополнительный Реквизит (не измерение!) с типом Число. В этот реквизит при записи движения можно помещать универсальное время в миллисекундах.

Проанализируем пример реализации в модуле набора записей регистра:


Процедура ПередЗаписью(Отказ, Замещение)
    Для Каждого Запись Из ЭтотОбъект Цикл
        // Используем функцию платформы для получения точного времени создания
        Запись.ТочноеВремя = ТекущаяУниверсальнаяДатаВМиллисекундах();
    КонецЦикла;
КонецПроцедуры

Теперь в любом отчете или запросе вы сможете сортировать данные не только по полю Период, но и по полю ТочноеВремя. Это позволит выстроить движения в идеальном порядке их фактического возникновения.

Решение 4: Использование Автоупорядочивания в запросах

Посмотрим на пример запроса, который позволяет корректно получить данные из основной таблицы регистра. Если мы просто выберем записи, они могут прийти в случайном порядке. Чтобы заставить систему использовать внутренние механизмы сортировки 1С (те самые Recorder_TYPE и Recorder_RRef), используйте ключевое слово АВТОУПОРЯДОЧИВАНИЕ.


ВЫБРАТЬ
    МойРегистр.Период,
    МойРегистр.Регистратор,
    МойРегистр.Ресурс
ИЗ
    РегистрНакопления.МойРегистр КАК МойРегистр
ГДЕ
    МойРегистр.Период = &НужнаяДата
УПОРЯДОЧИТЬ ПО
    Период
АВТОУПОРЯДОЧИВАНИЕ

Важно понимать: АВТОУПОРЯДОЧИВАНИЕ в конце запроса добавляет к сортировке поля, которые гарантируют стабильный порядок (включая ссылку регистратора и номер строки). Это не изменит тот факт, что сторно может быть раньше основного документа (если так решит платформа на основе типов метаданных), но это сделает выдачу данных предсказуемой.

Подведем итоги

Разберем основные выводы нашего анализа:

  1. В пределах одной секунды порядок записей разных видов документов в 1С жестко не регламентирован логикой бизнеса, а зависит от внутренних ID метаданных и GUID.
  2. Для получения корректных остатков на момент документа всегда используйте МоментВремени и объект Граница.
  3. Если вам критически важна последовательность, старайтесь выполнять сторнирование тем же видом документа, что и исходная операция (например, через сторно-записи в «Корректировке записей регистров»).
  4. Для сложных систем идеальным решением будет внедрение реквизита ТочноеВремя с фиксацией значения через ТекущаяУниверсальнаяДатаВМиллисекундах().

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

← На главную