Перенос каталога из старой самописной базы в 1С-Битрикс выглядит как задача на вечер. Есть таблица products, есть инфоблок, осталось сопоставить поля. Обычно на этом месте всё и ломается.
Свойств в старом проекте оказывается под сотню. Названия повторяются («Размер», «Размеры», «Размер блока»), единицы измерения живут внутри значений, цвет лежит сразу в двух местах. Импортёр пишут с ходу, а через день в каталоге появляются дубли, цены без остатков и товары с половиной характеристик.
Больше всего потерь приносит отсутствие правил: что делать с конфликтом значений, куда писать цену, как отличить повторный импорт от нового. Об этих правилах и пойдёт речь.
1. Что должно получиться на выходе
Главное требование - идемпотентность. Слово звучит страшно, смысл простой: повторный запуск импорта не создаёт второй такой же товар, а обновляет уже перенесённый.
Старая база при этом открыта только для чтения. Преобразования детерминированы, то есть на одних и тех же данных дают один и тот же результат. Ошибки и конфликты обязаны попадать в отчёт. Работа идёт через штатные API Битрикс, прямые запросы на запись в его таблицы запрещены.
Отдельно про структуру. Её создают миграции sprint.migration, а импортёр только наполняет готовое данными. Свойства, справочники и единицы измерения внутри импортёра не создаются. Ядро Битрикс не трогаем.
2. Аудит перед кодом
Сначала надо найти то, что уже написано. Импортёр в проекте почти всегда есть, пусть и неполный, как и своя логика группировки товаров в родительские позиции и торговые предложения.
Выяснить до первой строки кода придётся немало:
- ID инфоблока товаров и инфоблока торговых предложений;
- свойство связи предложения с товаром;
- существующие свойства, их ID, коды и типы;
- тип базовой цены и валюту;
- используемые единицы измерения;
- способ идентификации ранее импортированных товаров;
- структуру
products,properties, таблиц значений свойств,vendorsиcolors; - способ формирования старого полного URL карточки;
- принятый в проекте порядок создания и запуска миграций
sprint.migration.
Заполненность каждого исходного свойства смотрят SQL-запросами, а структуру базы сверяют с реальной БД, а не с именами моделей. Заодно получают список уникальных значений products.stock_unit, чтобы заранее создать нужные единицы измерения миграцией.
Согласованную логику группировки products в родительские товары и торговые предложения не меняют. Если однозначного правила в проекте нет, придумывать его по похожим названиям нельзя. Работа останавливается, а в отчёт идут реальные примеры конфликтующих товаров.
3. Структура через sprint.migration
Торговое предложение в Битриксе - это конкретный вариант товара, который продаётся: свой артикул, цена, остаток. Родительский товар объединяет варианты и хранит общие свойства.
Всё, что относится к структуре, живёт только в миграциях. Через sprint.migration создают новые свойства для товаров и торговых предложений, Highload-блоки для справочников Производитель, Цвет и Размер, привязку свойств типа «Справочник» к этим блокам, коды, типы, множественность и сортировку, а также нужные единицы измерения. Highload-блок, если не встречались, - это таблица-справочник внутри Битрикса.
Требования к миграциям выглядят скучно, но нарушения потом дорого стоят:
- перед созданием проверяем текущую структуру и не плодим дубли;
- формат и namespace
Sprint\Migrationберём из проекта; - у миграции есть понятное описание;
up()проверяет, что создаваемой сущности ещё нет;- повторный прогон не создаёт дубли;
- откат не удаляет молча заполненные свойства, справочники и пользовательские данные;
- свойства с ID
119и126не пересоздают, а проверяют их принадлежность нужному инфоблоку и настройки; - коды новых свойств и таблиц Highload-блоков зафиксированы в миграциях и используются импортёром;
- файлы миграций входят в итоговый список изменённых файлов;
- миграции обкатаны на тестовой базе до запуска импортёра.
Если обязательная миграция не применена, импорт обязан остановиться до записи данных и внятно сказать, какого свойства, справочника или единицы измерения не хватает.
4. Куда попадают данные
Родительский товар получает NAME, CODE, DETAIL_TEXT, ACTIVE и общие свойства из маппинга. Коммерческая часть уходит в торговое предложение: цена, остаток, единица измерения, доступность, Артикул, Размер и Цвет.
Если в проекте коммерческие поля разложены иначе, это сначала доказывают в отчёте, а потом сохраняют как есть. Ломать работающую архитектуру ради красивой схемы не нужно.
Основные поля
| Поле Битрикс | Источник |
|---|---|
NAME |
products.title |
CODE |
products.slug |
DETAIL_TEXT |
products.description |
PRICE |
products.price |
ACTIVE |
products.is_active |
MEASURE |
products.stock_unit |
QUANTITY |
products.stock_count |
AVAILABLE |
всегда Y |
Правила преобразования:
DETAIL_TEXTпереносим без потери HTML и выставляем корректный тип текста;ACTIVE: истину превращаем вY, ложь вN;PRICEпишем через штатный API цен в базовый тип цены; если цены нет или она некорректна, фиктивную не создаём, а товар уходит в отчёт;MEASUREв Битриксе - это ID единицы измерения, и нужные единицы уже созданы миграцией; импортёр только сопоставляетproducts.stock_unitс существующей единицей, а если не нашёл, останавливает обработку товара и пишет ошибку;QUANTITY: пустое значение считаем нулём;AVAILABLEв значениеYприводит штатная настройка каталожного товара, при необходимости настраиваемQUANTITY_TRACEиCAN_BUY_ZEROи проверяем доступность через API;- вычисляемые поля напрямую SQL не обновляем.
5. Свойства товара
Все свойства с пометкой (N) создаются миграциями. По умолчанию они строковые, потому что старые значения содержат единицы измерения, диапазоны и текст. Переводить свойство в числовой тип без проверки всех фактических значений нельзя.
Артикул, Размер и Цвет из таблицы ниже относятся к инфоблоку торговых предложений, а не к товару. Свойства Технология изготовления и Теплопроводность, Вт/мС° в Битриксе уже есть, их ID перед использованием проверяют на принадлежность нужному инфоблоку.
| Целевое свойство | Источник |
|---|---|
Артикул (N) |
products.CML2_ARTICLE |
Производитель (N) |
products.vendor_id |
Масса изделия, кг (N) |
Масса: ID 53, 2; Масса изделия: ID 72; Массм изделия: ID 74 |
Длина, мм (N) |
Длина: ID 52, 3 |
Марка прочности (N) |
Марка по прочности: ID 4; Марка прочности: ID 73 |
Водопоглощение, % (N) |
Водопоглощение: ID 5 |
Ширина, мм (N) |
Ширина: ID 6 |
Морозостойкость, F (N) |
Морозостойкость: ID 7 |
Плотность, кг/м³ (N) |
Плотность: ID 9 |
Пустотность (N) |
Пустотность: ID 10 |
ГОСТ/ТУ (N) |
ГОСТ/ТУ: ID 12 |
Вместимость в 20-тонник (N) |
Вместимость в 20-тонник: ID 25 |
Область применения (N) |
Область применения: ID 26 |
Состав (N) |
Состав: ID 33 |
Материал (N) |
Материал: ID 34 |
Форма нарезки (N) |
Форма нарезки: ID 35 |
Тип изделия (N) |
Тип изделия: ID 36 |
Температура использования (N) |
Температура использования: ID 37 |
Время использования (N) |
Время использования: ID 38 |
Объём на поддоне, м³ (N) |
Объём на поддоне: ID 23 |
Усадка при высыхании (N) |
Усадка при высыхании: ID 22 |
Группа горючести (N) |
Группа горючести: ID 40 |
Марка бетона (N) |
Марка бетона: ID 41 |
Класс бетона (N) |
Класс бетона: ID 42 |
Толщина слоя (N) |
Толщина слоя: ID 39 |
Толщина, мм (N) |
Толщина: ID 30 |
Технология изготовления, свойство ID 126 |
Технология изготовления: ID 28 |
Пруток (N) |
Пруток: ID 43 |
Объем (N) |
Объем: ID 18 |
Прочность (N) |
Прочность: ID 16 |
Вес упаковки (N) |
Вес упаковки: ID 80 |
Вес блока (N) |
Вес блока: ID 70 |
Вес изделия (N) |
Вес изделия: ID 71 |
Механическая прочность (N) |
Механическая прочность: ID 82 |
Вид штукатурки (N) |
Вид штукатурки: ID 91 |
Назначение (N) |
Назначение: ID 92 |
Вид блока (N) |
Вид блока: ID 13 |
Серия (N) |
Серия: ID 85 |
Коллекция (N) |
Коллекция: ID 86; Коллекция Ликолор: ID 84; Коллекция Braer: ID 75; Коллеция Поревит: ID 76; Коллеции Поревит: ID 29 |
Поверхность (N) |
Поверхность: ID 20; Поверхность гладкая: ID 45; Антик: ID 46; Сланец: ID 47; Сахара: ID 48; Руст: ID 49 |
Количество (N) |
Количество на поддоне: ID 14, 50, 56; Количество в упаковке: ID 31 |
Кол-во на поддоне м² (N) |
Кол-во на поддоне: ID 27 |
Теплопроводность, Вт/мС°, свойство ID 119 |
Коэффициент теплопроводности: ID 11; Теплопроводнос: ID 88; Ть: ID 89; Теплопроводность: ID 21 |
Высота, мм (N) |
Высота: ID 8; Высота бордюра: ID 78 |
Размер ячейки (N) |
Размер ячейки: ID 44 |
Размер поддона (N) |
Размер поддона: ID 24 |
URL донора (N) |
Старый полный URL карточки товара |
6. Правила для нескольких источников
Несколько исходных свойств в одной строке таблицы - это альтернативные источники одного целевого свойства. Алгоритм такой:
- получаем значения всех перечисленных исходных свойств;
- выбрасываем пустые;
- делаем только безопасную нормализацию: убираем пробелы по краям, повторяющиеся пробелы меняем на один, единицы измерения и содержание не трогаем;
- одинаковые значения не дублируем;
- если уникальное значение одно, записываем его;
- если значений несколько, у множественного свойства записываем все уникальные, у одиночного берём первое по порядку ID из ТЗ и обязательно пишем конфликт в отчёт с
products.id, исходными ID свойств и найденными значениями.
Смысловое объединение похожих значений без отдельного правила не делаем. Импортёр обновляет только перечисленные в задании поля и свойства, остальные данные элемента не чистит и не меняет.
7. Восстановление старых адресов
URL донора хранит полный адрес старой карточки товара. URL картинки сюда не попадает. Домен https://example.ru, путь определяется по реальной маршрутизации старого проекта, а не догадкой по одному slug. Если в URL участвовал путь категории, его учитывают.
Сформированные адреса проверяют минимум на десяти товарах из разных разделов. Если URL однозначно восстановить нельзя, его не записывают, а товар попадает в отчёт.
8. Торговые предложения
Точные ID и коды свойств определяют по конфигурации связанного инфоблока торговых предложений, отсутствующие свойства создают миграцией.
| Свойство предложения | Источник |
|---|---|
| Артикул | products.article |
| Размер | старые свойства размеров |
| Цвет | свойство «Цвет производителя» и products.color_id |
Размер собирают из свойств «Размер кирпича» (ID 1, 57), «Размер блока» (ID 15, 51), «Размеры черепицы» (ID 81), «Размер плиты» (ID 17, 55), «Размер перемычки» (ID 19), «Размер» (ID 54, 32), «Размеры» (ID 62) и «Размер клинкера» (ID 83). Это свойство-справочник, его Highload-блок и свойство создаёт миграция, а значения справочника импортёр добавляет по ходу обработки товаров. Если у одного исходного товара нашлось несколько разных размеров, работает общее правило разрешения конфликтов, а ситуация уходит в отчёт.
С цветом источников два. Первый - свойство «Цвет производителя», ID 79. Второй - products.color_id со связью на таблицу colors. Если свойство 79 заполнено, берут его. color_id остаётся резервным вариантом. Когда заполнены оба источника и значения расходятся, побеждает свойство 79, а конфликт всё равно попадает в отчёт.
9. Справочники
Справочников три: Производитель, Цвет и Размер. Highload-блоки и свойства типа «Справочник» готовят миграции. Импортёр наполняет уже созданные справочники значениями через штатные API.
Производитель приходит из старой таблицы vendors, товар ссылается на него через products.vendor_id. Название и остальные поля смотрят по фактической структуре таблицы. Внешний идентификатор - стабильное значение на основе ID старого производителя, поэтому повторный импорт не создаёт второй элемент справочника.
Цвет устроен сложнее, он лежит в двух местах. Основной источник - таблица colors, связь идёт через products.color_id. Значения из свойства ID 79 добавляют в тот же справочник. Дубли из-за регистра или пробелов по краям не создаём.
С размером иначе. Заранее его никто не заполняет. Значения появляются по мере обработки размеров торговых предложений, а после безопасной нормализации одинаковые размеры ссылаются на один элемент справочника. Латинскую x автоматически на кириллическую х не заменяют, формат размеров без отдельного согласованного правила не меняют.
Если справочники уже не пустые, сначала сопоставляем по сохранённому внешнему ID, а потом по точному нормализованному названию.
10. Повторный запуск
Существующий механизм идентификации импортированных товаров сначала ищут и сохраняют. Если такого механизма нет, берут стабильный внешний идентификатор на основе первичного ключа старой базы. Одно название товара для этого не годится.
Повторный запуск обновляет существующие товары и предложения и только те поля, что перечислены в задании. Он не создаёт дубли товаров, предложений и значений справочников, не затирает посторонние свойства и данные, не удаляет товары, которых нет в текущей выборке, и не трогает существующую группировку торговых предложений.
Все операции по одному товару лучше выполнять в отдельной транзакции или обеспечить такую же защиту от частично записанного состояния. Иначе после сбоя посередине придётся разбираться, что именно успело записаться.
11. Команда импорта
Команду либо дополняют существующую, либо делают отдельную консольную. Режимы нужны такие:
--dry-runсчитает всё, но не меняет Битрикс;- импорт одного исходного товара по
products.id; - ограничение количества товаров;
- пакетная обработка;
- безопасное продолжение импорта после остановки;
- подробный лог;
- итоговая статистика.
Если в проекте уже есть единый формат CLI, привязываться к точным названиям параметров не нужно.
Перед началом импорта команда проверяет, что миграции применены, нужные инфоблоки, свойства с ожидаемыми кодами и типами, Highload-блоки, единицы измерения и базовый тип цены на месте, а связь товаров и торговых предложений настроена корректно. Структура не совпала с ожидаемой - запись не начинается.
В логе по каждой записи указывают ID исходного товара, найденный или созданный ID родительского товара, ID торгового предложения, выполненное действие, предупреждения и ошибку, если она возникла. Ошибка одного товара не должна ронять весь импорт, пока продолжение безопасно.
12. Проверка и итоговый отчёт
Запрещено менять исходную базу, выполнять прямые INSERT, UPDATE и DELETE в таблицах Битрикс, править ядро, удалять существующие товары, менять группировку товаров без отдельного согласования, молча выбирать значение при конфликте данных. Также нельзя создавать свойства, Highload-блоки, привязки справочников и единицы измерения внутри команды импорта и запускать полный импорт в рабочую базу до успешного dry-run и проверки тестовой выборки.
Изображения, разделы и SEO-поля в задачу не входят, кроме свойства URL донора, если они уже не переносятся существующим импортёром.
Проверок перед сдачей двенадцать.
- миграции применены на тестовой копии Битрикс;
- повторный запуск миграций или штатная проверка их состояния проходит;
- структура не дублируется;
dry-runотработал минимум на 20 товарах;- в выборке есть производитель, цвет из
colors, цвет из свойства ID79, разные свойства размеров, коллекция, поверхность, теплопроводность, масса, пустая цена, пустой остаток и конфликтующие значения; - небольшая выборка реально импортирована в тестовую БД;
- та же выборка импортирована повторно;
- новых товаров, предложений и элементов справочников не появилось;
- цена, остаток, единица измерения и доступность проверены через API Битрикс;
- связи родительского товара и торгового предложения проверены;
- количество исходных и обработанных записей сверено SQL-запросом;
- старые URL проверены минимум на десяти товарах из разных разделов.
В отчёт после работы включают список изменённых файлов, список созданных миграций с описанием каждой, результат их применения на тестовой базе, описание найденной архитектуры товаров и торговых предложений, ID инфоблоков и коды использованных свойств, имена таблиц Highload-блоков, способ идентификации товаров и предложений, команды запуска миграций и импортёра, результаты dry-run, тестового импорта и повторного запуска.
Отдельно считают, сколько создано и обновлено товаров, предложений, производителей, цветов и размеров, сколько было пропусков, конфликтов и ошибок. К отчёту прикладывают список товаров с конфликтующими значениями, перечень сделанных допущений и оставшиеся блокеры.
Работа считается законченной, когда маппинг реализован целиком, изменения структуры оформлены миграциями, импортёр структуру не трогает, производитель, цвет и размер работают как справочники, артикул, размер и цвет записаны в торговые предложения, цена и остаток назначены продаваемой сущности, повторный импорт не создаёт дубли, исходная база не изменена, старые URL восстановлены доказательно, а контрольный импорт прошёл без критических ошибок.
Если переносите каталог в Битрикс и не хотите разбираться с дублями на проде, напишите нам. Посмотрим вашу базу, оценим объём и скажем, где импортёр справится сам, а где без миграций не обойтись.




Обсуждение
Поделитесь мнением — первый комментарий задаст тон.