Вытеснение по периоду действия в 1С — это механизм регистра расчёта, который исключает из периода действия одной записи те дни, где действует запись вытесняющего вида расчёта. Классический пример: оклад начисляется за месяц, но командировка с 3 по 5 число его вытесняет, и оклад должен считаться только за оставшиеся рабочие дни. Платформа сама строит фактический период действия — набор интервалов, где запись реально действует, — и отдаёт его через виртуальные таблицы регистра.
Ниже — пример на учебной модели: документ «Начисление зарплаты», регистр расчёта ОсновныеНачисления с поддержкой периода действия и график работы. Покажу, что настроить, как это выглядит в запросах и в каком порядке писать код.
Исходная модель
Для примера используем:
- план видов расчёта
ОсновныеНачисленияс видамиОкладиКомандировка, у плана включено использование периода действия; - регистр расчёта
ОсновныеНачисленияс измерениемСотрудник, ресурсомСумма, реквизитамиГрафикиПараметр(размер оклада); у регистра указан регистр сведений с графиком работы и связь по реквизитуГрафик; - документ
НачислениеЗарплатыс табличной частью: сотрудник, вид расчёта, даты начала и окончания, размер, график.
Для наглядности добавим в регистр два поля:
| Поле | Вид | Зачем |
|---|---|---|
ОтработаноЧасов | Ресурс | Фактически отработанные часы; по ресурсам можно получать базу для других начислений, например премии |
ЧасовПлан | Реквизит | Норма часов месяца — справочная информация |
Реквизиты регистра расчёта не участвуют ни в вытеснении, ни в получении базы. Если значение понадобится как база для другого расчёта, делайте его ресурсом.
Настройка вытеснения в плане видов расчёта
- Откройте план видов расчёта и убедитесь, что включено использование периода действия.
- Добавьте вид расчёта
Командировка. - У вида расчёта
Окладна закладке вытесняющих видов добавьтеКомандировка.
Ограничения, о которых стоит помнить:
- вытесняющий и вытесняемый виды должны принадлежать одному плану видов расчёта и иметь протяжённость во времени — для разовых начислений вытеснение не имеет смысла;
- список вытесняющих видов должен быть полным: если
КомандировкавытесняетОклад, аБольничныйвытесняетКомандировку, тоБольничныйдолжен быть и в списке оклада; - в режиме предприятия список можно только дополнить, но не сократить.
Как платформа строит фактический период действия

