При переносе данных между базами 1С, особенно если версии конфигураций различаются (например, из БГУ 1 в БГУ 2), мы часто сталкиваемся с проблемами, связанными с изменением структуры данных. Одной из наиболее распространенных является проблема с номенклатурой, когда коды объектов имеют разную длину в базе-источнике и базе-приемнике, а также отличаются уникальные идентификаторы (УИД). Это приводит к некорректному поиску существующих элементов и их задвоению при загрузке. Рассмотрим подробнее, как решить эту проблему с помощью "Конвертации Данных 2.0" (КД2).
Прежде чем приступить к настройке КД2, давайте разберем ситуацию, описанную в теме, и выделим основные сложности, которые нам предстоит преодолеть:
Для того чтобы код номенклатуры из базы-источника был корректно преобразован к требуемой длине и формату в базе-приемнике, мы можем использовать различные механизмы КД2. Рассмотрим два основных подхода: использование встроенной функции и установка специального флага.
ПривестиНомерКДлинеВ КД2 существуют специальные вспомогательные функции, которые значительно упрощают типовые сценарии преобразования данных. Одна из таких функций – ПривестиНомерКДлине. Она предназначена для приведения числовых или строковых кодов/номеров к заданной длине, корректно обрабатывая префиксы и дополняя строку нулями до необходимой длины. Эта функция идеально подходит для ситуаций, когда нужно просто дополнить код до определенной длины, сохраняя его числовую часть.
Разберем, как использовать эту функцию в Правиле конвертации свойств (ПКС) для реквизита "Код" номенклатуры:
// В обработчике "При выгрузке" или "Перед записью" ПКС для реквизита "Код"
Значение = ПривестиНомерКДлине(Источник.Код, 15);
Здесь Источник.Код – это код номенклатуры, который мы получаем из базы-источника, а 15 – это целевая длина кода, которую мы хотим получить в базе-приемнике. Функция ПривестиНомерКДлине самостоятельно проанализирует исходный код и дополнит его нулями до 15 знаков, сохраняя структуру номера.
В некоторых случаях, если обмен происходит между базами 1С:Предприятия 8, можно использовать встроенный функционал, который менее гибок, но проще в настройке.
При установке этого флага система автоматически попытается привести код или номер справочника к соответствующей длине в приемнике, сохраняя префиксы и преобразуя числовые части. Однако, этот метод может быть менее гибким, чем ручное использование функции ПривестиНомерКДлине, особенно если требуется очень специфическая логика добавления нулей (например, строго в определенную "середину" кода, а не просто дополнение слева).
В нашем случае, когда автор упомянул, что "типовой перенос добавляет нули в середине, примерно так", функция ПривестиНомерКДлине будет предпочтительнее для точного контроля, если под "в середине" имеется в виду правильное форматирование номера. Если же речь идет о строгой вставке нулей между определенными символами, то нам потребуется ручная строковая манипуляция, которую мы рассмотрим далее в контексте обработчика "Перед поиском".
Поскольку УИДы объектов в базе-источнике и базе-приемнике отличаются, стандартный механизм поиска по УИД работать не будет, что неизбежно приведет к созданию дубликатов. Нам нужно настроить КД2 таким образом, чтобы она искала существующие объекты по другим, более надежным критериям.
Первым делом, в Правиле конвертации объектов (ПКО) для "Номенклатуры" необходимо убедиться, что флажок "Искать объект приемника по вн. ид." (внутреннему идентификатору) снят. Это предотвратит попытки стандартного поиска по УИД, который гарантированно не совпадает и приведет к созданию дубликатов.
Как было предложено в обсуждении на форуме, простейший и часто эффективный способ найти существующую номенклатуру, если коды отличаются, – это поиск по наименованию. Обычно наименования остаются неизменными при переносе.
Если установить этот флажок для нескольких реквизитов (например, "Наименование" и "Артикул"), то поиск будет производиться по комбинации этих полей с использованием логического "И". То есть, будет найден объект, у которого одновременно совпадут и наименование, и артикул.
Это самый мощный инструмент для реализации произвольного алгоритма поиска, особенно когда стандартные методы не подходят или требуется предварительная модификация значений поиска, как в нашем случае с кодом номенклатуры. Обработчик ПередПоиском выполняется на стороне приемника перед тем, как система начнет стандартный поиск объекта. Он находится в ПКО для номенклатуры.
В этом обработчике мы можем:
ОбъектПриемника. В этом случае стандартный поиск выполняться не будет, и КД2 будет считать, что объект уже найден. Для отмены стандартного поиска необходимо установить Отказ = Истина.Рассмотрим пример логики в обработчике ПередПоиском, учитывая специфику добавления нулей:
// Обработчик события "ПередПоиском" в ПКО для Номенклатуры
// Получаем исходный код из базы-источника
ИсходныйКод = СокрЛП(Источник.Код);
ЦелеваяДлинаКода = 15; // Требуемая длина кода в приемнике
ЗначениеПоискаПоКоду = ИсходныйКод;
// --- Логика модификации кода для поиска ---
// Автор указал, что "типовой перенос добавляет нули в середине".
// Это может означать два варианта:
// 1. Стандартное дополнение до длины с сохранением числовой части (ПривестиНомерКДлине)
// 2. Специфическая вставка нулей в определенное место строки кода.
// Вариант 1: Если "нули в середине" - это просто дополнение до длины,
// при котором числовая часть кода остается справа, а слева добавляются нули.
// Например, "123" (3 знака) -> "000123" (6 знаков).
// Функция ПривестиНомерКДлине справляется с этим автоматически.
// В этом случае, мы можем применить ее для формирования значения для поиска:
ЗначениеПоискаПоКоду = ПривестиНомерКДлине(ИсходныйКод, ЦелеваяДлинаКода);
// Вариант 2: Если "нули в середине" означает специфическую вставку,
// например, если код 12 символов "123456789012" должен стать 15 символов "123000456789012"
// (3 нуля вставляются после 3-го символа).
// Такая логика требует ручной строковой манипуляции.
// Если ИсходныйКод имеет 12 символов и мы хотим вставить 3 нуля после 3-го символа:
// If СтрДлина(ИсходныйКод) = 12 Тогда
// ЧастьДо = Лев(ИсходныйКод, 3);
// ЧастьПосле = Сред(ИсходныйКод, 4); // Начиная с 4-го символа
// ЗначениеПоискаПоКоду = ЧастьДо + СтрПовторить("0", 3) + ЧастьПосле;
// Else
// // Если длина другая, используем ПривестиНомерКДлине или другую логику
// ЗначениеПоискаПоКоду = ПривестиНомерКДлине(ИсходныйКод, ЦелеваяДлинаКода);
// EndIf;
// Мы используем ЗначениеПоискаПоКоду, полученное ПривестиНомерКДлине,
// если нет точного определения "в середине" или оно соответствует стандартному поведению.
// --- Поиск объекта в приемнике ---
// Сначала пробуем найти по модифицированному коду
НайденныйОбъект = Справочники.Номенклатура.НайтиПоКоду(ЗначениеПоискаПоКоду);
Если НайденныйОбъект.Пустая() Тогда
// Если по модифицированному коду не нашли, пробуем по наименованию.
// Для этого необходимо, чтобы ПКС "Наименование" также имел флаг "Поиск объекта при загрузке по данному свойству"
// или мы сами реализовали поиск здесь.
НайденныйОбъект = Справочники.Номенклатура.НайтиПоНаименованию(Источник.Наименование);
КонецЕсли;
// Если объект найден нашим алгоритмом, возвращаем его и отменяем стандартный поиск КД2
Если НЕ НайденныйОбъект.Пустая() Тогда
ОбъектПриемника = НайденныйОбъект;
Отказ = Истина; // Отменяем стандартный поиск КД2 по полям, указанным в ПКО
КонецЕсли;
Важно: Логика добавления нулей "в середину" должна быть очень точно определена. Если это просто дополнение до заданной длины с сохранением числовой части справа, то функция ПривестиНомерКДлине справится оптимально. Если же это вставка нулей между определенными частями кода по строгим правилам, потребуется ручная строковая манипуляция, как показано в закомментированном примере.
Поля, которые участвуют в стандартном поиске после обработчика ПередПоиском (если Отказ = Ложь), должны иметь установленный признак "Поиск" в конвертации свойств. Если мы полностью перехватываем логику поиска в ПередПоиском (устанавливаем Отказ = Истина и присваиваем ОбъектПриемника), то флажки "Поиск" для других полей не влияют.
Помимо настроек поиска, в ПКО существуют дополнительные флаги, которые помогут контролировать создание новых объектов и обновление существующих:
ПередПоиском), новый элемент номенклатуры создан не будет. Это может быть полезно, если вы хотите перенести только те элементы, которые уже существуют в приемнике, и не создавать новые по каким-либо причинам.В более сложных сценариях наиболее надежным решением является использование дополнительного регистра сведений для хранения соответствий между объектами.
Мы создаем в базе-приемнике (или даже в обеих базах) специальный регистр сведений, в котором будут храниться пары идентификаторов: например, "КодОбъектаИзИсточника" и "СсылкаНаОбъектВПриемнике".
Принцип работы:
Этот подход значительно повышает надежность обмена и ускоряет его, поскольку поиск по регистру сведений обычно быстрее, чем сложные запросы или поиск по наименованию/коду в справочниках.
Всегда, без исключений, тестируйте разработанные правила обмена на копиях баз данных! Никогда не запускайте перенос на рабочих базах без предварительного многократного тестирования и проверки результатов. Недопустимо вносить изменения в рабочую базу без уверенности в корректности правил.
Мы рекомендуем проводить проверку на небольшом объеме данных, затем на более крупном. Убедитесь, что задвоений нет, а коды, наименования и другие реквизиты заполняются корректно и соответствуют ожиданиям. Проверяйте не только наличие элементов, но и их заполнение.
Начинайте настройку с самых простых правил. Убедитесь, что базовая передача данных работает без критических ошибок. Затем постепенно добавляйте логику модификации кода и настраивайте алгоритмы поиска. Такой поэтапный подход поможет легче выявлять и исправлять ошибки, поскольку вы будете изолировать проблемы на каждом этапе.
Если логика модификации кода или поиска становится очень сложной и объемной, рассмотрите возможность использования подключаемых обработок. Они позволяют вынести сложный код в отдельные модули, которые затем можно вызывать из обработчиков событий в КД2. Это значительно улучшает читаемость, модульность и поддерживаемость правил обмена, особенно при работе над крупными проектами или в команде разработчиков.
Подведем итоги: решение проблемы с задвоением номенклатуры при переносе между базами с разными УИДами и форматами кодов требует комплексного подхода в КД2. Нам необходимо отключить поиск по УИД, использовать функцию ПривестиНомерКДлине или реализовать специфическую строковую манипуляцию для кода, а также настроить поиск по другим полям, например, через обработчик ПередПоиском. Тщательное тестирование и поэтапная настройка гарантируют успешный перенос данных.