Почему не пересчитывается фактический период действия при отмене проведения документа в 1С 8.3?

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

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

Суть механизма вытеснения и фактического периода

Для начала разберем, как работает этот функционал на уровне платформы. В объекте РегистрРасчета существует два важных понятия: период действия (то, что мы вводим в документ) и фактический период действия (то, что остается после работы механизма вытеснения). Вытеснение настраивается в ПланеВидовРасчета, где мы указываем, какие виды расчета являются вытесняющими для текущего.

Когда мы записываем данные в регистр расчета с установленным признаком ПериодДействия, система анализирует пересечения дат и строит цепочки. Если "Оклад" введен на весь месяц, а "Болничный" на три дня внутри этого месяца, платформа должна автоматически "разрезать" запись оклада в виртуальной таблице на две части: до болезни и после нее.

Анализ проблемы: различие между 1С 8.2 и 8.3

Проанализируем ситуацию, описанную разработчиками. В платформе версии 8.2 механизм работал стабильно: любое изменение в наборе записей (добавление, изменение или удаление) инициировало полный пересчет виртуальных таблиц. В версии 8.3 движок регистров расчета претерпел изменения в сторону оптимизации производительности.

Выясним причину сбоя: платформа 8.3 использует более агрессивное кэширование и оптимизацию запросов к СУБД. При удалении набора записей (что происходит при отмене проведения документа), особенно если документ содержал несколько строк, инициирующих вытеснение, триггер на пересчет ФактическогоПериодаДействия для оставшихся записей других документов может не сработать. Это приводит к тому, что в виртуальной таблице продолжают числиться "дырки" от уже несуществующих записей невыходов.

Пошаговое воспроизведение ситуации

Рассмотрим по шагам, как воспроизводится данная ошибка в "лабораторных" условиях на пустой конфигурации:

  1. Создаем ПланВидовРасчета с включенным использованием периода действия.
  2. Создаем РегистрРасчета, связанный с этим планом, и назначаем ему график.
  3. Добавляем два вида расчета: "Оклад" и "Невыход" (где "Невыход" вытесняет "Оклад").
  4. Проводим документ с "Окладом" на период 01.08.2020 – 31.08.2020.
  5. Проводим документ с двумя строками "Невыхода" (например, с 3-го по 5-е и с 10-го по 12-е число).
  6. Проверяем виртуальную таблицу ФПД — она показывает 5 строк (3 части оклада и 2 невыхода). Это верно.
  7. Отменяем проведение документа с невыходами.
  8. Результат: В виртуальной таблице ФПД остаются те же 3 части оклада, хотя должна была вернуться одна цельная строка на весь месяц.

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

Вариант решения №1: Принудительная перезапись набора записей

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

Разберем пример кода для процедуры ОбработкаУдаленияПроведения:


Процедура ОбработкаУдаленияПроведения(Отказ)
    
    // Получаем набор записей регистра расчета по данному документу
    Набор = РегистрыРасчета.Начисления.СоздатьНаборЗаписей();
    Набор.Отбор.Регистратор.Установить(Ссылка);
    
    // Очищаем записи и записываем набор с явным указанием Замещать = Истина
    Набор.Записать(Истина);
    
    // В некоторых случаях для платформы 8.3 требуется дополнительный толчок.
    // Можно попробовать записать пустой набор по измерениям, если ошибка сохраняется.
    
КонецПроцедуры

Хотя при отмене проведения платформа и так должна очищать записи, явный вызов метода Записать(Истина) часто помогает "протолкнуть" изменения в виртуальные таблицы эффективнее, чем стандартный механизм удаления движком.

Вариант решения №2: Техническая транзакционная запись

Если первый вариант не помогает (что бывает на определенных релизах 8.3.15-8.3.17), проанализируем более радикальный метод. Мы можем создать вспомогательную запись в регистре и тут же ее удалить. Это гарантированно заставит платформу перестроить таблицу ФПД для всех записей, попадающих в период.

Рассмотрим, как это реализовать:


// В обработке удаления проведения после основной очистки
ТехническийНабор = РегистрыРасчета.Начисления.СоздатьНаборЗаписей();
// Устанавливаем отбор по какому-либо другому документу или пустому регистратору (не рекомендуется)
// Лучше использовать текущий регистратор, но создать временную запись
НоваяЗапись = ТехническийНабор.Добавить();
НоваяЗапись.ВидРасчета = ПланыВидовРасчета.Начисления.Оклад;
НоваяЗапись.ПериодРегистрации = ТекущаяДата();
НоваяЗапись.ПериодДействияНачало = НачалоМесяца(Дата);
НоваяЗапись.ПериодДействияКонец = КонецМесяца(Дата);
// Записываем и тут же очищаем
ТехническийНабор.Записать();
ТехническийНабор.Очистить();
ТехническийНабор.Записать();

Важно: Данный метод является "костылем" и должен применяться только в крайнем случае, если бизнес-логика критично зависит от моментальной точности виртуальной таблицы ФПД в рамках той же транзакции.

Рекомендации по настройке платформы

Проанализируем также настройки режима совместимости. Как было замечено в обсуждении, установка режима совместимости с версией 8.2 часто не решает проблему, так как изменения в движке SQL-запросов и механизмах обновления таблиц итогов в 8.3 глубже, чем настройки интерфейсной или программной совместимости.

Однако стоит обратить внимание на следующие моменты:

Резюме

Мы выяснили, что отсутствие пересчета фактического периода в 1С 8.3 — это следствие оптимизации работы с СУБД. Платформа старается минимизировать количество операций по обновлению вспомогательных таблиц. Чтобы обеспечить корректность данных, разработчику следует либо использовать программную перезапись наборов записей, либо проектировать алгоритмы так, чтобы они не зависели от состояния виртуальной таблицы непосредственно в момент отмены проведения документа. Помните, что метод Записать() с параметром Истина является вашим основным инструментом для управления состоянием регистра расчета.

← На главную