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