Как в 1С:Конвертации данных 2.1 обратиться к загружаемым данным в обработчике "ПриЗагрузке", если целевой объект не найден?

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

При работе с обменом данными в системе 1С:Конвертация данных 2.1 (КД 2.1) мы часто сталкиваемся с необходимостью выполнить определенную логику на этапе загрузки объекта в информационную базу. Особую сложность представляет ситуация, когда в обработчике ПриЗагрузке переменная Объект имеет значение Неопределено. Это происходит, когда объект-приемник не был найден в информационной базе по заданным правилам поиска, или же мы загружаем новый объект, для которого еще не сформирована ссылка в базе данных.

Возникает логичный вопрос: как же в этом случае получить доступ к самим данным, которые мы загружаем, чтобы, например, выполнить по ним собственный поиск, скорректировать их или использовать для других целей, до того как они будут присвоены свойствам объекта-приемника? Давайте рассмотрим подробнее механизмы, которые предоставляет КД 2.1 для решения этой задачи.

Понимание состояния переменной "Объект" в обработчике ПриЗагрузке

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

Существует несколько сценариев состояния переменной Объект:

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

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

Механизмы доступа к загружаемым данным при Объекте = Неопределено

Для доступа к входящим данным, когда переменная Объект имеет значение Неопределено, мы можем использовать следующие переменные, доступные в обработчике ПриЗагрузке:

1. Переменная "ВходящиеДанные": Доступ к сырым или частично конвертированным данным

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

Когда использовать:

  1. Для реализации собственной логики поиска объекта, если стандартные правила поиска КД 2.1 недостаточны. Например, если объект нужно найти по комбинации нескольких неочевидных полей или по данным из подчиненных табличных частей.
  2. Для предварительной валидации или модификации исходных данных перед их присвоением свойствам объекта.
  3. Для получения дополнительных полей, которые не являются прямыми реквизитами объекта, но используются в логике его создания или обработки.

Как это работает:

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

Рассмотрим пример. Допустим, мы загружаем документ "Заказ клиента", и у нас в источнике есть нестандартное поле "КодЗаказчикаПоДоговору", по которому мы хотим сначала найти существующего контрагента, если его нет – создать, и только потом привязать к документу. Стандартный поиск КД 2.1 не позволяет нам выполнить такую сложную логику без предварительной обработки.

В обработчике ПриЗагрузке Правила конвертации объекта "Заказ клиента" мы можем написать следующий код:


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

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

2. Переменная "Параметры": Обмен дополнительной информацией

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

Как данные попадают в "Параметры":

  1. На вкладке "Параметры" правила конвертации: Мы можем вручную определить параметры и их значения прямо в настройках правила.
  2. При выгрузке данных: Если в правиле выгрузки данных установлен флажок "Передавать параметр при выгрузке", то эти параметры будут включены в файл обмена и станут доступны при загрузке.
  3. Программно в обработчиках: Параметры могут быть заполнены или модифицированы программно в различных обработчиках, например, в ПередВыгрузкой, ПередЗагрузкой, ПриВыгрузке и других.

Когда использовать:

  1. Для передачи глобальных настроек обмена (например, организация-владелец, дата начала периода обмена, режим тестирования).
  2. Для передачи вспомогательных служебных данных, которые не являются частью основного объекта, но необходимы для его корректной обработки (например, логин пользователя, который инициировал обмен).
  3. Для реализации сложных алгоритмов, требующих информации, собранной на ранних этапах обмена или из других правил.

Пример использования:

Предположим, мы хотим, чтобы все загружаемые документы имели конкретную организацию, которая передается как параметр обмена. Или, например, мы хотим установить ответственного по умолчанию, если он не указан в выгрузке. Мы можем определить параметр "ОсновнаяОрганизация" и "ОтветственныйПоУмолчанию" и передать их.


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

Если Объект <> Неопределено И Параметры.Свойство("ОтветственныйПоУмолчанию") Тогда
    Если Объект.Свойство("Ответственный") И Объект.Ответственный = Неопределено Тогда
        Объект.Ответственный = Параметры.ОтветственныйПоУмолчанию;
    КонецЕсли;
