# Инструкция для ИИ-агента или программиста: YML-фид для импорта объявлений
Этот файл — техническое задание. Его передал тебе человек, который подключает свой каталог к импорту на сайте объявлений (дальше — «площадка»). Площадка примерно раз в час скачивает YML-файл (фид) по постоянной ссылке и по нему создаёт, обновляет и снимает объявления этого человека.
Твоя задача — в проекте человека сделать выгрузку такого файла, опубликовать её по постоянному адресу и проверить по правилам ниже. Правила описывают фактическую работу площадки. Всё, что здесь не названо, площадка не использует.
Из фида в объявление попадают название, описание, цена, фотографии и ссылка на страницу предложения. Раздел каталога площадки и контакты задаёт человек в личном кабинете площадки: в фиде их указывать не нужно. Город объявления тоже выбирается в кабинете. Если все позиции относятся к одному городу, в фиде его не указывай. Если позиции находятся в разных городах (например, агентство недвижимости сдаёт квартиры в нескольких городах), укажи у позиции её город элементом `param name="Город"` (раздел 7): человек один раз сопоставит каждый город фида с городом площадки.
Действия в личном кабинете (сохранить ссылку на фид, нажать «Проверить фид», выбрать разделы, контакты, отправить заявку) выполняет человек. Ты в кабинет не входишь.
## 1. Что должно получиться
1. Генератор фида в проекте человека: команда, скрипт или обработчик, который выгружает весь актуальный каталог в один XML-файл по правилам этого документа.
2. Постоянный адрес фида, который открывается из интернета без пароля, например `https://shop.example/export/adverts.xml`.
3. Регулярное обновление файла: по расписанию (например, раз в час) или при изменении каталога.
4. Файл подтверждения сайта в корне сайта (раздел 9).
5. Отчёт человеку (раздел 13).
## 2. Порядок работы
1. Изучи проект: где хранятся позиции (товары, объекты недвижимости, услуги), категории, цены, валюта, фотографии, адреса страниц позиций; какой у сайта публичный адрес; как в проекте запускаются задачи по расписанию.
2. Задай человеку вопросы из раздела 3 — только те, на которые проект не отвечает.
3. Напиши генератор. Данные бери из базы или API проекта, а не из HTML-страниц сайта. XML собирай библиотекой языка проекта, а не склейкой строк: так экранирование будет правильным.
4. Опубликуй файл по постоянному адресу и настрой обновление.
5. Проверь результат по чек-листу из раздела 12 и исправь всё, что не проходит.
6. Отчитайся человеку (раздел 13).
## 3. Что спросить у человека
- Какие позиции выгружать: все, только в наличии, только отдельные категории. По умолчанию площадка принимает до 1000 предложений (раздел 4). Если позиций больше, нужно либо выбрать часть, либо попросить площадку увеличить лимит через форму обратной связи.
- Находятся ли позиции в разных городах. Если да — где в проекте хранится город позиции: его нужно выгрузить в `param name="Город"` (раздел 7). Если нет — какой город человек выберет в кабинете для объявлений.
- Название города объявления запрещено в названиях предложений (раздел 8): для позиции с городом — её города, для позиции без города — города, выбранного в кабинете.
- Какую цену выгружать (обычную, со скидкой) и в какой валюте.
- Имя и содержимое файла подтверждения (раздел 9). Их показывает кабинет в блоке «Подтверждение сайта» после того, как человек сохранит ссылку на фид. Если ссылки ещё нет — сначала сделай фид, потом попроси человека сохранить ссылку и передать тебе файл.
## 4. Как площадка скачивает файл
- Адрес начинается с `http://` или `https://`, работает на стандартном порту (80 для HTTP, 443 для HTTPS; адреса вида `:8080` не подходят), не содержит логина и пароля, длина — до 255 символов. Секретный параметр в адресе (`?key=...`) допустим.
- Сервер доступен из интернета по публичному IP-адресу. Адреса локальной сети и `localhost` запрещены.
- Площадка скачивает файл обычным HTTP-клиентом, а не браузером: без JavaScript, cookies, капчи и заголовка Referer. Защита от ботов, проверка браузера, блокировка по стране или IP-адресу не должны закрывать фид, файл подтверждения и фотографии. Каждый запрос площадки несёт заголовок `User-Agent` с `PartnerImport/1.0` и адресом площадки: если защиту отключить нельзя, разреши запросы с этим значением. HTTPS-сертификат не проверяется — подойдёт любой.
- Ответ — код 200 и файл целиком. Пустой ответ, страница входа, коды 4xx и 5xx — ошибка загрузки.
- Перенаправлений — не больше 5. Весь запрос вместе с ними должен уложиться в 60 секунд.
- Размер — до 50 МБ после распаковки. Сжатие при передаче (`Content-Encoding: gzip` и другие) поддерживается, но сам файл должен быть XML, а не архивом `.zip` или `.gz`.
- Формат определяется по содержимому, а не по расширению или `Content-Type`. Рекомендуемый `Content-Type` — `application/xml` или `text/xml`.
- Каждый раз площадка получает весь каталог. Выгрузка только изменений, деление на несколько файлов и постраничная выдача не поддерживаются. Позиция, которой нет в новом файле, снимается с показа.
- Условные запросы. Если сервер отдал заголовок `ETag` или `Last-Modified`, следующий запрос придёт с `If-None-Match` или `If-Modified-Since`. Ответ `304 Not Modified` допустим, только если файл действительно не изменился. Статический файл на nginx или Apache отвечает правильно сам. Если файл формирует скрипт и правильный ответ 304 гарантировать нельзя, не отдавай эти заголовки совсем: ложный 304 означает, что изменения каталога не дойдут до площадки.
- Лучший вариант — статический файл, который генератор пересоздаёт по расписанию: сначала пишет во временный файл в той же папке, затем переименовывает его в постоянное имя. Так площадка не получит недописанный файл. Генерация при каждом запросе рискует не уложиться в 60 секунд.
Ограничения каталога:
- Предложений (`offer`) — до 1000 по умолчанию. Считаются все элементы `offer`, включая снятые (`available="false"`), ошибочные и повторные. Если предложений больше лимита, весь файл отклоняется, а не обрезается.
- Категорий (`category`) — до 150, включая родительские и пустые. Если больше, весь файл отклоняется. Если в магазине больше категорий, выгружай укрупнённое дерево (например, два верхних уровня), а предложению из более глубокой категории указывай в `categoryId` её ближайшую выгружаемую родительскую категорию. Состав дерева не должен зависеть от наличия товаров: категория, исчезнувшая из файла, теряет сопоставление с разделом площадки (раздел 6).
- Различных городов (`param name="Город"`) среди доступных предложений — до 150. Если больше, весь файл отклоняется.
## 5. Структура файла
```xml
Зоомагазин «Пример»
ООО «Пример»
https://shop.example/
Товары для кошек
Переноски и сумки
Переноска для кошки
https://shop.example/products/SKU-0042
1500
RUB
10
https://shop.example/images/SKU-0042-main.jpg
Новая переноска. Размер 48 × 32 × 30 см. Самовывоз.
```
Правила:
- Кодировка — UTF-8 (рекомендуется) или Windows-1251, объявленная в первой строке: ``. Без объявления файл читается как UTF-8. Другие кодировки не принимаются.
- XML должен быть корректным: `&`, `<` и `>` в тексте экранированы (`&`, `<`, `>`), значения атрибутов — в кавычках, управляющие символы с кодами 0x00–0x1F (кроме табуляции и переводов строк) удалены, байты — валидный UTF-8. Одна ошибка разметки отклоняет весь файл. Тексты из базы часто содержат управляющие символы и незакрытые HTML-теги — очищай их или передавай HTML через CDATA (раздел 7, `description`).
- Запрещены ``, объявления сущностей и XInclude: с ними весь файл отклоняется. Не добавляй строку ``, которую ставят многие старые генераторы YML.
- Корень — один элемент `yml_catalog`. В нём ровно один `shop`. В `shop` — не больше одного `categories` и одного `offers`, прямыми потомками. `offers` обязателен: без него файл отклоняется. `categories` обязателен, если в `offers` есть хоть одно предложение без `available` или с `available="true"`: без него или с пустым `categories` такой файл тоже отклоняется. Пустой `offers` или `offers` только из предложений с `available="false"` площадка примет и без категорий: так снимаются товары. Но проще и надёжнее выгружать `categories` всегда. `category` стоит только прямо внутри `categories`, `offer` — только прямо внутри `offers`. В других местах файла элементы `shop`, `categories`, `offers`, `category` и `offer` недопустимы — иначе весь файл отклоняется.
- Атрибут `yml_catalog@date` необязателен. Если указываешь его — с часовым поясом, как в примере; без пояса будет предупреждение.
Элементы внутри `shop`:
- `url` — обязателен. Абсолютный адрес сайта человека, например `https://shop.example/`: схема http или https, без номера порта, без логина и пароля, без пробелов, кавычек, `<`, `>` и `\`, до 255 символов. Это «сайт источника»: в его корне размещается файл подтверждения (раздел 9), и на него должны вести ссылки `offer/url`. Сам фид и фотографии могут лежать на других доменах. Без корректного `shop/url` весь файл отклоняется.
- `name`, `company` — необязательны: названия магазина и компании, человек видит их в кабинете. Длиннее 255 символов обрезаются.
- `currencies` — не нужен. Если он есть, площадка пропускает его без предупреждения; курсы валют не применяются.
- Любой другой элемент внутри `shop` (`platform`, `version`, `email`, `delivery-options` и т. п.) пропускается с предупреждением в отчёте.
## 6. Категории
- `id` — обязателен: только цифры, целое число больше 0, не длиннее 18 цифр, уникальное в файле. Нечисловой, нулевой или пустой `id`, повтор `id`, неверный `parentId` — весь файл отклоняется.
- `parentId` — необязателен: `id` родительской категории из этого же файла. У корневой категории `parentId` нет или он равен `0`. Ссылка на отсутствующую категорию и циклы недопустимы — весь файл отклоняется.
- Текст элемента — название категории, до 255 символов. Человек видит его в кабинете, когда сопоставляет категории фида с разделами площадки. В объявления название категории не попадает.
- Каждая категория, на которую ссылается `offer/categoryId` предложения к публикации (без `available` или с `available="true"`), должна быть в `categories`. У предложений с `available="false"` `categoryId` не сверяется (раздел 7).
- `id` категорий должны быть постоянными: бери их из базы проекта, а не нумеруй по порядку. Человек сопоставляет категории с разделами площадки по `id`. Категория, исчезнувшая из файла, теряет сопоставление, а категорию с новым `id` придётся настраивать заново. Исключение — файл совсем без категорий (пустой или отсутствующий `categories` при одних снятых предложениях): все сопоставления сохраняются до возвращения товаров. Поэтому, снимая товары, не сокращай `categories`: выгружай одно и то же дерево категорий, в том числе категории, в которых сейчас нет предложений.
- Предложения категории без выбранного раздела не публикуются. Когда после одобрения заявки в такой категории появляются предложения, площадка пишет владельцу подключения письмо, и человек выбирает раздел или «Не импортировать» в кабинете.
- Каждая категория сопоставляется отдельно: от родителя раздел не наследуется. Предложение может ссылаться на категорию любого уровня.
## 7. Предложения
Атрибуты `offer`:
- `id` — обязателен. От 1 до 80 символов после обрезки пробелов по краям. Постоянный: по нему площадка при следующих загрузках находит то же объявление. Регистр и ведущие нули значимы: `SKU-42`, `sku-42` и `SKU-0042` — три разных предложения. Бери артикул или первичный ключ из базы, а не номер строки выгрузки. Пустой или слишком длинный `id` — ошибка предложения.
- `available` — `true` или `false`, строчными буквами. Без атрибута предложение считается доступным, а в отчёте появляется общее предупреждение. Пустое значение, `True`, `1`, `yes` — ошибка предложения. Указывай атрибут всегда.
- `type` — не указывай для обычного предложения: название берётся из `name`. Значение `vendor.model` означает, что название составляется из `typePrefix`, `vendor` и `model`. Любой другой тип (`books`, `medicine`, `event-ticket` и прочие) — ошибка предложения.
Площадка читает только прямых потомков `offer`. Значения обрезаются по краям.
- `name` — обязателен для обычного предложения. Становится названием объявления. Правила текста — раздел 8.
- `typePrefix`, `vendor`, `model` — только для `type="vendor.model"`. Название объявления — `typePrefix vendor model` через пробел. `vendor` и `model` обязательны, `typePrefix` — нет. Без `vendor` или `model` — ошибка предложения.
- `categoryId` — обязателен: `id` категории из `categories`. Нечисловое значение или категория, которой нет в файле, — ошибка предложения. Если `categoryId` нет или он пустой, предложение не будет опубликовано.
- `description` — обязателен: текст объявления. HTML допустим — экранированный или внутри ``; CDATA надёжнее. Площадка удаляет `script` и `style` вместе с содержимым, превращает `p`, `div`, `br`, `li`, `h1`–`h6`, `tr`, `table`, `ul`, `ol`, `blockquote`, `pre`, `hr`, `dl`, `dt`, `dd` в переводы строк, ячейки `td` и `th` — в пробелы, остальные теги удаляет, HTML-сущности раскрывает, пустые строки убирает. Пустой после очистки текст — предложение не будет опубликовано. Необработанное описание больше 10 МБ отклоняет весь файл.
- `price` — необязателен. Неотрицательное десятичное число с точкой: `1500`, `1499.90`. Без пробелов, запятых, знака валюты и экспоненты, иначе ошибка предложения. Дробная часть округляется до целого, половина — вверх: `1499.49` → 1499, `1499.50` → 1500. После округления — не больше 4294967295. Отсутствующая, пустая или нулевая цена означает «договорная»; пометку «бесплатно» фид не ставит.
- `currencyId` — необязателен, регистр не важен. Допустимы `RUB` (и `RUR` как то же самое), `USD`, `EUR`, `AMD`, `KZT`, `GEL`, `BYN`, `UAH`, `AZN`, `KGS`, `RSD`. Без `currencyId` — рубли. Другая валюта — ошибка предложения. Цена не пересчитывается.
- `url` — необязателен, но желателен. Абсолютный адрес страницы предложения: http или https, до 255 символов, без пробелов и обратной косой черты, без логина и пароля. Домен — тот же, что в `shop/url`, его поддомен или вариант с `www` и без него. Иначе — ошибка предложения. В объявлении ссылка выводится строкой «Веб-сайт» и считается способом связи: без неё новое объявление создаётся, только если человек выбрал в кабинете телефон, email или Telegram.
- `picture` — необязателен, повторяется. Абсолютные адреса изображений в нужном порядке; первое — главное. Пустые элементы пропускаются, берутся первые 5 адресов, остальные игнорируются с предупреждением. Подробно — раздел 10.
- `param name="Город"` — необязателен: город предложения, например `Казань`. Нужен, только когда предложения находятся в разных городах. Атрибут `name` сравнивается без учёта регистра и пробелов по краям, атрибут `unit` не учитывается. Значение обрезается по краям, внутренние пробелы схлопываются; пустое значение равнозначно отсутствию элемента. Регистр и буква «ё» город не различают: «Казань», «казань» и «КАЗАНЬ» — один город. Город — до 255 символов, иначе ошибка предложения. Два и более непустых элемента «Город» в одном предложении — ошибка предложения. Пиши официальное название города, лучше по-русски, без «г.», района и региона: «Санкт-Петербург», а не «СПб» или «Питер». Такой город человеку проще сопоставить, а если название однозначно совпадёт с городом из справочника площадки, кабинет предложит этот город кнопкой «Подставить»: человек проверит страну и регион и сохранит настройки.
Предложение с `available="false"` площадка читает почти без проверок: нужен корректный `id`, остальные поля, включая город, не проверяются. Существующее объявление снимается с показа, новое не создаётся.
Как работает город:
- Город фида площадка сама с городом площадки не сопоставляет: названия городов повторяются, в том числе в пределах одного региона. Каждый город фида человек один раз сопоставляет в кабинете, в таблице «Города фида», после нажатия «Проверить фид».
- Предложение с городом, которому человек ещё не выбрал город площадки, не публикуется (ошибка «Городу предложения не выбран город сайта»). Заявка на импорт не отправляется, пока есть такие города с предложениями в импортируемых категориях.
- Если после одобрения заявки в фиде появится такой город, площадка пришлёт владельцу подключения письмо со списком новых городов и категорий без выбора. Поэтому, начиная передавать `param name="Город"` в уже подключённом фиде, предупреди человека: пока он не выберет города в кабинете, предложения с ними не публикуются, а прежние объявления не обновляются.
- Предложение без города публикуется в городе по умолчанию, выбранном в кабинете. Если в фиде есть предложения и с городом, и без него, отчёт предупреждает о числе предложений без города. Фид совсем без городов — обычный случай одного города, предупреждения нет.
- Выбор города площадки сохраняется, даже если город временно исчезнет из фида: когда предложения этого города вернутся, они опубликуются без новой настройки.
- Контакты в объявлениях общие для всех городов — из профиля владельца. Телефоны по городам в фиде не передаются.
Всё остальное внутри `offer` (прочие `param`, `oldprice`, `vendorCode`, `barcode`, `delivery`, `pickup`, `sales_notes`, `country_of_origin` и т. п.) пропускается, а имена элементов попадают в предупреждение отчёта. Это не ошибка, но лишние элементы лучше не выгружать. Если в характеристиках есть важное для покупателя — размеры, состав, комплектация, — перенеси это в `description` текстом.
## 8. Правила для названия и описания
Площадка проверяет название и описание по тем же правилам, что и объявления, поданные вручную. Предложение с нарушением пропускается, причина видна в отчёте. Тексты не обрезаются и не исправляются автоматически.
Важно: эти правила проверяются только при загрузках после одобрения заявки. Кнопка «Проверить фид» в кабинете их не проверяет. Она находит ошибки структуры файла и полей, которые отклоняет разбор (`id`, `available`, `type`, название, формат `price`, `categoryId`, город), а также пустое описание и отсутствующий `categoryId` у доступного предложения. Валюту, длину и домен `offer/url`, предел цены и правила текстов видят только загрузки после одобрения — проверь их сам до сдачи работы (раздел 12, пункты 8 и 10).
- Название — от 1 до 150 символов. Описание — от 1 до 5000 символов после очистки HTML.
- Нет ссылок: любые `http://`, `https://` или `www.` в тексте. Ссылку на страницу предложения передавай только в `offer/url`.
- Нет адресов email.
- Нет номеров телефонов. Телефоном считается ряд из 11 цифр, который начинается с `7`, `8` или `+7`, а также `+374` и ещё 8 цифр, если между цифрами нет букв (пробелы, скобки, точки, дефисы, запятые и косые черты не мешают) и ряд не стоит вплотную к другим цифрам или буквам. Под это правило попадают и артикулы вида `8-123-456-78-90`. Контакты площадка добавляет в объявление сама из настроек кабинета.
- Нет «слов» из 30 и более символов без пробелов — считаются любые символы, кроме пробельных, включая знаки препинания. Длинные артикулы, перечисления через косую черту (`кошек/собак/хомяков/попугаев`) и склеенные слова разделяй пробелами.
- В названии нет названия города объявления в любой форме — города, выбранного в кабинете для города предложения, или города по умолчанию для предложения без города: «Москва», «Москвы», «Москве». Проверка не различает регистр, считает латинские буквы-двойники кириллическими и ищет название и внутри других слов. В описании город упоминать можно.
- Нет нецензурной лексики и стоп-слов. Словари открыты: https://github.com/Vasiliy-Makogon/RussianBadWords — нецензурная лексика в файлах `data/profanity.php`, `data/rude.php`, `data/insults.php`, `data/anatomy.php`, стоп-слова — в каталоге `data/stop-words/`. Темы стоп-слов: алкоголь; табак, вейпы, кальяны; наркотики; оружие и средства самообороны; насилие; экстремизм; суицид; интим-услуги; казино и азартные игры; кредиты, займы, криптовалюта, страховки; рецептурные препараты и донорство; поддельные документы и дипломы; магия и гадания; пиратство и взлом; спам и мошенничество; запрещённые орудия лова; даркнет и названия даркнет-площадок (среди них есть обычные слова, например `empire`, `evolution`, `hydra`). Слово ищется целиком в любой форме из словаря, без учёта регистра, буквы «ё», латинских двойников и повторов букв; слово через дефис проверяется и по частям. Если такое слово — часть названия бренда или модели, обсуди с человеком, как переформулировать.
Повторяющиеся названия и описания у разных предложений допустимы.
Недвижимость. Отдельного формата для недвижимости нет: у объявления площадки нет полей комнат, площади, этажа, периода цены, залога и комиссии. Пиши их текстом:
- в название — тип объекта, число комнат, площадь и этаж, например «2-комнатная квартира, 54 м², 5/9 этаж». Название города в название не пиши — оно запрещено правилом выше; город передаётся элементом `param name="Город"`;
- в описание — период цены («45 000 ₽ в месяц»), коммунальные платежи («плюс счётчики» или «включены»), залог, комиссию, срок аренды, адрес и прочие подробности;
- в `price` — число без периода: `45000`. Период цены площадка не хранит, поэтому он обязательно указывается в описании;
- раздел каталога площадки для аренды и продажи выбирает человек в кабинете для каждой категории фида: держи аренду и продажу в разных категориях фида.
Пример фида агентства с квартирами в двух городах — раздел 16.
## 9. Подтверждение сайта
Площадка проверяет, что фид публикует владелец сайта из `shop/url`. После сохранения ссылки на фид кабинет показывает файл вида `partner-verification-<метка>.txt`, где метка — 32 шестнадцатеричных символа, а содержимое файла — та же метка.
- Размести файл в корне сайта из `shop/url`, чтобы он открывался по адресу `<схема и домен из shop/url>/partner-verification-<метка>.txt`, например `https://shop.example/partner-verification-0123456789abcdef0123456789abcdef.txt`. Порт площадка тоже берёт из `shop/url`, а обращается только к стандартным портам (раздел 4), поэтому с нестандартным портом в `shop/url` сайт не подтвердится.
- Ответ — код 200, тело — ровно метка; пробелы и переводы строк по краям допустимы. Размер ответа — не больше 1 КБ, время — до 10 секунд.
- Перенаправление допустимо только в пределах того же сайта: между http и https и между вариантами с `www` и без него. Перенаправление на другой домен или поддомен проверку не проходит.
- Не удаляй файл после подтверждения. Если человек перевыпустит метку или в `shop/url` появится другой домен, понадобится новый файл.
- Если файла подтверждения ещё нет, всё равно сделай фид: человек получит имя файла после сохранения ссылки и передаст его тебе.
## 10. Фотографии
- Абсолютные адреса http или https; относительные пути (`/images/1.jpg`) не загружаются. Те же сетевые правила, что для фида (раздел 4): стандартный порт, публичный адрес, без пароля и защиты от ботов. Защита от прямых ссылок по заголовку Referer не должна блокировать запросы без этого заголовка.
- Форматы — JPEG, PNG или WebP; определяются по содержимому, а не по расширению. GIF, SVG и прочие не принимаются.
- Размер одного файла — до 15 МБ, разрешение — до 25 мегапикселей (ширина × высота), ответ сервера — до 10 секунд.
- Площадка запоминает фотографию по адресу и повторно её не скачивает. Чтобы заменить изображение, измени адрес: имя файла или параметр вроде `?v=2`. Новый файл по старому адресу площадка не заметит.
- Порядок адресов задаёт порядок фотографий. Адрес, исчезнувший из первых пяти, отвязывает свою фотографию от объявления.
- Сбой фотографии — не ошибка предложения: объявление публикуется без неё, а площадка повторяет попытку примерно раз в сутки, пока адрес остаётся в фиде.
## 11. Обновление, снятие и возврат предложений
- Изменил цену, текст или фотографии — оставь прежний `id`: площадка обновит то же объявление, его адрес и дата публикации сохранятся. Обновление не поднимает объявление в списке.
- Новая позиция — новый `id`. Никогда не меняй `id` существующей позиции и не отдавай `id` снятой позиции другой: новый `id` создаёт новое объявление, а старое снимается.
- Временно нет в наличии — `available="false"` или убери предложение из файла; позиция снята с продажи навсегда — убери её из файла. В обоих случаях объявление скрывается и хранится 180 дней: если предложение вернётся с тем же `id`, вернётся прежнее объявление. Через 180 дней объявление удаляется. Учти, что предложения с `available="false"` занимают место в лимите.
- Пустой каталог `` снимает с показа все объявления. Если элемента `offers` в файле нет совсем, весь файл отклоняется, и объявления не меняются. Сопоставления категорий при снятии сохраняются, только если в файле всё дерево `categories` или категорий нет совсем (раздел 6).
- Если `id` повторяется, все предложения с этим `id` пропускаются, а прежнее объявление остаётся без изменений.
- Если у какого-то предложения `id` пустой или длиннее 80 символов, в этой загрузке площадка не снимает предложения, исчезнувшие из файла.
- Объявление, которое удалил администратор площадки, по тому же `id` заново не создаётся; причина видна в отчёте.
- Ошибка в новой версии предложения не портит объявление: оно остаётся с прежними данными до первой успешной загрузки исправленной версии.
## 12. Чек-лист самопроверки
Выполни перед отчётом. Каждый пункт — проверка результата, а не намерение.
1. Фид скачивается без cookies и авторизации так же, как его запрашивает площадка, — с переходами по перенаправлениям и с её `User-Agent`: `curl -sS -L --max-redirs 5 -A 'Mozilla/5.0 (compatible; PartnerImport/1.0)' -o feed.xml -w '%{http_code} %{size_download} %{time_total}\n' '<адрес фида>'` — код 200, размер до 50 МБ, время вместе с перенаправлениями заметно меньше 60 секунд. Запрос сделан не изнутри сервера проекта, а из внешней сети: так видно, что фид доступен из интернета.
2. Файл разбирается XML-парсером без ошибок (например, `xmllint --noout feed.xml`). В нём нет ``.
- «В файле несколько разделов shop.» — оставь один `shop`.
- «В файле отсутствует раздел offers с предложениями.» — добавь `offers` в `shop`.
- «В файле нет категорий: раздел categories отсутствует или пуст. …» — добавь `categories` в `shop` или заполни его, если он выгружается пустым: в нём должны быть все категории, на которые ссылаются `categoryId`.
- «В разделе shop отсутствует корректный HTTP- или HTTPS-адрес сайта источника в поле url.» — исправь `shop/url`.
- «Число предложений в фиде: N, разрешено не более M.» — уменьши выгрузку или договорись о лимите.
- «Количество категорий превышает допустимое» — сократи дерево категорий до 150.
- «Различных городов в предложениях: N, допускается не более M.» — сократи число городов фида.
- «У категории не указан или недопустим номер …», «Идентификатор категории N повторяется», «У категории N указан родитель, которого нет в фиде», «В дереве категорий найден цикл» — исправь `categories`.
- «Сайт источника не подтверждён. Причина: …» — раздел 9.
Ошибки предложения, которые показывает и «Проверить фид»:
- «Недопустимое значение available» — только `true` или `false`.
- «Неподдерживаемый тип предложения» — убери `type` или используй `vendor.model`.
- «Не заполнено название предложения в поле name», «Для типа vendor.model заполните поля vendor и model».
- «Некорректная цена» — формат `price`.
- «Идентификатор предложения id отсутствует или превышает 80 символов», «Идентификатор предложения повторяется».
- «Категория N не найдена в разделе categories».
- «Категории предложения не настроено соответствие» — у предложения нет `categoryId`. В отчёте загрузки после одобрения та же ошибка бывает и тогда, когда человек ещё не выбрал раздел для этой категории в кабинете.
- «Не заполнено описание предложения в поле description».
- «Элемент «Город» (param name="Город") указан в предложении несколько раз.» — оставь у предложения один город.
- «Название города «…» длиннее 255 символов.» — сократи название города.
Ошибки предложения, которые появляются только в отчётах загрузок после одобрения заявки:
- «Цена превышает максимально допустимое значение» — после округления `price` не больше 4294967295 (раздел 7).
- «Неизвестная валюта» — `currencyId` из списка раздела 7.
- «Ссылка на страницу предложения превышает допустимую длину», «Ссылка на страницу предложения должна вести на подтверждённый сайт магазина или его поддомен» — `offer/url`.
- «Городу предложения не выбран город сайта» — человек ещё не сопоставил этот город фида с городом площадки в кабинете; фидом не исправляется, если город указан верно.
- «Объявление не прошло проверки: …» — правила раздела 8 или настройки кабинета (способ связи, раздел площадки). Причина указана после двоеточия.
- «Создание объявления по этому предложению запрещено администрацией» — решение площадки, фидом не исправляется.
Предупреждения:
- «Неподдерживаемые элементы пропущены: …» — элементы, которых нет в этом документе; можно не выгружать.
- «Число предложений без атрибута available: N» — добавь `available`.
- «Предложений без элемента «Город»: N» — эти предложения публикуются в городе по умолчанию; если они относятся к другим городам, добавь им `param name="Город"`.
- «Дата фида указана без часового пояса» — добавь пояс в `yml_catalog@date` или убери атрибут.
- «Из N фотографий в файле берутся только первые 5», «Не удалось скачать фотографию …», «Фотография … не принята», «Фотография … превышает допустимый размер в мегапикселях» — раздел 10.
- «Объявления по предложениям, удалённым из файла, в этом запуске не скрываются» — есть предложения с пустым или слишком длинным `id`.
## 15. Пример фида магазина
Все поддерживаемые поля, кроме города: город показан в примере раздела 16.
```xml
Зоомагазин «Пример»
ООО «Пример»
https://shop.example/
Товары для кошек
Переноски и сумки
Когтеточки
Переноска для кошки
https://shop.example/products/SKU-0042
1500
RUB
10
https://shop.example/images/SKU-0042-main.jpg
https://shop.example/images/SKU-0042-side.jpg
Новая переноска.
Размер 48 × 32 × 30 см. Самовывоз.
]]>
Когтеточка
ПримерДом
Floor Tower S
https://shop.example/products/SKU-0107
3490.90
RUB
20
https://shop.example/images/SKU-0107.jpg
Когтеточка-стойка, обмотка из натурального сизаля. Высота 60 см.
Мяч для кошек, 2 шт.
1
Два мяча с колокольчиком.
Лежанка для кошки
1
```
## 16. Пример фида агентства недвижимости с городами
Предложения в двух городах: город передан элементом `param name="Город"`, в названиях городов нет, период цены и условия аренды — в описании (раздел 8). Объект, сданный арендатору, снят атрибутом `available="false"`.
```xml
Агентство «Пример»
ООО «Пример недвижимость»
https://agency.example/
Аренда
Квартиры в аренду
Комнаты в аренду
2-комнатная квартира, 54 м², 5/9 этаж
https://agency.example/objects/A1245
45000
RUB
11
Казань
https://agency.example/img/A1245-1.jpg
https://agency.example/img/A1245-2.jpg
Сдаётся на длительный срок: 45 000 ₽ в месяц плюс счётчики.Залог 45 000 ₽, комиссия агентства 50%. Мебель и бытовая техника, рядом метро.
]]>
Комната 18 м², 2/5 этаж
https://agency.example/objects/A1301
15000
RUB
12
Казань
https://agency.example/img/A1301-1.jpg
Сдаётся на длительный срок: 15 000 ₽ в месяц, коммунальные платежи включены. Залог 10 000 ₽, без комиссии.
1-комнатная квартира, 38 м², 3/10 этаж
https://agency.example/objects/S0310
25000
RUB
11
Самара
https://agency.example/img/S0310-1.jpg
Сдаётся на длительный срок: 25 000 ₽ в месяц плюс счётчики. Залог 25 000 ₽, комиссия агентства 30%.
Студия 26 м², 8/17 этаж
11
Самара
```