Как при заполнении начисления зарплаты проверить наличие табеля и вывести сообщение пользователю?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом
← На главную

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

Анализ проблемы и выбор архитектурного решения

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

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

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

Реализация серверной функции проверки наличия табелей

Для того чтобы определить, есть ли сотрудники без табеля, нам необходимо получить список всех актуальных сотрудников организации (или подразделения) и сопоставить его с данными документов ТабельУчетаРабочегоВремени. Выясним, как это сделать наиболее эффективно с помощью запроса.

Разберем пример кода функции, которую можно разместить в модуле формы или в серверном общем модуле:


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

Проанализируем этот код. Во-первых, мы используем МенеджерВременныхТаблиц и типовой метод КадровыйУчет.СоздатьВТСотрудникиОрганизации. Это гарантирует, что мы получим только актуальных сотрудников (не уволенных, работающих на текущий момент). Во-вторых, мы проверяем не просто наличие документа, а его проведение (ТабельШапка.Проведен = ИСТИНА), что критически важно для достоверности данных.

Интеграция проверки в интерфейс пользователя

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


&НаКлиенте
Процедура КомандаЗаполнить(Команда)
    
    // Вызываем серверную проверку
    Если ЕстьСотрудникиБезТабеляВМесяцеРасчета() Тогда
        // Используем стандартный метод сообщения, который работает в контексте формы
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
            "Документ не может быть рассчитан автоматически! У некоторых сотрудников отсутствует проведенный табель за текущий месяц."
        );
        Возврат; // Прерываем выполнение стандартного алгоритма заполнения
    КонецЕсли;
    
    // Дальнейший типовой код заполнения...
    
КонецПроцедуры

Важный момент: использование конструкции Если ЕстьСотрудникиБезТабеляВМесяцеРасчета() Тогда вместо Если ЕстьСотрудникиБезТабеляВМесяцеРасчета() = Истина Тогда является более лаконичным и правильным стилем программирования в 1С.

Альтернативные способы решения

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

В такой обработке в методе ВыполнитьКоманду мы можем реализовать аналогичную логику:

  1. Прочитать данные из объекта документа (организация, период).
  2. Выполнить запрос к табелям.
  3. Очистить табличную часть Начисления и заполнить её только теми сотрудниками, по которым табель найден.
  4. Вывести список «пропущенных» сотрудников в окно сообщений.

Также стоит рассмотреть использование расширений конфигурации. Это наиболее современный метод. В расширении можно создать метод с аннотацией &Перед для процедуры заполнения. Это позволит сохранить возможность типового обновления программы, так как ваш код будет храниться отдельно от основного ядра ЗУП.

Советы по оптимизации производительности

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

Таким образом, мы рассмотрели надежный способ реализации «защиты от ошибок» при начислении зарплаты. Помните принцип: минимум изменений в типовом коде — максимум комментариев. Это значительно облегчит поддержку вашей базы данных в будущем при выходе новых релизов от 1С.

← На главную