В практике разработки на платформе 1С:Предприятие 8, особенно в таких сложных конфигурациях, как УПП (Управление производственным предприятием) или ЗУП (Зарплата и управление персоналом), программисты часто сталкиваются с парадоксальной ситуацией. При отладке кода, например, в модуле расчета НДФЛ, запрос к регистру накопления возвращает записи, хотя документ-регистратор еще не проведен. Однако, если попытаться выполнить тот же самый запрос в обычной консоли запросов, результат оказывается пустым. Рассмотрим подробно, почему так происходит, разберем механизмы работы платформы и выясним, как эффективно отлаживать такие запросы.
Первое, что нам необходимо понять — это принцип работы транзакций в 1С и используемые уровни изоляции данных. Платформа 1С работает с СУБД (MS SQL Server, PostgreSQL и др.) в режиме Read Committed (чтение зафиксированных данных). Это означает, что данные, которые записываются в базу внутри одной транзакции, не «видны» другим пользователям или сеансам до тех пор, пока транзакция не будет успешно завершена командой ЗафиксироватьТранзакцию (Commit).
Проанализируем ситуацию автора: код выполняется внутри документа «Начисление зарплаты». В процессе расчета система может программно вызывать метод Движения.Записать() для регистра ВзаиморасчетыПоНДФЛ. В этот момент записи физически попадают в таблицу базы данных, но они помечены как принадлежащие открытой транзакции. Поскольку отладчик находится внутри этой же транзакции, запрос видит эти «свежие» данные. Ваша консоль запросов — это отдельный сеанс, для которого эти данные еще не существуют, так как транзакция документа не завершена.
Важно различать, к какой именно таблице регистра мы обращаемся. В примере автора используется запрос к основной физической таблице:
ВЫБРАТЬ РАЗЛИЧНЫЕ
Основной.Сотрудник КАК Сотрудник,
Основной.НалоговыйПериод КАК НалоговыйПериод
ИЗ
РегистрНакопления.ВзаиморасчетыПоНДФЛ КАК Основной
ГДЕ
Основной.Регистратор = &парамРегистратор
Физическая таблица хранит абсолютно все записи, переданные в нее набором записей. Ей «все равно», проведен документ или нет, если в коде была команда записи. Если мы обратимся к виртуальной таблице, например, РегистрНакопления.ВзаиморасчетыПоНДФЛ.Обороты, поведение может быть иным. Платформа 1С по умолчанию фильтрует в виртуальных таблицах записи непроведенных документов, если не указаны специальные параметры. Однако в случае с физической таблицей мы видим всё, что было записано в рамках текущего контекста выполнения.
Разберем, почему в УПП или ЗУП движения появляются раньше, чем документ получает статус «Проведен». Это архитектурная особенность сложных расчетов. Для того чтобы рассчитать налоги или взносы, системе часто нужно «увидеть» результаты предварительных расчетов (например, начисленные суммы), чтобы на их основе сформировать другие записи. Разработчики типовых конфигураций используют следующую схему:
Движения.Записать(). При этом свойство документа Проведен всё еще Ложь.ОбработкаПроведения транзакция фиксируется, и данные становятся доступны всем остальным пользователям.Именно поэтому, остановившись точкой останова на методе Запрос.Выполнить(), вы видите результат, а в консоли — нет. Мы имеем дело с состоянием базы данных в процессе изменений.
Выясним, как же посмотреть эти «невидимые» данные в удобном виде. Стандартная консоль запросов здесь не поможет, если просто скопировать в нее текст. Рассмотрим наиболее эффективные способы решения этой задачи.
Если у вас нет под рукой продвинутых инструментов разработчика, можно воспользоваться стандартными средствами отладки. Платформа позволяет выгрузить запрос со всеми его параметрами и временными таблицами в формат XML. Рассмотрим алгоритм действий:
Результат = Запрос.Выполнить();.ОбщегоНазначения.ЗапросВСтрокуXML(Запрос) (если такая функция есть в вашей конфигурации) или воспользуйтесь сериализатором.Проанализируем ситуацию, когда данных много и XML-метод неудобен. Существуют профессиональные инструменты (например, «Инструменты разработчика» А. Капралова или специализированные консоли от ИТС). Их преимущество заключается в том, что они могут запускаться «в контексте» текущего серверного вызова.
Такая консоль при вызове из отладчика не открывает новый сеанс, а использует текущий. Благодаря этому она «видит» все данные внутри открытой транзакции и все менеджеры временных таблиц, созданные в текущем коде. Это самый мощный способ отладки сложных расчетов в УПП.
Часто в запросах используется конструкция ПОМЕСТИТЬ. Посмотрим на фрагмент кода из вопроса:
ВЫБРАТЬ РАЗЛИЧНЫЕ
Основной.Сотрудник КАК Сотрудник,
Основной.НалоговыйПериод КАК НалоговыйПериод
ПОМЕСТИТЬ ВТСотрудникиПоНалоговымПериодам
ИЗ
РегистрНакопления.ВзаиморасчетыПоНДФЛ КАК Основной
Здесь результат сохраняется во временную таблицу. Если у объекта Запрос инициализирован МенеджерВременныхТаблиц, то эти данные будут жить столько, сколько живет сам менеджер в памяти. При отладке вы можете проверить содержимое временной таблицы, даже если физически в регистре ничего еще не зафиксировано. Для этого в отладчике можно временно создать новый запрос, привязать его к текущему менеджеру временных таблиц и выполнить ВЫБРАТЬ * ИЗ ВТСотрудникиПоНалоговымПериодам.
Подведем итог нашему разбору. Если вы видите данные в отладке для непроведенного документа — это не ошибка, а нормальное поведение платформы 1С при работе в транзакции. Для успешной работы и отладки таких механизмов придерживайтесь следующих правил:
Движения.Записать() или НаборЗаписей.Записать(). В УПП это стандарт для механизмов расчета зарплаты.Работа с транзакционными данными — это продвинутый уровень владения платформой 1С. Понимание этих процессов позволяет не только эффективно отлаживать чужой код, но и проектировать собственные высокопроизводительные механизмы расчетов, использующие промежуточное сохранение данных.