В практике разработчика 1С часто встречаются задачи, требующие не просто извлечения данных, но и сложного анализа их динамики. Одной из таких классических «проверочных» задач является поиск работающих сотрудников, общая сумма плановых начислений которых хотя бы раз удвоилась за период, не превышающий одного года, за всё время их работы в организации. В контексте конфигурации 1С:Управление производственным предприятием (УПП), которая базируется на логике, схожей с ЗУП 2.5, эта задача представляет особый интерес из-за специфической структуры хранения данных.
В этой статье мы подробно разберем, как спроектировать такой запрос, на какие подводные камни архитектуры УПП следует обратить внимание и как правильно обработать временные изменения начислений.
Прежде всего, проанализируем, где хранятся нужные нам сведения. Основным источником данных является периодический регистр сведений ПлановыеНачисленияРаботниковОрганизаций. В отличие от более современной 1С:ERP или ЗУП 3.1, где используются интервальные регистры, в УПП данные хранятся в «классическом» виде, но с существенным дополнением: механизмом Периода завершения.
Рассмотрим структуру этого регистра. Для каждого начисления фиксируется:
Сотрудник — объект анализа.Период — дата начала действия начисления или изменения его параметров.ВидРасчета — само начисление (оклад, надбавка и т.д.).Показатель1 (и далее) — числовые значения (сумма, процент).ПериодЗавершения — дата, когда начисление должно автоматически прекратиться или изменить значение.ДействиеЗавершения — что именно должно произойти в дату завершения.Критически важный момент: запись о прекращении начисления в ПериодЗавершения не создает новую физическую строку в таблице базы данных. Это означает, что если мы просто выберем данные из регистра, мы «пропустим» момент окончания временной надбавки, что приведет к неверному расчету общей суммы на определенную дату.
Разберем по шагам создание запроса. Первым делом нам необходимо получить все даты, в которые сумма плановых начислений сотрудника могла измениться. Такими датами являются как стандартные даты начала (Период), так и даты окончания (ПериодЗавершения).
Проанализируем логику объединения:
ВЫБРАТЬ
Регистр.Сотрудник КАК Сотрудник,
Регистр.Период КАК ДатаСобытия
ИЗ
РегистрСведений.ПлановыеНачисленияРаботниковОрганизаций КАК Регистр
ОБЪЕДИНИТЬ
ВЫБРАТЬ
Регистр.Сотрудник,
Регистр.ПериодЗавершения
ИЗ
РегистрСведений.ПлановыеНачисленияРаботниковОрганизаций КАК Регистр
ГДЕ
Регистр.ПериодЗавершения <> ДАТАВРЕМЯ(1, 1, 1)
Сформировав такую временную таблицу (назовем ее ВТ_ВсеДаты), мы получаем «каркас» временной шкалы для каждого сотрудника.
Теперь нам нужно выяснить, какая общая сумма начислений действовала в каждый момент из ВТ_ВсеДаты. Для этого мы соединяем наши даты с самим регистром начислений. Выясним причину сложности этого соединения: нам нужно отобрать все записи, которые «начались» до нашей даты и либо еще не «закончились», либо их окончание запланировано на будущее.
Рассмотрим пример условия связи в запросе:
ВЫБРАТЬ
Т_Даты.Сотрудник,
Т_Даты.ДатаСобытия,
СУММА(ЕСТЬNULL(Регистр.Показатель1, 0)) КАК ОбщаяСумма
ИЗ
ВТ_ВсеДаты КАК Т_Даты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ПлановыеНачисленияРаботниковОрганизаций КАК Регистр
ПО Т_Даты.Сотрудник = Регистр.Сотрудник
И Регистр.Период <= Т_Даты.ДатаСобытия
И (Регистр.ПериодЗавершения = ДАТАВРЕМЯ(1, 1, 1) ИЛИ Регистр.ПериодЗавершения > Т_Даты.ДатаСобытия)
ГРУППИРОВАТЬ ПО
Т_Даты.Сотрудник,
Т_Даты.ДатаСобытия
Важное примечание: В реальной конфигурации УПП нужно также учитывать ВидРасчета и Действие (Принять, Изменить, Прекратить). Если действие — «Прекратить», то такая запись не должна увеличивать сумму. Также следует помнить, что сумма начисления может храниться не только в Показатель1, но и в других полях, в зависимости от настроек видов расчета.
Когда у нас есть временная таблица (назовем ее ВТ_ИсторияСумм) с колонками Сотрудник, ДатаСобытия и ОбщаяСумма, мы можем приступить к самому интересному — поиску удвоения. Для этого мы выполним самосоединение таблицы ВТ_ИсторияСумм.
Проанализируем ситуацию: нам нужны две записи (условно «Раньше» и «Позже»), такие, что:
Посмотрим на пример реализации этого условия в коде запроса:
ВЫБРАТЬ РАЗЛИЧНЫЕ
ИсторияРаньше.Сотрудник
ИЗ
ВТ_ИсторияСумм КАК ИсторияРаньше
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ИсторияСумм КАК ИсторияПозже
ПО ИсторияРаньше.Сотрудник = ИсторияПозже.Сотрудник
И ИсторияПозже.ДатаСобытия > ИсторияРаньше.ДатаСобытия
И РАЗНОСТЬДАТ(ИсторияРаньше.ДатаСобытия, ИсторияПозже.ДатаСобытия, ДЕНЬ) <= 365
ГДЕ
ИсторияПозже.ОбщаяСумма >= ИсторияРаньше.ОбщаяСумма * 2
И ИсторияРаньше.ОбщаяСумма > 0
По условию задачи нам нужны только те сотрудники, которые работают на текущий момент. В УПП статус «работает/уволен» определяется по регистру сведений РаботникиОрганизаций. Нам необходимо получить срез последних данных по этому регистру и убедиться, что последнее состояние сотрудника — не «Увольнение».
Рассмотрим, как это добавить в финальный запрос:
ВЫБРАТЬ
Результат.Сотрудник КАК Сотрудник
ИЗ
(Вышеуказанный_Запрос_На_Поиск_Удвоения) КАК Результат
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.РаботникиОрганизаций.СрезПоследних(&ТекущаяДата, ) КАК Статус
ПО Результат.Сотрудник = Статус.Сотрудник
ГДЕ
Статус.ПричинаИзмененияСостояния <> ЗНАЧЕНИЕ(Перечисление.ПричиныИзмененияСостояния.Увольнение)
Мы проанализировали алгоритм решения сложной аналитической задачи в среде 1С:УПП. Основная сложность здесь заключается не в самом условии «удвоения», а в правильном формировании временной шкалы начислений с учетом ПериодаЗавершения.
Подведем итоги ключевых правил при написании таких запросов:
Период и ПериодЗавершения, чтобы не потерять точки падения доходов.РАЗНОСТЬДАТ. Это позволяет реализовать «скользящее окно» в один год.Такой подход гарантирует точность данных и позволяет пройти техническое интервью или решить реальную бизнес-задачу по анализу кадровой политики предприятия. Подобные алгоритмы эффективны для поиска аномалий в начислениях зарплаты, контроля ФОТ и аудита изменений условий труда.