Как программно открыть несколько форм документов на основании строк табличной части?

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

При стандартном подходе к вводу на основании в системе 1С:Предприятие, как правило, создается лишь один новый документ. Однако, на практике часто возникает задача, когда необходимо сформировать не один, а сразу несколько документов, причем каждый из них должен быть основан на отдельной строке табличной части исходного документа. Например, если в документе "Заказ клиента" три строки товаров, и мы хотим создать три отдельных документа "Реализация товаров и услуг" – по одному на каждую строку заказа. Стандартными средствами такой функционал не предусмотрен, и нам придется реализовать его программно. Рассмотрим подробнее, как мы можем достичь этой цели, используя различные подходы.

Для решения данной задачи существуют два основных пути: создание своей команды, интегрированной в стандартное меню "Ввод на основании", или разработка отдельной внешней обработки. Оба варианта позволяют нам получить необходимую гибкость и реализовать логику создания множества документов.

Подход 1: Создание своей команды в меню "Ввод на основании"

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

  1. Создание команды обработки:

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

    В дереве объектов конфигурации находим нужный документ ("ДокументОснование"), переходим на закладку "Команды" и добавляем новую команду, например, с именем СоздатьДокументыПоСтрокамТЧ. В свойствах этой команды устанавливаем флаг "Использование: Ввод на основании". Это позволит нашей команде появиться в стандартном меню "Создать на основании".

  2. Размещение команды в командном интерфейсе:

    После создания команды, нам необходимо разместить ее в командном интерфейсе документа. Это делается на закладке "Командный интерфейс" документа или через формы самого документа, если мы хотим разместить её на форме объекта.

  3. Реализация обработчика команды:

    В обработчике команды СоздатьДокументыПоСтрокамТЧ (который будет выполняться на клиенте), нам потребуется получить данные документа-основания и передать их на сервер для обработки, или же реализовать всю логику на клиенте, если это позволяет архитектура и объем данных.

    Рассмотрим пример, когда мы вызываем серверную процедуру для основной логики:

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

    Здесь мы используем метод ОткрытьФорму(), который позволяет открыть форму нового объекта. Критически важно передать в него ПараметрыЗаполнения – это структура, которую мы заполняем данными из текущей строки табличной части и ссылки на документ-основание. Эти параметры будут доступны в обработчике нового документа.

  4. Обработка заполнения в новом документе:

    Чтобы новая форма открылась уже заполненной данными из строки табличной части, необходимо реализовать обработчик ОбработкаЗаполнения в модуле объекта или модуле формы целевого документа ("ДокументЦелевой").

    В модуле объекта документа "ДокументЦелевой" это будет выглядеть примерно так:

    
    // Модуль объекта ДокументЦелевой
    Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
        // Стандартная обработка нам здесь не нужна, так как заполняем вручную
        СтандартнаяОбработка = Ложь;
    
        // Проверяем, были ли переданы наши ПараметрыЗаполнения
        Если ТипЗнч(ДанныеЗаполнения) = Тип("Структура") И ДанныеЗаполнения.Свойство("ПараметрыЗаполнения") Тогда
            Параметры = ДанныеЗаполнения.ПараметрыЗаполнения;
            
            // Получаем ссылку на документ-основание и данные строки ТЧ
            Если Параметры.Свойство("ДокументОснование") Тогда
                Объект.ДокументОснование = Параметры.ДокументОснование;
            КонецЕсли;
    
            Если Параметры.Свойство("СтрокаТабличнойЧасти") Тогда
                СтрокаТЧОснования = Параметры.СтрокаТабличнойЧасти;
                
                // Заполняем поля нового документа на основании данных из строки ТЧ
                Объект.Номенклатура = СтрокаТЧОснования.Номенклатура;
                Объект.Количество = СтрокаТЧОснования.Количество;
                Объект.Цена = СтрокаТЧОснования.Цена;
                Объект.Сумма = СтрокаТЧОснования.Сумма;
                
                // Если есть табличная часть в целевом документе, 
                // можно перенести туда данные или создать одну строку
                НоваяСтрокаТЧЦелевого = Объект.ТабличнаяЧасть2.Добавить();
                НоваяСтрокаТЧЦелевого.Номенклатура = СтрокаТЧОснования.Номенклатура;
                НоваяСтрокаТЧЦелевого.Количество = СтрокаТЧОснования.Количество;
                НоваяСтрокаТЧЦелевого.Цена = СтрокаТЧОснования.Цена;
                НоваяСтрокаТЧЦелевого.Сумма = СтрокаТЧОснования.Сумма;
                // ... и так далее для других реквизитов
            КонецЕсли;
            
            // Можно заполнить другие стандартные поля, если они не заполнились автоматически
            Объект.Дата = ТекущаяДата();
            Объект.Ответственный = Пользователи.ТекущийПользователь();
            // ...
        КонецЕсли;
    КонецПроцедуры
    

    В этом обработчике мы получаем переданную структуру ПараметрыЗаполнения и используем ее для заполнения полей нового документа. Таким образом, каждая открытая форма документа уже будет содержать данные, специфичные для соответствующей строки табличной части.

  5. Открытие без записи документа:

    Метод ОткрытьФорму() по умолчанию открывает форму нового документа в режиме создания, но не записывает его автоматически. Пользователь сможет просмотреть каждую из открытых форм, внести необходимые изменения и только потом сохранить документ. Это обеспечивает контроль пользователя над процессом создания документов.

