В современных конфигурациях 1С, таких как "Бухгалтерия предприятия 3.0", работа с торговым оборудованием и формами построена на асинхронных вызовах. Часто возникает задача автоматизировать процесс печати чека, исключив лишние клики пользователя. Однако при попытке программно закрыть форму сразу после открытия (например, в обработчике ПриОткрытии), разработчики сталкиваются с тем, что вызывающий модуль не получает сигнал о завершении операции. Разберем подробно, почему это происходит и как правильно реализовать программную печать с возвратом результата.
Когда мы открываем форму программно с помощью метода ОткрытьФорму, мы передаем в него объект ОписаниеОповещения. Этот объект указывает платформе, какую процедуру нужно выполнить после того, как форма будет закрыта. В штатном режиме пользователь нажимает кнопку, срабатывает команда, форма закрывается, и управление возвращается в вызывающий модуль.
Проблема возникает, если закрытие инициируется внутри процедуры ПриОткрытии. В этот момент форма еще не прошла полную инициализацию в клиентском приложении. Если вызвать ЭтаФорма.Закрыть() слишком рано, цепочка событий разрывается, и ОписаниеОповещения игнорируется. Особенно остро это проявляется в БСП (Библиотеке стандартных подсистем), где печать чека завязана на сложные многоуровневые вызовы клиентских общих модулей.
Для того чтобы форма успела корректно «зарегистрироваться» в системе и отработать все внутренние механизмы связи с торговым оборудованием, ее нельзя закрывать мгновенно. Рассмотрим вариант с использованием метода ПодключитьОбработчикОжидания. Это позволит форме «прожить» один такт событий, после чего будет выполнена печать и закрытие.
В модуле формы обработки "Печать чека" (или аналогичной) в процедуре ПриОткрытии проанализируем переданные параметры:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Если Параметры.Свойство("ПечататьПриОткрытии") И Параметры.ПечататьПриОткрытии Тогда
// Вместо прямого вызова команды печати подключаем обработчик
ПодключитьОбработчикОжидания("ВыполнитьПробитиеЧекаБезИнтерактива", 0.1, Истина);
КонецЕсли;
КонецПроцедуры
Затем создадим саму процедуру, которая будет вызвана обработчиком ожидания. Обратите внимание, что важно передать результат выполнения обратно. Проанализируем пример:
&НаКлиенте
Процедура ВыполнитьПробитиеЧекаБезИнтерактива()
// Эмулируем нажатие кнопки "Пробить чек"
// Важно: вызываем именно ту экспортную процедуру, которая отвечает за логику
Результат = ПробитьЧекНаСервереИлиКлиенте();
// Если форма должна вернуть данные в ОписаниеОповещения:
Если ОповещениеОЗакрытии <> Неопределено Тогда
ВыполнитьОбработкуОповещения(ОповещениеОЗакрытии, Результат);
КонецЕсли;
ЭтаФорма.Закрыть();
КонецПроцедуры
Если штатный механизм закрытия все же не передает данные, мы можем воспользоваться методом ВыполнитьОбработкуОповещения явно. В Управляемых формах 1С 8.3 объект оповещения, переданный при открытии, доступен через свойство расширения формы ОповещениеОЗакрытии.
Рассмотрим ситуацию, когда в форме печати чека уже есть процедура-завершение (например, НапечататьОдинЧекЗавершение). Выясним причину, по которой она может не возвращать данные в вызывающий модуль. Часто это происходит из-за того, что внутри логики БСП предусмотрен интерактивный вопрос пользователю, который блокирует поток. В режиме «без формы» такие вопросы должны подавляться.
Для корректного возврата результата в общий модуль используйте следующую структуру внутри формы:
&НаКлиенте
Процедура ПослеУспешнойПечати(РезультатПараметры)
// Формируем структуру ответа, которую ожидает вызывающий документ (ПКО или РКО)
СтруктураРезультата = Новый Структура;
СтруктураРезультата.Вставить("Статус", Истина);
СтруктураРезультата.Вставить("НомерЧека", РезультатПараметры.НомерЧека);
// Явно вызываем оповещение, которое было передано при ОткрытьФорму
Закрыть(СтруктураРезультата);
// Метод Закрыть(Параметр) автоматически инициирует выполнение ОписанияОповещения
КонецПроцедуры
Наиболее правильным и современным подходом для реализации функционала «печатать сразу» является полный обход формы печати чеков. В БСП за это отвечает общий модуль МенеджерОборудованияКлиент. Вместо того чтобы мучиться с жизненным циклом формы, проанализируем возможность прямого обращения к драйверу.
Для реализации этого метода нам потребуется подготовить структуру чека программно. Разберем по шагам:
Пример кода в вызывающем модуле (например, в форме ПКО):
&НаКлиенте
Процедура ПробитьЧекБезФормы()
// 1. Получаем параметры фискализации (подготовка данных)
ПараметрыЧека = ПолучитьПараметрыЧекаНаСервере(Объект.Ссылка);
// 2. Создаем описание оповещения для обработки результата
Оповещение = Новый ОписаниеОповещения("ПослеПробитияЧека", ЭтотОбъект);
// 3. Вызываем менеджер оборудования напрямую
// ИдентификаторУстройства - берется из настроек пользователя или организации
МенеджерОборудованияКлиент.ВыполнитьКоманду(Оповещение,
ИдентификаторУстройства,
"FiscalizeReceipt",
ПараметрыЧека);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПробитияЧека(РезультатКоманды, Параметры) Экспорт
Если РезультатКоманды.Результат Тогда
Сообщить("Чек успешно пробит: " + РезультатКоманды.НомерЧека);
// Здесь можно обновить данные в документе
Иначе
Предупреждение("Ошибка печати: " + РезультатКоманды.ОписаниеОшибки);
КонецЕсли;
КонецПроцедуры
Проанализируем важный нюанс, упомянутый в обсуждении: использование ПодключитьОбработчикОжидания иногда приводит к тому, что драйвер не успевает «подцепиться» к форме. Это происходит, если сеанс связи с ККТ монопольный. Если форма закрывается быстрее, чем драйвер завершает обмен данными, результат может быть непредсказуемым.
Рекомендации:
ОповещениеОЗакрытии перед вызовом. Если форма открыта не как вспомогательная, попытка выполнить оповещение приведет к ошибке.Подводя итог, можно сказать: наиболее надежный способ оповестить общий модуль при программном закрытии — это либо использование Закрыть(Результат) в обработчике ожидания, либо полный переход на использование процедур МенеджерОборудованияКлиент, что исключает визуальную составляющую и делает код более стабильным.