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

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

При разработке кассовых решений и механизмов взаимодействия с фискальными регистраторами часто возникает задача пробить два чека подряд (например, при разделении товаров по разным системам налогообложения). На платформе 1С в режиме управляемого приложения вызов форм не останавливает исполнение кода. В результате программа пытается сразу же сформировать второй чек, не дожидаясь завершения обработки первого. Это приводит к наложению интерфейсных окон, ошибкам драйвера ККТ и запросам на аннулирование чека.

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

Причины возникновения проблемы

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

  1. Неблокирующий клиентский код: В современных версиях 1С вызов ОткрытьФорму выполняется асинхронно. Код клиентской процедуры не ждет закрытия окна, а продолжается линейно, выполняя команды создания второго чека.
  2. Ограничения фискальных накопителей и драйверов: Торговое оборудование не может одновременно обрабатывать два документа. Если отправить команду печати второго чека до полного закрытия первого, кассовый драйвер вернет ошибку о занятости устройства.
  3. Попытка использовать циклы ожидания: Попытка заморозить поток через цикл вида Пока Форма.Открыта() Цикл ... КонецЦикла приводит к полному зависанию клиентского сеанса, так как интерфейс перестает откликаться на действия пользователя.

Способ 1. Использование механизма «ОписаниеОповещения»

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

Разберем пример кода передачи параметров и вызова обратного обработчика:


// Формируем дополнительные параметры для передачи в следующий шаг
ДопПараметры = Новый Структура;
ДопПараметры.Вставить("ДокументПродажи", СсылкаНаДокумент);
ДопПараметры.Вставить("СуммаВторойЧасти", СуммаВторогоЧека);

// Создаем описание оповещения, указывая имя процедуры-обработчика и контекст
ОповещениеОЗавершении = Новый ОписаниеОповещения("НапечататьВторойЧекЗавершение", ЭтаФорма, ДопПараметры);

// Открываем форму фронта кассира для первого чека
ОткрытьФорму("Обработка.РМК.Форма.ФормаОплаты", 
    ПараметрыОткрытия, 
    ЭтаФорма, 
    УникальныйИдентификатор, 
    , 
    , 
    ОповещениеОЗавершении, 
    РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);

Для корректной работы процедуры-обработчика необходимо соблюдать следующие требования:

  1. Процедура должна иметь директиву компиляции &НаКлиенте.
  2. Процедура обязательно должна быть объявлена с ключевым словом Экспорт.
  3. Сигнатура процедуры должна принимать два параметра (результат закрытия и дополнительные параметры).

Посмотрим на пример процедуры-обработчика, которая вызывается после закрытия формы первого чека:


&НаКлиенте
Процедура НапечататьВторойЧекЗавершение(РезультатЗакрытия, ДополнительныеПараметры) Экспорт

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

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

Способ 2. Использование событийной модели (Оповестить и ОбработкаОповещения)

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

Рассмотрим порядок действий при таком подходе:

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

Способ 3. Асинхронные вызовы (Асинх / Ждать)

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

Выясним, как выглядит этот подходом на практике:


&НаКлиенте
Асинх Процедура ОплатитьИПробитьДваЧекаАсинх()

    // Открываем форму первого чека и ждем ее закрытия
    РезультатПервогоЧека = Ждать ОткрытьФормуАсинх("Обработка.РМК.Форма.ФормаОплаты", ПараметрыПервогоЧека);
    
    Если РезультатПервогоЧека <> Неопределено Тогда
        // Код приостанавливает выполнение на строке Ждать и продолжит работу только после закрытия первого окна
        РезультатВторогоЧека = Ждать ОткрытьФормуАсинх("Обработка.РМК.Форма.ФормаОплаты", ПараметрыВторогоЧека);
    КонецЕсли;

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

Использование ОткрытьФормуАсинх и оператора Ждать сохраняет читаемость кода и полностью исключает наложение интерфесных окон кассы друг на друга.

← На главную