Как настроить правило для номенклатуры в КД2 при переносе между базами с разными форматами кодов и уникальными идентификаторами, чтобы избежать задвоения?

Программист 1С v8.3 (Управляемые формы) Бухгалтерский учет Сфера услуг, туризм и социальный сектор
← На главную

При переносе данных между базами 1С, особенно если версии конфигураций различаются (например, из БГУ 1 в БГУ 2), мы часто сталкиваемся с проблемами, связанными с изменением структуры данных. Одной из наиболее распространенных является проблема с номенклатурой, когда коды объектов имеют разную длину в базе-источнике и базе-приемнике, а также отличаются уникальные идентификаторы (УИД). Это приводит к некорректному поиску существующих элементов и их задвоению при загрузке. Рассмотрим подробнее, как решить эту проблему с помощью "Конвертации Данных 2.0" (КД2).

Анализируем исходную проблему и определяем ключевые задачи

Прежде чем приступить к настройке КД2, давайте разберем ситуацию, описанную в теме, и выделим основные сложности, которые нам предстоит преодолеть:

  1. Различная длина кодов номенклатуры: В базе-источнике коды номенклатуры имеют, например, 12 знаков, тогда как в базе-приемнике ожидается 15 знаков. Типовой перенос данных может добавлять нули, но не всегда корректно или в нужное место (например, "в середине" кода, как упомянул автор). Нам необходимо привести код к заданной длине и формату в базе-приемнике.
  2. Разные уникальные идентификаторы (УИД): Объекты номенклатуры в исходной и целевой базах имеют разные УИДы. Это критически важный момент, так как стандартный поиск по УИД не работает. В результате, система не находит существующий элемент и создает дубликат.
  3. Необходимость модификации кода для поиска: Чтобы найти существующий элемент номенклатуры в базе-приемнике по коду, нам нужно сначала преобразовать код из источника к формату, который ожидается в приемнике. Это означает добавление нулей или выполнение других строковых манипуляций.
  4. Настройка альтернативного поиска: Помимо модификации кода, нам потребуется настроить поиск объекта в базе-приемнике по альтернативным полям, таким как "Наименование", и реализовать более сложный алгоритм поиска с учетом всех особенностей.

Шаг 1: Модификация кода номенклатуры (добавление нулей) при переносе

Для того чтобы код номенклатуры из базы-источника был корректно преобразован к требуемой длине и формату в базе-приемнике, мы можем использовать различные механизмы КД2. Рассмотрим два основных подхода: использование встроенной функции и установка специального флага.

Использование функции ПривестиНомерКДлине

В КД2 существуют специальные вспомогательные функции, которые значительно упрощают типовые сценарии преобразования данных. Одна из таких функций – ПривестиНомерКДлине. Она предназначена для приведения числовых или строковых кодов/номеров к заданной длине, корректно обрабатывая префиксы и дополняя строку нулями до необходимой длины. Эта функция идеально подходит для ситуаций, когда нужно просто дополнить код до определенной длины, сохраняя его числовую часть.

Разберем, как использовать эту функцию в Правиле конвертации свойств (ПКС) для реквизита "Код" номенклатуры:

  1. Откроем конфигурацию "Конвертация Данных 2.0".
  2. Найдем Правило конвертации объектов (ПКО) для объекта "Номенклатура".
  3. Перейдем на закладку "Конвертация свойств" и найдем свойство "Код". Откроем его.
  4. В обработчике события "При выгрузке" (если мы хотим модифицировать код на стороне источника перед его отправкой) или "Перед записью" (если мы хотим модифицировать код непосредственно перед записью в приемнике) мы можем написать следующий код:

// В обработчике "При выгрузке" или "Перед записью" ПКС для реквизита "Код"

Значение = ПривестиНомерКДлине(Источник.Код, 15);

Здесь Источник.Код – это код номенклатуры, который мы получаем из базы-источника, а 15 – это целевая длина кода, которую мы хотим получить в базе-приемнике. Функция ПривестиНомерКДлине самостоятельно проанализирует исходный код и дополнит его нулями до 15 знаков, сохраняя структуру номера.

Использование флага "Автоматически приводить значение к длине приемника"

В некоторых случаях, если обмен происходит между базами 1С:Предприятия 8, можно использовать встроенный функционал, который менее гибок, но проще в настройке.

  1. В свойствах ПКС для реквизита "Код" можно установить флаг "Автоматически приводить значение к длине приемника".

При установке этого флага система автоматически попытается привести код или номер справочника к соответствующей длине в приемнике, сохраняя префиксы и преобразуя числовые части. Однако, этот метод может быть менее гибким, чем ручное использование функции ПривестиНомерКДлине, особенно если требуется очень специфическая логика добавления нулей (например, строго в определенную "середину" кода, а не просто дополнение слева).

В нашем случае, когда автор упомянул, что "типовой перенос добавляет нули в середине, примерно так", функция ПривестиНомерКДлине будет предпочтительнее для точного контроля, если под "в середине" имеется в виду правильное форматирование номера. Если же речь идет о строгой вставке нулей между определенными символами, то нам потребуется ручная строковая манипуляция, которую мы рассмотрим далее в контексте обработчика "Перед поиском".

Шаг 2: Настройка поиска номенклатуры в базе-приемнике и предотвращение задвоений

Поскольку УИДы объектов в базе-источнике и базе-приемнике отличаются, стандартный механизм поиска по УИД работать не будет, что неизбежно приведет к созданию дубликатов. Нам нужно настроить КД2 таким образом, чтобы она искала существующие объекты по другим, более надежным критериям.

Отключение поиска по УИД

Первым делом, в Правиле конвертации объектов (ПКО) для "Номенклатуры" необходимо убедиться, что флажок "Искать объект приемника по вн. ид." (внутреннему идентификатору) снят. Это предотвратит попытки стандартного поиска по УИД, который гарантированно не совпадает и приведет к созданию дубликатов.

Поиск по "Наименованию"

Как было предложено в обсуждении на форуме, простейший и часто эффективный способ найти существующую номенклатуру, если коды отличаются, – это поиск по наименованию. Обычно наименования остаются неизменными при переносе.

  1. В ПКО для "Номенклатуры", на закладке "Конвертация свойств", найдите реквизит "Наименование".
  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 по полям, указанным в ПКО
КонецЕсли;

Важно: Логика добавления нулей "в середину" должна быть очень точно определена. Если это просто дополнение до заданной длины с сохранением числовой части справа, то функция ПривестиНомерКДлине справится оптимально. Если же это вставка нулей между определенными частями кода по строгим правилам, потребуется ручная строковая манипуляция, как показано в закомментированном примере.

Поля, которые участвуют в стандартном поиске после обработчика ПередПоиском (если Отказ = Ложь), должны иметь установленный признак "Поиск" в конвертации свойств. Если мы полностью перехватываем логику поиска в ПередПоиском (устанавливаем Отказ = Истина и присваиваем ОбъектПриемника), то флажки "Поиск" для других полей не влияют.

Дополнительные флаги ПКО для предотвращения задвоений

Помимо настроек поиска, в ПКО существуют дополнительные флаги, которые помогут контролировать создание новых объектов и обновление существующих:

  1. "Не создавать новый объект в приемнике, если он НЕ найден": Если установить этот флаг, то при отсутствии найденного объекта в базе-приемнике (после всех попыток поиска, включая ваш алгоритм в ПередПоиском), новый элемент номенклатуры создан не будет. Это может быть полезно, если вы хотите перенести только те элементы, которые уже существуют в приемнике, и не создавать новые по каким-либо причинам.
  2. "Не замещать существующие объекты в приемнике при загрузке, а только создавать новые и заполнять их": Если задача состоит только в создании новых элементов, но не в изменении реквизитов уже существующих (даже если они были успешно найдены), установите этот флаг. Он полезен, когда вы хотите сохранить текущие данные существующих объектов в приемнике, но при этом добавить новые элементы из источника.

Шаг 3: Стратегии синхронизации и общие рекомендации

Использование регистра сведений для синхронизации

В более сложных сценариях наиболее надежным решением является использование дополнительного регистра сведений для хранения соответствий между объектами.

Мы создаем в базе-приемнике (или даже в обеих базах) специальный регистр сведений, в котором будут храниться пары идентификаторов: например, "КодОбъектаИзИсточника" и "СсылкаНаОбъектВПриемнике".

Принцип работы:

  1. При первой загрузке номенклатуры (или при ручном сопоставлении) мы ищем элемент в приемнике.
  2. Если элемент найден (например, по наименованию или модифицированному коду), мы записываем его код из источника и ссылку на найденный объект в приемнике в наш регистр сведений.
  3. При последующих обменах, прежде чем запускать сложный поиск, мы сначала ищем соответствие в этом регистре сведений по коду из источника.
  4. Если соответствие найдено, мы получаем прямую ссылку на объект приемника и используем ее, минуя сложную логику поиска.
  5. Если соответствие не найдено, тогда уже мы используем свой алгоритм поиска по полям или создаем новый объект и обязательно записываем это соответствие в регистр.

Этот подход значительно повышает надежность обмена и ускоряет его, поскольку поиск по регистру сведений обычно быстрее, чем сложные запросы или поиск по наименованию/коду в справочниках.

Важность тестирования

Всегда, без исключений, тестируйте разработанные правила обмена на копиях баз данных! Никогда не запускайте перенос на рабочих базах без предварительного многократного тестирования и проверки результатов. Недопустимо вносить изменения в рабочую базу без уверенности в корректности правил.

Мы рекомендуем проводить проверку на небольшом объеме данных, затем на более крупном. Убедитесь, что задвоений нет, а коды, наименования и другие реквизиты заполняются корректно и соответствуют ожиданиям. Проверяйте не только наличие элементов, но и их заполнение.

Поэтапная настройка

Начинайте настройку с самых простых правил. Убедитесь, что базовая передача данных работает без критических ошибок. Затем постепенно добавляйте логику модификации кода и настраивайте алгоритмы поиска. Такой поэтапный подход поможет легче выявлять и исправлять ошибки, поскольку вы будете изолировать проблемы на каждом этапе.

Подключаемые обработки

Если логика модификации кода или поиска становится очень сложной и объемной, рассмотрите возможность использования подключаемых обработок. Они позволяют вынести сложный код в отдельные модули, которые затем можно вызывать из обработчиков событий в КД2. Это значительно улучшает читаемость, модульность и поддерживаемость правил обмена, особенно при работе над крупными проектами или в команде разработчиков.

Подведем итоги: решение проблемы с задвоением номенклатуры при переносе между базами с разными УИДами и форматами кодов требует комплексного подхода в КД2. Нам необходимо отключить поиск по УИД, использовать функцию ПривестиНомерКДлине или реализовать специфическую строковую манипуляцию для кода, а также настроить поиск по другим полям, например, через обработчик ПередПоиском. Тщательное тестирование и поэтапная настройка гарантируют успешный перенос данных.

← На главную