Как во внешней обработке заполнения объекта создать договор, подставить его в форму и вывести печатную форму на экран?

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

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

Анализ проблемы и архитектурные ограничения

Выясним причину, почему первоначальная реализация через серверную команду ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода не решает поставленную задачу:

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

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

Реализация через клиентскую команду внешней обработки

Разберем по шагам правильную структуру внешней обработки для БСП.

Шаг 1. Регистрация обработки в модуле объекта

В модуле объекта внешней обработки указываем тип команды ТипКомандыВызовКлиентскогоМетода. Это позволит платформе БСП открыть служебную форму обработки и передать управление клиентскому методу.


Функция СведенияОВнешнейОбработке() Экспорт

    ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.1");
    ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиЗаполнениеОбъекта;
    ПараметрыРегистрации.Версия = "1.0";
    ПараметрыРегистрации.Назначение.Добавить("Документ.ЗаказКлиента");
    ПараметрыРегистрации.БезопасныйРежим = Ложь;

    НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
    НоваяКоманда.Представление = НСтр("ru = 'Сформировать договор и печатную форму'");
    НоваяКоманда.Идентификатор = "СформироватьДоговорИПечать";
    НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода;
    НоваяКоманда.ПоказыватьОповещение = Ложь;

    Возврат ПараметрыРегистрации;

КонецФункции

Шаг 2. Создание основной формы обработки

Добавим в состав внешней обработки новую форму и назначим её основной. В модуле этой формы опишем процедуру ВыполнитьКоманду с директивой &НаКлиенте.

Проанализируем алгоритм работы в модуле формы:

  1. Проверяем, откуда вызвана команда. Если она вызвана из формы документа, свойство ЭтаФорма.ВладелецФормы содержит контекст открытой формы заказа.
  2. Вызываем серверную функцию для создания договора и подготовки макета печатной формы.
  3. Заполняем реквизит прямо на форме-владельце через обращение к ВладелецФормы.Объект.Договор.
  4. Устанавливаем свойство ВладелецФормы.Модифицированность = Истина, чтобы платформа предложила сохранить документ при закрытии.
  5. Выводим сформированный ТабличныйДокумент на экран клиенту.
  6. Закрываем служебную форму обработки через ЭтаФорма.Закрыть().

&НаКлиенте
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначенияМассив) Экспорт

    Если ВладелецФормы = Неопределено Тогда
        ПоказатьПредупреждение(, НСтр("ru = 'Команда должна вызываться из формы документа!'"));
        Возврат;
    КонецЕсли;

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

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

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

Альтернативный вариант: вывод через стандартную подсистему печати БСП

Если в конфигурации принят единый стандарт работы с печатными формами (с панелью отправки по почте, предпросмотром и сохранением в PDF), вместо метода Показать() используем процедуры модуля УправлениеПечатьюКлиент.

Посмотрим на пример вызова стандартной подсистемы печати:


// На стороне сервера формируем коллекцию печатных форм:
Коллекция = УправлениеПечатью.ПодготовитьКоллекциюПечатныхФорм("СчетДоговор");
УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(Коллекция, "СчетДоговор", "Счет-договор", ТабДок);

// На стороне клиента открываем форму печати:
ПараметрыОткрытия = Новый Структура("ВспомогательныйМассив", Коллекция);
УправлениеПечатьюКлиент.ПечатьДокументов(Коллекция, Неопределено, ВладелецФормы);

Рекомендации по обработке исключительных ситуаций

  1. Вызов из формы списка: если пользователь запустит обработку, выделив строку в динамическом списке документов, ВладелецФормы.Объект будет недоступен. В этом случае следует либо выдать предупреждение о необходимости открывать форму документа, либо выполнять запись напрямую в объект базы данных через серверный вызов с последующим вызовом ОповеститьОбИзменении(ЭлементМассива).
  2. Проверка заполнения: перед созданием договора необходимо обязательно проверять обязательные реквизиты (организацию, контрагента, валюту), чтобы не создавать некорректные или пустые элементы в справочнике.
← На главную