Получение нормы времени между двумя датами из Производственного календаря

06.05.20

Разработка - Универсальные функции

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

Была поставлена задача автоматизировать ручной расчет сверхурочных часов по очень "замудренной" формуле, в которой нужно получить норму времени между двумя определенными датами из Производственного календаря.

 

 

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

&НаСервере
Функция ДанныеПроизводственногоКалендаря(ДатаНач,ДатаОконч,Помесячно);
	
	Времянка = Новый ТаблицаЗначений;
	Времянка.Колонки.Добавить("Дата",Новый ОписаниеТипов("Дата"));
	Времянка.Колонки.Добавить("ВидДня",Новый ОписаниеТипов("ПеречислениеСсылка.ВидыДнейПроизводственногоКалендаря"));
	Времянка.Колонки.Добавить("ДатаПереноса",Новый ОписаниеТипов("Дата"));
	Времянка.Колонки.Добавить("РабДни",Новый ОписаниеТипов("Число"));
	Времянка.Колонки.Добавить("Часы",Новый ОписаниеТипов("Число"));
	Времянка.Колонки.Добавить("Празд",Новый ОписаниеТипов("Число"));
	Времянка.Колонки.Добавить("Выходные",Новый ОписаниеТипов("Число"));
	
	Если Помесячно Тогда
		// "Раскладываем период ДатаНач,ДатаОконч по месяцам и для каждого месяца выполняем Запрос
	КонецЕсли;
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	ДанныеПроизводственногоКалендаря.Дата КАК Дата,
		|	ДанныеПроизводственногоКалендаря.ВидДня КАК ВидДня,
		|	ДанныеПроизводственногоКалендаря.ДатаПереноса КАК ДатаПереноса
		|ИЗ
		|	РегистрСведений.ДанныеПроизводственногоКалендаря КАК ДанныеПроизводственногоКалендаря
		|ГДЕ
		|	ДанныеПроизводственногоКалендаря.Дата МЕЖДУ &ДатаНач И &ДатаОконч
		|
		|УПОРЯДОЧИТЬ ПО
		|	Дата";
	
	Запрос.УстановитьПараметр("ДатаНач", ДатаНач);
	Запрос.УстановитьПараметр("ДатаОконч", КонецДня(ДатаОконч));
	
	РезультатЗапроса = Запрос.Выполнить();
	
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
	
	ЧасДень = 8; //Кол-во часов в день при 40-часовой рабочей неделе
	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
		НС = Времянка.Добавить();
		НС.Дата = ВыборкаДетальныеЗаписи.Дата;
		НС.ВидДня = ВыборкаДетальныеЗаписи.ВидДня;
		НС.ДатаПереноса = ВыборкаДетальныеЗаписи.ДатаПереноса;
		Если ВыборкаДетальныеЗаписи.ВидДня = Перечисления.ВидыДнейПроизводственногоКалендаря.Рабочий
			ИЛИ ВыборкаДетальныеЗаписи.ВидДня = Перечисления.ВидыДнейПроизводственногоКалендаря.Предпраздничный Тогда
		НС.РабДни = 1;
		КонецЕсли;
		ЧасыРаб = ?(ВыборкаДетальныеЗаписи.ВидДня = Перечисления.ВидыДнейПроизводственногоКалендаря.Рабочий,ЧасДень,0);
		ЧасыПр = ?(ВыборкаДетальныеЗаписи.ВидДня = Перечисления.ВидыДнейПроизводственногоКалендаря.Предпраздничный,ЧасДень-1,0);
		НС.Часы = ЧасыРаб + ЧасыПр;
		НС.Празд = ?(ВыборкаДетальныеЗаписи.ВидДня = Перечисления.ВидыДнейПроизводственногоКалендаря.Праздник,1,0);
		Суббота = ?(ВыборкаДетальныеЗаписи.ВидДня = Перечисления.ВидыДнейПроизводственногоКалендаря.Суббота,1,0);
		Воскресенье = ?(ВыборкаДетальныеЗаписи.ВидДня = Перечисления.ВидыДнейПроизводственногоКалендаря.Воскресенье,1,0);
		НС.Выходные = Суббота + Воскресенье;
	КонецЦикла;
	РабДни = Времянка.Итог("РабДни");
	Часы = Времянка.Итог("Часы");
	Празд = Времянка.Итог("Празд");
	Выходные = Времянка.Итог("Выходные");
	
	ВыбрРеквизиты = Новый Структура("РабДни,Часы,Празд,Выходные");
		
	ВыбрРеквизиты.Вставить("РабДни",РабДни);
	ВыбрРеквизиты.Вставить("Часы",Часы);
	ВыбрРеквизиты.Вставить("Празд",Празд);
	ВыбрРеквизиты.Вставить("Выходные",Выходные);
	Возврат ВыбрРеквизиты;
	
КонецФункции

Писал под свою конкретную задачу, возможно еще кому-нибудь пригодится. Камнями прошу сильно не кидаться, я самоучка, а не профессионал. Если у кого есть более "правильный" и компактный вариант, можете поделиться, буду рад.

Тестировалась на платформе 8.3.17, релиз 3.1.13.151, но думаю, что будет работать на любом релизе.

Вступайте в нашу телеграмм-группу Инфостарт

Получить норму времени из Производственного календаря.

См. также

Загрузка и выгрузка в Excel Универсальные функции Программист 1С:Предприятие 8 Россия Бесплатно (free)

