Базовый период в регистре расчёта 1С — это интервал, за который платформа собирает «базу» для расчёта начисления: например, сумму оклада за два предыдущих месяца, от которой считается премия. Включается флагом «Базовый период» у регистра расчёта, а сама база читается из виртуальной таблицы База<ИмяБазовогоРегистра>. Перерасчёт — подчинённый регистру объект, куда платформа автоматически записывает начисления, которые нужно пересчитать, если ведущие начисления изменились задним числом.

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

Исходные данные примера

Предполагаем, что в конфигурации уже есть:

  • план видов расчёта ОсновныеНачисления с видом Оклад (использует период действия);
  • регистр расчёта ОсновныеНачисления с измерением Сотрудник, ресурсом Сумма, графиком работы;
  • документ НачислениеЗарплаты с реквизитом ПериодРегистрации, который пишет оклад в этот регистр.

Задача: добавить премию, которая начисляется раз в месяц и равна проценту от оклада за указанный период (например, за два предыдущих месяца).

Шаг 1. План видов расчёта для разовых начислений

Премия не протяжённа во времени, поэтому хранить её в плане с периодом действия не стоит. Создаём план видов расчёта ДополнительныеНачисления. На вкладке «Расчёт»:

СвойствоЗначениеПочему
Использует период действияНетПремия — разовое начисление
Зависимость от базыЗависит по периоду действияБаза берётся за месяцы, к которым относится оклад
Базовые планы видов расчётаОсновныеНачисления, ДополнительныеНачисленияВ базу попадают оклад и прошлые премии

Про «Зависимость от базы» стоит понимать разницу. По периоду действия — база собирается по фактическому периоду действия базовых записей: если оклад за февраль доначислили в апреле, он всё равно относится к февралю. По периоду регистрации — база собирается по полю ПериодРегистрации: доначисление за февраль, зарегистрированное в апреле, попадёт в апрельскую базу.

Создаём предопределённый вид расчёта Премия и заполняем две вкладки:

  • Базовые — Оклад и Премия: от них считается база. Базовыми могут быть и протяжённые, и непротяжённые виды расчёта.
  • Ведущие — Оклад и Премия: при их изменении текущая премия становится неактуальной и должна попасть в перерасчёт.

Шаг 2. Регистр расчёта с базовым периодом

Создаём регистр расчёта ДополнительныеНачисления:

  • план видов расчёта — ДополнительныеНачисления;
  • периодичность — месяц;
  • флаг «Базовый период» — включён; у регистра появляются поля БазовыйПериодНачало и БазовыйПериодКонец;
  • регистратор — документ НачислениеЗарплаты;
  • измерение Сотрудник, ресурс Сумма, реквизит Параметр (процент премии).
Базовый период регистра расчёта 1С: база за два месяца превращается в премию третьего
Базовый период регистра расчёта 1С: база за два месяца превращается в премию третьего

Шаг 3. Движения документа

В документ добавляем табличную часть ДополнительныеНачисления с колонками Сотрудник, ВидРасчета (тип ПланВидовРасчетаСсылка.ДополнительныеНачисления), БазовыйПериодНачало, БазовыйПериодКонец, ПроцентПремии. В обработке проведения формируем движения без суммы — сумму посчитаем следующим шагом:

1С
Процедура ОбработкаПроведения(Отказ, РежимПроведения)

	// ... движения по регистру ОсновныеНачисления формируются выше.

	Движения.ДополнительныеНачисления.Записывать = Истина;

	Для Каждого СтрокаНачисления Из ДополнительныеНачисления Цикл
		Движение = Движения.ДополнительныеНачисления.Добавить();
		Движение.Сторно = Ложь;
		Движение.ПериодРегистрации = ПериодРегистрации;
		Движение.ВидРасчета = СтрокаНачисления.ВидРасчета;
		Движение.Сотрудник = СтрокаНачисления.Сотрудник;
		Движение.БазовыйПериодНачало = НачалоДня(СтрокаНачисления.БазовыйПериодНачало);
		Движение.БазовыйПериодКонец = КонецДня(СтрокаНачисления.БазовыйПериодКонец);
		Движение.Параметр = СтрокаНачисления.ПроцентПремии;
	КонецЦикла;

	Движения.Записать();

	РасчетЗарплаты.РассчитатьОклад(Ссылка, Движения.ОсновныеНачисления);
	РасчетЗарплаты.РассчитатьПремию(Ссылка, Движения.ДополнительныеНачисления);

