При настройке обмена данными между конфигурациями «Управление торговлей 10.3» и «Розница 1.0» разработчики часто сталкиваются с необходимостью переноса сложных иерархических структур. Типичный пример — перенос серий номенклатуры из источника (УТ) в серийные номера приемника (Розница) с одновременной генерацией или переносом штрихкодов в регистр сведений Штрихкоды.
Основная сложность здесь заключается в том, что в Рознице штрихкоды хранятся в подчиненном регистре сведений, где измерение Владелец ссылается на справочник Серийные номера. Если серийный номер переносится впервые, в процессе загрузки он создается как новый объект. Попытка записать штрихкод в обработчиках загрузки приводит к тому, что запись регистра создается с пустой или «битой» ссылкой на владельца, так как сам элемент справочника еще физически не записан в базу данных СУБД.
В этой статье мы подробно разберем причины возникновения этой проблемы и рассмотрим два практических способа ее решения в конфигурации «Конвертация данных 2.1».
Давайте проанализируем стандартный жизненный цикл объекта при загрузке через КД 2.1. Когда XML-пакет читается обработчиком загрузки, для каждого объекта создается программный экземпляр в оперативной памяти:
Справочники.СерийныеНомера.СоздатьЭлемент(). У него формируется уникальный идентификатор (ссылка), но физически в таблицах базы данных его еще нет.Если мы пытаемся в обработчике «После загрузки» обратиться к регистру сведений Штрихкоды и выполнить запись с отбором по Объект.Ссылка, платформа выдает ошибку либо создает пустую запись. Набор записей не может быть привязан к ссылке, которой физически не существует в СУБД на шаге 4. Для решения этой проблемы рассмотрим два метода.
Это самый быстрый и простой способ решения проблемы «в лоб». Мы принудительно записываем новый серийный номер в базу данных непосредственно перед тем, как начнется работа с регистром сведений Штрихкоды. Таким образом, к моменту создания набора записей ссылка на владельца гарантированно существует.
Откроем наши правила обмена в конфигурации «Конвертация данных 2.1», найдем ПКО для справочника серийных номеров (например, СерииНоменклатуры_СерийныеНомера) и в обработчик «После загрузки» пропишем следующий код:
// Проверяем, был ли объект найден в базе данных при поиске.
// Если это новый объект (ОбъектНайден = Ложь), записываем его принудительно.
Если Не ОбъектНайден Тогда
Объект.Записать();
// Сбрасываем флаг модифицированности. Это критически важно!
// Если этого не сделать, КД попытается записать объект повторно в штатном режиме,
// что приведет к лишней нагрузке на СУБД и возможным ошибкам блокировок.
ОбъектМодифицирован = Ложь;
КонецЕсли;
// Теперь ссылка гарантированно существует в СУБД.
// Создаем набор записей регистра сведений "Штрихкоды" с отбором по нашему объекту.
НаборЗаписей = РегистрыСведений.Штрихкоды.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Владелец.Установить(Объект.Ссылка);
НаборЗаписей.Прочитать();
Если НаборЗаписей.Количество() = 0 Тогда
// Если штрихкода еще нет, добавляем новую запись
НовыйНомер = НаборЗаписей.Добавить();
НовыйНомер.Владелец = Объект.Ссылка; // Указываем владельца
НовыйНомер.ТипШтрихкода = ПланыВидовХарактеристик.ТипыШтрихкодов.Code39; // Указываем тип штрихкода
НовыйНомер.ШтрихКод = Объект.КодСерийногоНомера; // Переносим код штрихкода
НаборЗаписей.Записать();
ИначеЕсли НаборЗаписей.Количество() = 1 Тогда
// Если запись уже есть, обновляем значение штрихкода при необходимости
НовыйНомер = НаборЗаписей[0];
НовыйНомер.ШтрихКод = Объект.КодСерийногоНомера;
НаборЗаписей.Записать();
КонецЕсли;
Преимущества метода: Простота реализации, весь код сосредоточен в одном обработчике ПКО.
Недостатки метода: Нарушается транзакционность загрузки КД. Принудительная запись объектов в обход штатного механизма КД может приводить к снижению скорости загрузки при больших объемах данных.
Для сохранения архитектурной чистоты правил обмена лучше использовать штатные механизмы КД 2.1. Мы можем передать данные для регистра через механизм выгрузки по правилу конвертации с использованием параметра ВходящиеДанные. При таком подходе КД сама определит очередность создания объектов: сначала запишет элемент справочника-владельца, а затем создаст запись в подчиненном регистре сведений.
Выполним настройку по шагам:
Создадим новое правило конвертации объектов (ПКО):
РегистрСведенийСсылка.Штрихкоды.ШтрихкодыСерийныхНомеров.Владелец, Штрихкод, ТипШтрихкода.Владелец укажите правило конвертации (ПКО) — то самое ПКО, которое конвертирует серии номенклатуры источника в серийные номера приемника (например, ПКО СерииНоменклатуры_СерийныеНомера).Теперь нам нужно инициировать выгрузку записи регистра. Сделать это лучше всего в обработчике «После выгрузки» ПКО СерииНоменклатуры_СерийныеНомера справочника-источника. Напишем алгоритм, который находит штрихкод серии в источнике и передает его в приемник через наше новое ПКО регистра:
// Выбираем штрихкод серии номенклатуры из регистра базы-источника (УТ)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Штрихкоды.Штрихкод КАК Штрихкод,
| Штрихкоды.ТипШтрихкода КАК ТипШтрихкода
|ИЗ
| РегистрСведений.Штрихкоды КАК Штрихкоды
|ГДЕ
| Штрихкоды.СерияНоменклатуры = &Серия";
Запрос.УстановитьПараметр("Серия", Источник.Ссылка);
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
// Формируем структуру входящих данных для передачи в ПКО регистра
ВходящиеДанные = Новый Структура;
// В качестве владельца передаем именно ссылку на Серию источника.
// КД сама сопоставит ее по ПКО "СерииНоменклатуры_СерийныеНомера"
// и подставит в приемнике уже созданный серийный номер.
ВходящиеДанные.Вставить("Владелец", Источник.Ссылка);
ВходящиеДанные.Вставить("Штрихкод", Выборка.Штрихкод);
ВходящиеДанные.Вставить("ТипШтрихкода", Выборка.ТипШтрихкода);
// Вызываем выгрузку по нашему новому правилу регистра штрихкодов
ВыгрузитьПоПравилу(,, ВходящиеДанные,, "ШтрихкодыСерийныхНомеров");
КонецЦикла;
КонецЕсли;
Если в вашей базе-источнике серии номенклатуры используются в качестве подарочных сертификатов (как описано в Сообщении 7 темы), у них может физически не быть записей в регистре Штрихкоды на стороне УТ. Однако в Рознице 1.0 наличие штрихкода для сертификата является обязательным условием для его корректного считывания на кассе.
В таком случае мы можем генерировать штрихкод искусственно прямо «на лету» в момент выгрузки, используя код или наименование серии номенклатуры. Модифицируем код обработчика «После выгрузки» ПКО серий следующим образом:
// Проверяем, является ли владелец серии подарочным сертификатом
Если Источник.Владелец.ВидНоменклатуры = Справочники.ВидыНоменклатуры.НайтиПоНаименованию("Подарочный сертификат") Тогда
// Создаем структуру входящих данных для генерации штрихкода
ВходящиеДанные = Новый Структура;
ВходящиеДанные.Вставить("Владелец", Источник.Ссылка);
// В качестве штрихкода передаем код серии из источника
ВходящиеДанные.Вставить("Штрихкод", Источник.Код);
ВходящиеДанные.Вставить("ТипШтрихкода", ПланыВидовХарактеристик.ТипыШтрихкодов.Code39);
// Выгружаем искусственно сформированный штрихкод
ВыгрузитьПоПравилу(,, ВходящиеДанные,, "ШтрихкодыСерийныхНомеров");
КонецЕсли;
Этот подход гарантирует стабильную загрузку данных без коллизий «незаписанного объекта», сохраняет высокую скорость обмена и позволяет гибко управлять генерацией сопутствующих данных в базе-приемнике.