Как программно создать и открыть несколько документов на основании одного в 1С

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

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

Анализ проблемы и ограничений платформы

Первое, с чем сталкивается разработчик — это попытка реализовать логику в стандартном обработчике ОбработкаЗаполнения в модуле объекта. Проанализируем, почему этот путь является тупиковым для нашей задачи:

  1. Контекст выполнения: Обработчик ОбработкаЗаполнения выполняется строго на сервере. Согласно архитектуре управляемого приложения, серверный код не может управлять интерфейсом. Мы не можем вызвать команду ОткрытьФорму из серверного контекста модуля объекта.
  2. Объектная модель: Этот метод предназначен для инициализации одного текущего объекта. Если мы попытаемся внутри него создавать другие документы кодом Документы.НужныйТип.СоздатьДокумент(), нам придется их записывать, чтобы не потерять.
  3. Транзакционность и логика: Если пользователь нажмет "Создать на основании", сработает ваш код, создаст и запишет три документа в базу, а потом пользователь передумает и закроет форму основного (четвертого) документа без записи — в базе останутся три "мусорных" документа.

Выясним причину: для корректного решения нам нужно перенести инициализацию процесса на сторону клиента.

Решение через использование расширений конфигурации

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

Разберем по шагам алгоритм создания команды:

  1. Создадим новое расширение и добавим в него документ-основание (например, РеализацияТоваровУслуг).
  2. Добавим новую команду. В свойствах команды укажем Тип параметра команды — ДокументСсылка.РеализацияТоваровУслуг.
  3. Установим Группу команды: Командная панель формы.Создать на основании. Теперь наша кнопка появится в стандартном подменю.

Теперь проанализируем код клиентского метода этой команды. Нам нужно получить данные из документа-основания и в цикле вызвать открытие форм новых документов.


&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
    
    // Получаем данные табличной части (нужен серверный вызов)
    ДанныеДляЗаполнения = ПолучитьДанныеДокументаНаСервере(ПараметрКоманды);
    
    Если ДанныеДляЗаполнения.Количество() > 10 Тогда
        ОписаниеОповещения = Новый ОписаниеОповещения("ВыполнитьСозданиеПослеПодтверждения", ЭтотОбъект, ДанныеДляЗаполнения);
        ПоказатьВопрос(ОписаниеОповещения, "Будет создано " + ДанныеДляЗаполнения.Количество() + " документов. Продолжить?", РежимДиалогаВопрос.ДаНет);
    Иначе
        ВыполнитьЦиклОткрытияФорм(ДанныеДляЗаполнения);
    КонецЕсли;
    
КонецПроцедуры

Передача параметров и заполнение объектов

Чтобы каждый новый документ "знал", какой именно строкой из основания он должен заполниться, мы будем использовать структуру ЗначенияЗаполнения. Рассмотрим, как правильно передать эти данные в функцию ОткрытьФорму.

В модуле команды (или формы) создадим процедуру открытия:


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

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


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

Альтернативный метод: Дополнительные обработки (БСП)

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

Посмотрим на преимущества этого метода:

Для реализации этого метода необходимо создать внешнюю обработку и в модуле объекта прописать функцию СведенияОВнешнейОбработке(). В таблице команд укажите вид ЗаполнениеОбъекта или СозданиеСвязанныхОбъектов. Важно указать использование ОткрытиеФормы, если вы хотите использовать клиентскую логику.

Меры предосторожности и юзабилити

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

Рекомендации по оптимизации:

  1. Лимит на открытие: Установите жесткий лимит (например, не более 5-10 окон). Если строк больше — выдавайте предупреждение или предлагайте другой сценарий.
  2. Промежуточная форма: Вместо немедленного создания создайте небольшую форму-ассистент, где пользователь увидит список строк и сможет отметить галочками только те, по которым действительно нужно создать документы.
  3. Фоновое создание: Если документов действительно много, рассмотрите вариант их создания на сервере без открытия форм. После завершения процесса можно вывести пользователю список ссылок на созданные объекты.

Таким образом, мы разобрали, что ключевым моментом решения является уход от стандартного серверного механизма заполнения в сторону клиентского управления формами. Использование Структуры в параметре ЗначенияЗаполнения позволяет гибко передавать контекст из одного документа в другой, обеспечивая корректное разделение данных табличной части.

← На главную