Моя предыдущая публикация содержала текст запроса, который вычислял конфликты кадровых неявок.
Сейчас я приведу конкретный пример, как этот запрос можно использовать в типовой конфигурации ЗУП (УПП) для информирования пользователя о конфликтах кадровых неявок при проведении любого кадрового документа, регистрирующего кадровые неявки.
Для этого в дереве конфигурации нужно создать новую подписку на событие, скажем, ОперативныйКонтрольНеявок :
Источник события = РегистрСведенийНаборЗаписей.СостояниеРаботниковОрганизаций,
Событие = ПриЗаписи,
а в качестве процедуры - обработчика события использовать следующий код :
Процедура ОперативныйКонтрольНеявокПриЗаписи(Источник, Отказ, Замещение) Экспорт
// в наборе нет записей - отслеживаемые неявки отсутствуют - контроль не нужен
Если Источник.Количество() = 0 Тогда
Возврат;
КонецЕсли;
// у всего набора записей регистратор - один и тот же
Регистратор1 = Источник[0].Регистратор;
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| СостояниеРаботниковОрганизаций.Период КАК Период,
| СостояниеРаботниковОрганизаций.Регистратор,
| СостояниеРаботниковОрганизаций.НомерСтроки,
| СостояниеРаботниковОрганизаций.Активность,
| СостояниеРаботниковОрганизаций.Сотрудник,
| СостояниеРаботниковОрганизаций.Организация,
| СостояниеРаботниковОрганизаций.Состояние,
| СостояниеРаботниковОрганизаций.ПериодЗавершения,
| СостояниеРаботниковОрганизаций.СостояниеЗавершения
|ПОМЕСТИТЬ ДвиженияОтслеживаемогоРегистратора
|ИЗ
| РегистрСведений.СостояниеРаботниковОрганизаций КАК СостояниеРаботниковОрганизаций
|ГДЕ
| СостояниеРаботниковОрганизаций.Регистратор = &ОтслеживаемыйРегистратор
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗЛИЧНЫЕ
| ДвиженияОтслеживаемогоРегистратора.Сотрудник
|ПОМЕСТИТЬ ОптимизацияОтслеживаемыеСотрудники
|ИЗ
| ДвиженияОтслеживаемогоРегистратора КАК ДвиженияОтслеживаемогоРегистратора
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| МИНИМУМ(ДвиженияОтслеживаемогоРегистратора.Период) КАК Период
|ПОМЕСТИТЬ ОптимизацияМинимальныеИнтересующиеПериодыКалендаря
|ИЗ
| ДвиженияОтслеживаемогоРегистратора КАК ДвиженияОтслеживаемогоРегистратора
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| РегламентированныйПроизводственныйКалендарь.ДатаКалендаря
|ПОМЕСТИТЬ ОптимизацияКалендарь
|ИЗ
| РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РегламентированныйПроизводственныйКалендарь
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ОптимизацияМинимальныеИнтересующиеПериодыКалендаря КАК ОптимизацияМинимальныеИнтересующиеПериодыКалендаря
| ПО РегламентированныйПроизводственныйКалендарь.ДатаКалендаря >= ОптимизацияМинимальныеИнтересующиеПериодыКалендаря.Период
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| СостояниеРаботниковОрганизаций.Период КАК Период,
| СостояниеРаботниковОрганизаций.Регистратор,
| СостояниеРаботниковОрганизаций.НомерСтроки,
| СостояниеРаботниковОрганизаций.Активность,
| СостояниеРаботниковОрганизаций.Сотрудник,
| СостояниеРаботниковОрганизаций.Организация,
| СостояниеРаботниковОрганизаций.Состояние,
| СостояниеРаботниковОрганизаций.ПериодЗавершения,
| СостояниеРаботниковОрганизаций.СостояниеЗавершения
|ПОМЕСТИТЬ ДвиженияБезОтслеживаемогоРегистратора
|ИЗ
| РегистрСведений.СостояниеРаботниковОрганизаций КАК СостояниеРаботниковОрганизаций
|ГДЕ
| СостояниеРаботниковОрганизаций.Регистратор <> &ОтслеживаемыйРегистратор
| И СостояниеРаботниковОрганизаций.Сотрудник В
| (ВЫБРАТЬ
| ОптимизацияОтслеживаемыеСотрудники.Сотрудник
| ИЗ
| ОптимизацияОтслеживаемыеСотрудники)
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| МАКСИМУМ(ВЫБОР
| КОГДА ДвиженияБезОтслеживаемогоРегистратора.ПериодЗавершения = ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)
| ТОГДА ДвиженияБезОтслеживаемогоРегистратора.Период
| КОГДА ДвиженияБезОтслеживаемогоРегистратора.ПериодЗавершения > РегламентированныйПроизводственныйКалендарь.ДатаКалендаря
| ТОГДА ДвиженияБезОтслеживаемогоРегистратора.Период
| ИНАЧЕ ДвиженияБезОтслеживаемогоРегистратора.ПериодЗавершения
| КОНЕЦ) КАК Период,
| РегламентированныйПроизводственныйКалендарь.ДатаКалендаря,
| ДвиженияБезОтслеживаемогоРегистратора.Сотрудник
|ПОМЕСТИТЬ ПериодыСостоянийСотрудниковБезОтслеживаемогоРегистратора
|ИЗ
| ДвиженияБезОтслеживаемогоРегистратора КАК ДвиженияБезОтслеживаемогоРегистратора
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ОптимизацияКалендарь КАК РегламентированныйПроизводственныйКалендарь
| ПО ДвиженияБезОтслеживаемогоРегистратора.Период <= РегламентированныйПроизводственныйКалендарь.ДатаКалендаря
|
|СГРУППИРОВАТЬ ПО
| РегламентированныйПроизводственныйКалендарь.ДатаКалендаря,
| ДвиженияБезОтслеживаемогоРегистратора.Сотрудник
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| МАКСИМУМ(ВЫБОР
| КОГДА ДвиженияОтслеживаемогоРегистратора.ПериодЗавершения = ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)
| ТОГДА ДвиженияОтслеживаемогоРегистратора.Период
| КОГДА ДвиженияОтслеживаемогоРегистратора.ПериодЗавершения > РегламентированныйПроизводственныйКалендарь.ДатаКалендаря
| ТОГДА ДвиженияОтслеживаемогоРегистратора.Период
| ИНАЧЕ ДвиженияОтслеживаемогоРегистратора.ПериодЗавершения
| КОНЕЦ) КАК Период,
| РегламентированныйПроизводственныйКалендарь.ДатаКалендаря,
| ДвиженияОтслеживаемогоРегистратора.Сотрудник
|ПОМЕСТИТЬ ПериодыСостоянийСотрудниковОтслеживаемогоРегистратора
|ИЗ
| ДвиженияОтслеживаемогоРегистратора КАК ДвиженияОтслеживаемогоРегистратора
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ОптимизацияКалендарь КАК РегламентированныйПроизводственныйКалендарь
| ПО ДвиженияОтслеживаемогоРегистратора.Период <= РегламентированныйПроизводственныйКалендарь.ДатаКалендаря
|
|СГРУППИРОВАТЬ ПО
| РегламентированныйПроизводственныйКалендарь.ДатаКалендаря,
| ДвиженияОтслеживаемогоРегистратора.Сотрудник
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ПериодыСостоянийСотрудников.ДатаКалендаря КАК ДатаКалендаря,
| ПериодыСостоянийСотрудников.Сотрудник,
| ДвиженияБезОтслеживаемогоРегистратора.Регистратор,
| ВЫБОР
| КОГДА ПериодыСостоянийСотрудников.Период = ДвиженияБезОтслеживаемогоРегистратора.Период
| ТОГДА ДвиженияБезОтслеживаемогоРегистратора.Состояние
| ИНАЧЕ ДвиженияБезОтслеживаемогоРегистратора.СостояниеЗавершения
| КОНЕЦ КАК Состояние
|ПОМЕСТИТЬ КалендарьСостоянийСотрудниковБезОтслеживаемогоРегистратора
|ИЗ
| ПериодыСостоянийСотрудниковБезОтслеживаемогоРегистратора КАК ПериодыСостоянийСотрудников
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ДвиженияБезОтслеживаемогоРегистратора КАК ДвиженияБезОтслеживаемогоРегистратора
| ПО (ПериодыСостоянийСотрудников.Период = ДвиженияБезОтслеживаемогоРегистратора.Период
| ИЛИ ПериодыСостоянийСотрудников.Период = ДвиженияБезОтслеживаемогоРегистратора.ПериодЗавершения)
| И ПериодыСостоянийСотрудников.Сотрудник = ДвиженияБезОтслеживаемогоРегистратора.Сотрудник
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ПериодыСостоянийСотрудников.ДатаКалендаря КАК ДатаКалендаря,
| ПериодыСостоянийСотрудников.Сотрудник,
| ДвиженияОтслеживаемогоРегистратора.Регистратор,
| ВЫБОР
| КОГДА ПериодыСостоянийСотрудников.Период = ДвиженияОтслеживаемогоРегистратора.Период
| ТОГДА ДвиженияОтслеживаемогоРегистратора.Состояние
| ИНАЧЕ ДвиженияОтслеживаемогоРегистратора.СостояниеЗавершения
| КОНЕЦ КАК Состояние
|ПОМЕСТИТЬ КалендарьСостоянийСотрудниковОтслеживаемогоРегистратора
|ИЗ
| ПериодыСостоянийСотрудниковОтслеживаемогоРегистратора КАК ПериодыСостоянийСотрудников
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ ДвиженияОтслеживаемогоРегистратора КАК ДвиженияОтслеживаемогоРегистратора
| ПО (ПериодыСостоянийСотрудников.Период = ДвиженияОтслеживаемогоРегистратора.Период
| ИЛИ ПериодыСостоянийСотрудников.Период = ДвиженияОтслеживаемогоРегистратора.ПериодЗавершения)
| И ПериодыСостоянийСотрудников.Сотрудник = ДвиженияОтслеживаемогоРегистратора.Сотрудник
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗЛИЧНЫЕ
| КалендарьСостоянийСотрудниковБезОтслеживаемогоРегистратора.ДатаКалендаря,
| КалендарьСостоянийСотрудниковБезОтслеживаемогоРегистратора.Сотрудник,
| КалендарьСостоянийСотрудниковБезОтслеживаемогоРегистратора.Регистратор,
| КалендарьСостоянийСотрудниковБезОтслеживаемогоРегистратора.Состояние
|ПОМЕСТИТЬ КалендарьНеявокСотрудниковБезОтслеживаемогоРегистратора
|ИЗ
| КалендарьСостоянийСотрудниковБезОтслеживаемогоРегистратора КАК КалендарьСостоянийСотрудниковБезОтслеживаемогоРегистратора
|ГДЕ
| КалендарьСостоянийСотрудниковБезОтслеживаемогоРегистратора.Состояние <> ЗНАЧЕНИЕ(Перечисление.СостоянияРаботникаОрганизации.Работает)
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ РАЗЛИЧНЫЕ
| КалендарьСостоянийСотрудниковОтслеживаемогоРегистратора.ДатаКалендаря,
| КалендарьСостоянийСотрудниковОтслеживаемогоРегистратора.Сотрудник,
| КалендарьСостоянийСотрудниковОтслеживаемогоРегистратора.Регистратор,
| КалендарьСостоянийСотрудниковОтслеживаемогоРегистратора.Состояние
|ПОМЕСТИТЬ КалендарьНеявокСотрудниковОтслеживаемогоРегистратора
|ИЗ
| КалендарьСостоянийСотрудниковОтслеживаемогоРегистратора КАК КалендарьСостоянийСотрудниковОтслеживаемогоРегистратора
|ГДЕ
| КалендарьСостоянийСотрудниковОтслеживаемогоРегистратора.Состояние <> ЗНАЧЕНИЕ(Перечисление.СостоянияРаботникаОрганизации.Работает)
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| КалендарьНеявокСотрудниковБезОтслеживаемогоРегистратора.ДатаКалендаря КАК ДатаКалендаряМаксимум,
| КалендарьНеявокСотрудниковБезОтслеживаемогоРегистратора.Сотрудник КАК Сотрудник,
| КалендарьНеявокСотрудниковБезОтслеживаемогоРегистратора.Регистратор КАК Регистратор,
| КалендарьНеявокСотрудниковБезОтслеживаемогоРегистратора.Состояние КАК СостояниеБезОтслеживаемогоРегистратора,
| КалендарьНеявокСотрудниковОтслеживаемогоРегистратора.Состояние КАК СостояниеОтслеживаемогоРегистратора,
| КалендарьНеявокСотрудниковБезОтслеживаемогоРегистратора.ДатаКалендаря КАК ДатаКалендаряМинимум
|ИЗ
| КалендарьНеявокСотрудниковБезОтслеживаемогоРегистратора КАК КалендарьНеявокСотрудниковБезОтслеживаемогоРегистратора
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ КалендарьНеявокСотрудниковОтслеживаемогоРегистратора КАК КалендарьНеявокСотрудниковОтслеживаемогоРегистратора
| ПО КалендарьНеявокСотрудниковБезОтслеживаемогоРегистратора.Сотрудник = КалендарьНеявокСотрудниковОтслеживаемогоРегистратора.Сотрудник
| И КалендарьНеявокСотрудниковБезОтслеживаемогоРегистратора.ДатаКалендаря = КалендарьНеявокСотрудниковОтслеживаемогоРегистратора.ДатаКалендаря
| И КалендарьНеявокСотрудниковБезОтслеживаемогоРегистратора.Состояние <> КалендарьНеявокСотрудниковОтслеживаемогоРегистратора.Состояние
|ИТОГИ
| МАКСИМУМ(ДатаКалендаряМаксимум),
| МИНИМУМ(ДатаКалендаряМинимум)
|ПО
| Сотрудник,
| Регистратор,
| СостояниеОтслеживаемогоРегистратора,
| СостояниеБезОтслеживаемогоРегистратора";
Запрос.УстановитьПараметр("ОтслеживаемыйРегистратор", Регистратор1);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Если Выборка.Количество() > 0 Тогда
ОбработкаКомментариев = глЗначениеПеременной("глОбработкаСообщений");
ОбработкаКомментариев.УдалитьСообщения();
ТекстСообщения = "Проведение документа " + Регистратор1 + " : ";
ЗаголовокСообщения = ОбработкаКомментариев.ДобавитьСообщение(ТекстСообщения, Перечисления.ВидыСообщений.ВажнаяИнформация);
Пока Выборка.СледующийПоЗначениюПоля("Сотрудник") Цикл
Если НЕ ЗначениеЗаполнено(Выборка.Сотрудник) Тогда
Продолжить;
КонецЕсли;
Пока Выборка.СледующийПоЗначениюПоля("Регистратор") Цикл
Если НЕ ЗначениеЗаполнено(Выборка.Регистратор) Тогда
Продолжить;
КонецЕсли;
Пока Выборка.СледующийПоЗначениюПоля("СостояниеОтслеживаемогоРегистратора") Цикл
Если НЕ ЗначениеЗаполнено(Выборка.СостояниеОтслеживаемогоРегистратора) Тогда
Продолжить;
КонецЕсли;
Пока Выборка.СледующийПоЗначениюПоля("СостояниеБезОтслеживаемогоРегистратора") Цикл
Если НЕ ЗначениеЗаполнено(Выборка.СостояниеБезОтслеживаемогоРегистратора) Тогда
Продолжить;
КонецЕсли;
ОбработкаКомментариев.ДобавитьСообщение("Сотрудник `" + Выборка.Сотрудник + "' (" + Выборка.СостояниеОтслеживаемогоРегистратора + " " + Формат(Выборка.ДатаКалендаряМинимум, "ДФ=dd.MM.yyyy") + " - " + Формат(Выборка.ДатаКалендаряМаксимум, "ДФ=dd.MM.yyyy") + ") уже переведен в состояние """ + Выборка.СостояниеБезОтслеживаемогоРегистратора + """ документом " + Выборка.Регистратор + ""
, Перечисления.ВидыСообщений.Информация, , ЗаголовокСообщения);
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецЦикла;
ОбработкаКомментариев.ПоказатьСообщения();
КонецЕсли;
КонецПроцедуры
Как это работает?
Данный обработчик "срабатывает" при каждой записи набора записей в регистр сведений СостояниеРаботниковОрганизаций вне зависимости от вида документа, которому заблагорассудится написать в этот регистр сведений.
Поскольку этот регистр сведений подчинён регистратору, запись (непустого набора) в регистр фактически происходит при проведении какого-либо кадрового документа (уполномоченного на запись в этот регистр).
Если записываемый набор оказывается пустым, то конфликтов неявок быть не может, и обработчик завершает работу. В противном случае набор записей содержит ссылку на документ, который сгенерировал этот набор записей.
Проведение документа и запись в регистр сведений произойдёт только после необходимых проверок, которые выполняет типовой код ЗУП (УПП). Если типовой код ЗУП (УПП) запрещает проведение документа, то запись в регистр СостояниеРаботниковОрганизаций не осуществляется и обработчик события ПриЗаписи не запустится.
Что же произойдёт после того, как типовой код ЗУП (УПП) разрешит проведение кадрового документа? В регистр сведений СостояниеРаботниковОрганизаций будет записан новый набор записей и сразу после этого запустится обработчик события.
Далее возможны 2 варианта :
- Если конфликты неявок не будут обнаружены, то подписка на событие отработает, не оставив после себя никаких видимых следов.
- Если конфликт неявок будет обнаружен, то документ будет проведён, но пользователю на экран выдастся табличка с сообщением такого вида:
Интервал конфликтных дат в этом информационном сообщении будет ТОЧНЫМ, то есть - в сообщении будут указаны только те календарные даты, за которые конфликтует проводимый документ со всеми другими проведёнными документами.
Примечание : поскольку никакие виды документов и никакие виды неявок в представленном мной коде явно не поименованы, этот код не нужно будет модифицировать при добавлении «своих» видов документов (например, «Отзыв из отпуска», «Отзыв из командировки») или при добавлении «своих» видов неявок.