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