Почему запрос к регистру накопления возвращает данные непроведенного документа и как это отладить

Программист 1С v8.3 (Обычные формы) Налоговый учет
← На главную

В практике разработки на платформе 1С:Предприятие 8, особенно в таких сложных конфигурациях, как УПП (Управление производственным предприятием) или ЗУП (Зарплата и управление персоналом), программисты часто сталкиваются с парадоксальной ситуацией. При отладке кода, например, в модуле расчета НДФЛ, запрос к регистру накопления возвращает записи, хотя документ-регистратор еще не проведен. Однако, если попытаться выполнить тот же самый запрос в обычной консоли запросов, результат оказывается пустым. Рассмотрим подробно, почему так происходит, разберем механизмы работы платформы и выясним, как эффективно отлаживать такие запросы.

Механизм транзакций и «грязное чтение» внутри сеанса

Первое, что нам необходимо понять — это принцип работы транзакций в 1С и используемые уровни изоляции данных. Платформа 1С работает с СУБД (MS SQL Server, PostgreSQL и др.) в режиме Read Committed (чтение зафиксированных данных). Это означает, что данные, которые записываются в базу внутри одной транзакции, не «видны» другим пользователям или сеансам до тех пор, пока транзакция не будет успешно завершена командой ЗафиксироватьТранзакцию (Commit).

Проанализируем ситуацию автора: код выполняется внутри документа «Начисление зарплаты». В процессе расчета система может программно вызывать метод Движения.Записать() для регистра ВзаиморасчетыПоНДФЛ. В этот момент записи физически попадают в таблицу базы данных, но они помечены как принадлежащие открытой транзакции. Поскольку отладчик находится внутри этой же транзакции, запрос видит эти «свежие» данные. Ваша консоль запросов — это отдельный сеанс, для которого эти данные еще не существуют, так как транзакция документа не завершена.

Различие между физическими и виртуальными таблицами

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


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Основной.Сотрудник КАК Сотрудник,
    Основной.НалоговыйПериод КАК НалоговыйПериод
ИЗ
    РегистрНакопления.ВзаиморасчетыПоНДФЛ КАК Основной
ГДЕ
    Основной.Регистратор = &парамРегистратор

Физическая таблица хранит абсолютно все записи, переданные в нее набором записей. Ей «все равно», проведен документ или нет, если в коде была команда записи. Если мы обратимся к виртуальной таблице, например, РегистрНакопления.ВзаиморасчетыПоНДФЛ.Обороты, поведение может быть иным. Платформа 1С по умолчанию фильтрует в виртуальных таблицах записи непроведенных документов, если не указаны специальные параметры. Однако в случае с физической таблицей мы видим всё, что было записано в рамках текущего контекста выполнения.

Программная запись движений до проведения

Разберем, почему в УПП или ЗУП движения появляются раньше, чем документ получает статус «Проведен». Это архитектурная особенность сложных расчетов. Для того чтобы рассчитать налоги или взносы, системе часто нужно «увидеть» результаты предварительных расчетов (например, начисленные суммы), чтобы на их основе сформировать другие записи. Разработчики типовых конфигураций используют следующую схему:

  1. Рассчитываются основные начисления.
  2. Формируется набор записей регистра и вызывается Движения.Записать(). При этом свойство документа Проведен всё еще Ложь.
  3. Запускается следующий этап расчета (например, НДФЛ), который делает запрос к этому же регистру, чтобы получить данные, записанные на шаге 2.
  4. Только после завершения всех этапов и выхода из процедуры ОбработкаПроведения транзакция фиксируется, и данные становятся доступны всем остальным пользователям.

Именно поэтому, остановившись точкой останова на методе Запрос.Выполнить(), вы видите результат, а в консоли — нет. Мы имеем дело с состоянием базы данных в процессе изменений.

Как отлаживать запросы внутри транзакции

Выясним, как же посмотреть эти «невидимые» данные в удобном виде. Стандартная консоль запросов здесь не поможет, если просто скопировать в нее текст. Рассмотрим наиболее эффективные способы решения этой задачи.

Способ 1: Использование XML-сериализации запроса

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

  1. Установите точку останова непосредственно перед строкой Результат = Запрос.Выполнить();.
  2. В окне «Вычислить выражение» (Shift+F9) выполните команду: ОбщегоНазначения.ЗапросВСтрокуXML(Запрос) (если такая функция есть в вашей конфигурации) или воспользуйтесь сериализатором.
  3. Для управляемых форм в современных версиях часто используют «Консоль запросов управляемую». В ней есть кнопка «Запрос из XML».
  4. Этот метод позволяет передать в консоль не только текст запроса, но и значения параметров, а также содержимое временных таблиц, которые были сформированы в коде до этого момента.

Способ 2: Использование специализированных инструментов разработчика

Проанализируем ситуацию, когда данных много и XML-метод неудобен. Существуют профессиональные инструменты (например, «Инструменты разработчика» А. Капралова или специализированные консоли от ИТС). Их преимущество заключается в том, что они могут запускаться «в контексте» текущего серверного вызова.

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

Способ 3: Временные таблицы и Менеджер временных таблиц

Часто в запросах используется конструкция ПОМЕСТИТЬ. Посмотрим на фрагмент кода из вопроса:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Основной.Сотрудник КАК Сотрудник,
    Основной.НалоговыйПериод КАК НалоговыйПериод
ПОМЕСТИТЬ ВТСотрудникиПоНалоговымПериодам
ИЗ
    РегистрНакопления.ВзаиморасчетыПоНДФЛ КАК Основной

Здесь результат сохраняется во временную таблицу. Если у объекта Запрос инициализирован МенеджерВременныхТаблиц, то эти данные будут жить столько, сколько живет сам менеджер в памяти. При отладке вы можете проверить содержимое временной таблицы, даже если физически в регистре ничего еще не зафиксировано. Для этого в отладчике можно временно создать новый запрос, привязать его к текущему менеджеру временных таблиц и выполнить ВЫБРАТЬ * ИЗ ВТСотрудникиПоНалоговымПериодам.

Резюме и рекомендации

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

  1. Не паникуйте, если консоль запросов пуста. Помните об изоляции сеансов.
  2. Проверяйте код на наличие явных вызовов Движения.Записать() или НаборЗаписей.Записать(). В УПП это стандарт для механизмов расчета зарплаты.
  3. Используйте современные инструменты. Перенос запроса в XML или использование консоли, работающей в контексте сеанса, сэкономит вам часы времени.
  4. Помните, что физические таблицы регистров всегда возвращают данные, которые были физически записаны в базу, независимо от логического статуса «Проведен» у документа-регистратора.

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

← На главную