При разработке в 1С мы часто сталкиваемся с необходимостью получить данные от пользователя непосредственно перед выполнением какой-либо операции, например, перед печатью документа. Типичная ситуация возникает, когда основная логика формирования печатной формы реализована в серверном модуле менеджера, а для ввода нужных параметров требуется вызвать клиентскую процедуру, такую как ВвестиСтроку или открыть пользовательскую форму. Однако, как мы выясним, прямой вызов клиентских процедур с сервера невозможен из-за архитектурных особенностей платформы 1С.
Давайте подробно разберем, почему возникает такая ситуация, и какие существуют эффективные способы решения этой задачи, чтобы мы могли обеспечить интерактивный ввод данных для наших печатных форм.
Суть проблемы: Клиент-серверное взаимодействие
Платформа 1С:Предприятие работает по принципу клиент-серверного взаимодействия. Клиент (тонкий клиент, веб-клиент) отвечает за пользовательский интерфейс, взаимодействие с пользователем, отображение форм и элементов управления. Сервер выполняет основную бизнес-логику, работает с данными в базе, проводит ресурсоемкие операции, не имея при этом доступа к пользовательскому интерфейсу. Попытка вызвать клиентскую процедуру, такую как ВвестиСтроку, из серверного кода равносильна попытке показать окно на компьютере, у которого может вообще не быть монитора или пользовательского сеанса. Это просто невозможно.
Модуль менеджера объекта метаданных (например, документа ЗаказПоставщику) по своей природе является серверным модулем. Все экспортные процедуры и функции, расположенные в нем, выполняются на сервере. Именно поэтому прямое использование клиентских функций, таких как ВвестиСтроку, внутри такого модуля приводит к ошибке.
Однако существуют проверенные и эффективные подходы для обхода этого ограничения. Мы рассмотрим несколько из них.
Это самый распространенный и архитектурно правильный способ решения нашей задачи. Вместо того чтобы пытаться вызвать клиентскую процедуру из серверного кода, мы должны инициировать открытие клиентской формы для ввода данных до вызова серверной процедуры печати. После того как пользователь введет необходимые данные и закроет форму, эти данные мы уже можем безопасно передать на сервер для формирования печатной формы.
Разберем по шагам, как это можно реализовать:
Инициация на клиенте: Когда пользователь нажимает кнопку печати (или выбирает печатную форму из списка), управление изначально находится на клиентской стороне. В этот момент мы и должны перехватить процесс.
Если мы используем стандартный механизм команд печати, как это реализовано в Библиотеке стандартных подсистем (БСП), то в процедуру ДобавитьКомандыПечати модуля менеджера объекта метаданных можно добавить команду, которая будет передавать управление в нужный модуль и функцию на клиенте. В качестве типа команды печати нужно будет указать КлиентскийМетод.
Открытие формы ввода на клиенте: На клиентской стороне, в нашей экспортной функции формирования печатной формы, мы описываем логику открытия формы для ввода параметров. Это может быть:
Специализированная форма: Создаем отдельную форму (например, форму обработки), предназначенную специально для сбора этих параметров. В этой форме размещаем поля для ввода строки, даты или других данных. Открываем ее с помощью ОткрытьФорму или ОткрытьФормуМодально.
// Пример клиентской процедуры, вызываемой при нажатии кнопки печати
Процедура КомандаПечати_МояФорма(Команда) Экспорт
// Создаем структуру для параметров формы
ПараметрыФормы = Новый Структура;
// ... возможно, передаем что-то в форму ввода ...
// Открываем форму для ввода параметров
ОткрытьФорму(
"ОбщаяФорма.ФормаВводаСтрокиДляПечати",
ПараметрыФормы,
Команда.Источник, // Владелец формы
УникальныйИдентификатор,
Новый ОписаниеОповещения("ПослеВводаСтроки", ЭтотОбъект, Команда.ДополнительныеПараметры)
);
КонецПроцедуры
ВвестиСтроку (если это простая строка): Если нужен только ввод одной строки, то ВвестиСтроку действительно является самым простым вариантом, но его можно вызвать только на клиенте.
// Пример использования ВвестиСтроку на клиенте
Перем ВведеннаяСтрока;
Если ВвестиСтроку(ВведеннаяСтрока, "Введите строку для печати", 50) Тогда
// Строка успешно введена, передаем ее на сервер
СформироватьИНапечататьСервер(ВведеннаяСтрока, СсылкиНаОбъекты);
КонецЕсли;
Обработка завершения формы: После того как пользователь введет данные и закроет форму, мы должны получить эти данные обратно в клиентской процедуре. Для этого при открытии формы используем механизм ОписаниеОповещения или ОбработчикЗакрытия:
// Обработчик закрытия формы ввода строки
Процедура ПослеВводаСтроки(Результат, Параметры) Экспорт
Если Результат <> Неопределено Тогда
ВведеннаяСтрока = Результат; // Результат - это введенная пользователем строка
// Теперь вызываем серверную процедуру для формирования печатной формы
СформироватьПечатнуюФормуНаСервере(ВведеннаяСтрока, Параметры.СсылкиНаОбъекты);
Иначе
// Пользователь отменил ввод
КонецЕсли;
КонецПроцедуры
Передача данных на сервер: Полученные от пользователя данные (например, введенная строка) затем передаются в серверную процедуру для формирования печатной формы. Обычно это делается через параметры серверного вызова. Например, можно передать их в структуру ПараметрыПечати или ДополнительныеПараметры, которая затем будет доступна в серверной процедуре.
// Серверная процедура формирования печатной формы
Процедура СформироватьПечатнуюФормуНаСервере(ВведеннаяСтрока, СсылкиНаОбъекты) Экспорт
// Здесь используем ВведеннаяСтрока для заполнения макета
Макет = ПолучитьМакет("МойМакетПечати");
ОбластьМакета = Макет.ПолучитьОбласть("Заголовок");
ОбластьМакета.Параметры.МояСтрокаИзПользователя = ВведеннаяСтрока;
// ... дальнейшая логика заполнения и вывода на печать
КонецПроцедуры
Ключевой момент: весь процесс инициируется на клиенте, ввод данных происходит на клиенте, и только затем, с уже готовыми данными, мы обращаемся к серверу.
Внешние печатные формы (ВПФ) являются мощным инструментом для расширения функционала типовых конфигураций без изменения основного кода. Если вы работаете с конфигурацией, которую нежелательно изменять (например, из-за поддержки вендора или необходимости регулярных обновлений), ВПФ — это отличное решение. В этом случае ВПФ может содержать свою собственную форму для ввода данных.
Разберем, как мы можем применить этот подход:
Создание ВПФ: Создаем внешнюю обработку и реализуем в ней логику формирования печатной формы. Внутри этой обработки мы можем создать и свою собственную форму для ввода параметров.
Регистрация ВПФ: При регистрации внешней печатной формы в системе 1С (обычно через раздел "Администрирование" -> "Печатные формы, отчеты и обработки" -> "Дополнительные отчеты и обработки") необходимо указать вид использования команды как "Вызов Клиентского Метода". Это гарантирует, что при выборе этой ВПФ система вызовет клиентскую процедуру из ее модуля, а не сразу серверную.
Реализация процедуры Печать в модуле ВПФ: В модуле объекта внешней обработки прописывается предопределенная экспортная процедура Печать (согласно спецификации БСП), которая может принимать массив объектов (ссылок на документы, для которых вызывается печать) и другие параметры.
// Пример процедуры Печать в модуле объекта ВПФ
Процедура Печать(МассивОбъектов, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
// 1. Открываем собственную форму для ввода параметров
ПараметрыФормы = Новый Структура("МассивОбъектов", МассивОбъектов);
ОткрытьФорму(
"ВнешняяОбработка.МояВПФ.Формы.ФормаВводаПараметров",
ПараметрыФормы,
ОбъектыПечати.Элементы[0].Владелец, // Владелец формы
УникальныйИдентификатор,
Новый ОписаниеОповещения("ОбработатьПараметрыИНапечатать", ЭтотОбъект,
Новый Структура("КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода", КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода))
);
КонецПроцедуры
Форма ввода параметров в ВПФ: Внутри этой же ВПФ создаем отдельную форму (например, ФормаВводаПараметров). Эта форма будет отвечать за сбор параметров от пользователя. Когда пользователь нажимает "ОК", форма возвращает введенные данные. Используем ЗавершитьРаботу для возврата значения.
Передача параметров и формирование на сервере: После того как пользователь введет данные в форму ВПФ, они возвращаются в клиентскую процедуру Печать (или ее обработчик закрытия). Эти параметры затем передаются в серверную процедуру ВПФ для формирования печатной формы. В модуле ВПФ могут быть как клиентские, так и серверные процедуры, что дает большую гибкость.
// Обработчик закрытия формы ввода параметров ВПФ
Процедура ОбработатьПараметрыИНапечатать(Результат, Параметры) Экспорт
Если Результат <> Неопределено Тогда
ВведеннаяСтрока = Результат.ВведеннаяСтрока; // Получаем данные из формы
// Вызываем серверную экспортную процедуру ВПФ для формирования печати
МояВПФНаСервере.СформироватьПечать(
Параметры.МассивОбъектов,
Параметры.КоллекцияПечатныхФорм,
Параметры.ОбъектыПечати,
Параметры.ПараметрыВывода,
ВведеннаяСтрока
);
Иначе
// Пользователь отменил ввод
КонецЕсли;
КонецПроцедуры
// Пример серверной экспортной процедуры в модуле ВПФ
Процедура СформироватьПечать(МассивОбъектов, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода, СтрокаДляПечати) Экспорт
// ... Логика формирования печатной формы с использованием СтрокаДляПечати ...
// Заполнение макетов, добавление в КоллекцияПечатныхФорм и т.д.
КонецПроцедуры
Преимущества ВПФ: Этот подход позволяет нам полностью инкапсулировать логику печати и ввода параметров в отдельную обработку, что очень удобно для поддержки и обновления.
Механизм ДополнительныеСвойства объекта документа (или другого объекта данных) может быть использован для передачи данных между клиентом и сервером. Однако это не является самостоятельным методом получения пользовательского ввода, а скорее способом его транспортировки. Этот метод предполагает, что данные уже должны быть где-то получены на клиентской стороне до вызова серверной процедуры печати.
Давайте посмотрим, как мы можем применить этот механизм:
Получение данных на клиенте: Сначала мы получаем данные от пользователя на клиенте, используя один из вышеописанных способов (открытие формы или ВвестиСтроку).
Запись в ДополнительныеСвойства: На клиентской стороне, после получения пользовательского ввода, мы записываем эти данные в ДополнительныеСвойства объекта документа, который затем будет передан на сервер для печати.
Например, если у нас есть объект документа (ОбъектДокумента) на клиенте:
// На клиентской стороне, после ввода строки
ВведеннаяСтрока = "Моя строка из пользователя"; // Получена через форму или ВвестиСтроку
// Добавляем строку в ДополнительныеСвойства объекта
Если ОбъектДокумента.ДополнительныеСвойства = Неопределено Тогда
ОбъектДокумента.ДополнительныеСвойства = Новый Структура;
КонецЕсли;
ОбъектДокумента.ДополнительныеСвойства.Вставить("МояСтрокаДляПечати", ВведеннаяСтрока);
// Теперь вызываем серверную процедуру, передавая объект
ВыполнитьПечатьНаСервере(ОбъектДокумента);
Важно: ДополнительныеСвойства должны быть инициализированы как Новый Структура, если они ещё не существуют.
Чтение на сервере: Затем этот объект документа, уже с дополнительными данными, передается на сервер для обработки и формирования печатной формы. На сервере мы получаем доступ к этим свойствам через ОбъектДокумента.ДополнительныеСвойства.
// На серверной стороне, в процедуре печати
Процедура ВыполнитьПечатьНаСервере(СсылкаИлиОбъект) Экспорт
// Если получили ссылку, нужно ее прочитать
ОбъектДокумента = СсылкаИлиОбъект;
Если ТипЗнч(СсылкаИлиОбъект) = Тип("ДокументСсылка.ЗаказПоставщику") Тогда
ОбъектДокумента = СсылкаИлиОбъект.ПолучитьОбъект();
КонецЕсли;
СтрокаИзПользователя = "";
Если ОбъектДокумента.ДополнительныеСвойства <> Неопределено И ОбъектДокумента.ДополнительныеСвойства.Свойство("МояСтрокаДляПечати") Тогда
СтрокаИзПользователя = ОбъектДокумента.ДополнительныеСвойства.МояСтрокаДляПечати;
КонецЕсли;
// Теперь СтрокаИзПользователя содержит данные, которые мы можем использовать в макете
// ... дальнейшая логика печати ...
КонецПроцедуры
Мы должны быть внимательны при использовании ДополнительныеСвойства, так как они существуют только в контексте данного объекта и не сохраняются в базе данных. Это временное хранилище для передачи данных в рамках одного вызова.
Полезным шагом для любого программиста 1С является изучение того, как реализована печать в типовых конфигурациях 1С. Разработчики "1С" уделяют большое внимание архитектуре и производительности, используя при этом проверенные механизмы Библиотеки стандартных подсистем (БСП).
Мы рекомендуем обратить внимание на механизмы печати таких документов, как ТТН (форма 1Т), где может требоваться ввод дополнительных данных (например, информации о водителе, машине и т.д.) перед формированием печатной формы. Анализируя их код, вы сможете увидеть, как именно реализовано взаимодействие клиентского и серверного кода, как используются вспомогательные формы для ввода параметров и как эти параметры передаются в серверные процедуры печати.
Типовые конфигурации часто используют следующие подходы:
КлиентскийМетод, которые вызывают клиентскую процедуру из общего модуля.Такой анализ не только даст вам конкретные примеры кода, но и поможет глубже понять принципы построения масштабируемых и поддерживаемых решений в 1С.
Чтобы успешно решать подобные задачи, мы должны всегда помнить о нескольких ключевых архитектурных принципах 1С:
Прямой вызов клиентской процедуры из серверного кода невозможен. Это фундаментальное ограничение, которое нельзя "обойти" напрямую. Любые решения будут строиться на инициировании действия на клиенте, получении данных на клиенте, а затем передаче их на сервер.
Модуль менеджера: Модуль менеджера объекта предназначен для "статической" функциональности, которая логически связана с объектом метаданных (например, ДокументЗаказПоставщику), но не зависит от состояния конкретного экземпляра объекта данных. В нем могут находиться функции для вывода на печать списка объектов, получения печатной формы по ссылке на объект или выполнения других серверных операций. Он не предназначен для интерактивного взаимодействия с пользователем.
Макеты печатных форм: Для формирования печатной формы используются макеты (например, типа "Табличный документ"), в которых параметры указываются в скобках <Параметр>. В коде необходимо заполнять эти параметры соответствующими значениями, которые могут быть получены как из объекта документа, так и из пользовательского ввода.
// Пример заполнения параметра макета
ОбластьМакета.Параметры.ДатаПечати = ТекущаяДата();
ОбластьМакета.Параметры.ВведеннаяСтрока = СтрокаИзПользователя; // Наш параметр!
Печать без участия оператора: Если речь идет о формировании печатной формы на сервере без участия оператора (например, в регламентных заданиях или при интеграции с другими системами), подходы будут принципиально иными. В этом случае данные для печати должны поступать из других источников (например, из настроек, параметров регламентного задания или данных, полученных по API), и не требуется интерактивный ввод. Обычно в таких сценариях формируются PDF-файлы, которые затем могут быть отправлены на принтер с помощью сторонних библиотек (например, Ghostscript) или сохранены в хранилище.
Таким образом, хотя прямой вызов клиентских процедур с сервера невозможен, у нас есть несколько надежных и гибких методов для получения пользовательского ввода перед печатью. Выбор конкретного метода будет зависеть от нашей задачи, используемой конфигурации и требований к модификации. Мы рекомендуем начать с подхода "Открытие формы для ввода параметра на клиенте", как наиболее универсального и соответствующего архитектуре 1С.