Как поймать событие проведения документа в динамическом списке?

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

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

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

Проблема контекста: почему обычные подписки не помогут?

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

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

Способ 1: Использование собственной команды проведения

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

  1. Скрытие стандартной команды: В командной панели динамического списка найдите стандартную группу кнопок «Провести» и снимите флаг видимости.
  2. Создание своей команды: Добавьте новую команду формы, назовите её КомандаПровестиСписком и выведите её на командную панель с заголовком «Провести».
  3. Программная реализация: В обработчике команды на клиенте мы будем вызывать серверный метод для проведения, а затем выполнять нужные нам действия.

Рассмотрим пример кода для такой команды:


&НаКлиенте
Процедура КомандаПровестиСписком(Команда)
    
    // Получаем выделенные строки из списка
    ВыделенныеСтроки = Элементы.Список.ВыделенныеСтроки;
    
    Если ВыделенныеСтроки.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    // Проводим документы на сервере
    ПровестиДокументыНаСервере(ВыделенныеСтроки);
    
    // Вот здесь мы уже точно знаем, что проведение завершено
    // Можем запустить синхронизацию или вызывать оповещение
    ВыполнитьПоследующиеДействия();
    
КонецПроцедуры

В серверной части процедуры мы будем использовать ДополнительныеСвойства, чтобы пометить объект. Это позволит подпискам на события понять, что документ пришел именно из нашей формы.


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

Способ 2: Использование механизма «ОбработкаОповещения»

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

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


&НаКлиенте
Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
    
    // Платформа посылает событие "Запись_ИмяДокумента" при изменении объекта
    Если ИмяСобытия = "Запись_ПриходнаяНакладная" Тогда
        
        // В параметре обычно передается ссылка на документ
        Если ТипЗнч(Параметр) = Тип("ДокументСсылка.ПриходнаяНакладная") Тогда
            // Проверим, что документ действительно проведен
            Если ПроверитьСтатусПроведения(Параметр) Тогда
                 // Выполняем логику после проведения
                 ЗапуститьСинхронизацию(Параметр);
            КонецЕсли;
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

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

Способ 3: Обработчик ожидания для «чистого» завершения

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

Выясним, как это реализовать в связке с кастомной командой:


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

&НаКлиенте
Процедура ВыполнитьСинхронизациюПослеВсехСобытий()
    // Этот код сработает, когда стек вызовов будет пуст
    // и все сообщения платформы будут доставлены пользователю
    Сообщить("Начинаем синхронизацию...");
    // ... логика синхронизации
КонецПроцедуры

Способ 4: Архитектурный подход через «Очередь событий»

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

  1. Подписка на событие: Создаем серверную подписку на ПриЗаписи документа.
  2. Проверка условий: В подписке проверяем: ЭтоНовый() или РежимЗаписи = Проведение.
  3. Регистрация задачи: Если условия соблюдены, записываем ссылку на документ в специальный регистр «ОчередьСинхронизации».
  4. Выполнение: Отдельное регламентное задание (или фоновое задание, запущенное из формы) подхватывает записи из этого регистра и обрабатывает их.

Этот метод гарантирует, что ни одно проведение не будет пропущено, даже если документ провел робот или пользователь из мобильного приложения, где ваша форма списка вообще не открывалась.

Резюме

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

← На главную