Подход 2: Использование внешней обработки или обработки, встроенной в конфигурацию

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

  1. Создание обработки:

    Мы создаем новую обработку (либо как внешнюю, либо как объект конфигурации "Обработка"). В этой обработке нам понадобится форма.

  2. Механизм вызова обработки:

    Обработка может быть зарегистрирована в системе как "Дополнительная обработка заполнения объектов" или "Дополнительная печатная форма", что позволит ей быть доступной из меню "Ввод на основании" или "Дополнительные обработки" документа-основания. При ее открытии мы передаем в нее ссылку на исходный документ как параметр.

    Например, в обработчике команды в документе-основании, вместо непосредственного открытия форм целевого документа, мы открываем форму нашей обработки:

    
    // Модуль формы ДокументаОснование
    &НаКлиенте
    Процедура СоздатьДокументыЧерезОбработку(Команда)
        // Получаем ссылку на текущий документ-основание
        СсылкаДокументаОснования = Объект.Ссылка;
        
        // Создаем структуру параметров для открытия формы обработки
        ПараметрыОткрытия = Новый Структура();
        ПараметрыОткрытия.Вставить("ДокументОснование", СсылкаДокументаОснования);
        
        // Открываем форму нашей обработки
        ОткрытьФорму(
            "Обработка.МояОбработкаДляСозданияДокументов.Форма", 
            ПараметрыОткрытия, 
            ЭтаФорма
        );
    КонецПроцедуры
    
  3. Функционал формы обработки:

    На форме обработки мы создаем табличное поле, которое будет отображать строки табличной части исходного документа. Добавляем колонку, позволяющую пользователю отмечать, какие именно строки он хочет использовать для создания документов. Также предусматриваем кнопку, например, "Создать документы".

    При открытии формы обработки, в ее обработчике ПриСозданииНаСервере или ПриОткрытии, мы получаем переданный параметр - ссылку на документ-основание, считываем его табличную часть и заполняем ею наше табличное поле на форме обработки.

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

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

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

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

Особенности платформы и открытие нескольких форм

Важно понимать, что платформа 1С:Предприятие не ограничивает количество одновременно открываемых форм. Мы можем последовательно вызывать метод ОткрытьФорму() в цикле, и каждая новая форма будет открываться в отдельном окне или вкладке, в зависимости от режима работы пользователя (тонкий клиент, веб-клиент) и его настроек. Таким образом, технически нет препятствий для открытия скольких угодно форм.

Однако, при реализации такого функционала, мы должны учитывать производительность и удобство для пользователя. Если в табличной части исходного документа сотни строк, и мы попытаемся открыть сотни форм одновременно, это может привести к значительной нагрузке на клиентское приложение и сервер, а также к неудобствам для пользователя, который будет вынужден закрывать или обрабатывать большое количество окон. В таких случаях целесообразно предоставлять пользователю возможность выбора строк для обработки или реализовать фоновое создание документов без открытия форм.

Дополнительные соображения

  1. Использование общих модулей:

    Если логика заполнения нового документа достаточно сложна или используется в нескольких местах, рекомендуем вынести ее в отдельный общий модуль. Это поможет избежать дублирования кода, упростит его поддержку и повысит читаемость. Серверные процедуры для создания документов также могут быть расположены в общих модулях.

  2. Контроль ссылок:

    При передаче ссылок на объекты (например, на родительский документ или элементы справочников) через ПараметрыЗаполнения, мы должны убедиться, что эти объекты существуют и доступны. В случае удаления или изменения объекта, ссылка может стать недействительной, что приведет к ошибкам.

  3. Пользовательский опыт и обратная связь:

    Если документов создается много, желательно предоставить пользователю обратную связь о ходе процесса. Это может быть индикатор выполнения, сообщение о количестве созданных документов или список ссылок на новые документы. Это позволит пользователю понять, что система работает, и избежать ощущения "зависания".

  4. Автоматическое заполнение полей:

    Помимо полей, непосредственно связанных со строкой табличной части, не забываем заполнять и другие обязательные или стандартные реквизиты нового документа, такие как дата, организация, ответственный и т.д. Некоторые из них могут быть заполнены автоматически при создании нового элемента через Документы.ДокументЦелевой.СоздатьДокумент(), а другие – вручную в ОбработкаЗаполнения.

Таким образом, для реализации создания нескольких документов на основании строк табличной части, оптимальным и наиболее гибким является программный подход. Мы можем использовать либо пользовательскую команду, встроенную в документ-основание, либо отдельную обработку. В обоих случаях ключевыми элементами являются метод ОткрытьФорму() с передачей ПараметрыЗаполнения и обработчик ОбработкаЗаполнения в целевом документе, который использует эти параметры для инициализации полей.

← На главную