Как программно закрыть форму печати чека с передачей оповещения в общий модуль

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

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

Анализ проблемы: почему не срабатывает оповещение

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

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

Решение №1: Использование однократного обработчика ожидания

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

В модуле формы обработки "Печать чека" (или аналогичной) в процедуре ПриОткрытии проанализируем переданные параметры:


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

Затем создадим саму процедуру, которая будет вызвана обработчиком ожидания. Обратите внимание, что важно передать результат выполнения обратно. Проанализируем пример:


&НаКлиенте
Процедура ВыполнитьПробитиеЧекаБезИнтерактива()
    
    // Эмулируем нажатие кнопки "Пробить чек"
    // Важно: вызываем именно ту экспортную процедуру, которая отвечает за логику
    Результат = ПробитьЧекНаСервереИлиКлиенте(); 
    
    // Если форма должна вернуть данные в ОписаниеОповещения:
    Если ОповещениеОЗакрытии <> Неопределено Тогда
        ВыполнитьОбработкуОповещения(ОповещениеОЗакрытии, Результат);
    КонецЕсли;
    
    ЭтаФорма.Закрыть();
    
КонецПроцедуры

Решение №2: Прямой вызов процедуры оповещения

Если штатный механизм закрытия все же не передает данные, мы можем воспользоваться методом ВыполнитьОбработкуОповещения явно. В Управляемых формах 1С 8.3 объект оповещения, переданный при открытии, доступен через свойство расширения формы ОповещениеОЗакрытии.

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

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


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

Решение №3: Работа через МенеджерОборудования (без открытия формы)

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

Для реализации этого метода нам потребуется подготовить структуру чека программно. Разберем по шагам:

  1. Подготавливаем данные чека на сервере (состав товаров, суммы, налоги).
  2. На клиенте получаем идентификатор устройства (ККТ).
  3. Вызываем команду фискализации.

Пример кода в вызывающем модуле (например, в форме ПКО):


&НаКлиенте
Процедура ПробитьЧекБезФормы()
    
    // 1. Получаем параметры фискализации (подготовка данных)
    ПараметрыЧека = ПолучитьПараметрыЧекаНаСервере(Объект.Ссылка);
    
    // 2. Создаем описание оповещения для обработки результата
    Оповещение = Новый ОписаниеОповещения("ПослеПробитияЧека", ЭтотОбъект);
    
    // 3. Вызываем менеджер оборудования напрямую
    // ИдентификаторУстройства - берется из настроек пользователя или организации
    МенеджерОборудованияКлиент.ВыполнитьКоманду(Оповещение, 
                                                ИдентификаторУстройства, 
                                                "FiscalizeReceipt", 
                                                ПараметрыЧека);
    
КонецПроцедуры

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

Важные замечания по работе с торговым оборудованием

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

Рекомендации:

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

← На главную