В данной задаче с точки зрения расчета проблему представляет разбить период работы сотрудника на под периоды с различным значением оклада, причем сделать это нужно запросом. Предлагаю свой достаточно короткий и интуитивный понятный запрос, для решения этой задачи.
Исходные данные:
1. Документ начисления по окладу:
Ниже данные периодического регистра сведений с периодичностью день, в котором мы храним первоначальное значение оклада:
Итоговые интервалы со значением оклада у нас будут выглядеть так:
Сотрудник | Дата начала | Дата окончания | Размер |
---|---|---|---|
Иванов | 05.09.2023 | 06.09.2023 | 250,00 |
Иванов | 07.09.2023 | 10.09.2023 | 200,00 |
Иванов | 11.09.2023 | 14.09.2023 | 100,00 |
Иванов | 15.09.2023 | 20.09.2023 | 150,00 |
Иванов | 21.09.2023 | 24.09.2023 | 400,00 |
Иванов | 25.09.2023 | 26.09.2023 | 300,00 |
Иванов | 27.09.2023 | 28.09.2023 | 200,00 |
Петров | 01.09.2023 | 06.09.2023 | 1 000,00 |
Петров | 07.09.2023 | 12.09.2023 | 2 000,00 |
Петров | 13.09.2023 | 20.09.2023 | 3 000,00 |
Петров | 21.09.2023 | 25.09.2023 | 4 000,00 |
Петров | 26.09.2023 | 30.09.2023 | 5 000,00 |
Эти итоговые данные мы должны получить запросом и рассчитать зарплату по окладу для нашим сотрудников:
План запроса:
1. объединяем срез последних РС на дату регистрации и записи РС с отбором внутри нашего месяца начисления, помещаем во временную таблицу, индексируем по Сотруднику и периоду.
2. полученную временную таблицу пронумеруем по порядку, порядок должен быть Сотрудник, Период, пронумерованную таблицу поместим во временную (таким образом можно пронумеровать только временную таблицу)
3. полученную таблицу соединяем саму с собой по сотруднику и по номеру строки со сдвигом номера на единицу, тем самым получая начало и окончания интервала. Одновременно, для конца интервала отнимаем день, а те записи которые по сотруднику не сошлись - устанавливаем для них конец периода = концу месяца регистрации, помещаем во временную таблицу
4. полученную таблицу соединяем с интервалами из табличной части документа по сотруднику, окончательные дату начала и дату конца получаем обрезая крайние значения которые не удовлетворяют интервалам из табличной части документа, накладываем дополнительное условие на полученные дата начала и дату конца интервала, что дата начала меньше дата конца.
Готово.
3,4 пункты покажутся сначала не очень понятными, но если попробовать покрутить запрос в консоле станет понятнее.
Нужно просто представить что пронумерованную таблицу регистра мы сдвигаем на строку вверх чтобы получить дату окончания, и моя мысль станет более понятной:
Период | |||
Сотрудник | Оклад | Период | 29.08.2023 |
Иванов | 200,00 | 29.08.2023 | 01.09.2023 |
Иванов | 300,00 | 01.09.2023 | 04.09.2023 |
Иванов | 250,00 | 04.09.2023 | 07.09.2023 |
Иванов | 200,00 | 07.09.2023 | 11.09.2023 |
Иванов | 100,00 | 11.09.2023 | 15.09.2023 |
Иванов | 150,00 | 15.09.2023 | 21.09.2023 |
Иванов | 400,00 | 21.09.2023 | 25.09.2023 |
Иванов | 300,00 | 25.09.2023 | 27.09.2023 |
Иванов | 200,00 | 27.09.2023 | 29.09.2023 |
Иванов | 500,00 | 29.09.2023 | 01.08.2023 |
Петров | 1 000,00 | 01.08.2023 | 07.09.2023 |
Петров | 2 000,00 | 07.09.2023 | 13.09.2023 |
Петров | 3 000,00 | 13.09.2023 | 21.09.2023 |
Петров | 4 000,00 | 21.09.2023 | 26.09.2023 |
Петров | 5 000,00 | 26.09.2023 | |
это период начала | Это период окончания - здесь сдвинули наверх на одну строку и отняли день, чтобы получить конец интервала, а если дата получилась пустая, то добавили месяц к периоду регистрации и тоже отняли день |
Запрос будет выглядеть следующим образом:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| СведенияОСотрудниках.Период КАК Период,
| СведенияОСотрудниках.Сотрудник КАК Сотрудник,
| СведенияОСотрудниках.Оклад КАК Оклад
|ПОМЕСТИТЬ ВТ
|ИЗ
| РегистрСведений.СведенияОСотрудниках КАК СведенияОСотрудниках
|ГДЕ
| СведенияОСотрудниках.Период МЕЖДУ &ПериодРегистрации И ДОБАВИТЬКДАТЕ(ДОБАВИТЬКДАТЕ(&ПериодРегистрации, МЕСЯЦ, 1), СЕКУНДА, -1)
|
|ОБЪЕДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| &ПериодРегистрации,
| СведенияОСотрудникахСрезПоследних.Сотрудник,
| СведенияОСотрудникахСрезПоследних.Оклад
|ИЗ
| РегистрСведений.СведенияОСотрудниках.СрезПоследних(&ПериодРегистрации, ) КАК СведенияОСотрудникахСрезПоследних
|
|ИНДЕКСИРОВАТЬ ПО
| Сотрудник,
| Период
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗЛИЧНЫЕ
| АВТОНОМЕРЗАПИСИ() КАК НомерСтроки,
| ВТ.Период КАК Период,
| ВТ.Сотрудник КАК Сотрудник,
| ВТ.Оклад КАК Оклад
|ПОМЕСТИТЬ ВТ1
|ИЗ
| ВТ КАК ВТ
|
|ИНДЕКСИРОВАТЬ ПО
| Сотрудник,
| Период
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗЛИЧНЫЕ
| ВТ1.Период КАК НачалоПериода,
| ДОБАВИТЬКДАТЕ(ЕСТЬNULL(ВТ11.Период, ДОБАВИТЬКДАТЕ(&ПериодРегистрации, МЕСЯЦ, 1)), ДЕНЬ, -1) КАК КонецПериода,
| ВТ1.Сотрудник КАК Сотрудник,
| ВТ1.Оклад КАК Оклад
|ПОМЕСТИТЬ ВТ2
|ИЗ
| ВТ1 КАК ВТ1
| ЛЕВОЕ СОЕДИНЕНИЕ ВТ1 КАК ВТ11
| ПО (ВТ1.НомерСтроки = ВТ11.НомерСтроки - 1)
| И ВТ1.Сотрудник = ВТ11.Сотрудник
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗЛИЧНЫЕ
| НачислениеЗарплатыОсновныеНачисления.Сотрудник КАК Сотрудник,
| ВЫБОР
| КОГДА ВТ2.НачалоПериода < НачислениеЗарплатыОсновныеНачисления.ДатаНачала
| ТОГДА НачислениеЗарплатыОсновныеНачисления.ДатаНачала
| ИНАЧЕ ВТ2.НачалоПериода
| КОНЕЦ КАК ДатаНачала,
| ВЫБОР
| КОГДА ВТ2.КонецПериода > НачислениеЗарплатыОсновныеНачисления.ДатаОкончания
| ТОГДА НачислениеЗарплатыОсновныеНачисления.ДатаОкончания
| ИНАЧЕ ВТ2.КонецПериода
| КОНЕЦ КАК ДатаОкончания,
| ВТ2.Оклад КАК Размер
|ИЗ
| ВТ2 КАК ВТ2
| ПОЛНОЕ СОЕДИНЕНИЕ Документ.НачислениеЗарплаты.ОсновныеНачисления КАК НачислениеЗарплатыОсновныеНачисления
| ПО ВТ2.Сотрудник = НачислениеЗарплатыОсновныеНачисления.Сотрудник
|ГДЕ
| НачислениеЗарплатыОсновныеНачисления.Ссылка = &Ссылка
| И НачислениеЗарплатыОсновныеНачисления.ВидРасчета = &Оклад
| И ВЫБОР
| КОГДА ВТ2.НачалоПериода < НачислениеЗарплатыОсновныеНачисления.ДатаНачала
| ТОГДА НачислениеЗарплатыОсновныеНачисления.ДатаНачала
| ИНАЧЕ ВТ2.НачалоПериода
| КОНЕЦ <= ВЫБОР
| КОГДА ВТ2.КонецПериода > НачислениеЗарплатыОсновныеНачисления.ДатаОкончания
| ТОГДА НачислениеЗарплатыОсновныеНачисления.ДатаОкончания
| ИНАЧЕ ВТ2.КонецПериода
| КОНЕЦ";
Тестирование проводилось на платформе 8.3.18.1289.