Как программно определить реквизит связи между документами при вводе на основании

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

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

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

Способ 1: Анализ метаданных Критериев отбора

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

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


Функция НайтиИмяРеквизитаСвязиЧерезКритерийОтбора(ИмяДокументаПриемника)
    Критерий = Метаданные.КритерииОтбора.СвязанныеДокументы;
    Для Каждого ЭлементСостава Из Критерий.Состав Цикл
        // Путь к данным имеет вид "Документ.РеализацияТоваровУслуг.Реквизит.ЗаказКлиента"
        МассивПути = СтрРазделить(ЭлементСостава.ПолноеИмя(), ".");
        Если МассивПути[0] = "Документ" И МассивПути[1] = ИмяДокументаПриемника Тогда
            Возврат МассивПути[3]; // Возвращаем имя реквизита
        КонецЕсли;
    КонецЦикла;
    Возврат Неопределено;
КонецФункции

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

Способ 2: Эвристический поиск по типу данных

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

Рассмотрим алгоритм поиска:

  1. Получим тип данных объекта ДанныеЗаполнения.
  2. Переберем все реквизиты создаваемого документа через метаданные.
  3. Проверим, может ли конкретный реквизит хранить значение полученного типа.
  4. Для повышения точности проверим имя реквизита на соответствие шаблонам (Основание, Заказ и т.д.).

Пример кода для реализации этого метода:


Процедура ОбработкаЗаполнения(ДанныеЗаполнения, СтандартнаяОбработка)
    Если ДанныеЗаполнения = Неопределено Тогда
        Возврат;
    КонецЕсли;

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

Способ 3: Использование свойства метаданных "Заполнять из данных заполнения"

В платформе 8.3 у реквизитов появилось свойство Заполнять из данных заполнения. Если этот флаг установлен, платформа автоматически пытается заполнить реквизит, если в ДанныеЗаполнения передана ссылка подходящего типа. Это самый "штатный" механизм связи.

Мы можем программно найти такой реквизит, обратившись к свойству метаданных ЗаполнятьИзДанныхЗаполнения. Выясним, как это сделать:


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

Важный момент: Если в документе несколько таких реквизитов (что бывает редко, но возможно), платформа заполнит их все, если типы совпадают.

Способ 4: Отмена стандартной обработки

Если задача стоит в том, чтобы запретить ввод на основании при определенных условиях (как упоминалось в обсуждении на форуме), самым правильным способом будет не очистка реквизита после заполнения, а управление параметром СтандартнаяОбработка.

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


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

Итоги и рекомендации

Для создания максимально стабильного кода рекомендуем комбинированный подход:

  1. Сначала проверяйте свойство ЗаполнятьИзДанныхЗаполнения, так как это прямой программный признак намерения разработчика связать объекты.
  2. Используйте Критерии отбора для поиска косвенных связей, которые используются в отчетах "Структура подчиненности".
  3. Применяйте эвристический поиск по типам и именам только в том случае, если первые два метода не дали результата.

Помните, что использование СтандартнаяОбработка = Ложь — это наиболее чистый способ управления логикой заполнения, который предотвращает запись лишних данных в объект еще на этапе его инициализации в памяти.

← На главную