КонецПроцедуры

Два момента. КонецДня у конца базового периода обязателен: без него последний день периода не войдёт в базу. И порядок расчёта важен — сначала оклад, потом премия, иначе база окажется пустой.

Шаг 4. Расчёт премии через виртуальную таблицу базы

Поскольку для плана ДополнительныеНачисления базовым указан ОсновныеНачисления, у регистра появляется виртуальная таблица БазаОсновныеНачисления. Её параметры:

  1. Измерения основного регистра — массив имён измерений текущего регистра;
  2. Измерения базового регистра — массив соответствующих измерений базового регистра;
  3. Разрезы — дополнительные разрезы базы (здесь не нужны);
  4. Условие — отбор записей основного регистра.

Измерения сопоставляются по порядку элементов массивов: в нашем случае Сотрудник текущего регистра соответствует Сотрудник базового.

1С
// Рассчитывает премию процентом от базы за базовый период.
Процедура РассчитатьПремию(Регистратор, НаборЗаписей) Экспорт

	ИзмеренияОсновного = Новый Массив;
	ИзмеренияОсновного.Добавить("Сотрудник");
	ИзмеренияБазового = Новый Массив;
	ИзмеренияБазового.Добавить("Сотрудник");

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	База.НомерСтроки КАК НомерСтроки,
	|	ЕСТЬNULL(База.СуммаБаза, 0) КАК СуммаБаза
	|ИЗ
	|	РегистрРасчета.ДополнительныеНачисления.БазаОсновныеНачисления(
	|			&ИзмеренияОсновного,
	|			&ИзмеренияБазового,
	|			,
	|			Регистратор = &Регистратор
	|				И ВидРасчета = &Премия) КАК База";

	Запрос.УстановитьПараметр("ИзмеренияОсновного", ИзмеренияОсновного);
	Запрос.УстановитьПараметр("ИзмеренияБазового", ИзмеренияБазового);
	Запрос.УстановитьПараметр("Регистратор", Регистратор);
	Запрос.УстановитьПараметр("Премия", ПланыВидовРасчета.ДополнительныеНачисления.Премия);

	БазаПоСтрокам = Новый Соответствие;
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		БазаПоСтрокам.Вставить(Выборка.НомерСтроки, Выборка.СуммаБаза);
	КонецЦикла;

	Для Каждого Запись Из НаборЗаписей Цикл
		Если Запись.ВидРасчета <> ПланыВидовРасчета.ДополнительныеНачисления.Премия Тогда
			Продолжить;
		КонецЕсли;
		СуммаБазы = БазаПоСтрокам.Получить(Запись.НомерСтроки);
		Запись.Сумма = ?(СуммаБазы = Неопределено, 0, Окр(СуммаБазы * Запись.Параметр / 100, 2));
	КонецЦикла;

	// Набор уже сформирован, нужно только записать рассчитанные суммы.
	НаборЗаписей.Записать(Истина, Истина);

КонецПроцедуры

Поле СуммаБаза — это ресурс Сумма базового регистра с суффиксом «База». Вместо поиска по выборке в цикле (НайтиСледующий + Сбросить на каждой записи) я складываю результат в соответствие по номеру строки: при сотнях сотрудников разница по времени заметна.

Проверка на числах: если по сотруднику за январь и февраль начислено 120 000 ₽ оклада, а процент премии 10, премия за март составит 12 000 ₽.

Шаг 5. Перерасчёт: как поймать изменения задним числом

