Как перехватить ошибку платформы "Номер не уникальный" при записи документа в 1С 7.7?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

Часто разработчики 1С:Предприятие 7.7 сталкиваются с неприятной ситуацией: при попытке записи документа с неуникальным номером платформа выдает собственное модальное окно с предупреждением "Номер не уникальный". Окно блокирует работу, и стандартная конструкция перехвата ошибок кажется бессильной. Давайте проанализируем эту ситуацию и разберем эффективные способы решения проблемы.

Почему конструкция Попытка... Исключение не всегда работает?

Для начала выясним причину, почему перехват ошибки работает не во всех случаях. Конструкция Попытка ... Исключение в версии 7.7 перехватывает только программные ошибки, которые возникают непосредственно в контексте выполнения вашего программного модуля.

Разберем поведение платформы при интерактивном сохранении (когда пользователь нажимает кнопку сохранения в форме документа). В этом случае платформа сначала выполняет код предопределенной процедуры ПриЗаписи(). Если вызов не отменен, платформа выходит из программного контекста и начинает транзакцию записи на низком уровне ядра (движка). Именно там осуществляется жесткая проверка уникальности. Поскольку это происходит уже вне вашего кода, генерируется системное модальное окно, которое невозможно обернуть в Попытку.

При программном вызове метода Записать() транзакция инициируется внутри вашего кода, поэтому исключение успешно генерируется и может быть обработано.

Решение для программной записи документа

Рассмотрим, как правильно обрабатывать ошибку, если мы записываем документ программно (например, при обработке массива данных). В этом случае конструкция перехвата отлично сработает, и мы сможем проанализировать ОписаниеОшибки().

Посмотрим на пример функции, которая безопасно записывает документ и, в случае сбоя нумерации, пытается исправить ситуацию:


Функция ЗаписатьДокБезопасно(Док)
    Завершение = 0;                  
    Результат = 1; 
    
    Пока Завершение = 0 Цикл
        Попытка
            Док.Записать();
            Завершение = 1;                                                                                                  
        Исключение             
            Описание = "Номер не уникальный";
            Ошибка = ОписаниеОшибки();
            // Проверяем текст ошибки
            Если Лев(Ошибка, СтрДлина(Описание)) = Описание Тогда
                Завершение = 0;
                // Пытаемся получить следующий номер
                Док.НомерДок = Инкремент(Док.НомерДок);
                Сообщить("Сбой нумератора, пробуем номер: " + Док.НомерДок);
            Иначе 
                Завершение = 1;
                Результат = 0;
                Сообщить("Необработанная ошибка при записи: " + Ошибка);
            КонецЕсли;            
        КонецПопытки; 
    КонецЦикла;       
    
    Возврат Результат;    
КонецФункции

Решение для интерактивной записи (проверка в модуле формы)

Проанализируем ситуацию с интерактивной записью. Так как ядро мы перехватить не можем, нам необходимо проверить уникальность номера до того, как управление перейдет к движку платформы. Идеальное место для этого — предопределенная процедура ПриЗаписи().

Самый простой подход — попытаться найти документ с таким же номером перед записью. Однако здесь есть критический нюанс, который часто упускают: если пользователь открыл уже существующий документ, изменил его и нажал "Сохранить", метод НайтиПоНомеру() найдет этот же самый документ! Из-за этого алгоритм выдаст ложную ошибку и заблокирует работу.

Рассмотрим правильный код с обязательной проверкой, не нашли ли мы самих себя:


Процедура ПриЗаписи()
    Док = СоздатьОбъект("Документ." + Вид());
    
    // Ищем документ с таким же номером за этот же период (год/месяц/день в зависимости от настроек)
    Если Док.НайтиПоНомеру(НомерДок, ДатаДок) = 1 Тогда
        
        // Важнейшая проверка: исключаем сам текущий документ
        Если ТекущийДокумент() <> Док.ТекущийДокумент() Тогда
            
            Сообщить("Внимание! Документ с таким номером уже существует в базе!");
            
            // Отменяем стандартную запись платформы
            СтатусВозврата(0); 
            Возврат;
            
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Использование СтатусВозврата(0) гарантирует, что платформа отменит дальнейшие действия и не дойдет до системного окна ошибки.

Дополнительные рекомендации и альтернативные подходы

Разберем по шагам, как можно улучшить алгоритм и какие еще технологии применяются для решения этой задачи:

  1. Автоматическое исправление нумерации. Чаще всего сбой нумерации происходит из-за ручного вмешательства пользователей (например, стирание нулей в префиксе). Чтобы не останавливать работу, в процедуре ПриЗаписи() при обнаружении дубля можно вызвать стандартный метод УстановитьНовыйНомер(). Программа сама исправит номер, и запись пройдет успешно. Пользователю достаточно вывести информационное сообщение: "Номер был занят. Документу автоматически присвоен новый номер".
  2. Ускорение проверки с помощью 1С++. Если у вас очень большая база данных (особенно файловая DBF) и метод НайтиПоНомеру() работает медленно из-за инициализации OLE-объектов, лучше использовать прямые SQL-запросы через компоненту 1cpp.dll. С помощью объекта ODBCRecordset можно мгновенно проверить таблицу журнала документов _1SJOURN на совпадение полей DOCNO и несовпадение IDDOC.
  3. Использование внешних компонент для перехвата окон. Существуют специализированные библиотеки (например, 1spy.dll или VKHook), которые позволяют устанавливать Hook на уровне операционной системы Windows для перехвата вызова функции MessageBox. Они могут программно нажать кнопку "ОК" в окне ядра 1С. Однако мы рекомендуем избегать таких методов: они считаются "грязными" хаками и могут приводить к внезапному аварийному завершению работы (крашу) клиента 1С. Программная проверка в ПриЗаписи() работает значительно стабильнее и безопаснее.

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

← На главную