Фактический период пересчитывается при каждой записи набора записей регистра. Платформа учитывает:
- пересечение периодов действия записей (в примере — записей одного сотрудника);
- списки вытесняющих видов расчёта;
- период регистрации: записи с более ранним периодом регистрации безусловно приоритетны, поздние их не вытесняют независимо от списков;
- сторно: сторнирующая запись действует, только если в её интервале есть фактически действующая более ранняя запись того же вида.
Полностью вытесненная запись получает пустой фактический период действия — она остаётся в регистре, но в расчётах «по факту» не участвует.
Запросы: ДанныеГрафика и ФактическийПериодДействия
Виртуальная таблица ДанныеГрафика возвращает по каждой записи значения ресурса графика за разные периоды. Для ресурса графика КоличествоЧасов платформа формирует поля КоличествоЧасовПериодДействия (норма за весь период действия) и КоличествоЧасовФактическийПериодДействия (за фактический период после вытеснения).
ВЫБРАТЬ
ДанныеГрафика.НомерСтроки КАК НомерСтроки,
ДанныеГрафика.Параметр КАК Оклад,
ЕСТЬNULL(ДанныеГрафика.КоличествоЧасовПериодДействия, 0) КАК ЧасовПлан,
ЕСТЬNULL(ДанныеГрафика.КоличествоЧасовФактическийПериодДействия, 0) КАК ЧасовФакт
ИЗ
РегистрРасчета.ОсновныеНачисления.ДанныеГрафика(
Регистратор = &Регистратор
И ВидРасчета = &ВидРасчетаОклад) КАК ДанныеГрафикаВиртуальная таблица ФактическийПериодДействия показывает сами интервалы. Удобно смотреть её в консоли запросов при отладке:
ВЫБРАТЬ
ФактическийПериод.Сотрудник КАК Сотрудник,
ФактическийПериод.ВидРасчета КАК ВидРасчета,
ФактическийПериод.ПериодДействияНачало КАК Начало,
ФактическийПериод.ПериодДействияКонец КАК Окончание,
ФактическийПериод.ОтработаноЧасов КАК ОтработаноЧасов
ИЗ
РегистрРасчета.ОсновныеНачисления.ФактическийПериодДействия(
Регистратор = &Регистратор
И ВидРасчета = &ВидРасчетаОклад) КАК ФактическийПериодДо ввода командировки запрос вернёт одну строку по окладу — весь период. После вытеснения строк станет две: до командировки и после неё. Остальные поля таблицы повторяют поля самой записи регистра.
Код: проведение документа и расчёт оклада
Порядок важен: сначала записываем движения, чтобы платформа вычислила фактический период, потом читаем данные графика и считаем суммы, потом записываем ещё раз.
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Движения.ОсновныеНачисления.Записывать = Истина;
Движения.ОсновныеНачисления.Очистить();
ПериодРегистрации = НачалоМесяца(Дата);
Для Каждого СтрокаНачисления Из Начисления Цикл
Движение = Движения.ОсновныеНачисления.Добавить();
Движение.ПериодРегистрации = ПериодРегистрации;
Движение.ВидРасчета = СтрокаНачисления.ВидРасчета;
Движение.Сотрудник = СтрокаНачисления.Сотрудник;
Движение.ПериодДействияНачало = СтрокаНачисления.ДатаНачала;
Движение.ПериодДействияКонец = КонецДня(СтрокаНачисления.ДатаОкончания);
Движение.График = СтрокаНачисления.График;
Движение.Параметр = СтрокаНачисления.Размер;
// Командировка в учебном примере начисляется фиксированной суммой.
Если СтрокаНачисления.ВидРасчета = ПланыВидовРасчета.ОсновныеНачисления.Командировка Тогда
Движение.Сумма = СтрокаНачисления.Размер;
КонецЕсли;
КонецЦикла;
// Первая запись: платформа вычисляет фактический период действия.
Движения.ОсновныеНачисления.Записать();
РасчетЗарплаты.РассчитатьОклад(Ссылка, Движения.ОсновныеНачисления);
КонецПроцедурыРасчёт оклада вынесен в общий модуль РасчетЗарплаты. Вместо поиска по выборке с Сбросить() на каждой итерации я выгружаю результат в таблицу значений и индексирую её по номеру строки — так код проще и не деградирует на больших наборах.
// Рассчитывает оклад пропорционально отработанным часам с учетом вытеснения.
//
// Параметры:
// Регистратор - ДокументСсылка.НачислениеЗарплаты - документ-регистратор.
// НаборЗаписей - РегистрРасчетаНаборЗаписей.ОсновныеНачисления - записанные движения.
//
Процедура РассчитатьОклад(Регистратор, НаборЗаписей) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДанныеГрафика.НомерСтроки КАК НомерСтроки,
| ДанныеГрафика.Параметр КАК Оклад,
| ЕСТЬNULL(ДанныеГрафика.КоличествоЧасовПериодДействия, 0) КАК ЧасовПлан,
| ЕСТЬNULL(ДанныеГрафика.КоличествоЧасовФактическийПериодДействия, 0) КАК ЧасовФакт
|ИЗ
| РегистрРасчета.ОсновныеНачисления.ДанныеГрафика(
| Регистратор = &Регистратор
| И ВидРасчета = &ВидРасчетаОклад) КАК ДанныеГрафика";
Запрос.УстановитьПараметр("Регистратор", Регистратор);
Запрос.УстановитьПараметр("ВидРасчетаОклад", ПланыВидовРасчета.ОсновныеНачисления.Оклад);
ДанныеРасчета = Запрос.Выполнить().Выгрузить();
ДанныеРасчета.Индексы.Добавить("НомерСтроки");
Для Каждого Запись Из НаборЗаписей Цикл
СтрокаДанных = ДанныеРасчета.Найти(Запись.НомерСтроки, "НомерСтроки");
Если СтрокаДанных = Неопределено Тогда
Продолжить; // Запись другого вида расчета.
КонецЕсли;
Если СтрокаДанных.ЧасовПлан = 0 Тогда
Запись.Сумма = 0;
Иначе
Запись.Сумма = Окр(СтрокаДанных.Оклад * СтрокаДанных.ЧасовФакт / СтрокаДанных.ЧасовПлан, 2);
КонецЕсли;
Запись.ЧасовПлан = СтрокаДанных.ЧасовПлан;
Запись.ОтработаноЧасов = СтрокаДанных.ЧасовФакт;
КонецЦикла;
// Повторная запись с замещением сохраняет рассчитанные суммы.
НаборЗаписей.Записать(Истина);
КонецПроцедурыЧто получается в результате
Проверка формулы на цифрах: норма месяца — 184 часа, оклад — 60 000, в документе оклад действует с 1 по 10 число, это 64 рабочих часа по графику. Сумма: 60 000 × 64 / 184 = 20 869,57.
Добавляем командировку с 3 по 5 число и перепроводим документ:
- по командировке начислена фиксированная сумма;
ОтработаноЧасовпо окладу уменьшился с 64 до 56 — вытеснен один рабочий день;- 4 и 5 число по графику выходные, поэтому три календарных дня командировки «съели» только 8 рабочих часов;
ФактическийПериодДействияпо окладу вернёт два интервала: 1–2 и 6–10 число.
Это и есть главный смысл механизма: вы не вычитаете дни вручную, а описываете правила, и платформа сама считает пересечения с учётом графика.
Типичные ошибки
- Расчёт до записи движений. Если читать
ДанныеГрафикадо первой записи набора, фактический период ещё не вычислен, и суммы будут по полному периоду. - Неполный список вытесняющих видов. Цепочки вытеснения должны быть замкнуты, иначе результат будет неожиданным.
- Разные периоды регистрации. Командировка, введённая в следующем месяце, не вытеснит уже начисленный оклад прошлого месяца — нужен сторно и перерасчёт.
- Попытка вытеснять разовые начисления. Премия без протяжённости во времени в механизме не участвует.
- Ожидание вытеснения по реквизитам. Реквизиты регистра — только справочные данные.
В типовой «1С:ЗУП» механизмы расчёта устроены сложнее, но на тех же принципах. Если нужно добавить свой вид начисления или поправить расчёт без потери обновляемости, это задача доработки 1С:ЗУП; собственные расчётные подсистемы проектирую в рамках разработки конфигураций 1С.
Итог
- Вытеснение по периоду действия исключает из периода записи дни, где действует вытесняющий вид расчёта.
- Настраивается списком вытесняющих видов в плане видов расчёта; список должен быть полным.
- Фактический период пересчитывается при каждой записи набора, поэтому сначала пишем движения, потом считаем.
ДанныеГрафикадаёт норму и факт по графику,ФактическийПериодДействия— сами интервалы.- Более ранний период регистрации всегда приоритетен: прошлые периоды исправляют сторнированием.




