Как при проведении документа вызвать процедуру на клиенте?

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

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

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

Почему сервер не может вызвать клиент напрямую?

Прежде чем перейти к практическим решениям, проанализируем причину этого ограничения. Клиентское приложение (тонкий, толстый или веб-клиент) отправляет запросы на сервер «1С:Предприятия». Сервер обрабатывает эти запросы, обращается к базе данных СУБД и возвращает результат клиенту. Инициатором соединения всегда выступает клиент. Сервер технологически не может отправить произвольный запрос на клиентский компьютер «в одностороннем порядке» вне контекста текущего вызова, так как у него нет постоянного открытого обратного канала связи для выполнения произвольного кода.

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

---

Вариант 1. Интерактивное проведение из формы (обработчик «ПослеЗаписи»)

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

Рассмотрим по шагам, как настроить этот механизм:

  1. Откроем форму документа в конфигураторе.
  2. В свойствах формы найдем событие ПослеЗаписи и создадим для него обработчик на клиенте.
  3. Внутри обработчика проверим, проведен ли документ, и выполним требуемое клиентское действие.

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


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

&НаКлиенте
Процедура ВыполнитьДействиеНаКлиенте()
    
    // Пример действия: запуск внешнего калькулятора на компьютере пользователя
    ИмяПриложения = "calc.exe";
    ЗапуститьПриложение(ИмяПриложения);
    
КонецПроцедуры

Преимущества: Простота реализации, полное соответствие стандартам разработки 1С, отсутствие лишней нагрузки на базу данных.

Недостатки: Метод работает исключительно при интерактивном проведении из конкретной формы. Если документ проводится программно (например, из формы списка, групповой обработкой или фоновым заданием), этот код не выполнится.

---

Вариант 2. Использование очереди в Регистре Сведений (для неинтерактивного проведения)

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

Разберем этот алгоритм подробнее:

  1. Создадим новый непериодический регистр сведений ОчередьЗадачКлиента.
  2. Добавим измерения: Пользователь (тип СправочникСсылка.Пользователи) и Документ (тип ссылки на наш документ).
  3. В модуле объекта документа в обработчике события ПриПроведении (выполняется на сервере) будем делать запись в этот регистр с указанием текущего пользователя.
  4. На клиенте запустим периодический опрос этого регистра с помощью обработчика ожидания.

Запись в регистр в модуле документа на сервере:


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

Настройка опроса на клиенте в модуле управляемого приложения (или в модуле конкретной открытой формы):


&НаКлиенте
Процедура ПриНачалеРаботыСистемы()
    
    // Подключаем обработчик ожидания, который будет срабатывать каждые 10 секунд
    ПодключитьОбработчикОжидания("ПроверитьОчередьЗадачНаКлиенте", 10);
    
КонецПроцедуры

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

Преимущества: Способ гарантирует, что действие на клиенте будет выполнено, даже если проведение произошло в фоне или через групповую обработку.

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

---

Вариант 3. Современный подход: «Уведомления клиента» (начиная с платформы 8.3.26)

В современных версиях платформы появился встроенный и эффективный инструмент, решающий проблему связи «сервер-клиент» без постоянных запросов к базе данных — механизм Уведомлений клиента.

Проанализируем, как работает эта технология:

  1. При запуске клиентского приложения происходит подписка на определенный тип уведомлений от сервера через объект УведомленияКлиента.
  2. В модуле проведения на сервере вызывается метод отправки уведомления конкретному адресату (сеансу пользователя).
  3. Платформа самостоятельно доставляет сигнал клиенту в режиме реального времени, используя оптимизированные каналы связи.

Пример подписки на клиенте (например, в модуле управляемого приложения):


&НаКлиенте
Процедура ПриНачалеРаботыСистемы()
    
    // Подключаем обработчик получения уведомлений с сервера
    ОписаниеОповещения = Новый ОписаниеОповещения("ОбработатьУведомлениеСервера", ЭтотОбъект);
    УведомленияКлиента.ПодключитьОбработчик("ЗапускПриложенияПослеПроведения", ОписаниеОповещения);
    
КонецПроцедуры

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

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


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    
    // Код проведения документа
    // ...
    
    // Формируем параметры для передачи на клиент
    ПараметрыУведомления = Новый Структура;
    ПараметрыУведомления.Вставить("ПутьКПрограмме", "C:\Program Files\MyApp\app.exe");
    
    // Определяем получателя (текущий сеанс пользователя)
    Адресаты = Новый Массив;
    Адресаты.Добавить(НомерСеансаИнформационнойБазы());
    
    // Отправляем системное уведомление на клиент
    УведомленияКлиента.ОтправитьУведомление("ЗапускПриложенияПослеПроведения", ПараметрыУведомления, Адресаты);
    
КонецПроцедуры

Преимущества: Работает мгновенно (push-технология), не нагружает базу данных периодическими запросами, поддерживается платформой на уровне ядра.

Недостатки: Требуется современная версия платформы (8.3.26 и выше).

---

Вариант 4. Система взаимодействия (для версий 8.3.11 и выше)

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

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

Пример подписки на новые сообщения на клиенте:


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

&НаКлиенте
Процедура ПриПолученииСлужебногоСообщения(Сообщение, ДополнительныеПараметры) Экспорт
    
    // Проверяем, что сообщение адресовано нашей задаче
    Если Сообщение.Текст = "ВыполнитьЗапускПриложения" Тогда
        ЗапуститьПриложение("C:\Program Files\MyApp\app.exe");
    КонецЕсли;
    
КонецПроцедуры

Преимущества: Быстрая доставка сообщений в режиме реального времени без использования циклов опроса СУБД.

Недостатки: Требуется предварительная настройка сервера Системы взаимодействия (1С:Диалог или собственный локальный сервер).

---

Вариант 5. Архитектурный пересмотр: Запуск приложения на сервере

Выясним ключевую причину, по которой автору обсуждения потребовалось запускать внешнее приложение именно на клиенте. Зачастую внешние утилиты выполняют служебные, интеграционные или расчетные функции (например, отправка логов, выгрузка данных в стороннюю базу, генерация PDF-файлов, отправка HTTP-запросов).

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

Рассмотрим, как это реализовать:

  1. Установим внешнее приложение на серверный компьютер, где запущен рабочий процесс «1С:Предприятия».
  2. В коде проведения документа на сервере вызовем стандартный метод ЗапуститьПриложение().

Посмотрим на пример серверного кода:


&НаСервере
Процедура ВыполнитьИнтеграциюНаСервере()
    
    // Запуск консольного приложения на сервере без вывода окон
    ИмяЗапускаемогоФайла = """C:\Program Files\MyServerApp\converter.exe"" --input data.xml";
    ЗапуститьПриложение(ИмяЗапускаемогоФайла, , Истина); // Третий параметр Истина ожидает завершения работы программы
    
КонецПроцедуры

Важное требование безопасности: Пользователь операционной системы (например, USR1CV8), под которым запущена служба сервера «1С:Предприятие», должен обладать правами на запуск данного исполняемого файла и доступ к соответствующим каталогам на диске сервера.

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

---

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

Выбор оптимального метода вызова клиентского кода при проведении документов зависит от бизнес-требований вашей системы:

← На главную