Учебный курс: Подготовка на 1С:Специалист по платформе 1С:Предприятие 8.3

Задачи по расчетным механизмам – тема № 10:
Как рассчитать зарплату при изменении оклада в рамках одного месяца

В некоторых задачах различные параметры начислений не являются постоянными величинами в течение месяца, а могут изменяться один или даже несколько раз. Например, в течение месяца может несколько раз измениться значение оклада, процента премии или любых других параметров для расчета начислений или удержаний.

В данном примере рассмотрим задачу по изменению оклада, но ее решение можно легко адаптировать для других задач, где изменяются параметры для других видов расчета. Приведенное здесь решение может использоваться в задачах 3.8, 3.9, 3.14, а также других.

Задача

«Сотрудники предприятия получают оплату по окладу пропорционально отработанному времени в днях. В течение расчетного периода тарифная ставка для расчета оклада может быть неоднократно изменена. Расчет оклада должен производиться исходя из действующей на рассчитываемую дату тарифной ставки. Например, если тарифная ставка изменилась 15 сентября, то до 15 сентября при расчете берется старое значение, а начиная с 15 сентября – новое.»

Решение

Для хранения истории изменения оклада будем использовать имеющийся в системе периодический регистр сведений (периодичность День) СведенияОСотрудниках. Первое измерение регистра Сотрудник (Справочник ФизическиеЛица), необходимое для хранения истории изменения оклада в разрезе сотрудников, оставим без изменений.

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

Измерение ВидРасчета регистра СведенияОСотрудниках

Рисунок 1 – Измерение ВидРасчета регистра СведенияОСотрудниках

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

В завершение переименуем ресурс Оклад в Размер для хранения числового показателя в разрезе сотрудника и вида расчета.

Такая структура регистра является универсальной, т.к. позволяет хранить историю изменения показателя для любых видов расчета (начислений или удержаний) и поэтому может использоваться также в других похожих задачах.

По аналогии с предыдущими главами приступим к настройкам документа НачислениеЗарплаты, а также плану видов расчетов ОсновныеНачисления и одноименного регистра расчетов. Подробно останавливаться не будем, а только кратко обозначим основные моменты.

Включим использование периода действия у плана видов расчета ОсновныеНачисления.

План видов расчета ОсновныеНачисления

Рисунок 2 – План видов расчета ОсновныеНачисления

Создадим регистр расчета ОсновныеНачисления, укажем в нем одноименный планов видов расчета и свяжем с регистром ГрафикиРаботы.

Закладка Основные регистра расчета ОсновныеНачисления

Рисунок 3 – Закладка Основные регистра расчета ОсновныеНачисления

Перейдем на закладку Данные и добавим:

  • измерение Сотрудник (Справочник ФизическиеЛица)
  • ресурс Результат (Число 10, 2)
  • реквизит Размер (Число 10, 2).

Закладка Данные регистра расчета ОсновныеНачисления

Рисунок 4 – Закладка Данные регистра расчета ОсновныеНачисления

В документ НачислениеЗарплаты добавим реквизит ПериодРегистрации (Дата).

Закладка Данные Документа НачислениеЗарплаты

Рисунок 5 – Закладка Данные Документа НачислениеЗарплаты

На закладке Движения укажем, что документ является регистратором для регистра ОсновныеНачисления и что документу не требуется оперативное проведение.

Закладка Движения Документа НачислениеЗарплаты

Рисунок 6 – Закладка Движения Документа НачислениеЗарплаты

В обработке проведения документа «Начисление зарплаты» напишем код, который будет учитывать изменение показателей в течение месяца и для каждой строки табличной части документа создавать нужное количество записей регистра расчета:

