Перенос данных между конфигурациями "1С:Управление производственным предприятием 1.3" (с подсистемой ТОиР) и современной "ТОиР 2.0 КОРП" часто сопряжен с трудностями из-за кардинального различия в архитектуре. Одной из самых сложных задач является перенос документов Выявленные дефекты, где логика переноса напрямую зависит от того, существуют ли объекты ремонта в новой базе и как они связаны иерархически. Рассмотрим, как решить эту задачу с помощью конфигурации "Конвертация данных 2.0" (КД 2.0).
В старых версиях ТОиР иерархия объектов ремонта была реализована классическим способом — через родителя в справочнике ОбъектыРемонта. В новой конфигурации "ТОиР 2.0" используется более гибкая, но сложная структура: иерархия вынесена в регистры сведений, такие как торо_ИерархическиеСтруктурыОР и торо_ОбъектыРемонтаГруппы. Это позволяет одному и тому же объекту находиться одновременно в функциональной и пространственной иерархиях.
Перед нами стоит задача: переносить только те строки документа Выявленные дефекты, для которых в базе-приемнике можно однозначно определить связь между "Родительским элементом" (основным объектом ремонта) и "Дочерним элементом" (узлом или деталью). Ситуация осложняется тем, что в базе-источнике у нас есть только код соответствия (например, КодВТоиР20), а реальную структуру иерархии мы можем проверить только в базе-приемнике в момент загрузки.
Проанализируем четыре сценария обработки строк:
Поскольку нам нужно передать в базу-приемник не только ссылки, но и специфические признаки (коды) для выполнения поисковых запросов, воспользуемся механизмом передачи параметров через ОбъектКоллекции. В правилах конвертации свойств (ПКС) для табличной части СписокДефектов мы создадим дополнительные вычисляемые поля, которые будут содержать структуру с необходимыми данными.
Рассмотрим пример кода в обработчике ПередВыгрузкой ПКС (для служебного поля, которое мы назовем, например, КодРодителяСтруктура):
СтруктураПараметров = Новый Структура("ИД, КодРодителя");
СтруктураПараметров.ИД = ОбъектКоллекции.ID; // Уникальный идентификатор строки для поиска в приемнике
СтруктураПараметров.КодРодителя = ОбъектКоллекции.ОбъектРемонта.КодВТОиР20;
// Сериализуем структуру в строку для передачи в XML
Значение = ЗначениеВСтрокуВнутр(СтруктураПараметров);
Такой подход позволяет передать любую дополнительную информацию, не изменяя структуру метаданных в приемнике. Аналогично поступим и для дочернего элемента (узла).
Основная работа происходит в правиле конвертации объекта (ПКО) документа ВыявленныеДефекты. Нам необходимо использовать обработчик ПослеЗагрузки. На этом этапе объект уже создан в памяти, его реквизиты заполнены из файла, но он еще не записан в базу данных. Это идеальный момент для выполнения запросов и модификации табличной части.
Выясним причину, почему нельзя делать это в ПередЗагрузкой: в тот момент у нас еще нет заполненного объекта Объект, а в ПКС мы не можем управлять отказом от записи всего документа на основании анализа всех строк ТЧ.
Проанализируем код обработчика ПослеЗагрузки:
// Извлекаем параметры, переданные из источника через ПКС
ТЧСписокДефектовПараметры = ПараметрыОбъекта["СписокДефектовТабличнаяЧасть"];
Если ТЧСписокДефектовПараметры <> Неопределено Тогда
МассивКУдалению = Новый Массив;
Для Каждого Стр Из ТЧСписокДефектовПараметры Цикл
// Десериализуем данные
СтруктураПараметровРодителя = ЗначениеИзСтрокиВнутр(Стр.КодРодителяСтруктура);
СтруктураПараметровПодчиненного = ЗначениеИзСтрокиВнутр(Стр.КодЭлементаСтруктура);
// Находим соответствующую строку в загруженном объекте документа
СтрокаДефектов = Объект.СписокДефектов.Найти(СтруктураПараметровРодителя.ИД, "ID");
Если СтрокаДефектов = Неопределено Тогда
Продолжить;
КонецЕсли;
// Логика обработки согласно условиям задачи
Если НЕ ЗначениеЗаполнено(СтруктураПараметровРодителя.КодРодителя) Тогда
// Сценарий 3 и 4: Родитель в источнике не указан
Если ЗначениеЗаполнено(СтруктураПараметровПодчиненного.КодЭлемента) Тогда
// Пытаемся найти родителя в иерархии ТОиР 2.0
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| торо_ИерархическиеСтруктурыОР.РодительИерархии КАК РодительОбъекта
|ИЗ
| РегистрСведений.торо_ИерархическиеСтруктурыОР КАК торо_ИерархическиеСтруктурыОР
|ГДЕ
| торо_ИерархическиеСтруктурыОР.ОбъектИерархии = &ОбъектРемонта";
Запрос.УстановитьПараметр("ОбъектРемонта", СтрокаДефектов.ОтказавшийЭлемент);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Если Выборка.Следующий() Тогда
// Успех: нашли родителя в приемнике
СтрокаДефектов.ОбъектРемонта = Выборка.РодительОбъекта;
Иначе
// Родитель не найден ни в источнике, ни в приемнике - удаляем строку
МассивКУдалению.Добавить(СтрокаДефектов);
КонецЕсли;
Иначе
// Ничего не заполнено - удаляем строку
МассивКУдалению.Добавить(СтрокаДефектов);
КонецЕсли;
Иначе
// Сценарий 1 и 2: Родитель заполнен
Если НЕ ЗначениеЗаполнено(СтруктураПараметровПодчиненного.КодЭлемента) Тогда
// Дочерний не заполнен - дублируем родителя (согласно условию)
СтрокаДефектов.ОтказавшийЭлемент = СтрокаДефектов.ОбъектРемонта;
КонецЕсли;
КонецЕсли;
КонецЦикла;
// Очищаем табличную часть от неподходящих строк
Для Каждого СтрКУдалению Из МассивКУдалению Цикл
Объект.СписокДефектов.Удалить(СтрКУдалению);
КонецЦикла;
КонецЕсли;
После того как мы проредили табличную часть СписокДефектов, может возникнуть ситуация, когда в документе не осталось ни одной значимой строки. Записывать такой пустой документ в базу ТОиР 2.0 не имеет смысла. Для этого в конце того же обработчика ПослеЗагрузки добавим проверку:
Если Объект.СписокДефектов.Количество() = 0 Тогда
// Сообщаем пользователю (опционально) и отменяем загрузку объекта
Сообщить("Документ " + Объект + " пропущен: отсутствуют подходящие объекты ремонта.");
Отказ = Истина;
КонецЕсли;
Важно помнить, что установка Отказ = Истина в этом обработчике предотвращает вызов метода Записать(), и объект не попадет в информационную базу приемника.
Рассмотрим критически важный момент: использование Новый Запрос внутри цикла по строкам табличной части. Если переносится документ с сотнями строк или тысячи маленьких документов, это существенно замедлит процесс загрузки. Для оптимизации рекомендуем придерживаться следующих правил:
ОтказавшийЭлемент в массив и выполните один запрос ко всему регистру иерархии перед началом цикла. Результат запроса выгрузите в Соответствие, где ключом будет ссылка на объект, а значением — его родитель.СтруктураИерархии, чтобы не получить случайного "родителя" из другой ветки учета.Проанализировав данную методику, мы видим, что она позволяет гибко управлять данными "на лету", используя мощь встроенного языка 1С и механизмов КД 2.0. Это исключает необходимость предварительной трудоемкой обработки данных в базе-источнике и гарантирует чистоту данных в целевой системе ТОиР 2.0.