Дата создания: 2025-11-07
Версия: 2.0
Статус: В разработке
Система управления продажами на маркетплейсах (Ozon, Wildberries, Яндекс.Маркет).
Основной функционал:
- Автоматическое подключение каналов продаж
- Управление юридическими лицами
- Управление складами и логистикой
- Обработка заказов
- Учёт товаров
User (пользователи)
↓
LegalEntity (юр.лица) → связь по ИНН
↓
Channel (каналы продаж)
↓
├─ Warehouse (склады)
├─ DeliveryService (службы доставки)
└─ ChannelStatusMapping (маппинг статусов)
Order (заказы)
├─ OrderItem (позиции заказа)
└─ OrderStatusHistory (история статусов)
Product (товары)
├─ ProductVariant (вариации)
├─ ProductImage (картинки)
└─ ProductChannelMapping (связь с каналами)
| Тип | Код | Описание |
|---|---|---|
| Собственный | own |
Физический склад продавца |
| Маркетплейс | marketplace |
Склад маркетплейса (FBO) |
| Дропшиппер | dropshipper |
Склад партнёра-дропшиппера |
| Партнёр | partner |
Склад партнёра для дозаказа |
| Виртуальный | virtual |
Виртуальный склад с фильтрацией |
| Схема | Код | Хранение | Доставка | Описание |
|---|---|---|---|---|
| FBO | fbo |
Маркетплейс | Маркетплейс | Полный фулфилмент |
| FBS | fbs |
Продавец | Маркетплейс | Со склада продавца |
| DBS | dbs |
Продавец | Продавец | Своя доставка |
| Crossdock | crossdock |
Транзит | Смешанная | Быстрая перегрузка |
| Режим | Код | Описание |
|---|---|---|
| Круглосуточно | 24/7 |
Работает всегда |
| По расписанию | schedule |
Определённые часы |
| По запросу | on_demand |
Нужна запись |
OZON:
- Максимум времени на сборку: 24 часа
- Минимум для планирования поставки: 12 часов
- График по умолчанию: 09:00-18:00 пн-пт
WILDBERRIES:
- Максимум на обработку: 120 часов (5 дней)
- Рекомендуется: 24 часа
- График по умолчанию: 08:00-22:00 ежедневно
- Штраф за просрочку: 50% от стоимости (мин. 100₽)
ЯНДЕКС.МАРКЕТ:
- Минимум рабочих дней: 5
- Целевое среднее время отгрузки: 36 часов
- График по умолчанию: 09:00-20:00 пн-вс
- Скидка 4% за 7 дней работы + отгрузка в день заказа
# Идентификация
external_id: str
name: str
# Типизация
warehouse_type: str # own/marketplace/dropshipper/partner/virtual
fulfillment_type: str # fbo/fbs/dbs/crossdock
work_mode: str # 24/7/schedule/on_demand
work_schedule: str # "09:00-18:00 пн-пт"
# Параметры работы
is_active: bool
can_ship_anytime: bool # Можно грузить в любой момент (DBS)
requires_appointment: bool # Нужна запись (crossdock)
min_prep_time_hours: int # Минимальное время подготовки
# Фильтрация (виртуальные склады)
filter_rules: JSON # {"category": ["Одежда"], "price_min": 1000}
# Контакты
address: str
contact_person: str
phone: str
На маркетплейсе Ozon существует 3 основные схемы обработки заказов, которые различаются по месту хранения товара и способу доставки покупателю.
| Схема | Код | Хранение | Доставка | Этикетки | Трекинг | Описание |
|---|---|---|---|---|---|---|
| FBO | fbo |
Склад Ozon | Ozon | Ozon | Ozon | Полный фулфилмент |
| FBS | fbs |
Склад продавца | Ozon | Ozon | Ozon | Со склада продавца |
| realFBS | realfbs |
Склад продавца | Продавец | Свои | Свои | Своя доставка |
Ключевое различие FBS vs realFBS:
- FBS: Товар на вашем складе, но доставляет Ozon → используются этикетки Ozon, трекинг Ozon, акты Ozon
- realFBS: Товар на вашем складе, доставляете вы сами → используются свои этикетки (СДЭК/Почта/курьер), свой трекинг, свои акты
Суть: Товар хранится на складе Ozon, Ozon полностью берёт на себя обработку и доставку.
Процесс:
Товар → Склад Ozon → Заказ → Ozon упаковывает → Ozon доставляет → Покупатель
Что делает продавец:
- Поставляет товар на склад Ozon (FBO-поставки)
- Следит за остатками
- Обрабатывает возвраты (опционально)
Что делает Ozon:
- Хранит товар
- Упаковывает заказы
- Генерирует этикетки
- Доставляет покупателю
- Обрабатывает возвраты
Преимущества:
- Минимальная нагрузка на продавца
- Быстрая доставка (товар в регионах Ozon)
- Высокая конверсия (badge "Ozon")
Недостатки:
- Высокие комиссии
- Нужно хранить товар на складе Ozon
- Меньше контроля над процессом
SLA:
- Поставка на склад: минимум за 12 часов до забора
- Доставка покупателю: 1-7 дней (зависит от региона)
API методы:
- create_fbo_supply() - создать поставку
- get_fbo_supply_status() - статус поставки
- get_fbo_stocks() - остатки на складе Ozon
Суть: Товар хранится на складе продавца, но доставляет Ozon.
Процесс:
Заказ → Продавец собирает → Ozon забирает → Ozon доставляет → Покупатель
Что делает продавец:
- Хранит товар на своём складе
- Получает заказ → собирает → упаковывает
- Печатает этикетки Ozon
- Передаёт заказы курьеру Ozon
Что делает Ozon:
- Забирает заказы со склада продавца (по графику: 10:00, 15:00)
- Доставляет покупателю
- Обрабатывает возвраты (частично)
Преимущества:
- Нет затрат на хранение на складе Ozon
- Контроль над остатками
- Ниже комиссия, чем FBO
Недостатки:
- Нужен свой склад
- Строгие SLA на сборку (24 часа)
- График забора курьером Ozon (2 раза в день)
SLA:
- Время на сборку: 24 часа с момента заказа
- График забора курьером Ozon: 10:00, 15:00 (ежедневно)
- Доставка покупателю: 1-7 дней (Ozon)
Workflow в системе:
1. Загрузить заказы (статус awaiting_packaging)
2. Перевести в сборку: start_packing(posting_numbers)
3. Собрать и упаковать
4. Печать этикеток Ozon: get_posting_labels(posting_numbers) → PDF
5. Печать акта для курьера: get_posting_act(date, delivery_service) → PDF
6. Передать курьеру Ozon (10:00 или 15:00)
7. Отметить отгрузку: ship_posting(posting_number, ozon_tracking) (трек-номер получаем от Ozon!)
API методы:
- fetch_orders() - получить заказы FBS
- start_packing() - перевести в сборку
- get_posting_labels() - этикетки Ozon (PDF)
- get_posting_act() - акт приёма-передачи Ozon (PDF)
- ship_posting() - отметить отгрузку с трек-номером Ozon
Важно:
- Этикетки генерирует Ozon (не СДЭК, не Почта!)
- Трекинг ведёт Ozon (не ваш!)
- Акт для курьера получаете через Ozon API
Суть: Товар хранится на складе продавца, доставляет продавец (или его служба доставки).
Процесс:
Заказ → Продавец собирает → Продавец доставляет → Покупатель
↓
Свои этикетки (СДЭК/Почта/курьер)
Свой трек-номер
Что делает продавец:
- Хранит товар
- Собирает и упаковывает
- Генерирует свои этикетки (через СДЭК API / Почта API / свои)
- Доставляет сам (курьером или через службу)
- Загружает свой трек-номер на Ozon
Что делает Ozon:
- Передаёт заказы продавцу
- Следит за соблюдением SLA
- Принимает трек-номера от продавца
Преимущества:
- Полный контроль над доставкой
- Можно использовать любую службу (СДЭК, Почта, Яндекс, свой курьер)
- Гибкость в выборе времени доставки
- Более высокая конверсия на экспресс-доставке
Недостатки:
- Нужно самому организовывать доставку
- Ответственность за срыв сроков
- Нужны интеграции с СДЭК/Почтой/и т.д.
SLA (3 типа):
| Тип | Код | Время доставки | Применение | Конверсия |
|---|---|---|---|---|
| Стандартная | standard |
До 30 дней | Регионы, негабарит | Базовая |
| Срочная (Comfort) | comfort |
До 8 часов | Город, популярные товары | +8% |
| Экспресс | express |
До 30 минут | Еда, цветы, срочное | +13% |
Workflow в системе:
Стандартная realFBS (до 30 дней):
1. Загрузить заказы (фильтр: fulfillment_scheme='realfbs', realfbs_type='standard')
2. Собрать и упаковать
3. Создать заказ в СДЭК/Почте через их API → получить свой трек-номер
4. Напечатать свою этикетку (СДЭК/Почта PDF)
5. Загрузить трек-номер на Ozon: ship_posting(posting_number, own_tracking)
6. Передать в СДЭК/Почту/курьеру
7. Отслеживать доставку через СДЭК/Почту API
Срочная realFBS (до 8 часов):
1. Мониторинг SLA: каждый заказ имеет дедлайн = order_date + 8 часов
2. Цветовая индикация:
- 🟢 Зелёный: осталось > 2 часов
- 🟡 Жёлтый: осталось 1-2 часа
- 🔴 Красный: осталось < 1 часа или просрочено
3. Процесс аналогичен стандартной, но с жёстким контролем времени
4. Рекомендуется: курьер на линии, мгновенная передача заказа
Экспресс realFBS (до 30 минут):
1. Критичный SLA: дедлайн = order_date + 30 минут
2. Минутный мониторинг:
- 🟢 > 15 минут
- 🟡 10-15 минут
- 🔴 < 10 минут или просрочено
3. Процесс:
- Товар уже упакован и готов к отправке
- Курьер постоянно на месте или доставка роботом
- Мгновенная отгрузка после заказа
4. Применение: готовая еда, цветы, экстренные товары
5. Конверсия +13% - покупатели готовы платить за скорость
API методы:
- fetch_orders() - получить заказы realFBS
- ship_posting(posting_number, own_tracking) - загрузить свой трек-номер
- Интеграция с СДЭК API (отдельный модуль)
- Интеграция с Почтой России API (отдельный модуль)
Важно:
- Этикетки генерируете вы (через API СДЭК/Почты или свои)
- Трек-номер ваш (от СДЭК/Почты/своего курьера)
- Акты доставки ваши (не Ozon)
- Ozon только следит за соблюдением SLA
| Параметр | FBO | FBS | realFBS |
|---|---|---|---|
| Хранение | Ozon | Продавец | Продавец |
| Доставка | Ozon | Ozon | Продавец |
| Этикетки | Ozon | Ozon | Свои |
| Трекинг | Ozon | Ozon | Свой |
| Акты | Ozon | Ozon | Свои |
| Контроль | Минимальный | Средний | Полный |
| Комиссия | Высокая | Средняя | Низкая |
| Сложность | Низкая | Средняя | Высокая |
| SLA сборки | - | 24 часа | 30 дней / 8 ч / 30 мин |
# Схема fulfillment
fulfillment_scheme = Column(String(50), default='fbs')
# Значения: 'fbo' / 'fbs' / 'realfbs'
realfbs_type = Column(String(50))
# Значения для realfbs: 'standard' / 'comfort' / 'express'
# NULL для fbo и fbs
# Доставка
delivery_type = Column(String(50)) # kts, pvz, courier, post
delivery_service = Column(String(50)) # pochta, yandex, kts, cdek, boxberry
# Трекинг
tracking_number = Column(String(255))
# FBO/FBS: трек-номер Ozon
# realFBS: NULL
own_tracking_number = Column(String(255))
# realFBS: свой трек от СДЭК/Почты/курьера
# FBO/FBS: NULL
track_uploaded = Column(Boolean, default=False)
shipped_at = Column(DateTime) # Дата отгрузки
📋 Заказы
│
├─ 📥 Загрузка заказов (expander, collapsed)
│
└─ 3 основных раздела (tabs):
│
├─ 📦 FBS - Доставка силами Ozon
│ ├─ Фильтр: fulfillment_scheme = 'fbs'
│ ├─ График забора: 10:00, 15:00
│ ├─ SLA: 24 часа на сборку
│ ├─ Операции:
│ │ ├─ Перевести в сборку
│ │ ├─ Печать этикеток Ozon (PDF)
│ │ └─ Печать акта Ozon (PDF)
│ └─ Кнопка отгрузки с Ozon трек-номером
│
├─ 🚚 Своя доставка (realFBS)
│ │
│ └─ 3 подраздела (nested tabs):
│ │
│ ├─ 📋 Обычная (до 30 дней)
│ │ ├─ Фильтр: realfbs_type = 'standard'
│ │ ├─ Выбор службы доставки (СДЭК/Почта/...)
│ │ ├─ Ввод своего трек-номера
│ │ └─ Загрузка трека на Ozon
│ │
│ ├─ ⚡ Срочная (до 8 часов)
│ │ ├─ Фильтр: realfbs_type = 'comfort'
│ │ ├─ SLA мониторинг: order_date + 8h
│ │ ├─ Цветовая индикация:
│ │ │ 🟢 > 2 часов
│ │ │ 🟡 1-2 часа
│ │ │ 🔴 < 1 час / просрочено
│ │ └─ Конверсия: +8%
│ │
│ └─ 🔥 Экспресс (до 30 минут)
│ ├─ Фильтр: realfbs_type = 'express'
│ ├─ SLA мониторинг: order_date + 30min
│ ├─ Минутный таймер:
│ │ 🟢 > 15 минут
│ │ 🟡 10-15 минут
│ │ 🔴 < 10 минут / просрочено
│ └─ Конверсия: +13%
│
└─ 🏢 Поставки FBO
├─ Фильтр: fulfillment_scheme = 'fbo'
├─ Создание поставки на склад Ozon
├─ Статус поставки
└─ Остатки на FBO складе
Сценарий 1: FBS заказ
# 1. Загрузить заказы FBS
orders = api.fetch_orders(date_from, date_to)
fbs_orders = [o for o in orders if o['fulfillment_scheme'] == 'fbs']
# 2. Перевести в сборку
posting_numbers = [o['posting_number'] for o in fbs_orders]
api.start_packing(posting_numbers)
# 3. Собрать товары, упаковать
# 4. Печать этикеток Ozon
labels_pdf = api.get_posting_labels(posting_numbers)
# 5. Печать акта для курьера Ozon
act_pdf = api.get_posting_act(date="2025-11-08", delivery_service="ozon")
# 6. Передать курьеру Ozon (10:00 или 15:00)
# 7. Отгрузить (трек-номер Ozon даст курьер или получим из API)
api.ship_posting(posting_number, ozon_tracking_number)
Сценарий 2: realFBS Экспресс (30 минут)
# 1. Загрузить заказы realFBS Express
orders = api.fetch_orders(date_from, date_to)
express = [o for o in orders if o['fulfillment_scheme'] == 'realfbs'
and o['realfbs_type'] == 'express']
# 2. Мониторинг SLA
for order in express:
deadline = order['order_date'] + timedelta(minutes=30)
time_left = (deadline - datetime.now()).total_seconds() / 60
if time_left < 10:
send_alert(f"🔴 КРИТИЧНО! Заказ {order['posting_number']} - {time_left} мин")
# 3. Товар УЖЕ упакован и готов
# 4. Передать курьеру немедленно
# 5. Загрузить свой трек-номер
api.ship_posting(order['posting_number'], own_tracking_from_courier)
# 6. Отслеживание доставки через GPS курьера
Ozon Fresh (для скоропортящихся продуктов):
- Особый тип FBO с ускоренной обработкой
- Склады с холодильниками
- Доставка до 2 часов
- Высокие требования к упаковке
Crossdock (быстрая перегрузка):
- Товар не хранится на складе Ozon
- Передаётся через транзитный терминал
- Нужна запись на приёмку
- Минимум времени на обработку
Обновлено: 2025-11-08 (добавлена документация схем fulfillment)
Ввод API ключей → Получение ИНН → Поиск юр.лица
↓
┌───────┴───────┐
↓ ↓
ЕСТЬ НЕТ
↓ ↓
Связать ФНС API → Создать
канал ↓
↓ Создать канал
└───────┬───────┘
↓
✅ ГОТОВО
Модуль: modules/utils/datetime_helper.py
WorkSchedule - работа с расписанием:
schedule = WorkSchedule.from_string("09:00-18:00 пн-пт")
schedule.is_working_now() # True/False
schedule.next_working_datetime() # Следующее рабочее время
MarketplaceSettings - настройки маркетплейсов:
MarketplaceSettings.OZON['max_prep_time_hours'] # 24
MarketplaceSettings.WILDBERRIES['max_prep_time_hours'] # 120
MarketplaceSettings.YANDEX['target_avg_hours'] # 36
is_holiday(dt) # Праздник?
is_weekend(dt) # Выходной?
is_working_day(dt) # Рабочий день?
add_working_days(dt, days) # +N рабочих дней
working_days_between(start, end) # Количество рабочих дней
format_duration(hours) # "2 д 4 ч"
api = OzonAPI(client_id, api_key)
# Основные
api.test_connection() -> bool
api.get_seller_info() -> Dict # Включая ИНН!
# Заказы - Получение
api.fetch_orders(date_from, date_to) -> List[Dict]
api.get_order_details(posting_number) -> Dict
# Заказы - Обработка FBS
api.start_packing(posting_numbers: List[str]) -> Dict
api.ship_posting(posting_number: str, tracking: str) -> Dict
api.cancel_posting(posting_number: str, cancel_reason_id: int) -> Dict
# Заказы - Документы
api.get_posting_labels(posting_numbers: List[str]) -> bytes # PDF этикеток
api.get_posting_act(date: str, delivery_service: str) -> bytes # PDF акта
api.get_package_list(posting_numbers: List[str]) -> bytes # PDF упаковочного листа
# Заказы - Трекинг (realFBS)
api.upload_tracking_numbers(data: List[Dict]) -> Dict
# Справочники
api.get_warehouses() -> List[Dict]
api.get_delivery_services() -> List[Dict]
api.get_posting_statuses() -> List[Dict]
api.get_categories(language="RU") -> List[Dict]
Система поддерживает 4 типа товаров:
| Тип | Код | Описание | Использование |
|---|---|---|---|
| Простой | simple |
Обычный товар | Один SKU, одна цена, один остаток |
| Вариации | variant_group |
Товар с вариантами | Размеры/цвета через parent_id |
| Комплект | kit |
Продаём → собираем | Списываем компоненты при заказе |
| Набор | bundle |
Собираем → продаём | Собираем заранее, новый SKU |
Структура:
Родительский товар (variant_group)
├─ Футболка "Nike Air"
├─ parent_id = NULL
└─ Общее описание, фото
│
├─ Вариант 1: Размер S, Красный
│ ├─ parent_id = ID родителя
│ ├─ SKU: NIKE-AIR-S-RED
│ └─ Свой остаток, своя цена
│
├─ Вариант 2: Размер M, Красный
│ ├─ parent_id = ID родителя
│ ├─ SKU: NIKE-AIR-M-RED
│ └─ Свой остаток, своя цена
│
└─ Вариант 3: Размер L, Синий
├─ parent_id = ID родителя
├─ SKU: NIKE-AIR-L-BLUE
└─ Свой остаток, своя цена
Реализация через parent_id:
- Родительский товар имеет parent_id = NULL и product_type = 'variant_group'
- Дочерние товары имеют parent_id = <ID родителя> и product_type = 'simple'
- У каждого варианта свой SKU, остаток, цена
Комплект (продаём → собираем):
# Продаём "Набор инструментов" за 5000₽
# Состоит из: Молоток (1 шт) + Отвёртка (2 шт) + Гвозди (100 шт)
При заказе:
1. Проверяем наличие всех компонентов
2. Резервируем компоненты
3. При отгрузке списываем со склада
Набор (собираем → продаём):
# Собираем "Подарочный набор" заранее
# Создаём новый SKU с остатком
При сборке:
1. Списываем компоненты (Молоток -1, Отвёртка -2)
2. Создаём остаток набора +1
3. Продаём как обычный товар
3 типа замен:
1. Автоматическая (AI)
Заказ: Товар A (нет в наличии)
↓
AI анализирует:
- Та же категория
- Цена ±10%
- Похожие характеристики
- Есть в наличии
- Хорошие отзывы
↓
Подбирает: Товар B (ai_confidence = 0.95)
↓
Автоподстановка (если auto_apply = True)
2. Ручная замена менеджером
Заказ: Товар A (нет в наличии)
↓
Создаётся задача менеджеру
↓
Менеджер выбирает замену вручную
↓
Клиент уведомляется
3. Предустановленные замены
# В системе заранее настроено:
Товар A → Товар B (priority = 1)
Товар A → Товар C (priority = 2)
При отсутствии A:
1. Проверяем наличие B
2. Если нет B → берём C
POST /v3/product/import
{
"items": [
{
"barcode": "1234567890123",
"description_category_id": 17028922,
"name": "Футболка мужская Nike",
"offer_id": "SKU-12345",
"price": "1299.00",
"old_price": "1999.00",
"vat": "0.2",
"height": 10,
"depth": 200,
"width": 150,
"dimension_unit": "mm",
"weight": 200,
"weight_unit": "g",
"images": [
"https://example.com/image1.jpg",
"https://example.com/image2.jpg"
],
"attributes": [
{
"complex_id": 0,
"id": 8229,
"values": [{"value": "Nike"}]
}
]
}
]
}
→ Возвращает task_id
→ Проверка статуса: POST /v1/product/import/info
POST /v2/product/list
{
"filter": {
"visibility": "ALL", # ALL/VISIBLE/INVISIBLE
"offer_id": ["SKU-001", "SKU-002"]
},
"limit": 100,
"last_id": ""
}
POST /v1/description-category/attribute
{
"category_id": 17028922,
"language": "RU"
}
→ Возвращает список обязательных атрибутов
POST /v1/description-category/attribute/values
{
"category_id": 17028922,
"attribute_id": 8229,
"language": "RU",
"limit": 1000
}
→ Возвращает допустимые значения для атрибута
POST /v1/product/import/prices
{
"prices": [
{
"product_id": 123456,
"price": "1299.00",
"old_price": "1999.00"
}
]
}
POST /v1/product/import/stocks
{
"stocks": [
{
"offer_id": "SKU-12345",
"product_id": 123456,
"stock": 10,
"warehouse_id": 789
}
]
}
Пример: товар с несколькими видео
"attributes": [
{
"complex_id": 1,
"id": 21841, # Название видео
"values": [{"value": "Обзор товара"}]
},
{
"complex_id": 1,
"id": 21837, # URL видео
"values": [{"value": "https://youtube.com/watch?v=xxx"}]
},
{
"complex_id": 2,
"id": 21841, # Название видео
"values": [{"value": "Инструкция"}]
},
{
"complex_id": 2,
"id": 21837, # URL видео
"values": [{"value": "https://youtube.com/watch?v=yyy"}]
}
]
complex_id группирует связанные атрибуты:
- complex_id = 1: Обзор товара + его URL
- complex_id = 2: Инструкция + её URL
Импорт из CSV:
SKU,Name,Category,Brand,Price,OldPrice,Stock,Weight,ImageURL
SKU-001,Футболка,Одежда,Nike,1299,1999,10,200,https://...
SKU-002,Джинсы,Одежда,Levis,2999,3999,5,400,https://...
Лимиты:
- Ozon API: 100 товаров за один запрос
- CSV импорт: рекомендуется до 1000 товаров
- Батчинг: разбиваем большие файлы на части по 100
Асинхронная обработка:
1. Отправка запроса → получаем task_id
2. Проверка статуса каждые 5 секунд
3. Получение результата с ошибками по каждому товару
id, email, password_hash, full_name, role, active
id, user_id, name_full, name_short, inn, ogrn, entity_type
address, director, is_default, active
id, entity_id, channel_name, channel_type, platform_type
client_id, api_key_encrypted, seller_id, status, active
id, channel_id, external_id, name
warehouse_type, fulfillment_type, work_mode, work_schedule
is_active, can_ship_anytime, requires_appointment
min_prep_time_hours, filter_rules
address, contact_person, phone
id, channel_id, external_id, name, is_available
delivery_time_from, delivery_time_to
id, channel_id, external_status, status_name, internal_status_id
id, channel_id, entity_id, external_order_id, order_date
status_external, status_internal
# Fulfillment схема
fulfillment_scheme # fbo/fbs/realfbs
realfbs_type # standard/comfort/express (для realfbs)
# Доставка
delivery_type # kts/pvz/courier/post
delivery_service # pochta/yandex/kts/cdek/boxberry
# Трекинг
tracking_number # Ozon трек (для FBO/FBS)
own_tracking_number # Свой трек (для realFBS)
track_uploaded, shipped_at
# Клиент
customer_name, customer_phone, customer_email
address_json, items_json, total_amount
# Основные поля
id, user_id, sku, barcode, article, name, description
# Тип товара
product_type # simple/variant_group/kit/bundle
parent_id # Для вариаций: ссылка на родительский товар
# Категория и бренд
category, brand, ozon_category_id
# Цены
price, old_price, cost_price, min_price
# Габариты и вес
weight # граммы
width # мм
height # мм
depth # мм
# Остатки
stock_quantity, reserved_quantity, available_quantity
# Статус
is_active, is_visible
# Ozon
ozon_product_id, vat
# Метаданные
created_at, updated_at
id, product_id, image_url, local_path
position, is_primary
image_type # product/360/marketing/size_chart
width, height, file_size
created_at
id, product_id
attribute_id, attribute_name # ID и название атрибута Ozon
value
complex_id # Группировка сложных атрибутов
is_required, is_collection, dictionary_id
created_at
id, kit_id, component_id
quantity # Количество компонента в комплекте
position # Порядок
created_at
id, product_id, substitute_product_id
substitution_type # auto/manual/ai_suggested/approved
priority # Приоритет замены
max_price_diff_percent # Макс. разница цены
active, auto_apply
times_used, last_used_at
ai_confidence, ai_reason # AI оценка замены
created_by, created_at
id, product_id, channel_id
external_product_id, external_sku
is_published, moderation_status
channel_price, channel_old_price
channel_stock
last_sync_at, sync_errors
created_at, updated_at
marketplace-mvp/
├── app.py # Главная страница
├── PROJECT-MASTER.md # Этот файл (вся документация)
├── requirements.txt
├── core/
│ ├── config.py # Настройки
│ ├── database.py # Подключение к БД
│ └── auth.py # Авторизация
├── database/
│ ├── models.py # Все модели
│ └── init_db.py # Инициализация БД
├── modules/
│ ├── api/
│ │ └── ozon.py # Ozon API
│ ├── legal_entities/
│ │ ├── crud.py # CRUD юр.лиц
│ │ └── inn_api.py # Получение данных по ИНН
│ └── utils/
│ └── datetime_helper.py # Работа с датами/временем
└── pages/
├── 01_🏢_Компании.py # Управление юр.лицами
├── 02_📡_Каналы.py # Управление каналами (визард)
├── 04_📋_Заказы.py # Обработка заказов (3 схемы)
└── 05_🏷️_Товары.py # Управление товарами
Расположение: /opt/claude-workspace/scripts/
Цель: Экономия 90% токенов - не генерировать код заново!
python/streamlit/wizard_3_step.py - Визард (экономия ~4500 tokens)python/database/crud_template.py - CRUD (экономия ~3000 tokens)python/api/rest_client_template.py - REST клиент (экономия ~2500 tokens)# 1. Копировать шаблон
cp /opt/claude-workspace/scripts/python/streamlit/wizard_3_step.py pages/
# 2. Попросить Claude внести правки (не генерировать!)
"Замени поля на: name, inn, address"
Email: admin@example.com
Пароль: admin1234
Приложение: http://91.218.142.168:8502
Последнее обновление: 2025-11-07
Версия документации: 2.0
Модель: StockMovement
id, warehouse_id, product_id, variant_id
quantity_before, quantity_after, quantity_delta
movement_type # in/out/reserve/unreserve/correction
order_id, user_id, reason, created_at
Функции:
- Учёт остатков по складам
- Резервирование при заказе
- Синхронизация с маркетплейсами
- История движения товаров
- Оповещения о низких остатках
Модель: Transaction
id, channel_id, order_id
transaction_type # sale/commission/refund/payout
amount, currency, marketplace_fee
status, transaction_date, payout_date
Модель: PriceHistory
id, product_id, channel_id
price, old_price, discount_percent
valid_from, valid_to, reason
Функции:
- Учёт продаж и комиссий
- История изменения цен
- Расчёт прибыли/убытков
- Акты сверки с маркетплейсами
- Выплаты (payout)
Модель: Shipment
id, warehouse_id, shipment_date
shipment_number, carrier, tracking_number
status, boxes_count, total_weight
Модель: ShipmentBox
id, shipment_id, box_number
barcode, weight, dimensions
items_json # [{order_id, product_id, quantity}]
Функции:
- Группировка заказов в отгрузки
- Печать этикеток и накладных
- Упаковочные листы
- Трекинг отгрузок
Модель: Return
id, order_id, channel_id
return_reason, return_type # customer/defect/damage
status, return_date, refund_amount
warehouse_id, restocked, notes
Функции:
- Обработка возвратов
- Возврат товара на склад
- Возврат денег покупателю
- Статистика по причинам возвратов
Показатели:
- GMV (Gross Merchandise Value)
- Конверсия по воронке
- Средний чек
- Процент возвратов
- Рейтинг продавца
- Скорость обработки заказов
Отчёты:
- Продажи по дням/неделям/месяцам
- ABC-анализ товаров
- Эффективность каналов
- Прибыльность по категориям
Модель: Notification
id, user_id, notification_type, priority
title, message, link, is_read
created_at
Типы уведомлений:
- Новый заказ
- Проблема с заказом
- Низкие остатки
- Изменение цен конкурентов
- Истечение API ключей
- Необходимость отгрузки
Каналы:
- Telegram бот
- Email
- Push-уведомления в браузере
- SMS (критические)
Роли:
- owner - Владелец (полный доступ)
- admin - Администратор (управление без удаления)
- manager - Менеджер (заказы, товары, не видит финансы)
- warehouse - Кладовщик (только отгрузки)
- viewer - Наблюдатель (только просмотр)
Модель: UserPermission
id, user_id, entity_id, channel_id
role, can_view, can_edit, can_delete
granted_by, granted_at
Нужно добавить:
- Шифрование API ключей (AES-256)
- Двухфакторная аутентификация (2FA)
- Аудит действий пользователей
- Rate limiting для API
- Резервное копирование БД
Маркетплейсы:
- ✅ Ozon
- ⏳ Wildberries
- ⏳ Яндекс.Маркет
- ⏳ AliExpress
- ⏳ Lamoda
Сервисы:
- ⏳ СДЭК (доставка)
- ⏳ Почта России
- ⏳ Boxberry
- ⏳ 1С:Бухгалтерия
- ⏳ МойСклад
- ⏳ Telegram Bot API
- ⏳ Bitrix24 (CRM)
Планы:
- PWA (Progressive Web App)
- Быстрое создание заказа
- Сканер штрих-кодов
- Push-уведомления
- Offline режим
Каналы: 3 активных Ozon канала
Заказы: 0 (страница готова, функционал загрузки реализован)
Товары: 0 (страница готова, интерфейс реализован)
Склады: Подключены через визард
Основная схема работы: realFBS (своя доставка)
Проект создаётся для всех случаев (FBO/FBS/realFBS поддерживаются), но приоритет на realFBS с дропшиппингом и работой с поставщиками.
Эти функции критичны для ежедневной работы и должны быть реализованы в первую очередь:
Что нужно:
- ✅ Загрузка заказов с Ozon (реализовано)
- ✅ Разделение по схемам FBS/realFBS/FBO (реализовано)
- ✅ UI с 3 разделами (реализовано)
- 🔴 Автоматическое создание заказов в СДЭК/Почте (приоритет #1)
- 🔴 Получение этикеток от СДЭК/Почты (приоритет #1)
- 🔴 Загрузка трек-номеров на Ozon (приоритет #1)
- 🔴 Мониторинг статусов доставки (приоритет #2)
- [ ] История изменений статусов заказов
Workflow realFBS:
Заказ Ozon → Автосоздание в СДЭК → Этикетка СДЭК → Трек на Ozon → Отслеживание
Что нужно:
- [ ] Модель Substitution - связь товаров-подмен
- [ ] Правила подмены - автоматические/ручные
- [ ] UI управления подменами - страница настройки
- [ ] Применение при заказе - если товара нет, подменить автоматически
- [ ] Уведомления покупателю - согласование подмены
- [ ] История подмен - какой товар чем заменили
Сценарий:
Заказ: Товар A (остаток: 0) → Система: Подмена на Товар B → Уведомление покупателю
Модель Substitution:
id, product_id, substitute_product_id
substitution_type # auto/manual/approved
priority # порядок подмены (если несколько вариантов)
price_diff_percent # макс. разница цены
active, created_by, created_at
Что нужно:
- [ ] Загрузка возвратов с Ozon API
- [ ] UI списка возвратов - таблица с фильтрами
- [ ] Обработка возврата - причина, решение
- [ ] Возврат на склад - увеличение остатков (для realFBS)
- [ ] Возврат денег - статус refund
- [ ] Статистика - причины возвратов, проблемные товары
- [ ] Повторная отправка - если товар можно продать снова
Модель Return:
id, order_id, channel_id, external_return_id
return_reason # customer_request/defect/damage/wrong_item
return_type # full/partial
status # new/approved/refunded/restocked
return_date, refund_amount, refund_date
warehouse_id # куда вернули (для realFBS)
restocked # вернули на склад?
condition # new/damaged/defect
notes, created_at
Что нужно:
- [ ] Синхронизация остатков с Ozon
- [ ] Резервирование при заказе - уменьшение available
- [ ] Списание при отгрузке - уменьшение quantity
- [ ] Возврат при отмене - увеличение available
- [ ] История движений - кто/когда/сколько изменил
- [ ] Оповещения о низких остатках
- [ ] Связь с дропшипперами - остатки с их складов
Модель StockMovement:
id, warehouse_id, product_id, variant_id
quantity_before, quantity_after, quantity_delta
movement_type # in/out/reserve/unreserve/correction/return
order_id, user_id, reason
created_at
Логика резервирования:
Товар: quantity=100, reserved=0, available=100
Заказ → reserved=10, available=90
Отгрузка → quantity=90, reserved=0, available=90
Отмена → reserved=0, available=100
Что нужно:
- [ ] Модель Supplier - поставщики
- [ ] Связь Product ↔ Supplier - кто поставляет товар
- [ ] Склады дропшипперов - warehouse_type='dropshipper'
- [ ] Остатки у дропшиппера - отдельный учёт
- [ ] Автозаказ у дропшиппера - при заказе на Ozon
- [ ] Отслеживание поставок - от поставщика
- [ ] Маржа и расчёты - price vs cost_price
Модель Supplier:
id, user_id, name, supplier_type # dropshipper/wholesale/manufacturer
contact_person, phone, email, address
inn, contract_number, payment_terms # 7/14/30 дней
is_dropshipper # True если отправляет сам
margin_percent # Наша маржа
rating, active, notes, created_at
Модель SupplierProduct:
id, supplier_id, product_id
supplier_sku # Артикул у поставщика
cost_price # Закупочная цена
stock_quantity # Остаток у поставщика
lead_time_days # Срок поставки
min_order_qty # Минимальный заказ
active, updated_at
Workflow дропшиппинга:
Заказ Ozon (realFBS) → Проверка остатков → Нет на складе → Заказ у дропшиппера
→ Дропшиппер отправляет → Получение трека → Трек на Ozon → Доставка покупателю
Функции для повышения эффективности работы:
Функции для масштабирования:
Цель: Полный цикл realFBS с СДЭК
Неделя 1-2:
- [x] UI страницы заказов (3 раздела) - ГОТОВО
- [x] Модели БД для схем - ГОТОВО
- [ ] Интеграция СДЭК API (создание заказов, этикетки)
- [ ] Интеграция Почта России API
Неделя 3-4:
- [ ] Автоматическое создание заказов в СДЭК при новом заказе Ozon
- [ ] Загрузка трек-номеров на Ozon
- [ ] Отслеживание статусов доставки
- [ ] Тестирование полного цикла
Результат: Заказ Ozon → СДЭК → Доставка (полностью автоматически)
Цель: Учёт остатков с резервированием + работа с поставщиками
Неделя 1-2:
- [ ] Модель StockMovement + логика резервирования
- [ ] Синхронизация остатков с Ozon
- [ ] История движений товаров
- [ ] Оповещения о низких остатках
Неделя 3-4:
- [ ] Модели Supplier + SupplierProduct
- [ ] UI управления поставщиками
- [ ] Связь товаров с поставщиками
- [ ] Остатки на складах дропшипперов
- [ ] Автозаказ у дропшиппера
Результат: Заказ без остатков → Автозаказ у дропшиппера → Трек → Ozon
Цель: Гибкая работа с ассортиментом + обработка возвратов
Неделя 1-2:
- [ ] Модель Substitution
- [ ] UI управления подменами
- [ ] Автоматическая подмена при отсутствии товара
- [ ] Согласование с покупателем
Неделя 3-4:
- [ ] Модель Return
- [ ] Загрузка возвратов с Ozon
- [ ] Обработка возвратов (возврат денег, на склад)
- [ ] Статистика по возвратам
Результат: Полная обработка исключительных ситуаций
🔴 СДЭК API интеграция (приоритет #1)
- [ ] Модуль modules/delivery/cdek.py
- [ ] Методы: создание заказа, получение этикетки, трекинг
- [ ] Тестирование на sandbox СДЭК
🔴 Почта России API интеграция (приоритет #1)
- [ ] Модуль modules/delivery/pochta.py
- [ ] Методы: создание заказа, получение этикетки, трекинг
- [ ] Тестирование на sandbox Почты
🔴 Автоматизация realFBS workflow (приоритет #2)
- [ ] При загрузке заказа realFBS → автосоздание в СДЭК/Почте
- [ ] Получение этикетки → сохранение в БД
- [ ] Загрузка трек-номера на Ozon
- [ ] Обновление статусов из СДЭК/Почты
🟡 Учёт остатков - базовая версия (приоритет #3)
- [ ] Модель StockMovement
- [ ] Резервирование при заказе
- [ ] Списание при отгрузке
- [ ] История движений
Ближайшие действия (неделя 1-2):
Далее (неделя 3-4):
Обновлено: 2025-11-08 02:00
Версия документации: 2.4
Последние изменения:
- ✅ Добавлена полная документация схем fulfillment (FBO/FBS/realFBS)
- ✅ Описаны workflow для каждой схемы
- ✅ Добавлены примеры кода
- ✅ Обновлён раздел API методов
- ✅ Обновлена модель Order с новыми полями
- ✨ Определены приоритеты проекта (realFBS + дропшиппинг)
- ✨ Добавлен roadmap на 3 месяца
- ✨ Определены первоочередные задачи (СДЭК/Почта API)
- ✨ Описаны модели: Substitution, Return, Supplier, StockMovement