При автоматизации обмена данными (например, с кассами ККМ Offline в конфигурации «1С:Розница») внешнюю обработку часто запускают по расписанию через планировщик задач Windows. Типовая проблема, с которой сталкиваются разработчики: если вызвать метод ЗавершитьРаботуСистемы() в обработчике формы ПриОткрытии, клиентское приложение закрывается мгновенно, прерывая выполнение фоновых процедур и запись документов.
Выясним причину такого поведения и разберем правильные способы организации ожидания и корректного завершения работы программы.
Методы подсистемы подключаемого оборудования (БПО), такие как ПодключаемоеОборудованиеOfflineКлиент.НачатьЗагрузкуОтчетовОРозничныхПродажах и ПодключаемоеОборудованиеOfflineКлиент.НачатьВыгрузкуТоваровВККМOffline, являются асинхронными. Они инициализируют процесс обработки и сразу же возвращают управление клиентскому коду, передавая реальную работу серверным процедурам и фоновым заданиям.
Когда в коде вызывается метод ЗавершитьРаботуСистемы(), платформа 1С принудительно завершает клиентский сеанс. Связанные с ним серверные задания аварийно прерываются, транзакции откатываются, и создаваемые документы «Отчет о розничных продажах» не сохраняются в базе данных.
Рассмотрим правильный подход к организации логики в управляемой форме. Чтобы действия выполнялись строго по очереди, свяжем их через механизм ОписаниеОповещения, а сам старт вынесем в обработчик ожидания, чтобы дать форме полностью инициализироваться.
Разберем по шагам реализацию этого механизма в модуле формы обработки:
ПриСозданииНаСервере получаем список оборудования без лишних клиент-серверных вызовов.ПриОткрытии подключаем однократный обработчик ожидания для запуска загрузки отчетов.ЗавершитьРаботуСистемы(Ложь).Посмотрим на пример кода управляемой формы:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ЗаполнитьТЗКассыККМ();
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьТЗКассыККМ()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПодключаемоеОборудование.Ссылка,
| ПодключаемоеОборудование.Наименование КАК НазваниеККМ
|ИЗ
| Справочник.ПодключаемоеОборудование КАК ПодключаемоеОборудование
|ГДЕ
| ПодключаемоеОборудование.ТипОборудования = &ТипОборудования";
Запрос.УстановитьПараметр("ТипОборудования", Перечисления.ТипыПодключаемогоОборудования.ККМOffline);
Объект.ТЗКассыККМ.Загрузить(Запрос.Выполнить().Выгрузить());
КонецПроцедуры
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Запускаем цепочку через минимальную паузу после открытия интерфейса
ПодключитьОбработчикОжидания("ЗапуститьЗагрузкуОтчетов", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ЗапуститьЗагрузкуОтчетов() Экспорт
МассивККМ = Новый Массив;
Для Каждого СтрТЗ Из Объект.ТЗКассыККМ Цикл
МассивККМ.Добавить(СтрТЗ.НазваниеККМ);
КонецЦикла;
// Оповещение сработает после того, как БПО завершит загрузку отчетов
Оповещение = Новый ОписаниеОповещения("ПослеЗагрузкиОтчетов", ЭтотОбъект);
ПодключаемоеОборудованиеOfflineКлиент.НачатьЗагрузкуОтчетовОРозничныхПродажах(Оповещение, МассивККМ);
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗагрузкиОтчетов(Результат, Параметры) Экспорт
МассивККМ = Новый Массив;
Для Каждого СтрТЗ Из Объект.ТЗКассыККМ Цикл
МассивККМ.Добавить(СтрТЗ.НазваниеККМ);
КонецЦикла;
// Передаем оповещение на финальную процедуру закрытия
Оповещение = Новый ОписаниеОповещения("ПослеВыгрузкиТоваров", ЭтотОбъект);
ПодключаемоеОборудованиеOfflineКлиент.НачатьВыгрузкуТоваровВККМOffline(Оповещение, МассивККМ, Ложь);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВыгрузкиТоваров(Результат, Параметры) Экспорт
// Закрываем клиентский сеанс без вывода диалоговых окон подтверждения
ЗавершитьРаботуСистемы(Ложь);
КонецПроцедуры
В ситуациях, когда обрабатывается большой массив касс и на стороне сервера создаются объемные документы, оповещение клиентского модуля может сработать чуть раньше, чем завершатся внутренние служебные процедуры записи. В таком случае перед вызовом ЗавершитьРаботуСистемы можно подключить обработчик ожидания на необходимое количество секунд.
Проанализируем пример завершающего шага:
&НаКлиенте
Процедура ПослеВыгрузкиТоваров(Результат, Параметры) Экспорт
// Задаем гарантированную паузу в 5-10 секунд для фиксации всех транзакций
ПодключитьОбработчикОжидания("ФинальноеЗавершениеРаботы", 5, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ФинальноеЗавершениеРаботы() Экспорт
ЗавершитьРаботуСистемы(Ложь);
КонецПроцедуры
Важно: Не используйте пустые циклы вида Пока А < 300000 Цикл для создания пауз. Такие циклы на 100% загружают процессорное ядро и блокируют обработку системных сообщений интерфейса 1С. Все задержки должны реализовываться исключительно через ПодключитьОбработчикОжидания.
Если нет необходимости открывать интерактивный интерфейс тонкого клиента, запуск регламентной обработки можно реализовать через скрипт VBScript или COM-соединение V83.COMConnector.
При COM-соединении код выполняется полностью на стороне сервера в синхронном режиме. Скрипт не перейдет к следующей строке и не закроет соединение до тех пор, пока серверная процедура полностью не завершит запись всех документов.
Посмотрим на пример вызова внешней обработки через VBScript:
Set v8 = CreateObject("V83.Application")
' Подключаемся к информационной базе
res = v8.Connect("Srvr=Server1C;Ref=BaseRetail;Usr=AutoExchange;Pwd=SecretPassword;")
' Создаем объект внешней обработки
Set obr = v8.ExternalDataProcessors.Create("C:\Exchange\OfflineKKM.epf")
' Вызываем экспортную процедуру модуля обработки
obr.ВыполнитьОбменСКассами()
' Завершаем сеанс
v8.Exit()
Сервер (например, ПодключаемоеОборудованиеOfflineСервер). Прямой вызов серверной логики гарантирует завершение всех транзакций до выхода из процедуры.