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