Інтеграція з Новою поштою в Python
Головна ідея: розробити Python-сервіс, який інтегрує K2 ERP / CRM / інтернет-магазин / WMS із API Нової пошти для створення експрес-накладних, розрахунку вартості доставки, синхронізації довідників, отримання статусів, друку маркувань та контролю відправлень.
Критично важливо: інтеграція не повинна створювати дублікати експрес-накладних. Кожне замовлення, кожна ЕН / ТТН, повторний запит, помилка API, друк маркування та зміна статусу повинні мати внутрішній ID, idempotency_key, журнал подій і контроль повторної обробки.
Важливо: у Нової пошти API-запити зазвичай будуються через поля modelName, calledMethod та methodProperties. Конкретні моделі та методи потрібно звіряти з актуальною офіційною документацією API перед реалізацією production-версії.
Технічний стек: Python 3.11+, FastAPI, PostgreSQL, SQLAlchemy, Alembic, httpx, Pydantic, Celery/RQ/APScheduler, Redis, Docker.
Управлінський результат: менеджер і керівник повинні бачити, скільки замовлень передано в Нову пошту, скільки ЕН створено, які посилки доставлені, які очікують отримання, які повертаються, де є помилки адреси, оплати, ваги або статусу.
1. Мета
Метою задачі є створення Python-сервісу для інтеграції з Новою поштою з метою автоматизації процесів доставки.
Сервіс повинен забезпечити:
- зберігання налаштувань інтеграції;
- отримання та оновлення довідників Нової пошти;
- пошук міст;
- пошук відділень;
- пошук поштоматів;
- пошук вулиць;
- створення контрагентів або використання існуючих;
- створення контактних осіб;
- створення адрес;
- розрахунок вартості доставки;
- розрахунок орієнтовної дати доставки;
- створення експрес-накладної;
- редагування експрес-накладної, якщо дозволено API;
- видалення / скасування експрес-накладної, якщо дозволено API;
- друк маркування;
- формування реєстру відправлень;
- отримання статусів відправлень;
- синхронізацію статусів назад у K2 ERP;
- журналювання всіх API-запитів;
- dashboard для контролю логістики.
2. Область застосування
Інтеграція призначена для:
- інтернет-магазинів;
- CRM;
- ERP;
- WMS;
- складів;
- служб доставки;
- торгових компаній;
- дистриб'юторів;
- компаній, які створюють багато експрес-накладних;
- компаній, які хочуть контролювати доставку прямо з K2 ERP.
3. Основні можливості API Нової пошти
API Нової пошти використовується для автоматизації логістичних процесів бізнесу. Офіційна сторінка інтеграції описує генерацію API Key у бізнес-кабінеті, а API-портал Nova Post окремо вказує можливості для бізнесу: обробка й відправлення замовлень, доступ до функцій Nova Post та інформації про посилки. :contentReference[oaicite:1]{index=1}
Типові моделі API:
| Модель | Призначення | Приклади використання |
|---|---|---|
| Address | Робота з адресними довідниками. | Міста, населені пункти, відділення, поштомати, вулиці. |
| InternetDocument | Робота з експрес-накладними. | Створення ЕН, розрахунок вартості, дата доставки, друк. |
| TrackingDocument | Відстеження відправлень. | Отримання статусів за номерами ЕН. |
| Counterparty | Контрагенти. | Відправники, отримувачі. |
| ContactPerson | Контактні особи. | Телефон, ПІБ, прив'язка до контрагента. |
| Common | Загальні довідники. | Типи вантажу, типи сервісу, форми оплати тощо. |
| ScanSheet | Реєстри прийому-передачі. | Формування реєстру відправлень. |
У старій відкритій документації API описані моделі `InternetDocument`, `Common`, `Counterparty`, `ContactPerson`, `Address`, `ScanSheet`, а також структура запиту через `modelName`, `calledMethod` і `methodProperties`; це корисно як орієнтир, але production-реалізацію потрібно звіряти з актуальним API-порталом. :contentReference[oaicite:2]{index=2}
4. Передумови
Для реалізації задачі необхідно отримати:
- бізнес-акаунт Нової пошти;
- API Key;
- доступ до актуальної API-документації;
- дані відправника;
- контактну особу відправника;
- адресу / відділення відправника;
- правила оплати доставки;
- правила зворотної доставки;
- правила післяплати;
- правила страхування;
- перелік типів вантажу;
- перелік типів доставки;
- правила друку маркувань;
- правила формування реєстрів;
- правила оновлення статусів;
- вимоги K2 ERP до збереження ЕН.
Критично важливо: API Key потрібно зберігати тільки в зашифрованому вигляді або secret storage. Заборонено зберігати API Key у коді, Git, frontend-змінних або відкритих логах.
5. Основні бізнес-сценарії
5.1. Створення експрес-накладної з K2 ERP
K2 ERP передає в Python-сервіс замовлення, дані отримувача, місто, відділення або адресу, параметри вантажу та оплату.
Python-сервіс:
- перевіряє замовлення;
- перевіряє отримувача;
- перевіряє місто;
- перевіряє відділення / адресу;
- розраховує вартість доставки;
- створює експрес-накладну;
- зберігає номер ЕН;
- передає номер ЕН назад у K2 ERP;
- формує маркування для друку.
5.2. Доставка у відділення
Замовлення доставляється у відділення Нової пошти.
Потрібно передати:
- місто отримувача;
- Ref міста;
- Ref відділення;
- ПІБ отримувача;
- телефон отримувача;
- кількість місць;
- вагу;
- об'єм;
- оголошену вартість;
- платника доставки;
- форму оплати;
- опис вантажу.
5.3. Доставка у поштомат
Замовлення доставляється у поштомат.
Особливості:
- потрібно обрати поштомат зі списку доступних;
- потрібно перевіряти обмеження по вазі та габаритах;
- потрібно валідувати телефон отримувача;
- потрібно контролювати статус прибуття й термін зберігання.
5.4. Адресна доставка
Замовлення доставляється кур'єром на адресу.
Потрібно передати:
- місто;
- вулицю;
- будинок;
- квартиру / офіс, якщо є;
- контактну особу;
- телефон;
- часові або сервісні параметри, якщо доступні;
- тип сервісу DoorsDoors або WarehouseDoors залежно від сценарію.
5.5. Зворотна доставка / післяплата
Якщо використовується післяплата або повернення коштів, потрібно передбачити:
- суму післяплати;
- платника комісії;
- тип зворотної доставки;
- контроль статусу оплати;
- зв'язок із фінансовими документами в K2 ERP.
5.6. Синхронізація статусів
Python-сервіс регулярно отримує статуси відправлень і оновлює K2 ERP.
Синхронізуються:
- створено;
- прийнято у відділенні;
- у дорозі;
- прибуло у відділення;
- прибуло у поштомат;
- видано отримувачу;
- відмова;
- повернення;
- повернуто відправнику;
- зберігання;
- помилка / уточнення.
6. Основні сутності
| Сутність | Опис |
|---|---|
| Integration Account | Налаштування API Нової пошти. |
| Sender | Відправник. |
| Recipient | Отримувач. |
| Counterparty | Контрагент API Нової пошти. |
| Contact Person | Контактна особа. |
| City | Місто / населений пункт з довідника Нової пошти. |
| Warehouse | Відділення або поштомат. |
| Address | Адреса для кур'єрської доставки. |
| Delivery Order | Замовлення на доставку в K2 ERP. |
| Internet Document | Експрес-накладна / ЕН / ТТН. |
| Scan Sheet | Реєстр прийому-передачі. |
| Tracking Status | Статус доставки. |
| API Event | Подія інтеграції. |
7. User Story
7.1. Створення ЕН
Як менеджер інтернет-магазину, я хочу натиснути кнопку «Створити ЕН Нової пошти», щоб система автоматично створила експрес-накладну без ручного введення в кабінеті Нової пошти.
7.2. Друк маркування
Як комірник, я хочу надрукувати маркування по створеній ЕН, щоб наклеїти його на посилку.
7.3. Контроль статусів
Як менеджер, я хочу бачити статус доставки прямо в K2 ERP, щоб швидко реагувати на відмови, повернення та прострочені доставки.
7.4. Формування реєстру
Як працівник складу, я хочу сформувати реєстр відправлень, щоб передати партію посилок у Нову пошту.
7.5. Dashboard керівника
Як керівник, я хочу бачити статистику по доставках, щоб контролювати якість логістики, повернення, затримки та помилки.
8. Типи доставки
| Тип | Код | Опис | Колір |
|---|---|---|---|
| Відділення → Відділення | WarehouseWarehouse | Класична доставка між відділеннями. | Базова |
| Відділення → Адреса | WarehouseDoors | Відправка з відділення на адресу отримувача. | Додаткова |
| Адреса → Відділення | DoorsWarehouse | Кур'єр забирає у відправника, доставка у відділення. | Додаткова |
| Адреса → Адреса | DoorsDoors | Кур'єрська доставка від дверей до дверей. | Важлива |
| Відділення → Поштомат | WarehousePostomat | Доставка в поштомат, якщо підтримується сценарієм. | Додаткова |
Важливо: коди сервісів і доступність конкретних сценаріїв потрібно перевірити за довідниками API Нової пошти, оскільки правила можуть змінюватися.
9. Статуси відправлень
| Статус K2 ERP | Код | Опис | Колір |
|---|---|---|---|
| Чернетка | DRAFT | Замовлення є в K2 ERP, але ЕН ще не створено. | Сірий |
| Очікує створення ЕН | PENDING_CREATE | Замовлення в черзі на створення ЕН. | Жовтий |
| Створюється | CREATING | Виконується API-запит до Нової пошти. | Блакитний |
| ЕН створено | CREATED | Експрес-накладну створено. | Зелений |
| Маркування надруковано | MARKING_PRINTED | Маркування або PDF отримано / надруковано. | Зелений |
| Передано у реєстр | IN_SCAN_SHEET | Відправлення додано в реєстр. | Блакитний |
| Прийнято Новою поштою | ACCEPTED_BY_NP | Відправлення прийнято оператором. | Блакитний |
| У дорозі | IN_TRANSIT | Посилка рухається між терміналами. | Блакитний |
| Прибуло | ARRIVED | Відправлення прибуло у відділення / поштомат / місто. | Жовтий |
| Доставлено | DELIVERED | Відправлення отримано. | Зелений |
| Відмова | REFUSED | Отримувач відмовився. | Червоний |
| Повернення | RETURNING | Відправлення повертається. | Помаранчевий |
| Повернуто | RETURNED | Відправлення повернуто відправнику. | Помаранчевий |
| Помилка | ERROR | Помилка створення або синхронізації. | Червоний |
| Потребує повтору | NEEDS_RETRY | Технічна помилка, можна повторити. | Помаранчевий |
| Скасовано | CANCELLED | ЕН або замовлення скасовано. | Сірий |
10. Єдина логіка кольорів
| Колір | HTML | Значення | Де використовується |
|---|---|---|---|
| Зелений | #c8e6c9 | Успішно: ЕН створено, маркування надруковано, доставлено. | Dashboard, список відправлень, картка замовлення. |
| Блакитний | #bbdefb | Операція виконується або доставка в процесі. | Черга, API-статуси, транспортування. |
| Жовтий | #fff9c4 | Очікування або прибуття. | Очікує створення, прибуло у відділення. |
| Помаранчевий | #ffcc80 | Потрібна дія або є ризик. | Повернення, retry, проблемні статуси. |
| Червоний | #ef9a9a | Помилка або негативний результат. | Відмова, помилка API, неправильна адреса. |
| Фіолетовий | #f3e5f5 | Спеціальний або ручний сценарій. | Ручна перевірка, нестандартна доставка. |
| Сірий | #eeeeee | Чернетка, скасовано або неактивно. | Архів, чернетки. |
11. Архітектура рішення
11.1. Загальна схема
K2 ERP / CRM / Website / WMS
|
| 1. Замовлення, клієнт, адреса, вантаж
v
Python Nova Poshta Integration Service
|
| 2. Валідація, мапінг, дедублікація, черга
v
Nova Poshta API Client
|
| 3. API Нової пошти
v
Нова пошта
|
| 4. ЕН, статуси, маркування, реєстри
v
Python Status Sync Worker
|
| 5. Оновлення статусів
v
K2 ERP / Dashboard / Склад / Менеджер
11.2. Основні компоненти Python-сервісу
| Компонент | Опис |
|---|---|
| API Layer | REST API для прийому замовлень і команд із K2 ERP. |
| Validation Layer | Перевіряє отримувача, адресу, відділення, вагу, габарити, оплату. |
| Mapping Layer | Перетворює структури K2 ERP у формат API Нової пошти. |
| Nova Poshta Client | Python-клієнт для API Нової пошти. |
| Directory Sync Worker | Оновлює довідники міст, відділень, поштоматів, вулиць. |
| Delivery Queue | Черга створення ЕН. |
| Tracking Worker | Оновлює статуси відправлень. |
| Print Service | Отримує PDF / маркування / друковані форми. |
| Scan Sheet Service | Формує реєстри відправлень. |
| Audit Logger | Зберігає запити, відповіді, помилки та зміни статусів. |
| Dashboard API | Дані для менеджера, складу та керівника. |
12. Nova Poshta Client
12.1. Призначення
Nova Poshta Client — це Python-клас або пакет, який інкапсулює роботу з API Нової пошти.
12.2. Загальний формат API-запиту
Типовий запит має містити:
{
"apiKey": "********",
"modelName": "InternetDocument",
"calledMethod": "save",
"methodProperties": {}
}
Важливо: конкретний modelName, calledMethod і methodProperties потрібно брати з актуальної документації API Нової пошти.
12.3. Основні методи Python-клієнта
class NovaPoshtaClient:
def check_connection(self) -> "ConnectionStatus":
pass
def call_api(self, model_name: str, called_method: str, properties: dict) -> dict:
pass
def get_cities(self, query: str | None = None) -> "CityListResponse":
pass
def get_warehouses(self, city_ref: str, warehouse_type: str | None = None) -> "WarehouseListResponse":
pass
def get_streets(self, city_ref: str, query: str) -> "StreetListResponse":
pass
def get_document_price(self, payload: "DeliveryPricePayload") -> "DeliveryPriceResponse":
pass
def get_document_delivery_date(self, payload: "DeliveryDatePayload") -> "DeliveryDateResponse":
pass
def create_internet_document(self, payload: "InternetDocumentPayload") -> "InternetDocumentResponse":
pass
def update_internet_document(self, ref: str, payload: "InternetDocumentPayload") -> "InternetDocumentResponse":
pass
def delete_internet_document(self, ref: str) -> "DeleteDocumentResponse":
pass
def get_tracking_statuses(self, document_numbers: list[str]) -> "TrackingStatusResponse":
pass
def get_print_form(self, document_refs: list[str], format: str = "pdf") -> bytes:
pass
def create_scan_sheet(self, document_refs: list[str]) -> "ScanSheetResponse":
pass
13. Конфігурація клієнта
from pydantic_settings import BaseSettings
class NovaPoshtaSettings(BaseSettings):
base_url: str = "https://api.novaposhta.ua/v2.0/json/"
api_key: str
timeout_seconds: int = 30
retry_count: int = 3
retry_backoff_seconds: int = 5
verify_ssl: bool = True
language: str = "ua"
Приклад `.env`:
NOVA_POSHTA_BASE_URL=https://api.novaposhta.ua/v2.0/json/ NOVA_POSHTA_API_KEY=******** NOVA_POSHTA_TIMEOUT_SECONDS=30 NOVA_POSHTA_RETRY_COUNT=3 NOVA_POSHTA_RETRY_BACKOFF_SECONDS=5 NOVA_POSHTA_LANGUAGE=ua
14. API Python-сервісу
14.1. Створення інтеграції
POST /api/v1/nova-poshta/integrations
14.2. Перевірка підключення
POST /api/v1/nova-poshta/integrations/{integration_id}/check-connection
14.3. Синхронізація довідників
POST /api/v1/nova-poshta/directories/sync
14.4. Пошук міст
GET /api/v1/nova-poshta/cities?query=Київ
14.5. Пошук відділень
GET /api/v1/nova-poshta/warehouses?city_ref={city_ref}
14.6. Розрахунок вартості доставки
POST /api/v1/nova-poshta/delivery/calculate-price
14.7. Розрахунок дати доставки
POST /api/v1/nova-poshta/delivery/calculate-date
14.8. Створення експрес-накладної
POST /api/v1/nova-poshta/internet-documents
14.9. Оновлення експрес-накладної
PATCH /api/v1/nova-poshta/internet-documents/{document_id}
14.10. Скасування / видалення експрес-накладної
POST /api/v1/nova-poshta/internet-documents/{document_id}/cancel
14.11. Друк маркування
GET /api/v1/nova-poshta/internet-documents/{document_id}/print-form
14.12. Синхронізація статусів
POST /api/v1/nova-poshta/tracking/sync
14.13. Створення реєстру
POST /api/v1/nova-poshta/scan-sheets
14.14. Dashboard
GET /api/v1/nova-poshta/dashboard?date_from=2026-05-01&date_to=2026-05-31
15. Приклад запиту на створення ЕН
{
"external_order_id": "K2-ORDER-2026-000123",
"idempotency_key": "K2-ORDER-2026-000123-np-v1",
"sender": {
"counterparty_ref": "sender-counterparty-ref",
"contact_ref": "sender-contact-ref",
"city_ref": "sender-city-ref",
"warehouse_ref": "sender-warehouse-ref",
"phone": "+380501112233"
},
"recipient": {
"first_name": "Іван",
"middle_name": "Іванович",
"last_name": "Петренко",
"phone": "+380671112233",
"city_ref": "recipient-city-ref",
"warehouse_ref": "recipient-warehouse-ref"
},
"delivery": {
"service_type": "WarehouseWarehouse",
"cargo_type": "Parcel",
"description": "Одяг",
"cost": 1500.00,
"seats_amount": 1,
"weight": 2.5,
"volume_general": 0.01,
"payer_type": "Recipient",
"payment_method": "Cash"
},
"backward_delivery": {
"enabled": true,
"amount": 1500.00,
"payer": "Recipient"
}
}
16. Валідація перед створенням ЕН
Перед створенням експрес-накладної система повинна перевірити:
- наявність external_order_id;
- наявність idempotency_key;
- чи не створена вже ЕН для цього замовлення;
- API Key активний;
- місто відправника існує;
- місто отримувача існує;
- відділення або поштомат існує;
- відділення активне;
- телефон отримувача валідний;
- ПІБ отримувача заповнено;
- вага більше 0;
- кількість місць більше 0;
- оголошена вартість більше або дорівнює 0;
- тип сервісу сумісний із адресними даними;
- післяплата не перевищує правила бізнесу;
- платник доставки визначений;
- форма оплати визначена;
- опис вантажу заповнений.
Критично важливо: якщо ЕН уже створена, повторний запит не повинен створювати нову ЕН. Система повинна повернути існуючу ЕН та її поточний статус.
17. Довідники Нової пошти
17.1. Довідник міст
Довідник міст потрібен для вибору коректного `CityRef`.
| Поле | Опис |
|---|---|
| Ref | Унікальний ідентифікатор міста в Новій пошті. |
| Description | Назва українською. |
| DescriptionRu | Назва російською, якщо доступна. |
| Area | Область. |
| SettlementTypeDescription | Тип населеного пункту. |
| IsBranch | Ознака наявності відділень, якщо доступна. |
У відкритій документації API метод `getCities` у моделі `Address` описується як метод отримання довідника населених пунктів; там же зазначено рекомендацію зберігати копію довідників на стороні клієнта й оновлювати її раз на добу. :contentReference[oaicite:3]{index=3}
17.2. Довідник відділень і поштоматів
Потрібно зберігати:
- Ref відділення;
- номер відділення;
- назву;
- адресу;
- місто;
- тип відділення;
- максимальну вагу;
- ознаку поштомата;
- графік роботи;
- координати;
- ознаку активності.
17.3. Довідник вулиць
Для адресної доставки потрібно підтримати пошук вулиць за містом.
17.4. Графік оновлення довідників
| Довідник | Частота оновлення | Коментар |
|---|---|---|
| Міста | 1 раз на добу | Базовий довідник. |
| Відділення | 1 раз на добу або частіше | Важливо для актуальності активних відділень. |
| Поштомати | 1 раз на добу або частіше | Потрібно враховувати активність і обмеження. |
| Вулиці | За потреби або кешуванням | Може бути великий обсяг. |
| Загальні довідники | 1 раз на добу | Типи вантажів, сервісів, оплат. |
18. Дедублікація
Система повинна не допускати дублювання ЕН.
Ключі дедублікації:
| Ключ | Призначення |
|---|---|
| external_order_id | ID замовлення в K2 ERP. |
| idempotency_key | Унікальний ключ конкретної спроби створення ЕН. |
| np_document_ref | Ref експрес-накладної в API. |
| np_document_number | Номер ЕН / ТТН. |
| document_hash | Hash основних параметрів відправлення. |
Приклад hash:
sha256(external_order_id + recipient_phone + city_ref + warehouse_ref + cost + weight)
19. Черга створення ЕН
19.1. Логіка черги
1. K2 ERP створює замовлення. 2. Користувач натискає «Створити ЕН» або спрацьовує автоматичне правило. 3. Python-сервіс виконує валідацію. 4. Створюється запис delivery_order зі статусом PENDING_CREATE. 5. Worker викликає API Нової пошти. 6. API повертає Ref і номер ЕН. 7. Python-сервіс зберігає номер ЕН. 8. K2 ERP отримує номер ЕН. 9. Print Service отримує маркування. 10. Tracking Worker оновлює статуси доставки.
19.2. Пріоритети задач
| Тип задачі | Пріоритет | Коментар |
|---|---|---|
| Створення ЕН | Високий | Основний процес відвантаження. |
| Друк маркування | Високий | Потрібно для складу. |
| Скасування ЕН | Високий | Важливо до передачі посилки. |
| Створення реєстру | Середній | Групова операція. |
| Синхронізація статусів | Середній | Фоновий процес. |
| Оновлення довідників | Низький | Регламентна задача. |
20. Модель даних
20.1. nova_poshta_integrations
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID інтеграції. |
| provider | varchar | nova_poshta. |
| name | varchar | Назва інтеграції. |
| base_url | varchar | URL API. |
| api_key_encrypted | text | Зашифрований API Key. |
| default_sender_ref | varchar | Відправник за замовчуванням. |
| default_contact_ref | varchar | Контакт за замовчуванням. |
| default_city_ref | varchar | Місто відправника. |
| default_warehouse_ref | varchar | Відділення відправника. |
| is_active | boolean | Активність. |
| created_at | timestamp | Дата створення. |
| updated_at | timestamp | Дата оновлення. |
20.2. np_cities
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | Внутрішній ID. |
| ref | varchar | Ref міста в Новій пошті. |
| description | varchar | Назва міста. |
| area | varchar | Область. |
| settlement_type | varchar | Тип населеного пункту. |
| is_active | boolean | Активність. |
| updated_at | timestamp | Дата оновлення. |
20.3. np_warehouses
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | Внутрішній ID. |
| ref | varchar | Ref відділення. |
| city_ref | varchar | Ref міста. |
| number | varchar | Номер відділення. |
| description | varchar | Назва / опис. |
| address | text | Адреса. |
| warehouse_type | varchar | Тип відділення. |
| max_weight | numeric | Максимальна вага. |
| latitude | numeric | Широта. |
| longitude | numeric | Довгота. |
| schedule | jsonb | Графік роботи. |
| is_active | boolean | Активність. |
20.4. np_delivery_orders
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID доставки. |
| external_order_id | varchar | ID замовлення K2 ERP. |
| idempotency_key | varchar | Ключ дедублікації. |
| np_document_ref | varchar | Ref ЕН. |
| np_document_number | varchar | Номер ЕН / ТТН. |
| service_type | varchar | Тип доставки. |
| cargo_type | varchar | Тип вантажу. |
| sender_ref | varchar | Відправник. |
| recipient_ref | varchar | Отримувач, якщо створений. |
| recipient_name | varchar | ПІБ отримувача. |
| recipient_phone | varchar | Телефон отримувача. |
| recipient_city_ref | varchar | Місто отримувача. |
| recipient_warehouse_ref | varchar | Відділення / поштомат. |
| recipient_address | text | Адреса для кур'єрської доставки. |
| seats_amount | integer | Кількість місць. |
| weight | numeric | Вага. |
| volume_general | numeric | Об'єм. |
| cost | numeric | Оголошена вартість. |
| delivery_price | numeric | Розрахована вартість доставки. |
| payer_type | varchar | Платник доставки. |
| payment_method | varchar | Форма оплати. |
| backward_delivery_amount | numeric | Сума післяплати. |
| status | varchar | Статус K2 ERP. |
| np_status | varchar | Оригінальний статус Нової пошти. |
| raw_request | jsonb | Запит. |
| raw_response | jsonb | Відповідь. |
| error_message | text | Помилка. |
| created_at | timestamp | Дата створення. |
| sent_at | timestamp | Дата створення ЕН. |
| delivered_at | timestamp | Дата доставки. |
20.5. np_scan_sheets
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID реєстру. |
| np_scan_sheet_ref | varchar | Ref реєстру в Новій пошті. |
| number | varchar | Номер реєстру. |
| status | varchar | Статус. |
| documents_count | integer | Кількість ЕН. |
| raw_response | jsonb | Відповідь API. |
| created_at | timestamp | Дата створення. |
20.6. np_events
| Поле | Тип | Опис |
|---|---|---|
| id | uuid | ID події. |
| entity_type | varchar | integration, order, document, scan_sheet, directory. |
| entity_id | uuid | ID сутності. |
| event_type | varchar | Тип події. |
| old_status | varchar | Попередній статус. |
| new_status | varchar | Новий статус. |
| source | varchar | K2_ERP, PYTHON_SERVICE, NOVA_POSHTA, USER. |
| payload | jsonb | Технічні дані. |
| created_at | timestamp | Дата події. |
21. Приклад Python-логіки
21.1. Базовий API-клієнт
import httpx
class NovaPoshtaApiError(Exception):
pass
class NovaPoshtaClient:
def __init__(self, base_url: str, api_key: str, timeout_seconds: int = 30):
self.base_url = base_url
self.api_key = api_key
self.timeout_seconds = timeout_seconds
async def call_api(
self,
model_name: str,
called_method: str,
properties: dict | None = None,
) -> dict:
payload = {
"apiKey": self.api_key,
"modelName": model_name,
"calledMethod": called_method,
"methodProperties": properties or {},
}
async with httpx.AsyncClient(timeout=self.timeout_seconds) as client:
response = await client.post(self.base_url, json=payload)
response.raise_for_status()
data = response.json()
if not data.get("success"):
raise NovaPoshtaApiError(str(data.get("errors") or data))
return data
21.2. Створення ЕН
async def create_np_document(command: "CreateNpDocumentCommand", db: "Session") -> "NpDeliveryOrder":
existing = np_order_repository.get_by_idempotency_key(
db=db,
idempotency_key=command.idempotency_key,
)
if existing:
return existing
np_validator.validate(command)
order = np_order_repository.create(
db=db,
data={
"external_order_id": command.external_order_id,
"idempotency_key": command.idempotency_key,
"status": "PENDING_CREATE",
"recipient_name": command.recipient.full_name,
"recipient_phone": command.recipient.phone,
"recipient_city_ref": command.recipient.city_ref,
"recipient_warehouse_ref": command.recipient.warehouse_ref,
"service_type": command.delivery.service_type,
"cargo_type": command.delivery.cargo_type,
"weight": command.delivery.weight,
"cost": command.delivery.cost,
"raw_request": command.model_dump(),
},
)
delivery_queue.enqueue(
task_name="send_np_document",
payload={"delivery_order_id": str(order.id)},
)
audit_logger.log(
entity_type="np_delivery_order",
entity_id=order.id,
event_type="NP_DOCUMENT_QUEUED",
new_status="PENDING_CREATE",
payload={"external_order_id": command.external_order_id},
)
db.commit()
return order
21.3. Worker створення ЕН
async def send_np_document(delivery_order_id: str, db: "Session") -> None:
order = np_order_repository.get_by_id(db, delivery_order_id)
if order.status in ["CREATED", "DELIVERED"] and order.np_document_number:
return
try:
order.status = "CREATING"
db.commit()
payload = np_mapper.to_internet_document_payload(order)
response = await nova_poshta_client.call_api(
model_name="InternetDocument",
called_method="save",
properties=payload,
)
document_data = response["data"][0]
order.np_document_ref = document_data.get("Ref")
order.np_document_number = document_data.get("IntDocNumber")
order.status = "CREATED"
order.raw_response = response
order.sent_at = utc_now()
audit_logger.log(
entity_type="np_delivery_order",
entity_id=order.id,
event_type="NP_DOCUMENT_CREATED",
old_status="CREATING",
new_status="CREATED",
payload={
"np_document_ref": order.np_document_ref,
"np_document_number": order.np_document_number,
},
)
except TemporaryNovaPoshtaError as exc:
order.status = "NEEDS_RETRY"
order.error_message = str(exc)
except Exception as exc:
order.status = "ERROR"
order.error_message = str(exc)
finally:
db.commit()
21.4. Синхронізація статусів
async def sync_np_statuses(document_numbers: list[str], db: "Session") -> None:
response = await nova_poshta_client.call_api(
model_name="TrackingDocument",
called_method="getStatusDocuments",
properties={
"Documents": [
{"DocumentNumber": number}
for number in document_numbers
]
},
)
for item in response.get("data", []):
number = item.get("Number")
order = np_order_repository.get_by_document_number(db, number)
if not order:
continue
old_status = order.status
new_status = np_status_mapper.from_np(item)
if old_status != new_status:
order.status = new_status
order.np_status = item.get("Status")
if new_status == "DELIVERED":
order.delivered_at = utc_now()
audit_logger.log(
entity_type="np_delivery_order",
entity_id=order.id,
event_type="NP_STATUS_SYNCED",
old_status=old_status,
new_status=new_status,
payload=item,
)
db.commit()
22. Обробка помилок
22.1. Типи помилок
| Тип помилки | Опис | Дія системи |
|---|---|---|
| ValidationError | Некоректні дані замовлення. | Не створювати ЕН, показати список помилок. |
| AuthError | Невірний API Key. | Зупинити інтеграцію, повідомити адміністратора. |
| CityNotFoundError | Місто не знайдено. | Перевести в NEEDS_CORRECTION. |
| WarehouseNotFoundError | Відділення або поштомат не знайдено. | Перевести в NEEDS_CORRECTION. |
| PhoneValidationError | Некоректний телефон отримувача. | Перевести в NEEDS_CORRECTION. |
| DeliveryCalculationError | Не вдалося розрахувати доставку. | Показати менеджеру. |
| ApiError | API повернув помилку. | Зберегти raw-відповідь. |
| TimeoutError | Перевищено час очікування. | Перевести в NEEDS_RETRY. |
| DuplicateDocumentError | ЕН уже створено. | Повернути існуючу ЕН. |
| TrackingError | Не вдалося отримати статус. | Повторити фоново. |
22.2. Retry-логіка
Retry дозволений для:
- timeout;
- HTTP 429;
- HTTP 500;
- HTTP 502;
- HTTP 503;
- HTTP 504;
- тимчасової недоступності API;
- тимчасової помилки друку маркування;
- тимчасової помилки синхронізації статусів.
Retry заборонений для:
- неправильного API Key;
- помилок валідації;
- неправильного міста;
- неправильного відділення;
- некоректного телефону;
- ЕН, яка вже створена;
- ЕН, яка вже доставлена;
- ЕН, яка вже скасована.
23. Dashboard менеджера і керівника
23.1. Основні KPI
| KPI | Опис | Колір |
|---|---|---|
| Замовлень до відправки | Замовлення без ЕН. | Увага |
| ЕН створено | Кількість створених ЕН. | Норма |
| Маркування надруковано | Готові до пакування відправлення. | Норма |
| У дорозі | Відправлення в транспортуванні. | В роботі |
| Прибуло | Очікує отримувача. | Контроль |
| Доставлено | Успішні доставки. | Норма |
| Відмова | Отримувач відмовився. | Критично |
| Повернення | Посилки повертаються. | Потрібна дія |
| Помилки API | Помилки створення або статусів. | Критично |
23.2. Приклад dashboard
| Показник | Значення | Стан |
|---|---|---|
| Замовлень до відправки | 84 | Увага |
| ЕН створено сьогодні | 312 | Норма |
| Маркування надруковано | 298 | Норма |
| У дорозі | 1270 | В роботі |
| Прибуло у відділення | 240 | Контроль |
| Доставлено | 980 | Норма |
| Відмова | 18 | Критично |
| Повернення | 35 | Потрібна дія |
| Помилки створення ЕН | 6 | Критично |
23.3. Проблемні відправлення
| Дата | Замовлення | ЕН | Отримувач | Статус | Причина | Дія |
|---|---|---|---|---|---|---|
| 07.05.2026 | K2-ORDER-123 | - | Іван Петренко | Помилка | Не знайдено відділення | Виправити адресу |
| 07.05.2026 | K2-ORDER-124 | 20450000000000 | Олена Сидоренко | Відмова | Відмова отримувача | Зв'язатися з клієнтом |
| 07.05.2026 | K2-ORDER-125 | 20450000000001 | ТОВ «Альфа» | Повернення | Не отримано вчасно | Контроль повернення |
24. Безпека
Система повинна забезпечити:
- зберігання API Key тільки у secret storage або в зашифрованому вигляді;
- заборону логування API Key;
- HTTPS для всіх API-запитів;
- перевірку SSL;
- рольову модель доступу;
- окремі права на створення ЕН;
- окремі права на скасування ЕН;
- окремі права на друк маркувань;
- окремі права на формування реєстрів;
- журнал усіх дій;
- захист від дублювання ЕН;
- маскування телефонів отримувачів у логах;
- контроль доступу до персональних даних.
25. Логування та аудит
Система повинна логувати:
| Подія | Що зберігати |
|---|---|
| Створення запиту на ЕН | Замовлення, отримувач, місто, відділення, сума. |
| Валідація | Результат, список помилок. |
| Розрахунок доставки | Параметри, вартість, дата. |
| Створення ЕН | Номер ЕН, Ref, дата, відповідь API. |
| Друк маркування | Хто надрукував, коли, формат. |
| Створення реєстру | Номер реєстру, список ЕН. |
| Отримання статусу | Старий статус, новий статус, джерело. |
| Помилка API | Код, повідомлення, raw-відповідь. |
| Повторна операція | Хто запустив, причина, результат. |
| Скасування ЕН | Хто скасував, причина. |
26. Acceptance Criteria
26.1. Інтеграція
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-1 | Адміністратор створює інтеграцію Нової пошти. | Інтеграція зберігається в системі. |
| AC-2 | Адміністратор перевіряє підключення. | Система повертає успішний або помилковий статус. |
| AC-3 | API Key неправильний. | Система показує AuthError і не створює ЕН. |
26.2. Довідники
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-4 | Система запускає синхронізацію міст. | Довідник міст оновлюється. |
| AC-5 | Система запускає синхронізацію відділень. | Довідник відділень оновлюється. |
| AC-6 | Відділення стало неактивним. | Його не можна вибрати для нових ЕН. |
26.3. Створення ЕН
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-7 | K2 ERP передає валідне замовлення. | Python-сервіс створює ЕН. |
| AC-8 | API повертає номер ЕН. | Номер зберігається в K2 ERP. |
| AC-9 | Повторний запит має той самий idempotency_key. | Друга ЕН не створюється. |
| AC-10 | Відділення не знайдено. | ЕН не створюється, статус NEEDS_CORRECTION. |
26.4. Друк і реєстри
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-11 | Користувач натискає «Друк маркування». | Система повертає PDF або інший доступний формат. |
| AC-12 | Користувач формує реєстр. | ЕН додаються до реєстру. |
| AC-13 | ЕН уже в реєстрі. | Повторне додавання блокується або обробляється за правилом. |
26.5. Статуси
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-14 | Tracking API повертає новий статус. | K2 ERP оновлює статус відправлення. |
| AC-15 | Відправлення доставлено. | Статус стає DELIVERED і підсвічується зеленим. |
| AC-16 | Отримувач відмовився. | Статус стає REFUSED і підсвічується червоним. |
| AC-17 | Відправлення повертається. | Статус стає RETURNING і підсвічується помаранчевим. |
26.6. Dashboard
| № | Критерій | Очікуваний результат |
|---|---|---|
| AC-18 | Менеджер відкриває dashboard. | Він бачить замовлення, ЕН, доставки, відмови, повернення та помилки. |
| AC-19 | Є помилки створення ЕН. | Вони підсвічуються червоним. |
| AC-20 | Є повернення. | Вони підсвічуються помаранчевим. |
27. MVP
До MVP входить:
- створення інтеграції Нової пошти;
- перевірка API Key;
- синхронізація міст;
- синхронізація відділень;
- пошук міст і відділень;
- розрахунок вартості доставки;
- створення ЕН;
- збереження номера ЕН;
- друк маркування;
- синхронізація статусів;
- дедублікація;
- retry-механізм;
- журнал подій;
- dashboard API;
- базові unit-тести;
- mock API для інтеграційних тестів.
До MVP не входить:
- повна підтримка всіх додаткових послуг;
- складна робота з міжнародною доставкою;
- повна автоматизація післяплати;
- автоматичне створення всіх типів контрагентів;
- складний UI складу;
- інтеграція з NovaPay;
- власна система доставки замість API Нової пошти.
28. Етапи реалізації
Етап 1. Аналіз API Нової пошти
- отримати API Key;
- перевірити доступ до API;
- отримати актуальну документацію;
- перевірити моделі Address, InternetDocument, TrackingDocument, ScanSheet;
- перевірити розрахунок вартості;
- перевірити створення тестової ЕН;
- перевірити друк маркування.
Етап 2. Базовий Python-сервіс
- створити FastAPI-проєкт;
- налаштувати PostgreSQL;
- створити моделі інтеграції, довідників, ЕН, подій;
- налаштувати Alembic;
- реалізувати healthcheck.
Етап 3. Nova Poshta Client
- реалізувати call_api;
- реалізувати get_cities;
- реалізувати get_warehouses;
- реалізувати get_document_price;
- реалізувати get_document_delivery_date;
- реалізувати create_internet_document;
- реалізувати get_tracking_statuses;
- реалізувати get_print_form;
- реалізувати create_scan_sheet;
- реалізувати обробку помилок.
Етап 4. Довідники
- реалізувати синхронізацію міст;
- реалізувати синхронізацію відділень;
- реалізувати пошук;
- реалізувати кешування;
- реалізувати регламентне оновлення.
Етап 5. ЕН і валідація
- реалізувати створення ЕН;
- реалізувати мапінг K2 ERP → API Нової пошти;
- реалізувати валідацію;
- реалізувати hash документа;
- реалізувати дедублікацію.
Етап 6. Статуси та друк
- реалізувати синхронізацію статусів;
- реалізувати друк маркування;
- реалізувати реєстри;
- реалізувати retry.
Етап 7. Dashboard та аудит
- реалізувати dashboard API;
- реалізувати список проблемних відправлень;
- реалізувати фільтри;
- реалізувати експорт, якщо потрібно.
Етап 8. Production hardening
- додати rate limiting;
- додати моніторинг;
- додати alerting;
- додати dead letter queue;
- додати резервне копіювання;
- додати безпечне зберігання секретів.
29. Ризики
| Ризик | Опис | Як зменшити |
|---|---|---|
| Неправильний API Key | Інтеграція не працюватиме. | Check-connection і повідомлення адміністратору. |
| Застарілі довідники | Користувач може обрати неактивне відділення. | Оновлювати довідники щодня або частіше. |
| Дублювання ЕН | Повторний запит може створити другу накладну. | Idempotency key і перевірка external_order_id. |
| Неправильний телефон | API може відхилити ЕН. | Валідація номера до відправки. |
| Неправильна вага / габарити | Вартість доставки буде некоректна. | Валідація параметрів вантажу. |
| Зміна API | Можуть змінитись методи або поля. | Версіонування клієнта і contract-тести. |
| Недоступність API | ЕН не створюються. | Черга, retry, dashboard помилок. |
| Повернення не контролюються | Менеджер може пропустити повернення. | Окрема шахматка повернень і статусів. |
30. Відкриті питання
- Який бізнес-кабінет і API Key використовуються?
- Чи потрібно підтримувати декілька відправників?
- Чи потрібно підтримувати декілька складів?
- Чи потрібна доставка у поштомати?
- Чи потрібна адресна доставка?
- Чи потрібна післяплата?
- Чи потрібна інтеграція з NovaPay?
- Чи потрібно створювати контрагентів через API?
- Чи потрібно автоматично друкувати маркування після створення ЕН?
- Який формат друку потрібен: A4, термопринтер, PDF, Zebra?
- Чи потрібно формувати реєстри?
- Як часто синхронізувати статуси?
- Чи потрібно показувати строк зберігання у відділенні?
- Чи потрібно автоматично сповіщати клієнта?
- Чи потрібно підтримувати міжнародну доставку?
- Чи потрібна інтеграція з K2 ERP документами реалізації та оплат?
31. Джерела
- Офіційна сторінка інтеграції Нової пошти для бізнесу.
- API Portal Nova Post.
- Офіційна документація API Нової пошти в кабінеті / API-порталі.
- Довідники API: міста, відділення, типи сервісів, типи вантажів.
- Документація моделей Address, InternetDocument, TrackingDocument, Counterparty, ContactPerson, ScanSheet.