Предположим, оклад за февраль исправили с 60 000 на 80 000 ₽. Мартовская премия теперь посчитана от неверной базы. Чтобы это не прошло незамеченным, у регистра ДополнительныеНачисления создаём перерасчёт ПерерасчетПремии:

  1. В ветке регистра «Перерасчёты» добавляем перерасчёт.
  2. Добавляем измерение перерасчёта Сотрудник.
  3. Связываем его с измерением Сотрудник самого регистра и с измерениями ведущих регистров.

Связь измерений определяет точность: при изменении оклада Иванова в перерасчёт попадёт премия Иванова, а не премии всех сотрудников.

Перерасчёт в регистре расчёта 1С: изменение оклада задним числом отмечает премию к пересчёту
Перерасчёт в регистре расчёта 1С: изменение оклада задним числом отмечает премию к пересчёту

Что попало в перерасчёт, видно запросом:

Запрос 1С
ВЫБРАТЬ
	Перерасчет.ОбъектПерерасчета КАК Документ,
	Перерасчет.ВидРасчета КАК ВидРасчета,
	Перерасчет.Сотрудник КАК Сотрудник
ИЗ
	РегистрРасчета.ДополнительныеНачисления.ПерерасчетПремии КАК Перерасчет

До изменения оклада таблица пуста. После перепроведения февральского документа с новым окладом в ней появляется мартовский документ с видом расчёта Премия по Иванову.

Важно: платформа только отмечает, но не пересчитывает

Записи перерасчёта — это список дел, а не исправление. Дальше прикладной код должен:

  • пересчитать отмеченные начисления — в ЗУП это делают специальными документами, в простых конфигурациях часто перепроведением исходного документа или отдельным документом доначисления;
  • очистить записи перерасчёта по обработанным документам.

Очистка выполняется набором записей перерасчёта:

1С
НаборПерерасчета = РегистрыРасчета.ДополнительныеНачисления.Перерасчеты.ПерерасчетПремии.СоздатьНаборЗаписей();
НаборПерерасчета.Отбор.ОбъектПерерасчета.Установить(ДокументПремии);
НаборПерерасчета.Записать(); // пустой набор с отбором удаляет записи

Как проверить настройку на тестовых данных

Прежде чем отдавать механизм расчётчикам, я прогоняю короткий сценарий:

  1. Провести начисление оклада за два месяца по одному сотруднику.
  2. Провести премию за третий месяц и сверить сумму с ручным расчётом.
  3. Изменить оклад за один из прошлых месяцев и перепровести документ.
  4. Убедиться, что в таблице перерасчёта появилась премия именно этого сотрудника и никого лишнего.
  5. Пересчитать премию и проверить, что запись перерасчёта очистилась.

Пять шагов занимают полчаса, а ловят почти все ошибки настройки: неверные базовые виды, несвязанные измерения перерасчёта и забытый конец дня в базовом периоде.

Типичные ошибки

  • Не задан конец дня у БазовыйПериодКонец — последний день не входит в базу.
  • Перепутаны базовые и ведущие — база считается верно, но изменения задним числом не ловятся, или наоборот.
  • Измерения перерасчёта не связаны с измерениями ведущих регистров — в перерасчёт попадает всё подряд или ничего.
  • Записи перерасчёта не очищаются — таблица разрастается, и пользователи перестают ей доверять.
  • Неверный порядок расчёта — премия считается раньше оклада и получает нулевую базу.

В типовой ЗУП этот механизм уже реализован, и вмешиваться в него стоит аккуратно, через доработку ЗУП с расширением, а не правкой типовых модулей. В собственных конфигурациях его удобно закладывать сразу при разработке конфигурации.

Итог

  • Флаг «Базовый период» добавляет регистру поля БазовыйПериодНачало и БазовыйПериодКонец, а база читается из виртуальной таблицы База<Регистр>.
  • «Зависимость от базы» задаёт, по какому периоду собирать базу: по периоду действия или регистрации.
  • Базовые виды расчёта отвечают за то, от чего считать, ведущие — за то, когда пересчитывать.
  • Перерасчёт только отмечает устаревшие начисления; пересчитывает и очищает их прикладной код.