При настройке обмена данными между конфигурациями «Управление торговлей 10.3» (УТ 10) и «Бухгалтерия предприятия 3.0» (БП 3.0) разработчики часто сталкиваются со специфическими требованиями бизнеса. Одно из наиболее распространенных требований — трансформация данных при переносе документов. Например, при переносе документа «Счет на оплату» необходимо передать номенклатуру, наименование которой должно формироваться динамически на основе нескольких реквизитов источника: родительской группы номенклатуры, самого наименования, свойств его характеристики и размера из табличной части документа.
В процессе реализации такой задачи в программе «Конвертация данных 2.1» (КД 2.1) неопытные разработчики часто совершают архитектурную ошибку, пытаясь передать обычную строку в стандартное Правило конвертации объектов (ПКО) номенклатуры, настроенное на работу со ссылочным типом источника. Это приводит к ошибкам выгрузки или к тому, что табличная часть документа в приемнике загружается пустой.
В этой статье мы подробно разберем, почему возникает эта ошибка, и рассмотрим два надежных варианта решения проблемы: классическую конвертацию «Строка в Справочник» через ПКО с пустым источником и передачу данных с помощью механизма исходящих и входящих данных.
Типичная ошибка, с которой сталкивается программист при попытке передать собранную строку в качестве номенклатуры, выглядит следующим образом:
Ошибка получения значения свойства объекта (по имени свойства источника)
ПКО = Номенклатура (Справочник: Номенклатура)
ПКС = 2 (Наименование --> Наименование)
Объект = Куртки женские Куртка Какао 48 (Строка)
СвойствоПриемника = Наименование (Строка)
ОписаниеОшибки = Получение элемента по индексу для значения не определено
Проанализируем ситуацию. Данная ошибка возникает из-за того, что в Правилах конвертации свойств (ПКС) табличной части документа для свойства Номенклатура было указано стандартное ПКО, в котором Источник определен как справочник (ссылочный тип СправочникСсылка.Номенклатура).
Когда мы пишем произвольный код в обработчике «Перед выгрузкой» ПКС табличной части и присваиваем переменной Значение обычную строку (например, собранный текст с группой, размером и характеристикой), система КД 2.1 пытается применить к этой строке выбранное ПКО. На этапе обработки ПКС «Наименование» внутри этого ПКО движок конвертации пытается прочитать из источника его свойства. Физически это выглядит как обращение вида Источник.Наименование или Источник["Наименование"]. Но поскольку наш Источник в данный момент — это примитивный тип (обычная строка), попытка обратиться к нему по индексу или через точку вызывает критический сбой в модуле обработки обмена.
Для того чтобы избежать этого поведения, нам нужно изменить подход к настройке правил конвертации.
Этот способ является классическим для КД 2.1, когда в качестве источника выступает строка, а в приемнике необходимо найти или создать элемент справочника. Разберем этот вариант по шагам.
Шаг 1. Создание специального ПКО для Номенклатуры
Строка_В_Номенклатуру).СправочникСсылка.Номенклатура.Значение = Источник;
Примечание: Так как ПКО имеет пустой источник, переменная Источник при вызове правила будет содержать то значение, которое мы в него передали (нашу сформированную строку). Мы просто перенаправляем ее в выгружаемое значение наименования.
Шаг 2. Настройка ПКС в правиле конвертации документа
Теперь нам нужно настроить выгрузку табличной части «Товары» (или аналогичной) в документе «Счет на оплату».
Номенклатура.Строка_В_Номенклатуру.Номенклатура. Именно здесь мы будем динамически собирать наше уникальное наименование. Напишем следующий код:
// Получаем родительскую группу номенклатуры
РодительТекст = "";
Если ЗначениеЗаполнено(ОбъектКоллекции.Номенклатура.Родитель) Тогда
РодительТекст = Строка(ОбъектКоллекции.Номенклатура.Родитель) + " ";
КонецЕсли;
// Получаем свойства характеристики (адаптируйте под ваши метаданные УТ 10)
ХарактеристикаТекст = "";
Если ЗначениеЗаполнено(ОбъектКоллекции.Характеристика) Тогда
// Если свойства хранятся в дополнительных реквизитах характеристики
// Для примера предположим получение текстовых представлений свойств
Свойство1 = Строка(ОбъектКоллекции.Характеристика.Свойство1);
Свойство2 = Строка(ОбъектКоллекции.Характеристика.Свойство2);
Если ЗначениеЗаполнено(Свойство1) Или ЗначениеЗаполнено(Свойство2) Тогда
ХарактеристикаТекст = Свойство1 + " " + Свойство2 + " ";
КонецЕсли;
КонецЕсли;
// Получаем значение размера из табличной части документа
РазмерТекст = "";
Если ЗначениеЗаполнено(ОбъектКоллекции.Размер) Тогда
РазмерТекст = Строка(ОбъектКоллекции.Размер);
КонецЕсли;
// Собираем итоговую строку для поиска и создания номенклатуры в БП 3.0
Значение = СокрЛП(РодительТекст + Строка(ОбъектКоллекции.Номенклатура) + " " + ХарактеристикаТекст + РазмерТекст);
В КД 2.1 при выгрузке табличных частей текущая выгружаемая строка доступна через предопределенную переменную ОбъектКоллекции. Используя этот объект, мы безопасно обращаемся ко всем необходимым реквизитам строки и связанного справочника номенклатуры, формируя итоговую строку в переменной Значение.
Первый вариант отлично подходит, если в базе-приемнике (БП 3.0) вся необходимая номенклатура уже гарантированно создана, и нам требуется только найти ее по сформированному наименованию. Но что делать, если такой номенклатуры в БП 3.0 еще нет, и ее нужно автоматически создать в процессе загрузки счета?
Для создания нового полноценного элемента номенклатуры в приемнике одной строки наименования недостаточно. Как минимум, потребуются такие реквизиты, как ЕдиницаИзмерения, СтавкаНДС, Услуга и другие обязательные поля. Передать этот комплекс данных из строки табличной части документа в ПКО номенклатуры нам поможет механизм ИсходящиеДанные.
Шаг 1. Передача структуры данных из ПКС документа
В ПКС Номенклатура табличной части документа в обработчике «Перед выгрузкой» мы инициализируем специальную структуру ИсходящиеДанные:
ИсходящиеДанные = Новый Структура;
// Собираем наше динамическое наименование
РодительТекст = ?(ЗначениеЗаполнено(ОбъектКоллекции.Номенклатура.Родитель), Строка(ОбъектКоллекции.Номенклатура.Родитель) + " ", "");
ХарактеристикаТекст = ?(ЗначениеЗаполнено(ОбъектКоллекции.Характеристика), Строка(ОбъектКоллекции.Характеристика) + " ", "");
РазмерТекст = ?(ЗначениеЗаполнено(ОбъектКоллекции.Размер), Строка(ОбъектКоллекции.Размер), "");
ИмяДляПоиска = СокрЛП(РодительТекст + Строка(ОбъектКоллекции.Номенклатура) + " " + ХарактеристикаТекст + РазмерТекст);
// Заполняем структуру передаваемых свойств
ИсходящиеДанные.Вставить("Наименование", ИмяДляПоиска);
ИсходящиеДанные.Вставить("НаименованиеПолное", ИмяДляПоиска);
ИсходящиеДанные.Вставить("БазоваяЕдиницаИзмерения", ОбъектКоллекции.Номенклатура.БазоваяЕдиницаИзмерения);
ИсходящиеДанные.Вставить("СтавкаНДС", ОбъектКоллекции.Номенклатура.СтавкаНДС);
// Поле Значение оставляем пустым или Неопределено, так как вся информация передается в структуре
Значение = Неопределено;
Шаг 2. Настройка ПКО для приема структуры данных
Наименование, НаименованиеПолное, БазоваяЕдиницаИзмерения, СтавкаНДС).Наименование обязательно устанавливаем флаг «Поиск».При такой настройке XML-выгрузка сформирует узел с набором свойств из структуры ИсходящиеДанные. При загрузке в БП 3.0 система сначала выполнит поиск номенклатуры по переданному значению наименования. Если элемент не будет найден, она автоматически создаст новый элемент и заполнит его всеми реквизитами, которые мы передали во входящих данных.
Иногда при стандартном поиске по наименованию могут возникать неточности: например, из-за скрытых пробелов в строке, различий в регистрах или знаках препинания. Чтобы гарантировать корректное сопоставление номенклатуры при загрузке, мы можем переопределить стандартный алгоритм поиска.
Для этого в ПКО номенклатуры откроем обработчик «Поля поиска» и напишем следующий алгоритм:
Если НомерВариантаПоиска = 1 Тогда
// Исключаем лишние пробелы по краям строки поиска
СтрокаПоиска = СокрЛП(СвойстваПоиска["Наименование"]);
// Выполняем явный поиск по наименованию в базе БП
НайденнаяСсылка = Справочники.Номенклатура.НайтиПоНаименованию(СтрокаПоиска, Истина);
Если ЗначениеЗаполнено(НайденнаяСсылка) Тогда
СсылкаНаОбъект = НайденнаяСсылка;
ПрекратитьПоиск = Истина; // Прерываем дальнейшие стандартные попытки поиска
КонецЕсли;
КонецЕсли;
Параметр Истина в методе НайтиПоНаименованию указывает системе на необходимость точного совпадения строки. Это исключит ситуации, когда, к примеру, «Куртка Какао» будет ошибочно сопоставлена с элементом «Куртка Какао демисезонная».
Также обратите внимание на настройку ПКО: флаг «Не создавать новые объекты в приемнике, если они не найдены» должен быть снят, если вы хотите, чтобы новые уникальные комбинации номенклатуры и характеристик автоматически создавались в БП 3.0 в процессе загрузки документов.