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

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При разработке и поддержке конфигураций на платформе 1С:Предприятие 7.7 программисты часто сталкиваются со специфическим поведением регистров накопления. Одна из классических проблем — попытка получить остатки по регистрам на конец дня (или на любой момент времени «после» текущего документа) внутри модуля проведения при групповом перепроведении документов или восстановлении последовательностей.

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

Анализ проблемы: почему стандартный код не работает при групповом проведении?

Рассмотрим типичный фрагмент кода, который разработчики используют в модуле проведения документа для получения остатков на конец дня:


ВремРегистры.Актуальность(1);
ГраницаРасчета = ДатаДок;
Если ПолучитьДатуТА() <= ДатаДок Тогда
    ГраницаРасчета = ПолучитьПозициюТА();
КонецЕсли;
ВремРегистры.РассчитатьРегистрыПо(ГраницаРасчета);

Давайте разберем по шагам, что происходит при выполнении этого алгоритма в различных режимах проведения:

  1. Обычное (одиночное) проведение пользователем: Точка актуальности (ТА) базы данных находится на самом последнем проведенном документе (например, в конце сегодняшнего дня или даже в будущем периоде). В этом случае функция ПолучитьДатуТА() возвращает дату, которая больше или равна дате проводимого документа (ДатаДок). Условие ПолучитьДатуТА() <= ДатаДок возвращает Ложь. Переменная ГраницаРасчета остается равной ДатаДок (что интерпретируется платформой как конец дня 23:59:59). Временные регистры успешно рассчитываются на конец дня, и документ видит все движения до конца суток.
  2. Групповое перепроведение или восстановление последовательности: При проведении документов «задним числом» платформа последовательно двигает точку актуальности по каждому документу. В момент проведения конкретного документа ТА временно устанавливается прямо на этот документ. Здесь поведение программы меняется кардинально:
    • Функция ПолучитьДатуТА() теперь возвращает дату текущего проводимого документа, так как ТА временно находится на нем.
    • Условие ПолучитьДатуТА() <= ДатаДок превращается в равенство (например, 15.10.2023 <= 15.10.2023), которое возвращает Истина.
    • Программа выполняет ветку условия и присваивает переменной ГраницаРасчета значение ПолучитьПозициюТА() (то есть позицию текущего документа со временем его проведения).
    • Метод РассчитатьРегистрыПо рассчитывает итоги на момент проведения документа, а не на конец дня. Все документы, проведенные в этот же день позже по времени, в расчет не попадают.

Техническое ограничение платформы 1С 7.7

Почему нельзя просто убрать условие проверки ТА и всегда рассчитывать на ДатаДок (конец дня)?

Дело в жестком ограничении ядра платформы 1С 7.7: запрещено рассчитывать временные регистры на момент времени, находящийся строго после Точки Актуальности. Если в процессе группового перепроведения (когда ТА стоит на текущем документе в 12:00) вы попытаетесь выполнить метод РассчитатьРегистрыПо(ДатаДок) (что означает расчет на конец дня — 23:59:59), платформа аварийно завершит работу системы с критической ошибкой базы данных.

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

Решение 1. Изменение архитектуры проведения (Рекомендуемый подход)

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

Попытка заглянуть в конец дня нарушает базовые принципы последовательности учета:

Как сделать правильно:

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

Решение 2. Использование прямых SQL-запросов (компонента 1С++)

Если бизнес-требования невозможно изменить, и вам обязательно нужно знать остатки на конец дня в процессе группового проведения, стандартные механизмы 1С 7.7 не помогут. В этом случае на помощь приходит использование прямых SQL-запросов к базе данных (при работе 1С 7.7 в SQL-режиме) с помощью внешней компоненты 1С++.

Прямой запрос обращается непосредственно к таблицам итогов (RG*) и движений (RA*) СУБД, полностью игнорируя виртуальные ограничения платформы 1С 7.7 на работу с ТА.

Рассмотрим пример логики построения такого запроса:


// Пример концепта прямого запроса через 1С++ для получения остатков на конец дня
// Запрос суммирует остатки на начало месяца и движения по указанную дату включительно
ТекстЗапроса = "
|SELECT 
|    Рег.Товар [Товар $Справочник.Товары],
|    SUM(Рег.Остаток) ТоварОстаток
|FROM 
|    (
|        // Получаем остатки на начало месяца
|        SELECT Товар, Остаток FROM $РегистрИтоги.ОстаткиТоваров WHERE Период = :НачалоМесяца
|        UNION ALL
|        // Прибавляем движения с начала месяца по конец дня проводимого документа
|        SELECT Товар, Расход * -1 + Приход FROM $Регистр.ОстаткиТоваров WHERE ДатаДок BETWEEN :НачалоМесяца AND :КонецДняДокумента
|    ) Рег
|GROUP BY 
|    Рег.Товар
|";

Преимущества данного подхода:

Решение 3. Предварительный кэш (Двухпроходный алгоритм)

Если использование внешних компонент нежелательно (например, база работает в файловом DBF-формате), можно применить двухпроходный алгоритм группового проведения через специальную обработку:

  1. Перед запуском транзакции группового проведения обработка делает один общий стандартный запрос по регистрам (используя объект Запрос) и собирает все остатки на концы нужных дней за весь период перепроведения.
  2. Эти данные сохраняются во временную таблицу значений или индексированную таблицу (в памяти).
  3. В модуле проведения документов добавляется проверка: если документ проводится в специальном режиме группового проведения, он не пытается рассчитывать временные регистры самостоятельно. Вместо этого он обращается к глобальной таблице-кэшу и считывает уже готовое значение остатка на конец своего дня.

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

← На главную