Штрихкод в карточке маркетплейса стоит, а товар по нему не находится. Какой формы не хватает
Из сорока шести карточек, которые я взял на контрольную выборку, правильно были заполнены девятнадцать. Товар на площадке при этом был у всех сорока шести, карточка была, штрихкод в ней был виден глазами. И всё равно почти шесть позиций из десяти не находились по тому номеру, который напечатан на коробке.
Разбираться пришлось потому, что к первому октября карточка товара на маркетплейсе перестаёт быть витриной и становится объектом проверки: площадка сверяет сведения сама. Штрихкод тут не главное поле, но он ключ, по которому к товару цепляется остальное.
Работал я на Ozon и Яндекс Маркете, из типового учёта на УТ 11.5. Дальше говорю про обоих и каждый раз называю, про кого речь: поведение у них разное, и в этом половина сюжета.
Один номер, два штрихкода
Начну с того, что сбивает с толку первым. В карточке товара на Ozon нет поля "штрихкод". Там список.
Пока в голове стоит "у товара один штрихкод", логика выгрузки строится неправильно: вы пишете код, который кладёт значение, хотя нужен код, который добавляет элемент в список и смотрит, чего в этом списке ещё нет.
Теперь про две формы. Глобальный номер товарной позиции, он же GTIN (Global Trade Item Number), хранится у нас четырнадцатизначным, с ведущим нулём. На коробке напечатан тринадцатизначный, он же EAN-13. Это один и тот же номер: тринадцатизначная форма получается отбрасыванием ведущего нуля, и контрольная цифра остаётся прежней.
Проверить это стоит руками, потому что весь дальнейший разговор на этом стоит. Возьмём номер из диапазона внутренней нумерации предприятия, префикс 20, такие номера не выдаются никому:
// Контрольная цифра EAN-13: веса 1 и 3 попеременно, слева направо по первым 12 знакам. // 2*1 + 0*3 + 0*1 + 0*3 + 0*1 + 0*3 + 0*1 + 0*3 + 0*1 + 0*3 + 0*1 + 1*3 = 5 // Дополнение до десятки: (10 - 5 % 10) % 10 = 5 EAN13 = "2000000000015"; // Контрольная цифра GTIN-14: те же веса, сдвинутые на знак, по первым 13 знакам. // 0*3 + 2*1 + 0*3 + 0*1 + 0*3 + 0*1 + 0*3 + 0*1 + 0*3 + 0*1 + 0*3 + 0*1 + 1*3 = 5 // Дополнение то же: 5 GTIN14 = "02000000000015";
Ведущий ноль попадает на позицию с весом 3 и умножается на ноль. Поэтому он ничего не меняет, и поэтому приём работает:
EAN13 = Сред(GTIN14, 2); // "2000000000015"
Ozon это знает, но ведёт себя не так, как ожидаешь. Он хранит 02000000000015 и 2000000000015 как два разных элемента списка. Не как одно значение в двух видах. Он их не склеивает, одну форму из другой не выводит и недостающую не достраивает. Лежит одна форма, значит по второй товар не находится.
Если ваш обмен кладёт одну форму, вы уже потеряли половину способов найти товар, и узнаете об этом от склада.
Где отбрасывание нуля даёт неверный номер
Приём с отбрасыванием первого знака легко превратить в общее правило и испортить себе справочник, поэтому сразу про границу.
Отбрасывать можно только ведущий ноль. Первый знак четырнадцатизначного номера это индикатор уровня упаковки: ноль у штучного товара, единица и дальше до восьми у короба и паллеты. У такого номера контрольная цифра посчитана уже вместе с индикатором.
Возьмём тот же номер, но коробом:
GTIN14 = "12000000000012"; // индикатор 1, контрольная цифра 2 Обрезанный = Сред(GTIN14, 2); // "2000000000012"
У 2000000000012 контрольная цифра по формуле EAN-13 должна быть 5, а стоит 2. Это уже не штрихкод штучного товара, это строка из тринадцати цифр, похожая на штрихкод.
Поэтому проверка на ведущий ноль обязательна и стоит одну строку:
Если СтрДлина(GTIN14) = 14 И Лев(GTIN14, 1) = "0" Тогда Штрихкоды.Добавить(Сред(GTIN14, 2)); КонецЕсли;
Правило формулируется через ведущий ноль, и слово "ведущий" тут несущее. "Отбрасываем первый знак" звучит так же, работает иначе, и разница видна в испорченном справочнике.
Оговорюсь, чего я не проверял: примет ли Ozon номер с несошедшейся контрольной цифрой. Битый номер я туда не заливал и утверждать не буду. Проверять такое на живом каталоге мне не хотелось, а стенда под рукой не было.
Отдельного поля под GTIN у Ozon нет вовсе
Первая мысль была другая. Раз номер глобальный и стандартный, у карточки должен быть отдельный атрибут под него, а штрихкоды это про своё, внутреннее.
Я прогнал все атрибуты карточки через /v4/product/info/attributes и посмотрел, в каком из них живёт номер. Атрибутов оказалось 66. Поля с глобальным номером товарной позиции среди них нет ни одного.
Документация Ozon говорит то же самое с другой стороны: она предписывает класть такой номер в штрихкоды и следить, чтобы он совпадал с указанным на товаре. Отдельной сущности для него не предусмотрено намеренно.
Оговорюсь честно: состав атрибутов у Ozon категорийный, и 66 это одна категория. Утверждение "атрибута нет" держится на документации, а прогон показал только, что в моей категории искать больше негде.
Прежде чем писать маппинг под "атрибут GTIN", проверьте, существует ли он у вашей категории. Скорее всего вы потратите день на поле, которого нет.
Заодно про типовую, чтобы снять вопрос сразу. В УТ 11.5.22.67 интеграция с маркетплейсами есть, и немаленькая, но в перечислении ВидыОбъектовМаркетплейсов вида "Штрихкод" нет: номер уезжает внутри вида "Товар". Вопрос "сколько форм должно лежать в карточке" типовая не ставит и за вас не решает.
Код ответа 200 у Яндекс Маркета ничего не значит
У Яндекса отказ приезжает внутри тела. Код ответа при этом двухсотый.
Запрос принят, разобран, и дальше в теле лежит поле status. Если в нём стоит ошибка, порция не применяется целиком: не отдельная строка, а всё, что вы прислали одним запросом. Отчёт покажет успех по транспорту, в карточках не изменится ничего.
Вердикт читается из тела. Код ответа отвечает на другой вопрос, доехал ли запрос, и если писать проверку по нему, журнал обмена будет зелёным всегда.
Обновление дополняет. Но соседнее поле того же метода затирает
Тут я едва не сломал чужие данные, и спасло только то, что проверял на одном товаре.
Запись штрихкодов у Яндекса через offer-mappings/update дополняет список. Прислали одно значение, остальные остались на месте. Плюс обновление асинхронное: сразу после записи чтение отдаёт прежний список, примерно через минуту оба значения.
А поле certificates того же самого метода ведёт себя обратно: набор заменяется целиком, и прежние номера надо отправлять вместе с новым, иначе сотрёте чужие.
Один метод, два поля, противоположное поведение. Разница сидит в поле, и в документации она никак не подсвечена.
Перед первой массовой записью проверьте на товаре, у которого в поле уже лежит что-то постороннее. Не на пустом. Пустой товар покажет вам успех в обоих случаях.
Отказ, который называет не ту причину
Метод Ozon /v1/barcode/add отвечал, что штрихкодов должно быть от одного до ста. Читается однозначно: пачка слишком большая, уменьшай. Пачка была меньше сотни.
Причина сидела в другом слое. Тело запроса уходило строкой вместо структуры, и Ozon получал пустой список. Пустой список так же не попадает в диапазон от одного до ста, как и список из трёхсот элементов, и текст отказа у них общий.
// КоннекторHTTP.Post(URL, , Доп) - тело передаётся третьим параметром, // и ключ внутри решает, как оно будет сериализовано. Доп = Новый Структура; Доп.Вставить("Json", ТелоЗапроса); // структура уедет как JSON // Доп.Вставить("Строка", ТелоЗапроса); // а так Ozon увидит пустоту
Сообщение честное, но указывает не туда: элементов действительно не от одного до ста, их ноль. Мы же читаем диапазон и идём проверять размер пачки, потому что про ноль не думаем.
Когда отказ говорит про диапазон, проверяйте сначала нижнюю границу. Ноль встречается чаще перебора и стоит дороже, потому что выглядит как ваша арифметика.
Пачка на сто, и считаются в ней штрихкоды
Ограничение у /v1/barcode/add такое: не больше ста штрихкодов за запрос и не чаще двадцати запросов в минуту.
Пока мы слали одну форму, пачка в сто пар товара и номера укладывалась ровно в лимит. Как только каждая пара стала давать два штрихкода, сто пар превратились в двести штрихкодов.
Лечится арифметикой: пачка уменьшается вдвое.
// было: Если Пачка.Количество() >= 100 Тогда ... // стало: каждая пара даёт два штрихкода, поэтому Если Пачка.Количество() >= 50 Тогда Порции.Добавить(Пачка); Пачка = Новый Массив; КонецЕсли;
Лимит считается в тех единицах, которые площадка пишет в документации. Написано "штрихкодов", значит товары к делу не относятся.
Отдельно про чтение, и это уже Яндекс. У метода offer-mappings свой потолок на список offerIds, и сейчас он равен сотне. У нас в коде стояло двести, и откуда взялась эта цифра, я честно не знаю: то ли потолок был другим, когда обмен писался, то ли мы её однажды придумали и с тех пор не перепроверяли. Поймали отказом на боевом прогоне, чтение документации тут не помогло бы. Если у вас в обмене стоит число, которого вы сегодня не можете объяснить, считайте его неверным, пока не проверите запросом.
Ночной регламент отработал без ошибок и недобрал
Разовая дозаливка это половина работы. Вторая половина в том, чтобы новые карточки получали обе формы сами, поэтому правились сами методы, а не только данные.
Первая же ночь после правки подняла долю связанных карточек Ozon с трёх сотых очереди до семи десятых. Это рост в двадцать три раза, и тут я сам едва не соврал в свою невыгоду: в черновике у меня стояло "почти на порядок", то есть вдвое с лишним меньше того, что получилось.
И при этом регламент недобрал часть очереди, закончившись без единой ошибки в журнале.
Что оказалось не так, как я думал
Две гипотезы я проверил, и обе не подтвердились. Вторая не подтвердилась уже при подготовке этого текста.
Первая: Яндекс берёт только тринадцать знаков. Это убеждение я принёс с собой и написал по нему метод, который аккуратно срезал ведущий ноль перед отправкой. Прогон показал, что четырнадцатизначную форму Яндекс принимает и хранит спокойно. Метод годами срезал то, что срезать было не нужно, и оставлял карточку с одной формой вместо двух.
Вторая: недобор ночного прогона это лимит запросов. Объяснение выглядело очевидным: пачку мы уменьшили вдвое, запросов стало вдвое больше, значит упёрлись в двадцать запросов в минуту. Так и было записано у меня в протоколе прогона.
Арифметика это не подтверждает. За ту ночь связано 1 647 карточек. При пачке в сто штрихкодов это семнадцать запросов, меньше минуты работы при лимите двадцать в минуту. Лимит столько карточек остановить не может физически.
Чем регламент упёрся на самом деле, я не знаю: журнал прогона такой детализации не держал, а воспроизводить ночь ради этого дорого. Поэтому в тексте остаётся дыра, и пусть она лучше будет видна, чем закрыта правдоподобной причиной.
Общее у обеих гипотез одно: каждая звучала убедительно и каждая объясняла наблюдаемое. Убедительность тут и есть ловушка, она снимает вопрос вместо того, чтобы его поставить. Вторую гипотезу я поймал только потому, что сел пересчитывать числа для этой статьи.
Что в итоге поменялось в цифрах
Контрольная выборка та же самая, сорок шесть карточек, замер до работы и после.
| Что в карточке | До | После |
|---|---|---|
| обе формы | 19 | 45 |
| только четырнадцатизначная | 26 | 0 |
| только тринадцатизначная | 0 | 0 |
| ни одной | 1 | 1 |
Строка про тринадцатизначную форму пустая в обеих колонках намеренно: ни одна карточка не держала только её. Это и подсказало, где искать. Дело было в двух методах выгрузки, написанных под разные площадки в разное время: один слал длинную форму, другой короткую, и ни один не смотрел, что лежит в карточке сейчас.
Карточка, оставшаяся без штрихкодов совсем, такой и осталась: у товара нет номера в самой учётной базе, и площадка тут ни при чём. Это честный остаток почти любой такой работы: то, что решается кодом, кончается быстрее, чем кажется.
Всего операций записи по всем кабинетам получилось около семи тысяч двухсот пятидесяти. Ошибок в отчёте прогона ноль, и я уточню, что это значит: ноль отказов, которые вернула площадка и которые дошли до счётчика. Сетевых сбоев на такой серии я не видел, но отдельного счётчика повторов у меня там нет, так что про идеальную сеть утверждать не буду.
Чем я это делал
Всё описанное собиралось под конкретную задачу, руками, поверх типового учёта. Под соседнюю часть той же истории у меня выложены три обработки по разрешительным документам: там то же взаимодействие с карточкой товара, только со стороны документов.
- Загрузка сертификатов и деклараций в Яндекс Маркет из 1С - там та же механика пачки и то же чтение вердикта из поля
status, что описано выше; - Загрузка сертификатов в OZON из 1С;
- Загрузка сертификатов и деклараций в Wildberries из 1С.
Что меняется с первого октября и почему документ становится частью карточки, разбирал отдельно в статье Платформенная экономика РФ: почему сертификат становится частью карточки товара. Там же про то, что у одного товара может быть несколько кодов, и почему привязываться надо к артикулу.
Другие наши инструменты
- Сводная таблица в Excel из 1С без COM - выгрузить результат сверки и отдать людям.
- Анализ кода внешних обработок 1С - посмотреть, что делают обработки, которые ходят наружу с вашими данными.
- Журнал регистрации, свёрнутый для нейросети - разобрать, кто и когда трогал справочник штрихкодов.
Вопрос
Держать в карточке обе формы я решил из осторожности: так товар находится любым способом. Площадка при этом обе не требует, она пишет, что примет товар с любым из действующих штрихкодов. То есть мы сознательно дублируем данные.
И вот чего я не знаю. Что происходит на стороне 1С, когда обе формы лежат в справочнике штрихкодов у одной номенклатуры? Поиск на ТСД отработает по любой, это понятно. А загрузка отчёта о продажах, где площадка присылает тринадцать знаков, а у вас ключом четырнадцать, не начинает двоить строки при сверке? И ловил ли кто-нибудь коллизию, когда тринадцатизначная форма одного товара уже занята в базе другой номенклатурой?
Вступайте в нашу телеграмм-группу Инфостарт
Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
См. также
67620 руб.
22.03.2021 313506 2604 2186
23.01.2023 82693 783 user1468243 212
28800 руб.
12.05.2021 123646 1073 274
5490 руб.
12.08.2021 48498 654 71
6000 руб.
11.12.2019 68092 1163 3
6000 руб.
26.11.2020 51315 865 4