Corp/docs/guides/COMMERCE.md

85 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Commerce, МойСклад и маркетплейсы
Commerce-контур хранит нормализованные товары, внешние привязки, продажи,
возвраты, расходы, остатки и локальные изображения товаров. Источником истины
для структуры данных служат модели `backend/commerce/models/`, для HTTP API —
`backend/api/v1/commerce/`, для импорта — provider-specific services в
`backend/commerce/services/`.
## Импорт
Синхронизация любого подключения запускается Celery-задачей
`commerce.sync_connection_run`; сервис выбирается по `connection.provider`.
Для работы ручного импорта нужен Celery worker,
для расписания — также Celery Beat.
Импорт МойСклад выполняет следующие этапы:
1. Загружает ассортимент страницами по 100 позиций с `expand=images`.
2. Нормализует товары, модификации, комплекты, привязки и остатки.
3. Скачивает оригиналы изображений по авторизованному `downloadHref`, проверяет
формат и лимит 25 МБ, создаёт локальную WebP-миниатюру.
4. Импортирует отгрузки и возвраты вместе с позициями.
5. Сохраняет итоговую статистику и публикует состояние через общий WebSocket.
Прогресс запуска сохраняется и отправляется frontend каждые 25 товаров или
документов. Ошибка отдельного изображения учитывается в `image_errors`, но не
отменяет импорт товарных и финансовых данных.
## Wildberries
Подключение принимает API-токен с категорией «Финансы». Проверка токена читает
`GET https://common-api.wildberries.ru/api/v1/seller-info`, сохраняет ID,
название магазина и ИНН без сохранения токена в открытом виде, а затем вызывает
`GET https://finance-api.wildberries.ru/ping`, чтобы подтвердить доступ именно
к финансовой категории.
Финансовая синхронизация использует актуальный
`POST https://finance-api.wildberries.ru/api/finance/v1/sales-reports/detailed`.
Отключённый 15 июля 2026 года legacy-метод `reportDetailByPeriod` не используется.
Каждая строка отчёта сохраняется как `SourceRecord`, затем идемпотентно создаёт
или обновляет `Sale`, `SaleLine` и связанные `Cost`. Поддерживаются продажи,
возвраты, комиссия, эквайринг, доставка, хранение, приёмка, удержания, штрафы и
расходы программы лояльности.
Товар сопоставляется сначала по существующей WB-привязке, затем по артикулу и
штрихкоду. Неоднозначные строки сохраняются, но не привязываются к случайному
товару; их количество видно в `unmatched_products`. Повторный импорт после
ручной привязки дополняет аналитику.
Один ответ ограничен 100 000 строками. После каждой непустой страницы `rrdId` и
границы периода сохраняются в metadata источника, а следующий запуск продолжает
импорт. Завершённым отчёт считается только после ответа WB `204`; длина страницы
не используется как признак конца. После завершения первичной истории каждый
запуск повторно проверяет последние 30 дней, чтобы корректировки финансового
отчёта обновили существующие факты.
## Изображения
`ProductImage` хранит оригинал и миниатюру в `MEDIA_ROOT/commerce/products/`.
Временные внешние ссылки МойСклад не возвращаются клиенту и не используются как
публичные URL. Повторная синхронизация сравнивает внешний размер и время
изменения, поэтому неизменённое изображение не скачивается повторно. Удалённые
в источнике изображения удаляются локально после успешного чтения списка.
REST `ProductSerializer` возвращает `images[]` с локальными `url` и
`thumbnail_url`. Каталог использует миниатюру, карточка товара — оригинал для
полноэкранного просмотра.
## Realtime и fallback
Событие `commerce_connection_updated` содержит состояние подключения и
последнего запуска, включая `processed`, `images`, `sales` и `costs`. При рабочем
WebSocket frontend не опрашивает connections endpoint. Если WebSocket
недоступен во время активного импорта, включается REST fallback раз в 30 секунд.
## Проверка
```bash
cd backend
pytest tests/commerce -q
python manage.py makemigrations --check --dry-run
python manage.py check
ruff check commerce api/v1/commerce tests/commerce
```