Как проверить наличие уже введенного документа на основании в 1С и предотвратить дублирование?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В процессе реальной эксплуатации ERP-систем (будь то «1С:Управление торговлей», «1С:ERP» или «1С:Комплексная автоматизация») разработчики и аналитики часто сталкиваются с так называемым человеческим фактором. Пользователи из-за спешки, невнимательности или банального двойного клика могут повторно ввести документ на основании уже отработанного заказа или возврата. Яркий пример — создание нескольких документов Расходный кассовый ордер (РКО) на основании одного и того же Возврата товаров от клиента, что приводит к повторной выдаче денежных средств и головной боли для бухгалтерии.

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

Способ 1. Решение проблемы типовыми средствами конфигурации (без программирования)

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

Сценарий А. Защита от избыточных выплат по Возвратам (Ремонт кейса с РКО)

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

  1. Перейдем в раздел НСИ и администрирование, выберем пункт Казначейство и взаиморасчеты и активируем опцию Заявки на расходование денежных средств.
  2. Перейдем в настройки конкретной кассы нашей организации и обязательно снимем флажок Разрешить выдачу денежных средств без заявок на оплату.

Выясним, как теперь изменится логика работы системы. Пользователь физически больше не сможет создать РКО напрямую на основании документа возврата. Цепочка документов станет строго регламентированной:

  1. На основании Возврата товаров создается промежуточный документ Заявка на расходование ДС.
  2. Типовая система автоматически контролирует лимит: провести заявку на сумму, превышающую остаток долга по возврату-основанию, невозможно.
  3. РКО вводится строго на основании согласованной и утвержденной Заявки. Кассир физически не сможет выдать сумму больше той, что утвердил финансовый менеджер.

Сценарий Б. Контроль превышения объемов отгрузки (Заказ клиента -> Реализация)

Для цепочки отгрузки товаров в программе также предусмотрен встроенный логический контроль:

Способ 2. Программный запрет дублирования через расширение (Модуль объекта)

Если бизнес-требования диктуют жесткое правило: «На один документ-основание может быть введен строго один подчиненный документ», нам потребуется использовать механизм расширений. Это позволит сохранить конфигурацию на поддержке и гарантировать корректность учета.

Наиболее надежный программный способ контроля — перехват события заполнения в модуле объекта создаваемого документа. Этот метод сработает всегда, независимо от того, вводит ли пользователь документ интерактивно кнопкой из формы или документ создается обработкой в фоне.

Разберем по шагам алгоритм создания проверки:

  1. Создадим новое расширение конфигурации и снимем у него флажок Безопасный режим (для возможности полноценной работы с базой данных).
  2. Заимствуем в расширение документ-приемник (например, РеализацияТоваровУслуг) и добавим в его модуль объекта обработчик события ОбработкаЗаполнения с аннотацией &Перед.
  3. Внутри обработчика напишем запрос к информационной базе, чтобы проверить, нет ли уже проведенных документов с аналогичным основанием.

Посмотрим на пример реализации данного кода:


&Перед("ОбработкаЗаполнения")
Процедура Расш1_ПередОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
    
    // Проверяем, что заполнение происходит на основании Заказа клиента
    Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ЗаказКлиента") Тогда
        
        // Формируем запрос для поиска существующих некорректных дублей
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1
            |   Реализация.Ссылка КАК Ссылка,
            |   Реализация.Номер КАК Номер,
            |   Реализация.Дата КАК Дата
            |ИЗ
            |   Документ.РеализацияТоваровУслуг КАК Реализация
            |ГДЕ
            |   Реализация.ДокументОснование = &ДокументОснование
            |   И Реализация.ПометкаУдаления = ЛОЖЬ";
        
        Запрос.УстановитьПараметр("ДокументОснование", ДанныеЗаполнения);
        
        Выборка = Запрос.Выполнить().Выбрать();
        Если Выборка.Следующий() Тогда
            
            // Если документ найден, генерируем жесткое исключение
            ТекстОшибки = СтрШаблон(
                "Внимание! На основании этого заказа уже создана Реализация № %1 от %2. 
                |Повторное создание документов запрещено правилами документооборота!", 
                Выборка.Номер, 
                Формат(Выборка.Дата, "ДФ=dd.MM.yyyy")
            );
            
            ВызватьИсключение ТекстОшибки;
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

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

Способ 3. Интерактивная проверка в форме с предложением открыть дубликат

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

Для этого выполним следующие действия:

  1. Заимствуем в расширение форму создаваемого документа (например, форму документа РасходныйКассовыйОрдер).
  2. Создадим обработчик события формы ПриСозданииНаСервере с аннотацией &После.
  3. Проверим параметры открытия формы. Если передан параметр заполнения и в базе найден дубликат, установим параметр Отказ = Истина и выведем пользователю предупреждение.

Проанализируем структуру программного кода для формы документа:


&После("ПриСозданииНаСервере")
Процедура Расш1_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
    
    // Проверка актуальна только для новых (еще не записанных) документов
    Если Объект.Ссылка.Пустая() И Параметры.Свойство("ЗначениеЗаполнения") Тогда
        
        ДокументОснование = Параметры.ЗначениеЗаполнения;
        
        // Проверяем тип документа-основания (например, Возврат товаров от клиента)
        Если ТипЗнч(ДокументОснование) = Тип("ДокументСсылка.ВозвратТоваровОтКлиента") Тогда
            
            Запрос = Новый Запрос;
            Запрос.Текст = 
                "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1
                |   РКО.Ссылка КАК Ссылка
                |ИЗ
                |   Документ.РасходныйКассовыйОрдер КАК РКО
                |ГДЕ
                |   РКО.ДокументОснование = &ДокументОснование
                |   И РКО.ПометкаУдаления = ЛОЖЬ";
            
            Запрос.УстановитьПараметр("ДокументОснование", ДокументОснование);
            
            Выборка = Запрос.Выполнить().Выбрать();
            Если Выборка.Следующий() Тогда
                
                // Формируем навигационную ссылку для удобного открытия
                СсылкаНаДокумент = ПолучитьНавигационнуюСсылку(Выборка.Ссылка);
                
                // Выводим информативное сообщение пользователю
                ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
                    СтрШаблон("В базе уже существует РКО по данному возврату! Оформление дубликата отменено."),
                    ,,,
                    Отказ
                );
                
                // Блокируем открытие формы новой копии
                Отказ = Истина;
                
            КонецЕсли;
            
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Использование параметра Отказ = Истина аккуратно предотвращает отрисовку и открытие формы. В сочетании с выводом понятного сообщения через ОбщегоНазначенияКлиентСервер.СообщитьПользователю это обеспечивает высокий уровень юзабилити системы и защищает учет от дублирующихся транзакций.

Таким образом, мы рассмотрели как организационно-методические приемы предотвращения ошибок ввода (через казначейские лимиты и заявки), так и технические варианты жесткого программного контроля в коде 1С. Выбор конкретного метода зависит от архитектуры вашей базы данных и критичности бизнес-процесса.

← На главную