Полноценный обмен с учётной системой есть не у всех. Очень часто каталог живёт по-другому: поставщик присылает xlsx или csv, контент-менеджер открывает его, сверяет цены глазами и правит карточки руками. На трёхстах позициях это терпимо, на трёх тысячах — полдня работы раз в неделю и гарантированные ошибки. Автоматический импорт прайса решает задачу, но у него есть несколько мест, где всё разваливается, и они всегда одни и те же.
Главный вопрос: по какому полю сопоставлять
Импорт — это не загрузка файла, а сопоставление строк файла с уже существующими товарами. Всё остальное вторично. Поэтому первое, что нужно определить, — ключ сопоставления.
Сопоставлять по названию нельзя. Поставщик напишет «Кабель ВВГнг 3х1,5», в следующий раз — «Кабель ВВГ-нг 3*1.5», и это уже другая строка. Любой лишний пробел, дефис вместо тире, перестановка слов — и импорт создаёт дубль вместо обновления. Ключ должен быть машинным: артикул, код поставщика, штрихкод.
Если у товара нет стабильного кода со стороны поставщика, автоматический импорт настроить нельзя. Сначала код, потом импорт — обратный порядок всегда заканчивается разбором дублей вручную.
Отдельная сложность — несколько поставщиков. Артикул 1024 может быть у двух разных компаний, и это разные товары. Решение: хранить составной ключ из кода поставщика и артикула, а не артикул сам по себе. Хранится он в отдельном поле внешнего кода, по которому обязательно строится индекс в базе, — иначе на каждой строке файла будет полный перебор каталога, и импорт десяти тысяч позиций растянется на часы.
Файл: кодировка, разделители и числа
Половина обращений «импорт сломался» — это не импорт, а файл. Типовой набор проблем выглядит так.
- CSV из 1С и из Excel сохраняется в Windows-1251, а скрипт читает UTF-8 — на выходе вопросительные знаки вместо названий
- UTF-8 с BOM: первая колонка первой строки получает невидимые символы в начале, и заголовок перестаёт совпадать
- Разделитель в русской локали — точка с запятой, а не запятая; при смене локали файл меняет формат без предупреждения
- Цена приходит строкой вида 1 200,00 — с десятичной запятой и неразрывным пробелом как разделителем тысяч
- Excel превращает артикул 00123 в 123, а длинный цифровой код — в экспоненциальную запись
- В конце файла десятки пустых строк, которые читаются как товары без названия
Выводы практические. Кодировку определять и приводить к UTF-8 на входе, а не надеяться на договорённость с поставщиком. Числа чистить перед разбором: убирать обычные и неразрывные пробелы, менять запятую на точку, отрезать символ валюты. Все кодовые поля читать как строку, а не как число. А xlsx разбирать библиотекой, работающей с форматом напрямую, — при ручном пересохранении в csv теряются и ведущие нули, и длинные коды.
Сопоставление колонок — один раз, а не каждый импорт
Удобный импорт устроен как профиль: для каждого поставщика один раз задаётся карта «колонка файла → поле каталога», и дальше файл просто загружается. В карте указывается и номер строки с заголовками, и строка, с которой начинаются данные, — у половины прайсов сверху шапка с логотипом и контактами.
Привязываться нужно к названию заголовка, а не к номеру колонки. Поставщик однажды вставит колонку «Акция» в середину, и импорт по номерам начнёт записывать цену в поле веса. Если заголовок не найден, импорт должен остановиться с понятным сообщением, а не продолжить с пустым значением.
Что именно обновлять, а что не трогать
Прайс — источник правды только для части данных. Обычно это цена, остаток и, может быть, срок поставки. Название, описание, фотографии и SEO-тексты ведёт контент-менеджер, и их перезапись прайсом — самая обидная потеря: человек неделю писал описания, импорт за минуту заменил их на строки из файла поставщика.
Поэтому в профиле импорта поля делятся на обновляемые и защищённые, и защищённые по умолчанию — все текстовые. Отдельно полезен флаг на уровне товара: «ведётся вручную», который выводит карточку из-под импорта целиком. Он нужен для топовых позиций, которые оформляли отдельно.
Ещё одна деталь — сравнение перед записью. Если значения не изменились, писать в базу не нужно: это экономит время импорта и, что важнее, не мусорит датой изменения. Иначе каждый импорт помечает весь каталог как обновлённый, и в выгрузках для маркетплейсов и в sitemap поля даты становятся бесполезны.
Цены: наценка, округление, несколько типов
В прайсе почти всегда закупочная цена, а на сайте нужна розничная. Значит, в импорте живёт правило наценки — и оно редко бывает одним числом. Обычно это таблица: по категориям, по поставщикам, по диапазонам цены. Хранить её нужно в настройках, а не в коде скрипта, чтобы менять без разработчика.
Дальше округление. Цена 1 843,70 на витрине выглядит как ошибка, поэтому задаётся правило — до десяти рублей вверх, до красивого окончания, до целых. Это настройка бизнеса, а не программиста, и её стоит проговорить заранее.
- Розничная, оптовая и дилерская цены — это разные поля, а не одна цена со скидкой на лету
- Валюта и курс: если прайс в валюте, нужно решить, пересчитывается цена при импорте или при показе
- Старая цена для зачёркивания — отдельное поле, иначе скидка исчезнет при первом же импорте
- Ручные акционные цены должны переживать импорт, иначе каждая акция будет жить до ближайшей ночи
Товары, которых нет в новом прайсе
Самое опасное место. Строка исчезла из файла — что делать с карточкой на сайте? Ответ почти всегда один: не удалять. За удалённой карточкой стоит страница, которая уже в индексе, на неё могут быть внешние ссылки и история переходов. Правильное поведение — снять с продажи и показать как отсутствующую, сохранив страницу и адрес.
И отдельно — защита от битого файла. Поставщик может прислать прайс, выгруженный наполовину, или файл с одной категорией вместо всего ассортимента. Без предохранителя импорт честно спрячет девяносто процентов каталога, и магазин утром окажется пустым.
Простое правило, которое спасает магазины: если по итогам импорта из продажи уходит больше заранее заданной доли каталога, импорт не применяется, а присылает предупреждение. Порог подбирается по ассортименту, но он должен быть всегда.
Как не положить сайт импортом
Импорт десяти тысяч строк — это длинная операция, и запускать её обычным веб-запросом нельзя: упрётесь в время выполнения скрипта или в размер загружаемого файла, получите обрыв на середине и половину обновлённого каталога.
- Файл читается потоково, строка за строкой, а не загружается в память целиком
- Запись идёт пачками по несколько сотен строк, с фиксацией прогресса между пачками
- Сам импорт выполняется фоновой задачей или по расписанию, а не в браузере
- Параллельный запуск блокируется: два импорта одновременно дают гонку за одни и те же карточки
- После завершения сбрасывается кеш каталога и переиндексируется поиск, иначе витрина покажет старые цены
Последний пункт встречается чаще, чем хотелось бы: данные в базе уже новые, а страница отдаёт закешированную версию. Эту же механику мы разбирали применительно к обмену с учётом — симптомы один в один, см. почему на сайте и в 1С разные остатки.
Отчёт, без которого импорт нельзя принимать
Импорт, который молча отрабатывает и ничего не рассказывает, доверия не заслуживает. После каждого запуска должен оставаться протокол: сколько строк прочитано, сколько товаров создано, сколько обновлено, сколько пропущено и по какой причине — с номерами строк.
- Список новых позиций — их нужно дооформить руками: фото, описание, категория
- Список исчезнувших позиций — проверить, действительно ли сняты с продажи
- Изменения цены больше заданного процента — защита от лишнего нуля в прайсе
- Строки с ошибками разбора — с указанием колонки и значения
- Время выполнения — рост времени обычно первый признак, что пора добавлять индексы
И крайне полезен режим проверки: прогон без записи, который показывает, что именно произойдёт. Перед первым импортом нового поставщика он обязателен, иначе исправлять придётся по факту.
Когда пора переходить на нормальный обмен
Импорт прайса — рабочее решение, но у него есть потолок. Он односторонний: заказы с сайта в нём никак не участвуют, остатки обновляются раз в сутки или реже, а резервы под уже оформленные заказы не учитываются вовсе. Как только магазин начинает терять деньги на продаже того, чего нет на складе, дешевле перейти на обмен с учётной системой.
Какая система подойдёт, зависит от того, как устроен бизнес: сравнение вариантов есть в статье МойСклад или 1С для небольшого магазина. Технически обмен с МойСклад идёт по обычному REST API и настраивается быстрее, обмен с 1С — по CommerceML и требует больше подготовки.
Мы делаем импорт прайсов с профилями под каждого поставщика, защитой контента от перезаписи и протоколом по каждому запуску — и как часть разработки интернет-магазина, и отдельной задачей на существующем сайте. Если прайс уже загружается, но делает это непредсказуемо, начинаем с разбора протоколов и ключа сопоставления: обычно причина там. Сопровождение таких импортов — обычная часть поддержки сайта.