gifts2017

Проверка пересечения кадровых неявок, отпусков, командировок

Опубликовал Сергей Смирнов (smirnov0ser) в раздел Программирование - Практика программирования

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

В работе кадрового отдела часто возникают ситуации, когда пересекаются периоды отпусков, командировок или болезней.
Например, больничный сотрудника 11.05 - 20.05. Но вводится кадровый отпуск отпуск с 18.05.
При этом рассчетчики, формируя документы через АнализНеявок, получают неверные данные: больничный создается с 11.05 по 17.05.
Чтобы избежать подобных проблем, предлагаю контроль пересечений кадровых отклонений, найденные пересечения сообщаются пользователю. Реализовано это подпиской на события "Обработка проведения" документов "ОтпускаОрганизаций", "НеявкиИБолезниОрганизаций", и "КомандировкиОрганизаций".

Ниже код, который желательно поместить в отдельный модуль и в подписке на события выбрать процедуру "ОбработкаПроведенияКонтрольПересеченияНеявкиИБолезни()".

Процедура ОбработкаПроведенияКонтрольПересеченияНеявкиИБолезни(Источник,Отказ, Режим)   Экспорт
	
	Если ТипЗнч(Источник) = тип("ДокументОбъект.НеявкиИБолезниОрганизаций") Тогда
	
		//если несколько строк в ТЧ, то нужно фиктивно нарисовать им дату окончания
		ТЧ=источник.РаботникиОрганизации.Выгрузить();
		ТЧ.Сортировать("Сотрудник,ДатаНачала");
		НайденоОкончание=Ложь;
		ПоследнийП=ТЧ.Количество()-1;
		Для п=0 по ПоследнийП Цикл
			Сотрудник=ТЧ[п].Сотрудник;
			Если п<>ПоследнийП и ТЧ[п].Сотрудник=ТЧ[п+1].Сотрудник Тогда
				НайденоОкончание=Истина;
				Если ТЧ.Колонки.Найти("ДатаОкончания")=неопределено Тогда
					ТЧ.Колонки.Добавить("ДатаОкончания",новый ОписаниеТипов("Дата"));
				КонецЕсли;
				ТЧ[п].ДатаОкончания=ТЧ[п+1].ДатаНачала-86400;
			КонецЕсли;
			п=п+1;
		КонецЦикла;
		
		Запрос = Новый Запрос;
		Запрос.УстановитьПараметр("ТЧ",ТЧ);	
		Запрос.УстановитьПараметр("ПричинаОтсутствияРаботает",Перечисления.СостоянияРаботникаОрганизации.Работает);
		
		//если есть фиктивная дата окончания
		Если НайденоОкончание Тогда
			//КОНТРОЛЬ ОШИБОК С ДАТОЙ ЗАВЕРШЕНИЯ
			Запрос.Текст = ПолучитьТекстЗапросаДляСостоянияСДатойОкончания();
			СообщитьПользователюКонфликтыСДатойОкончания(Запрос);
			
			//удаляем строки с датой завершения
			п=0;
			пока п < ТЧ.Количество() Цикл
				Если ЗначениеЗаполнено(ТЧ[п].ДатаОкончания) Тогда
					ТЧ.Удалить(п);
				Иначе
					п=п+1;
				КонецЕсли;
			КонецЦикла;
			
			//КОНТРОЛЬ ОШИБОК БЕЗ ДАТЫ ЗАВЕРШЕНИЯ
		    Запрос.Текст = вернутьТекстЗапросаДляСостоянияБезДатыОкончания();
		    СообщитьПользователюКонфликтыБезДатыОкончания(Запрос);
			
		Иначе   //нет фиктивной даты окончания
			//КОНТРОЛЬ ОШИБОК БЕЗ ДАТЫ ЗАВЕРШЕНИЯ
			Запрос.Текст = вернутьТекстЗапросаДляСостоянияБезДатыОкончания();
			СообщитьПользователюКонфликтыБезДатыОкончания(Запрос);
		КонецЕсли;



	ИначеЕсли ТипЗнч(Источник) = тип("ДокументОбъект.ОтпускаОрганизаций") Тогда
		
		//КОНТРОЛЬ ОШИБОК С ДАТОЙ ЗАВЕРШЕНИЯ
		Запрос = Новый Запрос;
		Запрос.Текст = ПолучитьТекстЗапросаДляСостоянияСДатойОкончания();

		Запрос.УстановитьПараметр("ТЧ",источник.РаботникиОрганизации);	
		Запрос.УстановитьПараметр("ПричинаОтсутствияРаботает",Перечисления.СостоянияРаботникаОрганизации.Работает);
		Запрос.УстановитьПараметр("СостояниеКомандировка",Перечисления.СостоянияРаботникаОрганизации.ОтпускЕжегодный);

        СообщитьПользователюКонфликтыСДатойОкончания(Запрос);
		
		
		
	ИначеЕсли ТипЗнч(Источник) = тип("ДокументОбъект.КомандировкиОрганизаций") Тогда
		
		//запрос с указанной датой окончания
		Запрос = Новый Запрос;
		

		//причина отсутствия у этого документа - командировка
		ТЗ=источник.РаботникиОрганизации.Выгрузить();
		ТЗ.Колонки.Добавить("ПричинаОтсутствия",новый ОписаниеТипов("ПеречислениеСсылка.СостоянияРаботникаОрганизации"));
		ТЗ.ЗаполнитьЗначения(Перечисления.СостоянияРаботникаОрганизации, "ПричинаОтсутствия");
		
		
		Запрос.УстановитьПараметр("ТЧ",ТЗ);	
		Запрос.УстановитьПараметр("ПричинаОтсутствияРаботает",Перечисления.СостоянияРаботникаОрганизации.Работает);
		
		//КОНТРОЛЬ ОШИБОК С ДАТОЙ ЗАВЕРШЕНИЯ
		Запрос.Текст = ПолучитьТекстЗапросаДляСостоянияСДатойОкончания();
        СообщитьПользователюКонфликтыСДатойОкончания(Запрос);

		
		//КОНТРОЛЬ ОШИБОК БЕЗ ДАТЫ ЗАВЕРШЕНИЯ
		
		//удаляем строки с датой завершения
		п=0;
		пока п < ТЗ.Количество() Цикл
			Если ЗначениеЗаполнено(ТЗ[п].ДатаОкончания) Тогда
				ТЗ.Удалить(п);
			Иначе
				п=п+1;
			КонецЕсли;
		КонецЦикла;
		
		Запрос.Текст = вернутьТекстЗапросаДляСостоянияБезДатыОкончания();		
        СообщитьПользователюКонфликтыБезДатыОкончания(Запрос);
		
		

	КонецЕсли;
	
