Как реализовать расчет рабочего времени и настроить навигацию в 1С 8.3

Программист 1С v8.3 (Управляемые формы) Управленческий учет IT и автоматизация бизнеса
← На главную

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

Метод 1: Получение интервалов времени через запрос (Self-join)

Первый и наиболее профессиональный способ — это использование языка запросов 1С. Если ваша таблица (регистр сведений) хранит записи линейно (например: Дата-Событие), то для получения интервала «Вход-Выход» нам необходимо соединить таблицу саму с собой. Рассмотрим ситуацию, когда у нас есть записи о времени входа и времени выхода.

Для того чтобы вычислить разницу, нам нужно сопоставить каждой записи о входе ближайшую по времени запись о выходе. Разберем логику построения такого запроса:


ВЫБРАТЬ
    Слева.Сотрудник КАК Сотрудник,
    Слева.Период КАК ВремяВхода,
    МИНИМУМ(Справа.Период) КАК ВремяВыхода
ИЗ
    РегистрСведений.ИсторияДоступа КАК Слева
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ИсторияДоступа КАК Справа
        ПО Слева.Сотрудник = Справа.Сотрудник
        И Слева.Период < Справа.Период
        И Справа.ВидСобытия = ЗНАЧЕНИЕ(Перечисление.ВидыСобытийДоступа.Выход)
ГДЕ
    Слева.ВидСобытия = ЗНАЧЕНИЕ(Перечисление.ВидыСобытийДоступа.Вход)
СГРУППИРОВАТЬ ПО
    Слева.Сотрудник,
    Слева.Период

Проанализируем этот код: мы берем таблицу Слева (только входы) и присоединяем к ней таблицу Справа (только выходы), где время выхода больше времени входа. Функция МИНИМУМ позволяет нам найти именно тот выход, который случился сразу после входа, не захватывая последующие дни.

Метод 2: Программный расчет разницы во времени на встроенном языке

Если задача стоит проще — например, при нажатии кнопки на форме вывести, сколько времени текущий пользователь уже провел в системе (с момента последнего входа до текущего системного времени), — мы можем обойтись без сложных соединений в запросе. Выясним, как это сделать программно.

Тип Дата в 1С хранит в себе и календарный день, и время с точностью до секунды. При вычитании одной даты из другой платформа возвращает результат в виде числа секунд. Разберем по шагам алгоритм расчета:

  1. Получаем из регистра сведений последнюю запись о входе текущего пользователя.
  2. Получаем текущее системное время с помощью функции ТекущаяДата().
  3. Вычитаем из текущего времени время входа.
  4. Преобразуем секунды в человекочитаемый формат (часы и минуты).

Рассмотрим пример кода для обработки нажатия кнопки:


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

В этом примере мы использовали функцию Цел() для получения целого количества часов и оператор % (остаток от деления) для вычисления оставшихся минут. Это наиболее эффективный способ быстрого расчета «на лету».

Метод 3: Использование системного Журнала регистрации

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

Платформа 1С автоматически фиксирует события начала и завершения сеанса. Мы можем получить эти данные программно, используя метод ВыгрузитьЖурналРегистрации(). Основные события, которые нас интересуют: _$Session$_.Start и _$Session$_.Finish.

Преимущества этого метода:

Настройка интерфейса: управление окнами и закладками

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

Режим отображения «В закладках»

Чтобы формы не открывались в отдельных окнах и их не приходилось закрывать по одной, перейдем в меню Сервис — Параметры (в верхнем правом углу). В разделе «Внешний вид» выберем пункт «Интерфейс в закладках». Теперь каждое новое окно (справочник, документ или отчет) будет открываться как новая вкладка. Пользователь сможет быстро переключаться между ними, а не закрывать их для возврата на главную страницу.

Программное закрытие всех окон при смене раздела

Если стоит задача принудительно закрывать все открытые документы при переходе пользователя в другую подсистему (например, в раздел «Главная»), можно воспользоваться методом встроенного языка ПолучитьОкна(). Рассмотрим пример реализации:


&НаКлиенте
Процедура ЗакрытьВсеОкнаКромеГлавного()
    СписокОкон = ПолучитьОкна();
    Для Каждого ТекущееОкно Из СписокОкон Цикл
        Если НЕ ТекущееОкно.Основное И НЕ ТекущееОкно.Главное Тогда
            ТекущееОкно.Закрыть();
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Этот код перебирает все открытые в данный момент окна приложения. Свойство Основное указывает на то, является ли окно главным окном приложения. Закрывая все остальные, мы фактически «очищаем» рабочее пространство пользователя.

Дополнительные рекомендации по оптимизации

Выясним, как сделать расчет времени еще более точным. В крупных компаниях часто сталкиваются с проблемой «зависших» сессий. Если сотрудник ушел домой, не закрыв 1С, счетчик рабочего времени будет продолжать идти. Чтобы этого избежать, проанализируем следующие инструменты:

  1. ПолучитьСеансыИнформационнойБазы(): Этот метод позволяет проверить, активен ли сеанс пользователя в данный момент. Если в вашем регистре есть вход, но нет выхода, а сеанс уже отсутствует в списке активных — значит, время выхода можно считать равным времени последнего обращения к серверу (которое также фиксируется системой).
  2. Регламентные задания: Создадим фоновое задание, которое каждую полночь будет проверять незакрытые «входы» и проставлять им время выхода 23:59:59. Это позволит избежать ошибок в отчетах за прошлые периоды.
  3. Оконные функции: Если вы используете платформу версии 8.3.21 и выше, для расчета интервалов в запросах вместо тяжелых соединений ПО Слева.Дата < Справа.Дата можно использовать оконную функцию LEAD. Это значительно ускорит получение данных на больших объемах (десятки тысяч записей).

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

← На главную