Почему при записи и проведении документа в 1С некорректно срабатывают проверки и как правильно разделить эту логику?

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

При разработке механизмов интеграции (например, обмена EDI-сообщениями) часто возникает задача: регистрировать изменения в информационной базе при выполнении различных действий с документом. Типичный сценарий — запись определенной информации в регистр сведений при обычной записи документа и совершенно другой информации при его проведении.

Однако начинающие разработчики часто сталкиваются с ситуацией, когда проверки отрабатывают некорректно: данные записываются хаотично, перезаписывают друг друга или условия в коде вовсе игнорируются платформой. В этой статье мы подробно разберем, почему возникает эта проблема, проанализируем внутренние механизмы платформы «1С:Предприятие» и напишем правильный, отказоустойчивый код.

В чем заключается проблема?

Рассмотрим ситуацию: у нас есть документ, который при записи должен делать запись в регистр сведений с вариантом заполнения ПовкладкеМТСС, а при проведении — с вариантом заполнения ПовкладкеТовары. Разработчик написал два отдельных обработчика: один в процедуре ПередЗаписью, а второй — в ОбработкаПроведения. Но при тестировании выясняется, что система ведет себя непредсказуемо, записывая не те значения или игнорируя проведение.

Давайте выясним причину такого поведения и разберем архитектурные ошибки исходного кода.

Анализ жизненного цикла записи и проведения документа в 1С

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

  1. Запускается транзакция записи документа.
  2. Вызывается обработчик события ПередЗаписью. При этом в параметре РежимЗаписи передается значение РежимЗаписиДокумента.Проведение.
  3. Документ записывается в базу данных.
  4. Вызывается обработчик события ПриЗаписи.
  5. Вызывается обработчик события ОбработкаПроведения.
  6. Транзакция фиксируется.

Обратите внимание на ключевой момент: при проведении документа всегда вызывается обработчик события ПередЗаписью!

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

Разбор ошибок в исходном коде

Проанализируем исходный код разработчика и выявим критические ошибки:

  1. Отсутствие фильтрации по режиму записи в ПередЗаписью.

    Код в этой процедуре выполняется всегда — и при обычном сохранении документа по кнопке «Записать», и при его проведении. Без явной проверки параметра РежимЗаписи мы получаем дублирование логики.

  2. Сравнение разных типов перечислений в условиях.

    Обратите внимание на эту строку в обработчике проведения:

    торговаяточка.ВариантОтправкиORDRSP = Перечисления.ВариантыЗаполненияORDRSP.ПриКаждомИзменении

    Здесь реквизит ВариантОтправкиORDRSP (который относится к перечислению ВариантыОтправкиORDRSP) сравнивается со значением перечисления ВариантыЗаполненияORDRSP. Такое сравнение в 1С всегда будет возвращать Ложь, из-за чего условие проведения никогда не выполнится.

  3. Неоптимальное обращение к реквизитам базы данных.

    Условие НЕ (ТоварыSFA = ссылка.ТоварыSFA) выполняет неявный запрос к базе данных для получения старого значения реквизита из СУБД. Это существенно снижает производительность системы при проведении и записи документов.

  4. Использование менеджера записи в транзакции.

    Использование метода СоздатьМенеджерЗаписи() внутри транзакции документа для записи независимого регистра — не самое лучшее решение. Оно может вызывать избыточные блокировки таблиц СУБД при параллельной работе пользователей.

Пошаговое решение проблемы

Теперь, когда мы выяснили все причины некорректного поведения системы, разработаем правильную архитектуру решения. Разберем по шагам, как исправить код.

Шаг 1. Разделение логики в обработчике ПередЗаписью

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

Рассмотрим пример реализации:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Если документ проводится, то логику записи выполнять не нужно, 
    // так как для проведения у нас есть отдельный обработчик
    Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
        Возврат;
    КонецЕсли;
    
    // Выполняем проверки только для режима обычной записи
    Если (ТорговаяТочка.АвтоматическаяОтправкаORDRSP И Контрагент.АвтоматическаяОтправкаORDRSP) = Истина 
        И ТорговаяТочка.ВариантОтправкиORDRSP = Перечисления.ВариантыОтправкиORDRSP.ПриКаждомИзменении 
        И ТорговаяТочка.ВариантЗаполненияORDRSP = Перечисления.ВариантыЗаполненияORDRSP.ПовкладкеМТСС Тогда
        
        // Оптимальная проверка модифицированности реквизита
        Если ЭтотОбъект.Модифицированность() Тогда
            РегистрУведомленияORDRSP("Запись");
        КонецЕсли;
        
    КонецЕсли;

КонецПроцедуры

Шаг 2. Корректировка логики в обработчике ОбработкаПроведения

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


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    // Проверяем условия для автоматической отправки при проведении
    Если (ТорговаяТочка.АвтоматическаяОтправкаORDRSP И Контрагент.АвтоматическаяОтправкаORDRSP) = Истина 
        И ТорговаяТочка.ВариантОтправкиORDRSP = Перечисления.ВариантыОтправкиORDRSP.ПриКаждомИзменении 
        И ТорговаяТочка.ВариантЗаполненияORDRSP = Перечисления.ВариантыЗаполненияORDRSP.ПовкладкеТовары Тогда
        
        РегистрУведомленияORDRSP("Проведение");
        
    КонецЕсли;

КонецПроцедуры

Шаг 3. Оптимизация записи в регистр сведений

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

Рассмотрим, как будет выглядеть оптимизированная процедура регистрации записи:


Процедура РегистрУведомленияORDRSP(ТипЗаполнения) 

    ЗаказEDI = ПолучитьЗаказEDI();
    Если ЗаказEDI = Неопределено Тогда 
        Возврат; 
    КонецЕсли; 
    
    Если НетЗаписейУведомленияORDRSP(Ссылка) Тогда 
        
        // Используем набор записей вместо менеджера записи
        НаборЗаписей = РегистрыСведений.УведомленияORDRSP.СоздатьНаборЗаписей();
        НаборЗаписей.Отбор.ЗаказПокупателя.Установить(Ссылка);
        
        НоваяЗапись = НаборЗаписей.Добавить();
        НоваяЗапись.ЗаказПокупателя = Ссылка;
        НоваяЗапись.ЗаказEDI = ЗаказEDI;
        НоваяЗапись.УникальныйИдентификатор = Новый УникальныйИдентификатор();
        НоваяЗапись.ОтправленВРучную = Ложь;
        НоваяЗапись.Состояние = Перечисления.СостоянияORDRSP.Ожидает;
        НоваяЗапись.ДатаПостановки = ТекущаяДата();
        
        // Устанавливаем вариант заполнения в зависимости от контекста вызова
        Если ТипЗаполнения = "Запись" Тогда 
            НоваяЗапись.ВариантЗаполнения = Перечисления.ВариантыЗаполненияORDRSP.ПовкладкеМТСС; 
        ИначеЕсли ТипЗаполнения = "Проведение" Тогда 
            НоваяЗапись.ВариантЗаполнения = Перечисления.ВариантыЗаполненияORDRSP.ПовкладкеТовары; 
        КонецЕсли; 
        
        // Записываем данные в транзакции
        НаборЗаписей.Записать(Истина); 
        
    КонецЕсли; 

КонецПроцедуры

Резюме

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

← На главную