КонецПроцедуры

Функция вернутьТекстЗапросаДляСостоянияБезДатыОкончания()
	Возврат
	"ВЫБРАТЬ
	|	ТЧ.Сотрудник КАК Сотрудник,
	|	ТЧ.ПричинаОтсутствия КАК ПричинаОтсутствия,
	|	ТЧ.ДатаНачала КАК ДатаНачала
	|ПОМЕСТИТЬ Таблица
	|ИЗ
	|	&ТЧ КАК ТЧ
	|;
	|
	| X 
	|ВЫБРАТЬ
	|	МАКСИМУМ(СостояниеРаботниковОрганизаций.Период) КАК Период,
	|	Таблица.Сотрудник
	|ПОМЕСТИТЬ ПериодыСвязи
	|ИЗ
	|	Таблица КАК Таблица
	|		ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СостояниеРаботниковОрганизаций КАК СостояниеРаботниковОрганизаций
	|		ПО Таблица.Сотрудник = СостояниеРаботниковОрганизаций.Сотрудник
	|			И Таблица.ДатаНачала >= СостояниеРаботниковОрганизаций.Период
	|ГДЕ
	|	Таблица.ПричинаОтсутствия <> &ПричинаОтсутствияРаботает
	|
	|СГРУППИРОВАТЬ ПО
	|	Таблица.Сотрудник
	|;
	|
	| X 
	|ВЫБРАТЬ
	|	МИНИМУМ(СостояниеРаботниковОрганизаций.Период) КАК Период,
	|	Таблица.Сотрудник
	|ПОМЕСТИТЬ ПериодыСвязиПосле
	|ИЗ
	|	Таблица КАК Таблица
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СостояниеРаботниковОрганизаций КАК СостояниеРаботниковОрганизаций
	|		ПО Таблица.Сотрудник = СостояниеРаботниковОрганизаций.Сотрудник
	|			И Таблица.ДатаНачала  &ПричинаОтсутствияРаботает
	|
	|СГРУППИРОВАТЬ ПО
	|	Таблица.Сотрудник
	|;
	|
	| X 
	|ВЫБРАТЬ
	|	Таблица.Сотрудник,
	|	Таблица.ПричинаОтсутствия КАК НовоеСостояние,
	|	ЕСТЬNULL(ВЫБОР
	|			КОГДА СостояниеРаботниковОрганизаций.ПериодЗавершения <> ДАТАВРЕМЯ(1, 1, 1)
	|					И СостояниеРаботниковОрганизаций.ПериодЗавершения  ДАТАВРЕМЯ(1, 1, 1)
	|					И СостояниеРаботниковОрганизаций.ПериодЗавершения  ДАТАВРЕМЯ(1, 1, 1)
	|						И СостояниеРаботниковОрганизаций.ПериодЗавершения  &ПричинаОтсутствияРаботает
	|;
	|
	| X 
	|ВЫБРАТЬ
	|	Таблица.Сотрудник,
	|	Таблица.ПричинаОтсутствия КАК НовоеСостояние,
	|	СостояниеРаботниковОрганизаций.Состояние КАК ТекущееСостояние,
	|	СостояниеРаботниковОрганизаций.Регистратор,
	|	СостояниеРаботниковОрганизаций.Период,
	|	Таблица.ДатаНачала
	|ИЗ
	|	Таблица КАК Таблица
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПериодыСвязиПосле КАК ПериодыСвязиПосле
	|			ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СостояниеРаботниковОрганизаций КАК СостояниеРаботниковОрганизаций
	|			ПО ПериодыСвязиПосле.Сотрудник = СостояниеРаботниковОрганизаций.Сотрудник
	|				И ПериодыСвязиПосле.Период = СостояниеРаботниковОрганизаций.Период
	|		ПО Таблица.Сотрудник = ПериодыСвязиПосле.Сотрудник
	|ГДЕ
	|	СостояниеРаботниковОрганизаций.Состояние <> &ПричинаОтсутствияРаботает"
КонецФункции

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

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

Процедура СообщитьПользователюКонфликтыСДатойОкончания(Запрос)
		Результат = Запрос.ВыполнитьПакет();
		ВыборкаНаНачало = Результат[3].Выбрать();
		Пока ВыборкаНаНачало.Следующий() Цикл
			Сообщить("Внимание! "+ВыборкаНаНачало.Сотрудник+" из состояния """+ВыборкаНаНачало.ТекущееСостояние+"("+Формат(ВыборкаНаНачало.ДатаТекущегоСостояния,"ДФ=dd.MM.yyyy")+")"" переходт в состояние """+ВыборкаНаНачало.НовоеСостояние+" ("+Формат(ВыборкаНаНачало.ДатаНачала,"ДФ=dd.MM.yyyy")+")"" (документ "+ВыборкаНаНачало.Регистратор+")");
		КонецЦикла;
		
		ВыборкаВМомент = Результат[4].Выбрать();
		Пока ВыборкаВМомент.Следующий() Цикл
			Сообщить("Внимание! "+ВыборкаВМомент.Сотрудник+" "+Формат(ВыборкаВМомент.ДатаИзменения,"ДФ=dd.MM.yyyy")+" переходт в состояние """+ВыборкаВМомент.ТекущееСостояние+""" (документ "+ВыборкаВМомент.Регистратор+")");
		КонецЦикла;

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

Скачать файлы

Наименование Файл Версия Размер Кол. Скачив.
Новый общий модуль
.txt 15,01Kb
20.12.13
94
.txt 15,01Kb 94 Скачать

См. также

Вознаграждение за ответ
Сумма: 0 $m
Добавили:
Nick Bylichev (colco) (0.40 $m)
Подписаться Добавить вознаграждение

Комментарии

1. наташа (pattyx) 23.09.13 15:52
Склоняюсь к тому, чтобы подобным образом сделать у нас. Кадры утверждают, что раньше кадровые "Неявки и болезни" не проводились, ругались, если для сотрудника был введен документ "Отпуска организаций"). Скажите пожалуйста, так ли это, если существует типовой механизм, то как его настроить?
2. Сергей Смирнов (smirnov0ser) 24.09.13 11:43
Если неявка и отпуск будут введены одним днем, тогда программа будет ругаться. Так как оба документа пишут данные в регистр СостояниеРаботниковОрганизаций с периодичностью день.
А данные подписки на события позволят видеть, какое состояние прерываем мы новым приказом, и какие состояния прервут наш приказ.
Типового механизма нет.
3. Алексей Беспалов (FreeArcher) 20.12.13 15:46
(1) Вот и мне тоже высказали, что раньше или, где то там у них программа ругалась, а у меня не ругается...
Придется че-то приколхозить, чтобы не быть плохим программистом, а то у других то ругается, а у меня нет ))
4. Алексей Беспалов (FreeArcher) 20.12.13 16:05
Вот тут запрос недописан:
    |ВЫБРАТЬ
            |    ТаблицаТЧ.Сотрудник,
            |    ЕСТЬNULL(ВЫБОР
            |            КОГДА СостояниеРаботниковОрганизаций.ПериодЗавершения <> ДАТАВРЕМЯ(1, 1, 1)
            |                    И СостояниеРаботниковОрганизаций.ПериодЗавершения  ДАТАВРЕМЯ(1, 1, 1)
            |                    И СостояниеРаботниковОрганизаций.ПериодЗавершения  ДАТАВРЕМЯ(1, 1, 1)
            |                    И СостояниеРаботниковОрганизаций.ПериодЗавершения  ДАТАВРЕМЯ(1, 1, 1)
            |                        И СостояниеРаботниковОрганизаций.ПериодЗавершения  &ПричинаОтсутствияРаботает
...Показать Скрыть


надо тогда и что там будет
5. Сергей Смирнов (smirnov0ser) 20.12.13 16:59
(4) FreeArcher,
И правда, почему-то при сохранении публикации код запроса портится (независимо от раскраски).
Скачай файл или, если хочешь, вышлю код в личку.

P.S. Обновил публикацию, теперь корректно отрабатываются несколько строк по сотруднику в одном документе.
6. Алексей Беспалов (FreeArcher) 20.12.13 19:00
(5) Спасибо, а вот ты не решал эту же проблему, только если зарплатчики не пользуются кадровыми документами, а только "Расчет отпуска сотрудников организации" и т.д. ?
7. Деля (adelya) 20.12.13 19:36
(6) для этого в настройках Учетной политики на закладке расчет зарплаты есть параметр контролировать пересечение периодов начислений контролирующих норму времени
FreeArcher; +1 Ответить
8. Деля (adelya) 20.12.13 21:14
Очень нужная вещь, у нас примерно 5000 сотрудников, а так как в программе нет контроля пересечения периодов по кадрам, (как правильно заметил автор - если период не один день), просто необходима. Интегрировала в нашу УПП 1.3 - проверила на двух документах - Все работает!. без единого вмешательства в процедуру. Огромное спасибо автору. Завтра покажу кадрам :-)
9. Михаил Суслов (MisSus) 24.02.14 15:06
Спасибо большое, обработка работает хорошо.
Хотелось ещё (если возможно), чтобы при наложении периодов, документ всё-же не проводился. А то о наложении периодов сообщает, но при этом документ всё же проводится.
10. Сергей Смирнов (smirnov0ser) 24.02.14 15:31
(9), Подразумевается, что пересечение периодов не всегда является ошибкой. Но можно и запрещать проводить:
в процедуры СообщитьПользователюКонфликтыБезДатыОкончания(Запрос) и СообщитьПользователюКонфликтыСДатойОкончания(Запрос) передавайте "Отказ", а при наступлении ошибки нужного вида присваивайте Отказ=Истина;
11. Андрей Ро (AndrewVVS) 30.06.14 12:08
(5) smirnov0ser, а можешь в самой публикации данный текст запроса подредактировать, а то просто "взрыв мозга" происходит при анализе этого куска запроса )). Или в комменте написать, что там конкретно имелось ввиду? А вариант переделки типового запроса - функции "СформироватьЗапросПоРаботникиОрганизации" - не рассматривали?
12. Сергей Смирнов (smirnov0ser) 24.07.14 12:17
(11)AndrewVVS, при сохранении публикации текст запроса "портится", ничего не могу поделать - качай файл.
Не вижу смысла переделывать типовой запрос, в этом случае обновление конфигурации проходит значительно сложнее, чем в случае использования подписки на событие.
13. Алена Андреевна (00alenka00) 24.07.14 17:37
В ОбработкаПроведенияКонтрольПересеченияНеявкиИБолезни(Источник,Отказ, Режим) при обработке документа Коммандировки организаций не дописал причину отсутствия.
И в публикации и в файле тоже самое.
ТЗ.ЗаполнитьЗначения(Перечисления.СостоянияРаботникаОрганизации, "ПричинаОтсутствия");
Значение перечисления Командировка не выбрано.

14. Алена Андреевна (00alenka00) 24.07.14 17:48
Еще переделала выдаваемые сообщение на 1совскую обработку комментариев.
Там много удобнее, в документы пересекающиеся сразу по ссылке зайти можно.
15. Сергей Смирнов (smirnov0ser) 25.07.14 12:00
(13)00alenka00, действительно, не дописал. Но это значение используется только при выводе сообщения).
Исправлю при следующем обновлении
18. Степан Шушаков (Hawk_sib) 24.12.14 12:50
спасибо, хорошая идея по реализации, от себя могу сказать, что регистр сведений "состояния работников организаций" в зупе хороший, но выходит проконтроировать до конца у разработчиков его не получилось, сам не так давно столкнулся несколько с иной проблемой http://infostart.ru/public/316095/
19. Сергей Докторов (doctorov_s) 17.09.15 10:02
Кто то может скинуть нормальный код на почту doctorov_s@mail.ru заранее спасибо!
20. Евгений Чудов (bpirate999) 24.08.16 13:22
Здравствуйте
У вас есть готовый файл Проверка пересечения кадровых неявок, отпусков, командировок? Могли бы поделиться
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа