Как проверить уникальность номера счета-фактуры при записи документа в 1С

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

При работе с первичными документами в 1С часто возникает необходимость контролировать уникальность пользовательских реквизитов. Например, когда номер счета-фактуры хранится в документе реализации отдельным строковым реквизитом НомерСчетФактуры, а не формируется встроенным нумератором платформы, возникает риск появления дублей. Рассмотрим, как правильно организовать алгоритм проверки уникальности при записи документа, исправим распространенные ошибки взаимодействия модуля объекта и формы, а также проанализируем способы защиты от дублирования данных.

Ошибки обращения к реквизитам: модуль объекта против формы

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


номсф = МетаДанные.Документы.Реализация.Формы.ФормаДокумента.Элементы.Поле2.ТекстРедактирования;

вызовет фатальную ошибку: «Поле объекта не обнаружено (Элементы)». Выясним причину этого сбоя.

Коллекция Элементы и свойство ТекстРедактирования существуют исключительно в контексте формы (на клиенте или сервере формы). В модуле объекта (МодульОбъекта) доступ к реквизитам документа осуществляется напрямую по их имени без обращения к метаданным или элементам формы.

Если проверка выполняется в модуле объекта, обращение к строковому номеру должно выглядеть следующим образом:

номсф = НомерСчетФактуры; // Обращение к реквизиту текущего объекта

Если же код вызывается из модуля формы, к реквизиту объекта обращаются через свойство Объект.НомерСчетФактуры.

Реализация проверки уникальности через событие ПередЗаписью

Рассмотрим рабочий алгоритм проверки уникальности реквизита в процедуре ПередЗаписью модуля объекта. Проверка состоит из запроса к информационной базе, который ищет документы с таким же номером счета-фактуры.

Проанализируем ключевые условия запроса:

  1. Исключение текущей ссылки: Условие Ссылка <> &Ссылка необходимо, чтобы при перепроведении или изменении ранее записанного документа система не нападала на собственную запись и не выдавала ложное сообщение о дубле.
  2. Ограничение по периоду: Номера счетов-фактур нумеруются в рамках календарного года. Если не ограничить поиск периодом, документ за прошлый год с таким же номером заблокирует запись нового документа.

Посмотрим на готовый пример реализации в модуле объекта:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    Если Отказ Или ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    Если ЗначениеЗаполнено(НомерСчетФактуры) И Не НомерСчетФактурыУникален(НомерСчетФактуры, Ссылка, Дата) Тогда
        Сообщение = Новый СообщениеПользователю;
        Сообщение.Текст = "Документ с номером счета-фактуры """ + НомерСчетФактуры + """ уже существует в текущем периоде!";
        Сообщение.Поле = "НомерСчетФактуры";
        Сообщение.Сообщить();
        
        Отказ = Истина;
    КонецЕсли;
    
КонецПроцедуры

Функция НомерСчетФактурыУникален(Знач ПроверяемыйНомер, Знач ТекущаяСсылка, Знач ДатаДокумента)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |	1 КАК Поле
        |ИЗ
        |	Документ.РеализацияТоваровУслуг КАК Реализация
        |ГДЕ
        |	Реализация.НомерСчетФактуры = &НомерСчетФактуры
        |	И Реализация.Ссылка <> &Ссылка
        |	И Реализация.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, ГОД) И КОНЕЦПЕРИОДА(&Дата, ГОД)";
    
    Запрос.УстановитьПараметр("НомерСчетФактуры", ПроверяемыйНомер);
    Запрос.УстановитьПараметр("Ссылка", ТекущаяСсылка);
    Запрос.УстановитьПараметр("Дата", ДатаДокумента);
    
    РезультатЗапроса = Запрос.Выполнить();
    
    Возврат РезультатЗапроса.Пустой();
    
КонецФункции

Использование штатной функции ОбработкаПроверкиЗаполнения

Альтернативным и наиболее корректным местом для проверки корректности введенных данных является событие ОбработкаПроверкиЗаполнения в модуле объекта. Это штатный механизм платформы 1С, который автоматически подсвечивает поле с ошибкой на форме красной рамкой и переводит фокус на нужный элемент управления.

Рассмотрим пример переноса логики в данный обработчик:


Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    
    Если ЗначениеЗаполнено(НомерСчетФактуры) И Не НомерСчетФактурыУникален(НомерСчетФактуры, Ссылка, Дата) Тогда
        Сообщение = Новый СообщениеПользователю;
        Сообщение.Текст = СтрШаблон("Счет-фактура №%1 уже зарегистрирован в %2 году!", НомерСчетФактуры, Формат(Дата, "ДФ=гггг"));
        Сообщение.Поле = "Объект.НомерСчетФактуры";
        Сообщение.УстановитьДанные(ЭтотОбъект);
        Сообщение.Сообщить();
        
        Отказ = Истина;
    КонецЕсли;
    
КонецПроцедуры

Рекомендации по оптимизации и параллельной работе

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

  1. Индексирование реквизита: Поиск по строковому реквизиту без индекса приводит к полному сканированию таблицы документов в СУБД (Full Scan). Чтобы запрос выполнялся мгновенно, откройте свойства реквизита НомерСчетФактуры в Конфигураторе и установите значение свойства Индексировать в значение Индексировать или Индексировать с доп. упорядочиванием.
  2. Защита от параллельного ввода (гонка состояний): Если два пользователя одновременно сохраняют документы с одинаковым номером счета-фактуры, обычный запрос у обоих вернет позитивный результат (так как ни один из документов еще не записан в БД). Чтобы исключить дубли при одновременной работе, перед выполнением запроса в транзакции записи следует устанавливать управляемую блокировку БлокировкаДанных по значению проверяемого номера.
  3. Использование нумераторов: Если учет требует строгого контроля номеров, рекомендуется выделить сбытовые счета-фактуры в отдельный документ конфигурации (например, «Счет-фактура выданный») и использовать встроенный нумератор 1С с нужной периодичностью.
← На главную