Как реализовать расчет количества рабочих дней в табеле учета рабочего времени в 1С

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

При разработке самописных конфигураций для учета персонала одной из классических задач является создание документа "Табель учета рабочего времени". Часто заказчики просят реализовать максимально простой интерфейс, напоминающий таблицу Excel, где по горизонтали расположены дни месяца (с 1 по 31), а по вертикали — сотрудники. Основная сложность здесь заключается в том, чтобы корректно и эффективно собрать данные из тридцати одной колонки и вычислить общее количество отработанных дней. В этой статье мы подробно разберем, как автоматизировать этот процесс, избежав написания громоздкого и трудночитаемого кода.

Анализ структуры данных

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

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

Решение №1: Прямой перебор (нерекомендуемый способ)

На начальном этапе часто возникает соблазн использовать конструкцию Если...Тогда для каждой колонки. Выглядит это примерно так:


Если СтрокаТаблицы.День1 = СтатусЯвка Тогда
    КоличествоДней = КоличествоДней + 1;
КонецЕсли;
Если СтрокаТаблицы.День2 = СтатусЯвка Тогда
    КоличествоДней = КоличествоДней + 1;
КонецЕсли;
// И так до 31-го дня...

Такой код очень сложно поддерживать. Если потребуется изменить логику (например, добавить учет «ночных» смен или командировок), придется вносить правки в 31 блок кода. Рассмотрим более профессиональный подход.

Решение №2: Динамическое обращение к реквизитам (оптимальный способ)

В платформе 1С реализована возможность обращаться к свойствам объектов (в том числе к колонкам табличной части) по их имени, используя квадратные скобки. Это позволяет нам использовать цикл. Проанализируем, как сократить код в десятки раз:


&НаКлиенте
Процедура РассчитатьДниСтроки(СтрокаТаблицы)
    
    Перем КоличествоДней;
    КоличествоДней = 0;
    
    // Получаем значение статуса "Явка" из заранее определенных констант или функций
    СтатусЯвка = ОбщегоНазначения.СтатусБытияНаРаботе(1); 
    
    // Используем цикл для обхода всех 31 реквизита
    Для НомерДня = 1 По 31 Цикл
        ИмяРеквизита = "День" + НомерДня;
        
        // Обращаемся к колонке по сформированному имени
        Если СтрокаТаблицы[ИмяРеквизита] = СтатусЯвка Тогда
            КоличествоДней = КоличествоДней + 1;
        КонецЕсли;
    КонецЦикла;
    
    СтрокаТаблицы.КоличествоРабочихДней = КоличествоДней;
    
КонецПроцедуры

В данном примере мы динамически формируем строку "День" + НомерДня, что позволяет системе последовательно обращаться к День1, День2 и так далее. Это решение универсально и легко расширяется.

Решение №3: Работа с коллекцией элементов формы

Иногда требуется пересчитать данные, основываясь не на значениях объектной модели, а на подчиненных элементах формы (например, если колонки сгруппированы). Рассмотрим вариант перебора элементов в группе:


КоличествоСтрок = Объект.ТабельПосещения.Количество();
Для Счетчик = 0 По КоличествоСтрок - 1 Цикл
    СтрокаТаблицы = Объект.ТабельПосещения[Счетчик];
    КоличествоРабДней = 0;
    
    // Перебор элементов формы внутри группы "ГруппаДни"
    Для Каждого ЭлементДня Из Элементы.ГруппаДни.ПодчиненныеЭлементы Цикл
        // Логика проверки значения в связанном реквизите
        Если ЗначениеЗаполнено(СтрокаТаблицы[ЭлементДня.Имя]) Тогда
            КоличествоРабДней = КоличествоРабДней + 1;
        КонецЕсли;
    КонецЦикла;
    
    СтрокаТаблицы.КоличествоРабочихДней = КоличествоРабДней;
КонецЦикла;

Этот метод удобен тем, что если вы решите скрыть колонки День30 и День31 для февраля, цикл может автоматически подстроиться под видимые элементы (при наличии соответствующей проверки).

Важные нюансы и рекомендации

Чтобы табель работал корректно и удобно для пользователя, рекомендуем внедрить следующие доработки:

  1. Событие ПриИзменении: Назначьте для всех колонок дней один и тот же обработчик события ПриИзменении. В нем вызывайте процедуру пересчета только для ТекущиеДанные. Это обеспечит мгновенное обновление итогов без задержек.
  2. Обработка разного количества дней в месяце: Перед началом цикла пересчета полезно определить количество дней в выбранном месяце с помощью функции КонецМесяца(). Это позволит избежать логических ошибок, когда в феврале данные случайно попадают в 31-е число.
  3. Использование справочника: Вместо числовых статусов (1 или 2) используйте ссылку на справочник ВидыИспользованияРабочего Времени. В нем можно хранить признак ЭтоРабочееВремя (Булево). Тогда проверка в коде станет еще проще: Если СтрокаТаблицы[ИмяРеквизита].ЭтоРабочееВремя Тогда...
  4. Оптимизация видимости: При выборе месяца в документе, программно скрывайте лишние колонки. Например, если в месяце 30 дней, установите Элементы.ТабельПосещенияДень31.Видимость = Ложь;.

Заключение

Мы проанализировали несколько способов получения количества рабочих дней в табеле. Использование динамического обращения к реквизитам через конструкцию СтрокаТаблицы["День" + Д] является стандартом качественной разработки в среде 1С. Это делает код компактным, снижает вероятность ошибок и упрощает дальнейшее развитие конфигурации. Применяя предложенные подходы, вы сможете создать гибкую систему учета времени, которая будет работать быстро и надежно.

← На главную