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