При разработке конфигураций с нуля часто возникает задача учета времени нахождения сотрудника в системе. Это может быть как простая фиксация входа/выхода, так и полноценный расчет отработанных часов за месяц. В этой статье мы подробно разберем, как реализовать механизм расчета рабочего времени, используя данные из регистра сведений, и как оптимизировать пользовательский интерфейс для удобной работы с подсистемами.
Первый и наиболее профессиональный способ — это использование языка запросов 1С. Если ваша таблица (регистр сведений) хранит записи линейно (например: Дата-Событие), то для получения интервала «Вход-Выход» нам необходимо соединить таблицу саму с собой. Рассмотрим ситуацию, когда у нас есть записи о времени входа и времени выхода.
Для того чтобы вычислить разницу, нам нужно сопоставить каждой записи о входе ближайшую по времени запись о выходе. Разберем логику построения такого запроса:
ВЫБРАТЬ
Слева.Сотрудник КАК Сотрудник,
Слева.Период КАК ВремяВхода,
МИНИМУМ(Справа.Период) КАК ВремяВыхода
ИЗ
РегистрСведений.ИсторияДоступа КАК Слева
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ИсторияДоступа КАК Справа
ПО Слева.Сотрудник = Справа.Сотрудник
И Слева.Период < Справа.Период
И Справа.ВидСобытия = ЗНАЧЕНИЕ(Перечисление.ВидыСобытийДоступа.Выход)
ГДЕ
Слева.ВидСобытия = ЗНАЧЕНИЕ(Перечисление.ВидыСобытийДоступа.Вход)
СГРУППИРОВАТЬ ПО
Слева.Сотрудник,
Слева.Период
Проанализируем этот код: мы берем таблицу Слева (только входы) и присоединяем к ней таблицу Справа (только выходы), где время выхода больше времени входа. Функция МИНИМУМ позволяет нам найти именно тот выход, который случился сразу после входа, не захватывая последующие дни.
Если задача стоит проще — например, при нажатии кнопки на форме вывести, сколько времени текущий пользователь уже провел в системе (с момента последнего входа до текущего системного времени), — мы можем обойтись без сложных соединений в запросе. Выясним, как это сделать программно.
Тип Дата в 1С хранит в себе и календарный день, и время с точностью до секунды. При вычитании одной даты из другой платформа возвращает результат в виде числа секунд. Разберем по шагам алгоритм расчета:
ТекущаяДата().Рассмотрим пример кода для обработки нажатия кнопки:
&НаСервере
Функция ПолучитьРабочееВремяНаСервере()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ИсторияДоступа.Период КАК ВремяВхода
|ИЗ
| РегистрСведений.ИсторияДоступа КАК ИсторияДоступа
|ГДЕ
| ИсторияДоступа.Пользователь = &ТекущийПользователь
| И ИсторияДоступа.ВидСобытия = ЗНАЧЕНИЕ(Перечисление.ВидыСобытийДоступа.Вход)
|УПОРЯДОЧИТЬ ПО
| Период УБЫВ";
Запрос.УстановитьПараметр("ТекущийПользователь", Пользователи.ТекущийПользователь());
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Возврат "Данные о входе не найдены";
КонецЕсли;
Выборка = РезультатЗапроса.Выбрать();
Выборка.Следующий();
ОбщееКоличествоСекунд = ТекущаяДата() - Выборка.ВремяВхода;
Часы = Цел(ОбщееКоличествоСекунд / 3600);
Минуты = Цел((ОбщееКоличествоСекунд % 3600) / 60);
Возврат СтрШаблон("Вы работаете уже: %1 ч. %2 мин.", Часы, Минуты);
КонецФункции
В этом примере мы использовали функцию Цел() для получения целого количества часов и оператор % (остаток от деления) для вычисления оставшихся минут. Это наиболее эффективный способ быстрого расчета «на лету».
Разберем ситуацию, когда пользователь не нажал кнопку выхода или произошел сбой системы. В этом случае запись в ваш самописный регистр может не попасть. Профессиональный подход подразумевает использование данных Журнала регистрации.
Платформа 1С автоматически фиксирует события начала и завершения сеанса. Мы можем получить эти данные программно, используя метод ВыгрузитьЖурналРегистрации(). Основные события, которые нас интересуют: _$Session$_.Start и _$Session$_.Finish.
Преимущества этого метода:
Перейдем ко второй части вопроса автора — удобству навигации. В управляемых формах 1С 8.3 существует два основных режима отображения открытых окон, которые настраиваются пользователем или администратором. Если вы хотите, чтобы работа в 1С была похожа на работу в браузере, необходимо выполнить следующие действия.
Чтобы формы не открывались в отдельных окнах и их не приходилось закрывать по одной, перейдем в меню Сервис — Параметры (в верхнем правом углу). В разделе «Внешний вид» выберем пункт «Интерфейс в закладках». Теперь каждое новое окно (справочник, документ или отчет) будет открываться как новая вкладка. Пользователь сможет быстро переключаться между ними, а не закрывать их для возврата на главную страницу.
Если стоит задача принудительно закрывать все открытые документы при переходе пользователя в другую подсистему (например, в раздел «Главная»), можно воспользоваться методом встроенного языка ПолучитьОкна(). Рассмотрим пример реализации:
&НаКлиенте
Процедура ЗакрытьВсеОкнаКромеГлавного()
СписокОкон = ПолучитьОкна();
Для Каждого ТекущееОкно Из СписокОкон Цикл
Если НЕ ТекущееОкно.Основное И НЕ ТекущееОкно.Главное Тогда
ТекущееОкно.Закрыть();
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Этот код перебирает все открытые в данный момент окна приложения. Свойство Основное указывает на то, является ли окно главным окном приложения. Закрывая все остальные, мы фактически «очищаем» рабочее пространство пользователя.
Выясним, как сделать расчет времени еще более точным. В крупных компаниях часто сталкиваются с проблемой «зависших» сессий. Если сотрудник ушел домой, не закрыв 1С, счетчик рабочего времени будет продолжать идти. Чтобы этого избежать, проанализируем следующие инструменты:
ПО Слева.Дата < Справа.Дата можно использовать оконную функцию LEAD. Это значительно ускорит получение данных на больших объемах (десятки тысяч записей).Таким образом, мы рассмотрели комплексный подход к решению задачи: от простого вычитания дат до сложных аналитических запросов и настройки интерфейса «под пользователя». Используя эти методы, вы сможете создать надежную систему учета времени в любой конфигурации 1С.