КонецЕсли;

Как видите, Параметры позволяют нам получать доступ к заранее определенным или переданным значениям, что значительно расширяет возможности по управлению логикой загрузки.

3. Переменная "ПолученныеДанные": Предварительная обработка структуры данных

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

Когда использовать:

  1. Для корректной обработки входящих данных, например, для замены номера документа, форматирования строк или дат, до их переноса в данные объекта информационной базы.
  2. Для объединения или разделения значений из нескольких исходных полей в одно целевое, или наоборот.
  3. Для выполнения сложных преобразований данных, которые не могут быть реализованы стандартными правилами конвертации свойств.

Как это работает:

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

Пример использования:

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


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

Если ПолученныеДанные.Свойство("Дата") И ТипЗнч(ПолученныеДанные.Дата) = Тип("Строка") Тогда
    // Допустим, дата приходит в формате "DD.MM.YYYY" в виде строки
    Попытка
        ПолученныеДанные.Дата = Дата(Сред(ПолученныеДанные.Дата, 7, 4), Сред(ПолученныеДанные.Дата, 4, 2), Лев(ПолученныеДанные.Дата, 2));
    Исключение
        Сообщить("Не удалось преобразовать дату '" + ПолученныеДанные.Дата + "'. " + ОписаниеОшибки());
        ПолученныеДанные.Дата = '00010101'; // Устанавливаем минимальную дату в случае ошибки
    КонецПопытки;
КонецЕсли;

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

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

Управление поиском и созданием объекта: Переменная "ОбъектНайден"

Особое внимание следует уделить переменной ОбъектНайден. Это булево значение, которое по умолчанию устанавливается системой КД 2.1 в зависимости от результата выполнения правил поиска объекта.

Когда Объект = Неопределено, это обычно означает, что ОбъектНайден = Ложь. Однако, если мы реализуем собственную логику поиска (как в примере с ВходящиеДанные) и успешно находим или создаем объект, мы должны явно сообщить об этом системе КД 2.1.


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

Значение ОбъектНайден = Истина имеет критическое значение по нескольким причинам:

  1. Оно информирует КД 2.1, что объект-приемник для текущих входящих данных уже определен (либо найден, либо создан нами вручную).
  2. Это предотвращает попытки КД 2.1 создать новый объект автоматически, если мы уже сделали это или нашли существующий.
  3. Оно влияет на применение правил конвертации свойств. Если ОбъектНайден = Истина, то КД 2.1 продолжит заполнять свойства объекта Объект согласно правилам конвертации свойств. Если ОбъектНайден = Ложь (и Объект = Неопределено), то КД 2.1 будет пытаться создать новый объект по умолчанию, а затем заполнять его.
  4. При ОбъектНайден = Истина корректно работают флажки "Не замещать значение свойства" для существующих объектов, даже если Объект изначально был Неопределено, но мы его идентифицировали по собственному алгоритму.

Без установки ОбъектНайден = Истина, даже если мы вручную создадим и заполним Объект, КД 2.1 может воспринять это как временную переменную и все равно попытаться создать новый объект, что приведет к дублированию или некорректной загрузке.

Различие между "ПриЗагрузке" и "ПослеЗагрузки"

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

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

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

Заключение

Система 1С:Конвертация данных 2.1 предоставляет гибкие инструменты для работы с данными на этапе загрузки, даже в таких нетривиальных ситуациях, как отсутствие определенного объекта-приемника. Используя переменные ВходящиеДанные, Параметры и ПолученныеДанные, а также управляя переменной Объект и флагом ОбъектНайден, мы можем реализовать практически любую логику преобразования и создания объектов.

Мы рекомендуем всегда начинать с анализа входящих данных и требований к конечному объекту. Разбейте сложную логику на небольшие, управляемые шаги. Не забывайте использовать механизм отладки в КД 2.1 (через внешнюю обработку или конфигурацию), чтобы наглядно видеть содержимое всех переменных и отслеживать выполнение кода. Это поможет нам быстро выявлять и исправлять ошибки, а также подтверждать корректность нашей логики.

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

← На главную