В процессе работы с конфигурацией 1С:Зарплата и управление персоналом 3.1 программисты иногда сталкиваются с аномальным поведением регистров расчета. Одной из наиболее трудноуловимых проблем является ситуация, когда при расчете зарплаты за полный месяц вытеснения (например, отпуск или больничный) учитываются корректно, а при начислении за первую половину месяца (аванс) — игнорируются, хотя все документы введены и проведены. Рассмотрим, почему это происходит и как исправить данную ошибку.
Типичный сценарий проблемы выглядит следующим образом: мы проводим документ Отпуск, который должен вытеснить Оклад сотрудника. Когда мы формируем итоговое Начисление зарплаты и взносов, система видит, что сотрудник был в отпуске, и фактический период действия оклада сокращается. Однако при формировании документа Начисление за первую половину месяца программа начисляет оклад полностью, как будто отпуска не существует.
Выясним причину, проведя технический аудит. Если мы обратимся к менеджеру регистра расчета и проанализируем таблицу ФактическийПериодДействия, то увидим странную закономерность:
В ходе тестов было выявлено, что граница "нормального" поведения может плавать (например, ошибка проявляется, если дата окончания записи меньше 19-го числа). Это указывает не на ошибку в коде конфигурации, а на специфический сбой механизма платформы или повреждение внутренних таблиц связей.
Для понимания сути проблемы важно помнить, что в 1С механизм вытеснения опирается на две составляющие:
Когда мы запрашиваем ФактическийПериодДействия, платформа не просто сравнивает даты. Она обращается к этой внутренней таблице, чтобы понять, какие виды расчета имеют приоритет. Если связи в этой таблице нарушены или кэш метаданных устарел, оптимизатор запросов платформы может выдавать неверный результат для интервалов, не охватывающих полный месяц.
Как показывает практика, наиболее эффективным способом решения данной проблемы является "встряхивание" настроек плана видов расчета. Это заставляет платформу полностью пересчитать и перезаписать внутренние физические таблицы связей.
Рассмотрим пошагово, как это сделать:
План видов расчета (например, Основные начисления).Оклад).Отпуск основной).Оклад.Отпуск основной обратно в список вытесняющих начислений и снова нажмем "Записать".Важный момент: такие действия инициируют обновление структуры данных на уровне СУБД, что часто исправляет "залипшие" индексы, которые мешали корректному расчету фактического периода для коротких записей аванса.
Если манипуляции с планом видов расчета не помогли, проанализируем состояние итогов и кэша. Проблема может крыться в несоответствии рассчитанных итогов регистра расчета реальности.
Для исправления выполним следующие действия:
Администрирование — Тестирование и исправление. Установим флажок только на пункте "Пересчет итогов". Это обновит агрегаты и виртуальные таблицы регистров расчета.1C:Enterprise Server и очистить содержимое папок в каталоге snccntxt (для серверов под Windows это обычно C:\Program Files\1cv8\srvinfo\reg_1541\...).Если вы пишете собственный алгоритм расчета аванса и сталкиваетесь с тем, что ФактическийПериодДействия пуст, проверьте, как именно вы записываете данные в регистр. Рассмотрим пример кода, который гарантирует правильное получение фактического периода в рамках транзакции расчета:
// Перед получением фактического периода записи должны быть зафиксированы в базе
НаборЗаписей = РегистрыРасчета.Зарплата.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(ДокументОбъект.Ссылка);
// Заполняем записи по сотруднику для аванса
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.ВидРасчета = ПланыВидовРасчета.Начисления.Оклад;
НоваяЗапись.ПериодДействияНачало = НачалоМесяца(ДатаРасчета);
НоваяЗапись.ПериодДействияКонец = КонецДня(ДатаАванса); // Например, 15-е число
НоваяЗапись.ПериодРегистрации = НачалоМесяца(ДатаРасчета);
// Важно: записываем с флагом Замещать = Истина
НаборЗаписей.Записать(Истина);
// Теперь виртуальная таблица увидит записи и сможет рассчитать вытеснения
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РР.ФактическийПериодДействияНачало,
| РР.ФактическийПериодДействияКонец
|ИЗ
| РегистрРасчета.Зарплата.ФактическийПериодДействия(Регистратор = &Регистратор) КАК РР";
Запрос.УстановитьПараметр("Регистратор", ДокументОбъект.Ссылка);
Посмотрим на этот код внимательнее: если мы просто добавим записи в таблицу регистра, но не вызовем Записать(), виртуальная таблица ФактическийПериодДействия не будет содержать актуальных данных. Платформа рассчитывает пересечения только для физически существующих в базе данных записей (даже если транзакция еще не завершена).
Странное поведение регистра расчета при начислении аванса чаще всего связано с ошибками оптимизации виртуальных таблиц при работе с периодами меньше месяца. Если вы столкнулись с тем, что 15-го числа вытеснение "исчезает", а 30-го "появляется", не спешите переписывать код. В первую очередь попробуйте перезаписать настройки приоритетов в Плане видов расчета и обновить итоги регистра. В 90% случаев это решает проблему, восстанавливая корректную работу механизма вытеснения 1С.