Процедура ОбработкаПроведения(Отказ, РежимПроведения)
	
		// 1. Установка маркера Записи у регистра
		Движения.ОсновныеНачисления.Записывать = Истина;
		
		Запрос = Новый Запрос;
		Запрос.Текст =
		// 2. Получение данных из документа
		"ВЫБРАТЬ
		|    ОсновныеНачисления.Ссылка.ПериодРегистрации КАК ПериодРегистрации,
		|    ОсновныеНачисления.НомерСтроки КАК НомерСтроки,
		|    ОсновныеНачисления.Сотрудник КАК Сотрудник,
		|    ОсновныеНачисления.ВидРасчета КАК ВидРасчета,
		|    ОсновныеНачисления.ДатаНачала КАК НачалоПериода,
		|    КонецПериода(ОсновныеНачисления.ДатаОкончания, ДЕНЬ) КАК КонецПериода
		|ПОМЕСТИТЬ ВТДокумент
		|ИЗ
		|    Документ.НачислениеЗарплаты.ОсновныеНачисления КАК ОсновныеНачисления
		|ГДЕ
		|    ОсновныеНачисления.Ссылка = &Ссылка
		|
		|ИНДЕКСИРОВАТЬ ПО
		|    Сотрудник,
		|    ВидРасчета,
		|    КонецПериода
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		// 3. Получение плановых начислений
		|ВЫБРАТЬ
		|    ВТДокумент.ПериодРегистрации,
		|    ВТДокумент.НомерСтроки КАК НомерСтроки,
		|    ВТДокумент.Сотрудник КАК Сотрудник,
		|    ВТДокумент.ВидРасчета КАК ВидРасчета,
		|    ЕСТЬNULL(ПлановыеНачисления.Период, ВТДокумент.НачалоПериода) КАК Период,
		|    ЕСТЬNULL(ПлановыеНачисления.Размер, 0) КАК Размер,
		|    ВТДокумент.НачалоПериода,
		|    ВТДокумент.КонецПериода
		|ПОМЕСТИТЬ ВТПлановыеНачисления
		|ИЗ
		|    ВТДокумент КАК ВТДокумент
		|        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СведенияОСотрудниках КАК ПлановыеНачисления
		|        ПО ВТДокумент.Сотрудник = ПлановыеНачисления.Сотрудник
		|            И ВТДокумент.ВидРасчета = ПлановыеНачисления.ВидРасчета
		|            И ВТДокумент.КонецПериода >= ПлановыеНачисления.Период
		|
		|ИНДЕКСИРОВАТЬ ПО
		|    Сотрудник,
		|    ВидРасчета,
		|    Период
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		// 4. Получение последней записи по плановым начислениям на начало периода
		|ВЫБРАТЬ
		|    ВТПлановыеНачисления.Сотрудник КАК Сотрудник,
		|    ВТПлановыеНачисления.ВидРасчета КАК ВидРасчета,
		|    МАКСИМУМ(ВТПлановыеНачисления.Период) КАК Период
		|ПОМЕСТИТЬ ВТПериоды
		|ИЗ
		|    ВТПлановыеНачисления КАК ВТПлановыеНачисления
		|ГДЕ
		|    ВТПлановыеНачисления.Период <= ВТПлановыеНачисления.НачалоПериода
		|
		|СГРУППИРОВАТЬ ПО
		|    ВТПлановыеНачисления.Сотрудник,
		|    ВТПлановыеНачисления.ВидРасчета
		|
		|ИНДЕКСИРОВАТЬ ПО
		|    Период,
		|    Сотрудник,
		|    ВидРасчета
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		// 5. Получение плановых начислений на начало периода
		|ВЫБРАТЬ
		|    ВТПлановыеНачисления.ПериодРегистрации,
		|    ВТПлановыеНачисления.НомерСтроки КАК НомерСтроки,
		|    ВТПлановыеНачисления.Сотрудник,
		|    ВТПлановыеНачисления.ВидРасчета,
		|    ВТПлановыеНачисления.НачалоПериода КАК Период,
		|    ВТПлановыеНачисления.Размер,
		|    ВТПлановыеНачисления.НачалоПериода КАК НачалоПериода,
		|    ВТПлановыеНачисления.КонецПериода КАК КонецПериода
		|ИЗ
		|    ВТПлановыеНачисления КАК ВТПлановыеНачисления
		|        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТПериоды КАК ВТПериоды
		|        ПО ВТПлановыеНачисления.Сотрудник = ВТПериоды.Сотрудник
		|            И ВТПлановыеНачисления.ВидРасчета = ВТПериоды.ВидРасчета
		|            И ВТПлановыеНачисления.Период = ВТПериоды.Период
		|
		|ОБЪЕДИНИТЬ ВСЕ
		|
		// 6. Получение плановых начислений, которые изменялись в текущем месяце
		|ВЫБРАТЬ
		|    ВТПлановыеНачисления.ПериодРегистрации,
		|    ВТПлановыеНачисления.НомерСтроки,
		|    ВТПлановыеНачисления.Сотрудник,
		|    ВТПлановыеНачисления.ВидРасчета,
		|    ВТПлановыеНачисления.Период,
		|    ВТПлановыеНачисления.Размер,
		|    ВТПлановыеНачисления.НачалоПериода,
		|    ВТПлановыеНачисления.КонецПериода
		|ИЗ
		|    ВТПлановыеНачисления КАК ВТПлановыеНачисления
		|ГДЕ
		|    ВТПлановыеНачисления.Период > ВТПлановыеНачисления.НачалоПериода
		|
		|УПОРЯДОЧИТЬ ПО
		|    НомерСтроки,
		|    Период
		// 7. Группировка данных
		|ИТОГИ
		|    МИНИМУМ(НачалоПериода),
		|    МАКСИМУМ(КонецПериода)
		|ПО
		|    НомерСтроки";

	Запрос.УстановитьПараметр("Ссылка", Ссылка);
	
	// 8. Формирование выборки для движений
	ВыборкаИтоги = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
	
	Пока ВыборкаИтоги.Следующий() Цикл
		
		ПредыдущаяЗапись = Неопределено;
		ПериодДействияНачало = ВыборкаИтоги.НачалоПериода;
		ПериодДействияКонец = ВыборкаИтоги.КонецПериода;
        		 	
		Выборка = ВыборкаИтоги.Выбрать();
		
		// если для одного номера строки табличной части запрос вернул несколько строк,
		// то это означает, что плановые начисления неоднократно изменялись в течение месяца
		Пока Выборка.Следующий() Цикл 
			НоваяЗапись = Движения.ОсновныеНачисления.Добавить();
			ЗаполнитьЗначенияСвойств(НоваяЗапись, Выборка);
			// 9. Первой всегда будет строка табличной части документа с показателем на начало периода действия надбавки
			// если размер надбавки изменялся в течение месяца, то начало периода действия должно совпадать с периодом ее изменения 
			ПериодДействияНачало = Макс(Выборка.НачалоПериода, Выборка.Период); 
			НоваяЗапись.ПериодДействияНачало = ПериодДействияНачало;
			НоваяЗапись.ПериодДействияКонец = ПериодДействияКонец;
			// 10. Окончание периода действия предыдущей строки должно предшествовать текущей 
			Если ПредыдущаяЗапись <> Неопределено Тогда
				ПредыдущаяЗапись.ПериодДействияКонец = КонецДня(ПериодДействияНачало - 1);
			КонецЕсли;
			ПредыдущаяЗапись = НоваяЗапись;
		КонецЦикла;
		
	КонецЦикла; 
    
	// 11. Предварительная запись движений документа
	Движения.Записать();
    
	// 12. Выполнение расчетов для записанных наборов записей
	ПроведениеРасчетов.Рассчитать(Движения.ОсновныеНачисления, Ссылка);
    
