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

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

В процессе разработки в конфигураторе «1С:Предприятие» программисты часто сталкиваются с ситуацией, когда стандартный Конструктор заполнения (ввод на основании) не справляется со сложными задачами. Типичный пример: необходимо создать документ «А», большая часть данных которого берется из документа «В», но одна специфическая колонка или реквизит шапки должны заполниться из совершенно другого объекта — документа или справочника «С».

Основная сложность заключается в том, что стандартный механизм платформы передает в обработчик заполнения только один объект-основание. Рассмотрим подробнее, почему так происходит и какие существуют способы решения этой задачи.

Почему стандартный конструктор не видит второй источник?

Проанализируем работу системы: когда вы нажимаете кнопку «Создать на основании», платформа инициирует создание нового объекта и передает ссылку на текущий документ в параметр ДанныеЗаполнения процедуры ОбработкаЗаполнения. Этот параметр по умолчанию является одиночной ссылкой. По законам логики 1С, переменная ДанныеЗаполнения не может быть одновременно и Документом «В», и Справочником «С».

Разберем основные стратегии, которые позволяют обойти это ограничение и корректно заполнить все необходимые данные.

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

Если создание документа «А» инициируется программно (например, кнопкой на форме или из списка), мы можем передать в ДанныеЗаполнения не одну ссылку, а целую Структуру. Это самый гибкий и мощный метод.

Рассмотрим пример кода, который вызывается при нажатии кнопки «Создать документ А»:


ПараметрыЗаполнения = Новый Структура;
ПараметрыЗаполнения.Вставить("ОснованиеВ", Объект.Ссылка); // Ссылка на текущий документ В
ПараметрыЗаполнения.Вставить("ДополнительныйИсточникС", Объект.НужныйСправочник); // Ссылка на объект С

ПараметрыФормы = Новый Структура("ЗначенияЗаполнения", ПараметрыЗаполнения);
ОткрытьФорму("Документ.ДокументА.ФормаОбъекта", ПараметрыФормы);

Теперь в модуле создаваемого документа «А» нам необходимо вручную прописать логику обработки этой структуры в процедуре ОбработкаЗаполнения. Посмотрим на пример реализации:


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

Способ 2. Создание логической связи через реквизиты

Если вы хотите продолжать использовать стандартную кнопку «Создать на основании» без написания сложного программного вызова формы, выясним причину, по которой данные «С» недоступны из «В». Самый простой путь — сделать так, чтобы документ «В» уже содержал ссылку на объект «С».

Выполним следующие шаги:

  1. Добавим в документ «В» новый реквизит (например, СвязанныйОбъектС).
  2. При заполнении документа «В» будем указывать этот объект.
  3. В конструкторе заполнения документа «А» мы просто обращаемся к ДанныеЗаполнения.СвязанныйОбъектС.

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

Способ 3. Получение данных запросом в обработчике заполнения

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

Проанализируем ситуацию: документ «А» вводится на основании «В». Нам нужно найти в базе справочник «С», связанный с этим контрагентом. Используем следующий подход:


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

Важные рекомендации по работе с табличными частями

При заполнении на основании нескольких источников важно помнить о методах работы с коллекциями строк. Рассмотрим типичные ошибки:

Итог: Для решения проблемы «ввода на основании двух объектов» лучше всего использовать передачу Структуры в параметрах открытия формы или реализовать поиск недостающих данных через запрос внутри модуля создаваемого документа. Конструктор является лишь вспомогательным инструментом для простых случаев, а настоящая гибкость достигается только через написание кода в процедуре ОбработкаЗаполнения.

← На главную