При настройке правил обмена в конфигурации «Конвертация данных 2.1» разработчики часто сталкиваются с ситуацией, когда данные справочника переносятся частично. Типичный пример — перенос справочника Номенклатура, у которого реквизиты ЕдиницаХраненияОстатков и ЕдиницаДляОтчетов остаются пустыми в базе-приемнике, несмотря на то, что подчиненный справочник ЕдиницыИзмерения успешно выгружается. Вторая сопутствующая задача — необходимость перенести связанные с товаром записи регистра сведений Штрихкоды, которые не переносятся по стандартным ссылкам из табличных частей документов.
Разберем по шагам причины возникновения этих трудностей и рассмотрим надежные способы их устранения.
Проанализируем механику работы универсального обмена. В типовых конфигурациях 1С элемент справочника ЕдиницыИзмерения подчинен конкретной номенклатуре через реквизит Владелец. В то же время сам элемент номенклатуры ссылается на единицы измерения в своих реквизитах ЕдиницаХраненияОстатков и ЕдиницаДляОтчетов.
Возникает классическая циклическая зависимость:
Кроме того, при обмене данными через универсальную обработку загрузка выполняется с установленным свойством ОбменДанными.Загрузка = Истина. Это отключает типовые прикладные обработчики событий конфигурации (например, ПередЗаписью или ПриЗаписи), которые при интерактивной работе пользователя автоматически создают базовую единицу измерения и подставляют ее в реквизиты новой карточки товара.
Рассмотрим наиболее стабильный способ решения проблемы, который позволяет избежать коллизий порядка записи объектов в базе-приемнике.
Суть подхода заключается в том, чтобы не передавать реквизиты ЕдиницаХраненияОстатков и ЕдиницаДляОтчетов напрямую из базы-источника, а заполнять их уже после того, как номенклатура и все ее подчиненные единицы записаны в приемнике.
Номенклатура отключаем передачу свойств для реквизитов ЕдиницаХраненияОстатков и ЕдиницаДляОтчетов (снимаем активность соответствующих строк в правилах конвертации свойств).Номенклатура в обработчике ПослеЗагрузки прописываем поиск нужной единицы среди уже подчиненных текущему объекту и заполняем реквизиты:
Если Не Объект.ЭтоГруппа Тогда
Выборка = Справочники.ЕдиницыИзмерения.Выбрать(, Объект.Ссылка);
Пока Выборка.Следующий() Цикл
// Находим базовую единицу измерения с коэффициентом 1
Если Выборка.Коэффициент = 1 Тогда
Объект.ЕдиницаХраненияОстатков = Выборка.Ссылка;
Объект.ЕдиницаДляОтчетов = Выборка.Ссылка;
Объект.Записать();
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Такой алгоритм гарантирует, что реквизиты будут связаны с корректным элементом подчиненного справочника без риска зацикливания механизма обмена.
Другой вариант решения — принудительно выгрузить объект-владелец в тот момент, когда алгоритм обращается к выгрузке единицы измерения. Выясним, как это реализовать программно.
В ПКО ЕдиницыИзмерения в обработчике ПередВыгрузкой добавим проверку коллекции уже выгруженных объектов правила Номенклатура:
Если Правила.Номенклатура.Выгруженные[Источник.Владелец] = Неопределено Тогда
ВыгрузитьПоПравилу(Источник.Владелец);
КонецЕсли;
Важное предостережение: при таком подходе необходимо строго следить за полями поиска в ПКО ЕдиницыИзмерения. Если поиск единицы настроен только по наименованию (например, «шт») без обязательного поиска по свойству Владелец, возникнет опасное дублирование или подмена данных: единица измерения «шт» одного товара перепишет владельца у единицы другого товара.
Посмотрим на пример использования параметров выгрузки через структуру ИсходящиеДанные. Нередко попытка использовать этот механизм приводит к ошибке: Получение элемента по индексу для значения не определено. Разберем причину сбоя.
Ошибка появляется тогда, когда для свойства Владелец в ПКС справочника ЕдиницыИзмерения включен флаг «Получить из входящих данных», но само правило вызывается не только из номенклатуры с подготовленной структурой, а еще и напрямую (например, по ссылке из табличной части документа). В этом случае переменная ВходящиеДанные равна Неопределено.
Чтобы исключить эту ошибку, разделим правила на два сценария:
ЕдиницыИзмерения:
Владелец и классификатор единицы.ЕдиницаХраненияОстатков справочника Номенклатура. В нем для поля Владелец включается флаг «Получить из входящих данных».Владелец в обработчике ПередВыгрузкой добавляем безопасную проверку наличия структуры:
Если ВходящиеДанные = Неопределено Тогда
Значение = Источник.Владелец;
Иначе
Значение = ВходящиеДанные.Владелец;
КонецЕсли;
В типовых конфигурациях штрихкоды хранятся не в подчиненном справочнике, а в регистре сведений Штрихкоды. Поскольку регистр не имеет объектной ссылки, при выгрузке только документов и номенклатуры записи регистра автоматически в файл обмена не попадают.
Рассмотрим, как выгрузить штрихкоды только для тех товаров, которые участвуют в текущем обмене. Для этого в ПКО Номенклатура в обработчике ПриВыгрузке перебираем записи регистра сведений с отбором по текущему элементу-владельцу:
Если Не Источник.ЭтоГруппа Тогда
ОтборПоВладельцу = Новый Структура("Владелец");
ОтборПоВладельцу.Владелец = Источник;
Выборка = РегистрыСведений.Штрихкоды.Выбрать(ОтборПоВладельцу);
Пока Выборка.Следующий() Цикл
ВыгрузитьПоПравилу(Выборка, , , , "Штрихкоды");
КонецЦикла;
КонецЕсли;
В правилах обмена должно быть заранее создано ПКО для регистра сведений Штрихкоды, в котором сопоставлены измерения и ресурсы (штрихкод, тип штрихкода, владелец, единица измерения).
При больших объемах номенклатуры построчная выгрузка через ВыгрузитьПоПравилу внутри выборки может снижать скорость обмена. В качестве оптимизации рекомендуется формировать отдельное ПВД для регистра сведений со способом выборки «Произвольный алгоритм», где одним запросом выбираются записи штрихкодов только для позиций из выгружаемых документов.