КонецПроцедуры

Ключевые моменты расчета подробно описаны в предыдущих главах, поэтому в данной главе подробно рассмотрим только запрос и формирование движений.

Так как текст запроса состоит из нескольких пакетов, для наглядности решения рассмотрим, какой результат получается в каждом из пакетов.

Для анализа запроса будут следующие исходные данные:

Начисляется заработная плата за февраль месяц. У сотрудника Бельдыева оклад изменялся следующим образом:

Дата

Сотрудник Оклад

01.01.2019

Бельдыев 10 000

15.01.2019

Бельдыев 20 000

05.02.2019

Бельдыев 25 000

10.02.2019

Бельдыев 23 000

15.03.2019

Бельдыев 30 000

Получение данных из документа (п.2)

Получаем необходимые данные из документа и помещаем их во временную таблицу ВТДокумент. По полям, которые будем использовать в соединениях, добавим индекс.

Результат первого пакета запроса

Рисунок 7 – Результат первого пакета запроса

Получение плановых начислений (п.3)

Соединим временную таблицу ВТДокумент с регистром сведений СведенияОСотрудниках. Получим только плановые начисления, которые актуальны на период действия начисления. Таким образом запись о изменении оклада 15.03.2019 не попала в результат запроса. По полям, которые будем использовать в соединениях, добавим индекс.

Результат второго пакета запроса

Рисунок 8 – Результат второго пакета запроса