Описанный ниже подход позволяет в три шага заполнять формулы в Excel файлы, вне зависимости от ОС сервера (MS Windows Server или Linux). Подход подразумевает отказ от работы с COM-объектом в пользу работы через "объектную модель документа" (DOM).

30.10.2025    2549    Abysswalker    7    

41

Универсальные функции Работа с интерфейсом Программист 1С:Предприятие 8 Бесплатно (free)

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

14.05.2025    5572    DeerCven    15    

57

Универсальные функции Программист 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

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

21.05.2024    46781    dimanich70    83    

165

Универсальные функции Программист 1С:Предприятие 8 1C:Бухгалтерия Абонемент ($m)

Задача: вставить картинку из буфера обмена на форму средствами платформы 1С.

1 стартмани

18.03.2024    6910    6    John_d    13    

59

Универсальные функции Программист Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Пришлось помучиться с GUID-ами немного, решил поделиться опытом, мало ли кому пригодится.

12.02.2024    58057    atdonya    31    

68

Универсальные функции Программист 1С:Предприятие 8 Бесплатно (free)

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

30.11.2023    8686    ke.92@mail.ru    17    

68
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. vkozak 07.05.20 14:49 Сейчас в теме
Забавно. Буду решать подобную задачу воспользуюсь идеей.
2. ivnik 624 07.05.20 18:46 Сейчас в теме
(1) Когда мне что-то нравиться, я обычно ставлю Плюсик и сохраняю в "Избранное", чтобы когда понадобиться, не долго искать.
3. pepper62 12.05.20 13:11 Сейчас в теме
Вот Вам немножко типового функционала с двумя вариантами. В "бою" используется первый.


&НаСервере
Функция ПолучитьНормуФактВремени(ТаблицаСотрудников, МесяцПолучения)

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


&НаСервере
Функция ПолучитьВТСотрудники(ТаблицаСотрудников)
	МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;
	
	МассивСотрудников = ТаблицаСотрудников.ВыгрузитьКолонку("Сотрудник");
	
	
	Запрос = Новый Запрос(
	"ВЫБРАТЬ
	|    ТаблицаСотрудники.Сотрудник,
	|    ТаблицаСотрудники.Месяц,
	|    ТаблицаСотрудники.ДатаАктуальности,        
	|    ТаблицаСотрудники.ДатаНачала,
	|    ТаблицаСотрудники.ДатаОкончания
	|ПОМЕСТИТЬ ВТСотрудники
	|ИЗ
	|    &ТаблицаСотрудники КАК ТаблицаСотрудники");
	
	Запрос.МенеджерВременныхТаблиц = МенеджерВременныхТаблиц;
	Запрос.УстановитьПараметр("ТаблицаСотрудники", ТаблицаСотрудников);
	Запрос.Выполнить();
	
	Возврат МенеджерВременныхТаблиц;
КонецФункции
Показать
Dziden; user_2010; +2 Ответить
4. ivnik 624 12.05.20 14:02 Сейчас в теме
(3) Большое Спасибо!!! Очень интересный вариант.
5. charivnick 46 09.03.22 13:18 Сейчас в теме
Все хорошо, только норма рассчитанная через УчетРабочегоВремениРасширенный, не обязательно будет соответствовать норме по
производственному календарю. Поэтому пока вариант расчета нормы, предложенный автором, единственный.
6. kvikster 95 08.04.22 23:46 Сейчас в теме
Возможно кому-то потребуются сумма часов за период:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ДанныеПроизводственногоКалендаря.ПроизводственныйКалендарь КАК ПроизводственныйКалендарь,
| СУММА(1) КАК КалендарныхДней,
| СУММА(ВЫБОР
| КОГДА ДанныеПроизводственногоКалендаря.ВидДня В (ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий), ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный))
| ТОГДА 1
| ИНАЧЕ 0
| КОНЕЦ) КАК РабочихДней,
| СУММА(ВЫБОР
| КОГДА ДанныеПроизводственногоКалендаря.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)
| ТОГДА &Часов / 5
| КОГДА ДанныеПроизводственногоКалендаря.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный)
| ТОГДА &Часов / 5 - 1
| ИНАЧЕ 0
| КОНЕЦ) КАК РабочихЧасовДлительностьНедели
|ИЗ
| РегистрСведений.ДанныеПроизводственногоКалендаря КАК ДанныеПроизводственногоКалендаря
|ГДЕ
| ДанныеПроизводственногоКалендаря.Дата >= &ДатаНачала
| И ДанныеПроизводственногоКалендаря.Дата <= &ДатаОкончания
| И ДанныеПроизводственногоКалендаря.ПроизводственныйКалендарь = &ПроизводственныйКалендарь
|
|СГРУППИРОВАТЬ ПО
| ДанныеПроизводственногоКалендаря.ПроизводственныйКалендарь
|
|УПОРЯДОЧИТЬ ПО
| ПроизводственныйКалендарь";

Запрос.УстановитьПараметр("Часов", ?(ДлительностьРабочейНедели>0,ДлительностьРабочейНедели,40));
Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания);
Запрос.УстановитьПараметр("ПроизводственныйКалендарь", Объект.Календарь);

РезультатЗапроса = Запрос.Выполнить();

ВДЗ = РезультатЗапроса.Выбрать();

Пока ВДЗ.Следующий() Цикл
ТС.НормаПоКалендарю = ВДЗ.РабочихЧасовДлительностьНедели;
КонецЦикла;
Для отправки сообщения требуется регистрация/авторизация