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