Получение последней записи по плановым начислениям на начало периода (п.4)

Получим информацию о том, какая запись об изменении оклада действовала на начало начисления заработной платы (в рассматриваемом примере 01.02.2019). Для этого выберем необходимые поля из временной таблицы ВТПлановыеНачисления и с помощью условия ВТПлановыеНачисления.Период <= ВТПлановыеНачисления.НачалоПериода отсечем лишние данные. Чтобы получить последнюю запись, сгруппируем поля, для поля Период воспользуемся функцией Максимум. Поместим результат во временную таблицу ВТПериоды.

Результат третьего пакета запроса

Рисунок 9 – Результат третьего пакета запроса

Получение плановых начислений на начало периода (п.5)

Получим значения плановых начислений на начало периода расчета заработной платы. Для этого соединим внутренним соединением временные таблицы ВТПериоды и ВТПлановыеНачисления. В результате останутся только записи, которые есть в обеих таблицах.

 

Результат первого запроса третьего пакета запроса

Рисунок 10 – Результат первого запроса третьего пакета запроса

Получение плановых начислений, которые изменялись в текущем месяце (п.6)

Получим значения плановых начислений, которые изменялись в текущем месяце. Для этого возьмем данные из временной таблицы и наложим условие ВТПлановыеНачисления.Период > ВТПлановыеНачисления.НачалоПериода.

Результат второго запроса четвертого пакета запроса

Рисунок 11 – Результат второго запроса четвертого пакета запроса

Группировка данных (п.7)

Секция ИТОГИ позволяет получить сгруппированные и детальные записи по номерам строк табличной части документа с разбивкой по периоду изменения плановых начислений.

В результате выполнения всего четвертого пакета получается следующий результат:

 

Результат четвертого пакета запроса

Рисунок 12 – Результат четвертого пакета запроса

Формирование движений (п.8, п.9, п.10)

Для формирования движений сформируем и обойдем выборку в цикле. Для каждой строки документа может быть несколько строк движений (если оклад изменялся несколько раз в текущем месяце).

Код серверного модуля ПроведениеРасчетов и процедуры Рассчитать аналогичен коду блока «6. Что такое механизм вытеснения и как он используется при расчете периодических начислений», поэтому повторять его не будем.

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

Изменение записи регистра ГрафикРаботы ресурса Значение

Рисунок 13 – Изменение записи регистра ГрафикРаботы ресурса Значение

Запустим конфигурацию в режиме «1С:Предприятие» и проверим выполненные доработки. Для начала заполним график.

Далее заполним тестовые данные регистра сведений о сотрудниках:

Данные регистра СведенияОСотрудниках

Рисунок 14 – Данные регистра СведенияОСотрудниках

Введем тестовые данные в документ и проведём его.

 

Пользовательские данные документа НачислениеЗарплаты

Рисунок 15 – Пользовательские данные документа НачислениеЗарплаты

 

Движения документа «Начисление зарплаты» регистра Основные начисления

Рисунок 16 – Движения документа Начисление зарплаты регистра Основные начисления

Проверим корректность расчетов для записей регистра расчета. Согласно информации об Окладе в регистре СведенияОСотрудниках Бельдыев получал оклад:

  • с 15.01 по 04.02 – 20 000
  • с 05.02 по 09.02 – 25 000
  • с 10.02 по 15.03 – 23 000.

В феврале всего 20 рабочих дней. В периоды изменения оклада Бельдыева:

  • с 15.01 по 04.02 – 2 рабочих дня
  • с 05.02 по 09.02 – 4 рабочих дня
  • с 10.02 по 15.03 – 14 рабочих дней

Рассчитаем результат:

  • 01.02 – 04.02: 20 000 * 2 / 20 = 2 000
  • 05.02 – 09.02: 25 000 * 4 / 20 = 5 000
  • 10.02 – 28.02: 23 000 * 14 / 20 = 16 100

В этой задаче был рассмотрен сложный случай, когда размер оклада в течение месяца может изменяться неоднократно. Чаще встречается более простое условие, когда оклад или любое другое начисление нужно брать на начало расчетного периода. В этом случае нужно использовать срез последних на период регистрации, для того чтобы получить актуальные значения расчетных показателей.

Перейти к следующей теме:
“Как рассчитать зарплату по шкале ставок в зависимости от отработанного времени” (№ 11)

Комментарии закрыты