Как правильно игнорировать изменения объектов в подписках на события при работе через COM-соединение

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

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

Почему нельзя просто снять флаг «Внешнее соединение» в свойствах общего модуля

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

Проанализируем механику работы платформы 1С:Предприятие. Когда внешнее приложение подключается к вашей базе через COMConnector и пытается записать документ, платформа на сервере начинает собирать все обработчики событий, зарегистрированные для этого объекта. Если в метаданных указано, что обработчик находится в модуле, который «не виден» для внешнего соединения (флаг снят), платформа просто не сможет скомпилировать этот модуль в контексте данного сеанса. Результат — критическая ошибка: «Метод обработчика события не обнаружен». Программа «развалится», и запись объекта станет невозможной.

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

Метод 1. Проверка имени приложения через параметры сеанса

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

Для начала нам нужно определить тип соединения при старте сеанса. Это лучше всего сделать в Модуле сеанса. Проанализируем пример кода:


Процедура УстановкаПараметровСеанса(ТребуемыеПараметры)
    
    // Определяем, является ли текущий сеанс внешним соединением
    ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы();
    ИмяПриложения = ТекущийСеанс.ИмяПриложения;
    
    Если ИмяПриложения = "COMConnection" Или ИмяПриложения = "COMServer" Тогда
        ПараметрыСеанса.ЭтоВнешнееСоединение = Истина;
    Иначе
        ПараметрыСеанса.ЭтоВнешнееСоединение = Ложь;
    КонецЕсли;
    
КонецПроцедуры

Обратите внимание, что мы проверяем два варианта: COMConnection (использование V83.COMConnector) и COMServer (полноценный запуск через V83.Application). Записав этот признак в параметр сеанса ЭтоВнешнееСоединение (его нужно предварительно создать в метаданных), мы получаем мгновенный доступ к этой информации в любой точке кода.

Теперь рассмотрим, как будет выглядеть обработчик подписки на событие в вашем общем модуле:


Процедура ОбработкаПроверкиЗаполненияПриЗаписи(Источник, Отказ) Экспорт
    
    // Проверяем параметр сеанса
    Если ПараметрыСеанса.ЭтоВнешнееСоединение Тогда
        Возврат; // Выходим из процедуры, не выполняя логику
    КонецЕсли;
    
    // Далее идет основной код подписки
    // ...
    
КонецПроцедуры

Метод 2. Использование свойств объекта (ДополнительныеСвойства)

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

У каждого объекта 1С (документа, справочника) есть коллекция ДополнительныеСвойства. Это структура, которая живет в памяти вместе с объектом и не записывается в базу данных. Посмотрим, как это использовать.

Со стороны внешнего соединения (код на языке вызывающей системы или скрипта):


// Пример на языке 1С, вызываемом через COM
НовыйДокумент = Соединение.Документы.РеализацияТоваровУслуг.СоздатьДокумент();
// ... заполнение реквизитов ...
НовыйДокумент.ДополнительныеСвойства.Вставить("ПропуститьОбработкуСобытий", Истина);
НовыйДокумент.Записать();

Теперь настроим обработчик в общем модуле 1С так, чтобы он реагировал на этот флаг:


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

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

Метод 3. Использование функций БСП (Библиотека стандартных подсистем)

Если ваша конфигурация создана на базе современных типовых решений от 1С (УТ 11, ERP, БП 3.0), то в ней, скорее всего, уже интегрирована БСП. Разберем, как упростить себе задачу, используя готовые инструменты библиотеки.

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

  1. ОбщегоНазначения.ЭтоВнешнееСоединение() — возвращает Истина, если код выполняется в сеансе COM-соединения.
  2. ОбщегоНазначения.ЭтоСеансИнформационнойБазы() — позволяет проверить, является ли текущий контекст обычным сеансом пользователя.

Использование типовых функций предпочтительнее, так как разработчики 1С уже учли в них нюансы разных версий платформы и специфику работы в облачных сервисах (Fresh).

Важный нюанс: Фоновые задания

Рассмотрим ситуацию, которую часто упускают из виду. Допустим, внешнее соединение инициирует на сервере выполнение какого-то длительного процесса через Фоновое задание. Внутри этого фонового задания проверка ПараметрыСеанса.ЭтоВнешнееСоединение или ОбщегоНазначения.ЭтоВнешнееСоединение() вернет Ложь.

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

Резюме и рекомендации

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

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

← На главную