Проект: Marketplace MVP (mp1)
Версия: 2.4.0
Последнее обновление: 2025-11-08
Документация: https://docs.ozon.ru/api/seller/
Модуль: modules/api/ozon.py
Класс: OzonAPI
from modules.api.ozon import OzonAPI
api = OzonAPI(
client_id="123456",
api_key="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
)
# Тест подключения
if api.test_connection():
print("✅ Подключено к Ozon API")
Проверка подключения к API
result = api.test_connection()
# Returns: True/False
Получить информацию о продавце
seller = api.get_seller_info()
# Response:
{
"name": "ООО Рога и Копыта",
"inn": "1234567890",
"status": "ENABLED"
}
Получить заказы за период
orders = api.fetch_orders(
date_from="2025-11-01T00:00:00Z",
date_to="2025-11-08T23:59:59Z"
)
# Response:
[
{
"posting_number": "12345-0001-1",
"order_date": "2025-11-08T10:30:00Z",
"status": "awaiting_packaging",
"fulfillment_scheme": "fbs", # fbo/fbs/realfbs
"delivery_type": "pvz", # pvz/courier/kts/post
"customer": {
"name": "Иванов Иван",
"phone": "+79991234567"
},
"items": [
{
"sku": "SKU-001",
"name": "Товар",
"quantity": 2,
"price": 1500.00
}
],
"total_amount": 3000.00
}
]
Получить детали заказа
details = api.get_order_details("12345-0001-1")
Перевести заказы в сборку (для FBS)
result = api.start_packing([
"12345-0001-1",
"12345-0002-1"
])
# Response:
{
"result": [
{"posting_number": "12345-0001-1", "status": "success"},
{"posting_number": "12345-0002-1", "status": "success"}
]
}
Отметить отгрузку заказа
# Для FBS (трек-номер Ozon)
api.ship_posting(
posting_number="12345-0001-1",
tracking_number="OZON-12345678"
)
# Для realFBS (свой трек-номер СДЭК/Почты)
api.ship_posting(
posting_number="12345-0001-1",
tracking_number="1234567890123" # Трек СДЭК
)
Отменить заказ
api.cancel_posting(
posting_number="12345-0001-1",
cancel_reason_id=352 # Нет в наличии
)
Получить этикетки для заказов (PDF)
# Получить этикетки Ozon для FBS
pdf_bytes = api.get_posting_labels([
"12345-0001-1",
"12345-0002-1"
])
# Сохранить PDF
with open("labels.pdf", "wb") as f:
f.write(pdf_bytes)
Получить акт приёма-передачи для курьера Ozon (PDF)
pdf_bytes = api.get_posting_act(
date="2025-11-08",
delivery_service="ozon"
)
with open("act.pdf", "wb") as f:
f.write(pdf_bytes)
Получить упаковочный лист (PDF)
pdf_bytes = api.get_package_list([
"12345-0001-1"
])
Загрузить трек-номера на Ozon (для realFBS)
result = api.upload_tracking_numbers([
{
"posting_number": "12345-0001-1",
"tracking_number": "1234567890123", # Ваш трек СДЭК
"delivery_company": "cdek"
}
])
Получить список складов
warehouses = api.get_warehouses()
# Response:
[
{
"id": "12345",
"name": "Склад Москва",
"city": "Москва"
}
]
Получить список служб доставки
services = api.get_delivery_services()
# Response:
[
{
"id": "ozon",
"name": "Ozon Логистика"
},
{
"id": "cdek",
"name": "СДЭК"
}
]
Получить список статусов заказов
statuses = api.get_posting_statuses()
Получить список категорий товаров
categories = api.get_categories(language="RU")
Документация: https://api-docs.cdek.ru/
Модуль: modules/delivery/cdek.py (в разработке)
Класс: CdekAPI
from modules.delivery.cdek import CdekAPI
api = CdekAPI(
account="xxxxx",
secure_password="yyyyy"
)
Создать заказ в СДЭК
order = api.create_order({
"tariff_code": 136, # Посылка дверь-дверь
"sender": {
"name": "ООО Компания",
"phones": [{"number": "+79991234567"}]
},
"recipient": {
"name": "Иванов Иван",
"phones": [{"number": "+79997654321"}]
},
"from_location": {
"code": 44, # Москва
"address": "ул. Примерная, д.1"
},
"to_location": {
"code": 270, # Новосибирск
"address": "ул. Ленина, д.10, кв.5"
},
"packages": [
{
"number": "1",
"weight": 500, # граммы
"length": 10, # см
"width": 10,
"height": 10
}
]
})
# Response:
{
"entity": {
"uuid": "72753031-a593-11ea-...",
"cdek_number": "1234567890"
}
}
Получить этикетку СДЭК (PDF)
pdf_bytes = api.get_label(order_uuid="72753031-...")
with open("cdek_label.pdf", "wb") as f:
f.write(pdf_bytes)
Трекинг заказа
status = api.track(order_uuid="72753031-...")
# Response:
{
"entity": {
"uuid": "72753031-...",
"cdek_number": "1234567890",
"statuses": [
{
"code": "CREATED",
"name": "Создан",
"date_time": "2025-11-08T10:00:00+03:00"
}
]
}
}
| Код | Название | Тип |
|---|---|---|
| 136 | Посылка дверь-дверь | Курьерская доставка |
| 137 | Посылка дверь-склад | До ПВЗ |
| 138 | Посылка склад-дверь | Из ПВЗ курьером |
| 139 | Посылка склад-склад | ПВЗ → ПВЗ |
URL: https://api.edu.cdek.ru/v2
Test account: z9GRRu7FxmO53CQ9cFfI6qiy32wpfTkd
Test password: w24JTCv4MnAcuRTx0oHjHLDtyt3I6IBq
Документация: https://otpravka.pochta.ru/specification
Модуль: modules/delivery/pochta.py (в разработке)
Класс: PochtaAPI
from modules.delivery.pochta import PochtaAPI
api = PochtaAPI(
token="your_access_token",
key="your_api_key"
)
Создать отправление
order = api.create_order({
"mail-category": "ORDINARY", # Простое
"mail-type": "POSTAL_PARCEL", # Посылка
"mass": 500, # граммы
"recipient": {
"given-name": "Иван",
"surname": "Иванов",
"tel-address": "+79997654321"
},
"recipient-address": {
"index": "630000",
"region": "Новосибирская обл",
"place": "Новосибирск",
"street": "Ленина",
"house": "10",
"room": "5"
}
})
# Response:
{
"barcode": "12345678901234",
"tracking-number": "12345678901234"
}
Получить печатную форму (этикетку)
pdf_bytes = api.get_label(barcode="12345678901234")
Трекинг отправления
status = api.track(barcode="12345678901234")
# Response:
{
"barcode": "12345678901234",
"operations": [
{
"operation-type": "Прием",
"date": "2025-11-08T10:00:00"
}
]
}
| Тип | Код | Описание |
|---|---|---|
| POSTAL_PARCEL | посылка | Стандартная посылка |
| EMS | ems | Ускоренная доставка |
| LETTER | письмо | Письмо |
from modules.api.ozon import OzonAPIError, OzonAuthError
try:
orders = api.fetch_orders(...)
except OzonAuthError as e:
logger.error(f"Ошибка авторизации Ozon: {e}")
# Проверить Client ID и API Key
except OzonAPIError as e:
logger.error(f"Ошибка Ozon API: {e}")
# Повторить запрос или сообщить пользователю
except Exception as e:
logger.error(f"Неожиданная ошибка: {e}")
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=4, max=10)
)
def fetch_with_retry():
return api.fetch_orders(...)
import time
# Не больше 100 запросов/минуту (Ozon)
requests_per_minute = 100
delay = 60 / requests_per_minute # 0.6 секунд
for batch in batches:
api.process(batch)
time.sleep(delay)
# ВСЕГДА указывать timeout
api = OzonAPI(
client_id=client_id,
api_key=api_key,
timeout=10 # 10 секунд
)
# НЕ делать 100 запросов
for posting_number in posting_numbers:
api.get_order_details(posting_number) # ❌ Плохо
# Делать 1 запрос с батчем
orders = api.fetch_orders(...) # ✅ Хорошо (до 100 заказов за раз)
Ozon Sandbox:
- URL: https://api-seller.ozon.ru/sandbox (если доступно)
- Тестовые ключи: получить в личном кабинете
СДЭК Sandbox:
- URL: https://api.edu.cdek.ru/v2
- Account: z9GRRu7FxmO53CQ9cFfI6qiy32wpfTkd
- Password: w24JTCv4MnAcuRTx0oHjHLDtyt3I6IBq
Почта России Sandbox:
- URL: https://otpravka-api.pochta.ru (sandbox нет, используйте dev ключи)
# tests/test_ozon_api.py
import pytest
from modules.api.ozon import OzonAPI
def test_ozon_connection():
api = OzonAPI(
client_id="test_client",
api_key="test_key"
)
result = api.test_connection()
assert result == True # или False если тестовые ключи невалидны
def test_fetch_orders():
api = OzonAPI(...)
orders = api.fetch_orders(
date_from="2025-11-01T00:00:00Z",
date_to="2025-11-08T23:59:59Z"
)
assert isinstance(orders, list)
if orders:
assert "posting_number" in orders[0]
// tests/test_realfbs_workflow.js
test('realFBS полный цикл', async ({ page }) => {
// 1. Загрузка заказов
await page.goto('http://localhost:8502');
await page.click('text=Заказы');
await page.click('text=Загрузить заказы');
// 2. Проверка что заказ realFBS появился
await expect(page.locator('text=realfbs')).toBeVisible();
// 3. Создание заказа в СДЭК
await page.click('text=Создать в СДЭК');
await expect(page.locator('text=✅ Заказ создан')).toBeVisible();
// 4. Загрузка трек-номера
await expect(page.locator('text=Трек:')).toBeVisible();
});
Последнее обновление: 2025-11-08
Автор: MP1 Team