Перейти до вмісту

Інтеграція з Новою поштою в Python

Матеріал з K2 ERP Wiki

!; |- | warehouse_type | varchar | Тип відділення.; | Повторне додавання блокується або обробляється за правилом.; {| class="wikitable"

!; |}


=== 12.2.; Загальний формат API-запиту ===
</div>
 )

<pre>

!; {| class="wikitable"

* додати rate limiting;
* додати моніторинг;
* додати alerting;
* додати dead letter queue;
* додати резервне копіювання;
* додати безпечне зберігання секретів.; |-
| is_active
| boolean
| Активність.; | style="background:#bbdefb;" | Блакитний
|-
| У дорозі
| IN_TRANSIT
| Посилка рухається між терміналами.; |}

=== 20.6. np_events ===

!; Типовий запит має містити:
{
 for item in response.get("data", []):
async def send_np_document(delivery_order_id: str, db: "Session") -> None:

!; |-
| longitude
| numeric
| Довгота.; # Чи потрібно автономно сповіщати клієнта?; Тип
!; |-
| entity_id
| uuid
| ID сутності.; * Довідники API: міста, відділення, типи сервісів, типи вантажів.; |-
| number
| varchar
| Номер реєстру.; |-
| documents_count
| integer
| Кількість ЕН.; |}

=== 7.3.; Контроль статусів ===

 "recipient_city_ref": command.recipient.city_ref,

* створення інтеграції Нової пошти;
* перевірка API Key;
* синхронізація міст;
* синхронізація відділень;
* пошук міст і відділень;
* розрахунок вартості доставки;
* створення ЕН;
* збереження номера ЕН;
* друк маркування;
* синхронізація статусів;
* дедублікація;
* retry-механізм;
* журнал подій;
* dashboard API;
* базові unit-тести;
* mock API для інтеграційних тестів.; | Створення ЕН, розрахунок вартості, дата доставки, друк.; v
<syntaxhighlight lang="python">

{| class="wikitable"
=== 14.4.; Пошук міст ===
 "calledMethod": called_method,
!; | style="background:#fff9c4;" | Жовтий
|-
| Створюється
| CREATING
| Виконується API-запит до Нової пошти.; | Черга, API-статуси, транспортування.; Тип

=== 20.3. np_warehouses ===

 finally:
 new_status = np_status_mapper.from_np(item)
!; |-
| Вулиці
| За потреби або кешуванням
| має змогу бути великий обсяг.; | style="background:#ef9a9a;" | Червоний
|-
| Повернення
| RETURNING
| Відправлення повертається.; Колір
 pass
 order.status = "NEEDS_RETRY"
|-
| Відділення → Відділення
| WarehouseWarehouse
| Класична доставка між відділеннями.; }
 api_key: str
Retry заборонений для:
 old_status="CREATING",
Nova Poshta Client — це Python-клас або пакет, який інкапсулює роботу з API Нової пошти.; |-
| name
| varchar
| Назва інтеграції.; | Перевести в NEEDS_CORRECTION.; характеристика

== 6.; Основні сутності ==

=== Етап 2.; Базовий Python-сервіс ===

* потрібно обрати поштомат зі списку доступних;
* потрібно перевіряти обмеження по вазі та габаритах;
* потрібно валідувати телефон отримувача;
* потрібно контролювати статус прибуття й термін зберігання.; |-
| актуалізація довідників
| Низький
| Регламентна задача.; актуалізація статусів
 order.status = "CREATING"
!; характеристика

 number = item.get("Number")

* місто отримувача;
* Ref міста;
* Ref відділення;
* ПІБ отримувача;
* телефон отримувача;
* кількість місць;
* вагу;
* об'єм;
* оголошену вартість;
* платника доставки;
* форму оплати;
* характеристика вантажу.; Колір
 db=db,
== 10.; Єдина логіка кольорів ==
!; Модель

 "status": "PENDING_CREATE",
"methodProperties": {}

Для адресної доставки потрібно підтримати пошук вулиць за містом.; | Перевести в NEEDS_RETRY.; |- | cargo_type | varchar | Тип вантажу.; характеристика


"description": "Одяг",


5.5.; Зворотна доставка / післяплата

Потрібно передати: Критично істотно: інтеграційні функціональні можливості не повинна створювати дублікати експрес-накладних.; | Формування реєстру відправлень.; | style="background:#eeeeee;" | Сірий |}

Етап 6.; Статуси та друк

</syntaxhighlight>

except Exception as exc:
order.np_status = item.get("Status")

NOVA_POSHTA_TIMEOUT_SECONDS=30 |- | style="background:#c8e6c9;" | Зелений | #c8e6c9 | Успішно: ЕН створено, маркування надруковано, доставлено.; | style="background:#ffcc80;" | Потрібна дія |- | Помилки API | Помилки створення або статусів.; !; Print Service отримує маркування.; |- | Dashboard API | інформаційні дані для менеджера, складу та керівника.; Значення

Python Nova Poshta Integration Service

from pydantic_settings import BaseSettings !; |- | Застарілі довідники | користувач системи має змогу обрати неактивне відділення.; |- | source | varchar | K2_ERP, PYTHON_SERVICE, NOVA_POSHTA, USER.; ЕН Retry дозволений для: class NovaPoshtaClient: !; |}

</syntaxhighlight>

def get_document_price(self, payload: "DeliveryPricePayload") -> "DeliveryPriceResponse":
  • timeout;
  • HTTP 429;
  • HTTP 500;
  • HTTP 502;
  • HTTP 503;
  • HTTP 504;
  • тимчасової недоступності API;
  • тимчасової помилки друку маркування;
  • тимчасової помилки синхронізації статусів.; !; |-

| sender_ref | varchar | Відправник.; |- | recipient_city_ref | varchar | Місто отримувача.; |- | cost | numeric | Оголошена вартість.; | Зберегти raw-відповідь.; |- | Валідація | Результат, список помилок.; Дія

5.1.; Створення експрес-накладної з K2 ERP

"payment_method": "Cash"

Особливості: |- | Замовлень до відправки | 84 | style="background:#fff9c4;" | Увага |- | ЕН створено сьогодні | 312 | style="background:#c8e6c9;" | Норма |- | Маркування надруковано | 298 | style="background:#c8e6c9;" | Норма |- | У дорозі | 1270 | style="background:#bbdefb;" | В роботі |- | Прибуло у відділення | 240 | style="background:#fff9c4;" | Контроль |- | Доставлено | 980 | style="background:#c8e6c9;" | Норма |- | Відмова | 18 | style="background:#ef9a9a;" | Критично |- | Повернення | 35 | style="background:#ffcc80;" | Потрібна дія |- | Помилки створення ЕН | 6 | style="background:#ef9a9a;" | Критично |}

pass

</syntaxhighlight>

pass

я хочу натиснути кнопку «Створити ЕН Нової пошти», !; |}

!; |- | Неправильна вага / габарити | Вартість доставки буде некоректна.; |- | Скасування ЕН | Високий | істотно до передачі посилки.; |- | Поштомати | 1 раз на добу або частіше | Потрібно враховувати активність і обмеження.; |- | Повернення не контролюються | Менеджер має змогу пропустити повернення.; Приклади використання

!; # Чи потрібна адресна доставка?; |- | payer_type | varchar | Платник доставки.; |- | Scan Sheet Service | Формує реєстри відправлень.; | Версіонування клієнта і contract-тести.; Сутність

pass

4.; |- | Створення реєстру | Номер реєстру, список ЕН.; !; |- | AC-16 | Отримувач відмовився.; |- | IsBranch | Ознака наявності відділень, якщо доступна.; |- | Створення реєстру | Середній | Групова операційна дія.; Тип

Сервіс повинен забезпечити: !; |}

pass
 response.raise_for_status()

== 24.; Безпека ==

!; | Не створювати ЕН, показати список помилок.; |-
| area
| varchar
| Область.; | Показати менеджеру.; |-
| InternetDocument
| Робота з експрес-накладними.;=== 26.6. Dashboard ===
 },
GET /api/v1/nova-poshta/cities?query=Київ

 return order
 "service_type": "WarehouseWarehouse",
Потрібно зберігати:

Nova Poshta API Client

 self.api_key = api_key
У старій відкритій документації API описані моделі `InternetDocument`, `Common`, `Counterparty`, `ContactPerson`, `Address`, `ScanSheet`, а додатково структура запиту через `modelName`, `calledMethod` і `methodProperties`; це корисно як орієнтир, але production-реалізацію потрібно звіряти з актуальним API-порталом.; Очікуваний результат
{| class="wikitable"
!; |-
| created_at
| timestamp
| Дата події.; Поле

[[Категорія:Доставка]]

* місто;
* вулицю;
* будинок;
* квартиру / офіс, якщо є собою;
* контактну особу;
* телефон;
* часові або сервісні параметри, якщо доступні;
* тип сервісу DoorsDoors або WarehouseDoors залежно від сценарію.; |-
| updated_at
| timestamp
| Дата актуалізація.; |-
| np_document_ref
| Ref експрес-накладної в API.; sha256(external_order_id + recipient_phone + city_ref + warehouse_ref + cost + weight)

!; Очікуваний результат
 new_status="CREATED",

=== 14.10.; Скасування / видалення експрес-накладної ===

<pre>
2.; | Друга ЕН не створюється.; * Документація моделей Address, InternetDocument, TrackingDocument, Counterparty, ContactPerson, ScanSheet.; користувач системи натискає «Створити ЕН» або спрацьовує автоматичне правило.; |-
| Audit Logger
| Зберігає запити, відповіді, помилки та зміни статусів.; | платформа показує AuthError і не створює ЕН.; | style="background:#bbdefb;" | Блакитний
|-
| ЕН створено
| CREATED
| Експрес-накладну створено.; Python Status Sync Worker

* бізнес-акаунт Нової пошти;
* API Key;
* доступ до актуальної API-документації;
* інформаційні дані відправника;
* контактну особу відправника;
* адресу / відділення відправника;
* правила оплати доставки;
* правила зворотної доставки;
* правила післяплати;
* правила страхування;
* перелік типів вантажу;
* перелік типів доставки;
* правила друку маркувань;
* правила формування реєстрів;
* правила актуалізація статусів;
* вимоги K2 ERP до збереження ЕН.; |-
| recipient_address
| text
| Адреса для кур'єрської доставки.; Частота актуалізація
 db=db,
{| class="wikitable"

<pre>

!; | Очікує створення, прибуло у відділення.; | платформа повертає PDF або інший доступний формат.; Очікуваний результат
== 27. MVP ==
=== 7.2.; Друк маркування ===
|-
| Замовлень до відправки
| Замовлення без ЕН.; !; Поле
=== 17.4.; Графік актуалізація довідників ===
|-
| AC-4
| платформа запускає синхронізацію міст.; Призначення

 "idempotency_key": "K2-ORDER-2026-000123-np-v1",

!; |-
| AC-6
| Відділення стало неактивним.; |-
| AC-12
| користувач системи формує реєстр.;<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
 def get_warehouses(self, city_ref: str, warehouse_type: str | None = None) -> "WarehouseListResponse":
|-
| id
| uuid
| Внутрішній ID.; |-
| AC-17
| Відправлення повертається.; |-
| TrackingDocument
| Відстеження відправлень.; def get_streets(self, city_ref: str, query: str) -> "StreetListResponse":

 def get_tracking_statuses(self, document_numbers: list [str]) -> "TrackingStatusResponse":
</pre>
Метою задачі є собою створення Python-сервісу для інтеграції з Новою поштою з метою автоматизації процесів доставки.; order.status = new_status

* Офіційна сторінка інтеграції Нової пошти для бізнесу.; Ризик
 response = await client.post(self.base_url, json=payload)
 order.np_document_number = document_data.get("IntDocNumber")
=== 17.3.; Довідник вулиць ===
POST /api/v1/nova-poshta/internet-documents
 try:
!; |-
| external_order_id
| varchar
| ID замовлення K2 ERP.; |-
| Internet Document
| Експрес-накладна / ЕН / ТТН.; |-
| AC-5
| платформа запускає синхронізацію відділень.; Поле
 )
<div style="border-left: 6px solid #f57c00; background: #fff3e0; padding: 12px 16px; margin: 16px 0;">
!; |-
| Recipient
| Отримувач.; |-
| description
| varchar
| Назва міста.; |-
| np_document_ref
| varchar
| Ref ЕН.; | інтеграційні функціональні можливості зберігається в системі.; | Міста, населені пункти, відділення, поштомати, вулиці.; |-
| default_city_ref
| varchar
| Місто відправника.;</div>

=== 5.6.; Синхронізація статусів ===

* отримати API Key;
* перевірити доступ до API;
* отримати актуальну документацію;
* перевірити моделі Address, InternetDocument, TrackingDocument, ScanSheet;
* перевірити розрахунок вартості;
* перевірити створення тестової ЕН;
* перевірити друк маркування.; Колір
=== 26.2.; Довідники ===
 "volume_general": 0.01,
|-
| external_order_id
| ID замовлення в K2 ERP.; entity_id=order.id,

</div>

* суму післяплати;
* платника комісії;
* тип зворотної доставки;
* контроль статусу оплати;
* зв'язок із фінансовими документами в K2 ERP.; if not order:

* реалізувати створення ЕН;
* реалізувати мапінг K2 ERP  API Нової пошти;
* реалізувати валідацію;
* реалізувати hash документа;
* реалізувати дедублікацію.; |-
| description
| varchar
| Назва / характеристика.; | style="background:#bbdefb;" | Блакитний
|-
| Прибуло
| ARRIVED
| Відправлення прибуло у відділення / поштомат / місто.; |-
| Counterparty
| Контрагент API Нової пошти.; |-
| recipient_phone
| varchar
| Телефон отримувача.; Python-сервіс виконує валідацію.; | style="background:#c8e6c9;" | Зелений
|-
| Передано у реєстр
| IN_SCAN_SHEET
| Відправлення додано в реєстр.; | style="background:#fff9c4;" | Додаткова
|}

!; |-
| raw_response
| jsonb
| Відповідь.; |-
| idempotency_key
| varchar
| Ключ дедублікації.; new_status="PENDING_CREATE",

!; характеристика
== 19.; Черга створення ЕН ==
!;<syntaxhighlight lang="python">

POST /api/v1/nova-poshta/integrations/{integration_id}/check-connection
<div style="border-left: 6px solid #2e7d32; background: #e8f5e9; padding: 12px 16px; margin: 16px 0;">
{| class="wikitable"
|-
| Integration Account
| конфігурація API Нової пошти.; NOVA_POSHTA_API_KEY=********
 "np_document_ref": order.np_document_ref,

!; |}

=== 20.5. np_scan_sheets ===

!; |}

 pass

 order.status = "ERROR"
 order = np_order_repository.create(
== 29.; Ризики ==
!; Колір
 def delete_internet_document(self, ref: str) -> "DeleteDocumentResponse":

=== 23.3.; Проблемні відправлення ===

 "seats_amount": 1,

 audit_logger.log(
До MVP не входить:
інтеграційні функціональні можливості призначена для:
я хочу надрукувати маркування по створеній ЕН, 
|-
| ValidationError
| Некоректні інформаційні дані замовлення.; | style="background:#fff9c4;" | Додаткова
|-
| Адреса  Відділення
| DoorsWarehouse
| Кур'єр забирає у відправника, доставка у відділення.;=== 5.4.; Адресна доставка ===

* створити FastAPI-проєкт;
* налаштувати PostgreSQL;
* створити моделі інтеграції, довідників, ЕН, подій;
* налаштувати Alembic;
* реалізувати healthcheck.; | Оновлювати довідники щодня або частіше.; | Довідник відділень оновлюється.; щоб оперативно реагувати на відмови, повернення та прострочені доставки.; Призначення
<pre>
 order.error_message = str(exc)

</pre>
 "amount": 1500.00,
 if old_status != new_status:

class NovaPoshtaSettings(BaseSettings):
 "enabled": true,
Типові моделі API:

 def get_cities(self, query: str | None = None) -> "CityListResponse":

<pre>
== 13.; Конфігурація клієнта ==
== 23.; Dashboard менеджера і керівника ==
{| class="wikitable"
<pre>
 "external_order_id": command.external_order_id,
=== 12.3.; Основні методи Python-клієнта ===
{| class="wikitable"
=== 19.2.; Пріоритети задач ===
!; # Який формат друку потрібен: A4, термопринтер, PDF, Zebra?; | style="background:#fff9c4;" | Жовтий
|-
| Доставлено
| DELIVERED
| Відправлення отримано.; Критерій
PATCH /api/v1/nova-poshta/internet-documents/{document_id}
!; Дата
 "middle_name": "Іванович",
=== Етап 1.; Аналіз API Нової пошти ===
 entity_type="np_delivery_order",
 pass
=== 14.8.; Створення експрес-накладної ===
!; KPI
!; |-
| TrackingError
| Не вдалося отримати статус.; | Вони підсвічуються червоним.; if existing:

!; |-
| AC-9
| Повторний запит має той самий idempotency_key.; Пріоритет
=== 23.2.; Приклад dashboard ===
 payload = np_mapper.to_internet_document_payload(order)
 self.timeout_seconds = timeout_seconds
{
Приклад `.env`:
 base_url: str = "https://api.novaposhta.ua/v2.0/json/"
!; | Відправники, отримувачі.; Поле
{| class="wikitable"

=== 19.1.; Логіка черги ===
 },
!; |-
| DeliveryCalculationError
| Не вдалося розрахувати доставку.; Значення

== 12. Nova Poshta Client ==
</pre>
Як менеджер, 
 "np_document_number": order.np_document_number,

 db.commit()
 v
POST /api/v1/nova-poshta/directories/sync
'''Критично істотно:''' якщо ЕН уже розроблена, повторний запит не повинен створювати нову ЕН.; properties: dict | None = None,
=== 20.4. np_delivery_orders ===
=== 14.5.; Пошук відділень ===

NOVA_POSHTA_LANGUAGE=ua

order.status = "CREATED"
self.base_url = base_url

Технічний стек: Python 3.11+, FastAPI, PostgreSQL, SQLAlchemy, Alembic, httpx, Pydantic, Celery/RQ/APScheduler, Redis, Docker.; |- | ContactPerson | Контактні особи.; "delivery": {

"last_name": "Петренко",

1.; Що зберігати

<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">
 )
<pre>
!; | style="background:#ffcc80;" | Помаранчевий
|-
| Повернуто
| RETURNED
| Відправлення повернуто відправнику.; |-
| volume_general
| numeric
| Об'єм.; | K2 ERP оновлює статус відправлення.; |}

!; Очікуваний результат

== 32.; Див.; додатково ==
 delivery_queue.enqueue(
{| class="wikitable"
|-
| Створення запиту на ЕН
| Замовлення, отримувач, місто, відділення, сума.;=== 7.4.; Формування реєстру ===

* реалізувати синхронізацію статусів;
* реалізувати друк маркування;
* реалізувати реєстри;
* реалізувати retry.; |-
| city_ref
| varchar
| Ref міста.; order.raw_response = response
 if new_status == "DELIVERED":
 )

!; |-
| max_weight
| numeric
| Максимальна вага.; |-
| payment_method
| varchar
| Форма оплати.; | style="background:#c8e6c9;" | Норма
|-
| У дорозі
| Відправлення в транспортуванні.; |-
| np_scan_sheet_ref
| varchar
| Ref реєстру в Новій пошті.; def call_api(self, model_name: str, called_method: str, properties: dict) -> dict:

* повна супровід всіх додаткових послуг;
* складна робота з міжнародною доставкою;
* повна автоматизація процесів післяплати;
* автоматичне створення всіх типів контрагентів;
* складний UI складу;
* інтеграційні функціональні можливості з NovaPay;
* власна платформа доставки замість API Нової пошти.; |-
| Зміна API
| Можуть змінитись методи або поля.; # Чи потрібно підтримувати декілька відправників?; |-
| Загальні довідники
| 1 раз на добу
| Типи вантажів, сервісів, оплат.; |-
| Створення ЕН
| Високий
| ключовий бізнес-процес відвантаження.; |}

5.; |-
| Counterparty
| Контрагенти.;=== 14.3.; Синхронізація довідників ===
я хочу бачити статистику по доставках, 

я хочу сформувати реєстр відправлень, 
GET /api/v1/nova-poshta/warehouses?city_ref={city_ref}

 "modelName": model_name,
 document_data = response ["data"][0]

=== 14.11.; Друк маркування ===
=== 20.2. np_cities ===

 order.np_document_ref = document_data.get("Ref")
 except TemporaryNovaPoshtaError as exc:

{| class="wikitable"
!; |-
| Отримання статусу
| Старий статус, новий статус, джерело.; |-
| created_at
| timestamp
| Дата створення.; Код

== 14.; API Python-сервісу ==

 pass

* створено;
* прийнято у відділенні;
* у дорозі;
* прибуло у відділення;
* прибуло у поштомат;
* видано отримувачу;
* відмова;
* повернення;
* повернуто відправнику;
* зберігання;
* помилка / уточнення.; |-
| Розрахунок доставки
| Параметри, вартість, дата.; |-
| base_url
| varchar
| URL API.; # Чи потрібна інтеграційні функціональні можливості з K2 ERP документами реалізації та оплат?; №
!; |-
| Warehouse
| Відділення або поштомат.; |-
| delivery_price
| numeric
| Розрахована вартість доставки.; :contentReference [oaicite:2]{index=2}
{| class="wikitable"

=== 20.1. nova_poshta_integrations ===
<div style="border-left: 6px solid #c62828; background: #ffebee; padding: 12px 16px; margin: 16px 0;">

<pre>
 pass

{| class="wikitable"
 "city_ref": "recipient-city-ref",
Ключі дедублікації:
<div style="border-left: 6px solid #f57c00; background: #fff3e0; padding: 12px 16px; margin: 16px 0;">
Якщо застосовується післяплата або повернення коштів, потрібно передбачити:

 properties=payload,

 order = np_order_repository.get_by_id(db, delivery_order_id)
!; Як зменшити
<pre>
 new_status=new_status,

=== Етап 3.; Nova Poshta Client ===
{| class="wikitable"
=== 21.1.; Базовий API-клієнт ===

POST /api/v1/nova-poshta/delivery/calculate-date

 )

 model_name: str,

!; # Чи потрібна доставка у поштомати?; properties={
 data={
!; |-
| service_type
| varchar
| Тип доставки.; | style="background:#c8e6c9;" | Зелений
|-
| Відмова
| REFUSED
| Отримувач відмовився.; |-
| delivered_at
| timestamp
| Дата доставки.; | style="background:#c8e6c9;" | Базова
|-
| Відділення  Адреса
| WarehouseDoors
| Відправка з відділення на адресу отримувача.; |-
| AC-13
| ЕН уже в реєстрі.; |-
| style="background:#f3e5f5;" | Фіолетовий
| #f3e5f5
| Спеціальний або ручний сценарій.; |-
| Delivery Queue
| Черга створення ЕН.; |-
| DuplicateDocumentError
| ЕН уже створено.; Дія системи
'''істотно:''' у Нової пошти API-запити зазвичай будуються через поля modelName, calledMethod та methodProperties.; Тип
створення експрес-накладних забезпечується через '''Головна ідея:''' розробити Python-сервіс.; |-
| payload
| jsonb
| Технічні інформаційні дані.; Тип

 old_status = order.status
 entity_id=order.id,
</pre>
 v
|-
| id
| uuid
| ID реєстру.; | style="background:#c8e6c9;" | Норма
|-
| Відмова
| Отримувач відмовився.; Критерій
!; |-
| np_document_number
| varchar
| Номер ЕН / ТТН.; характеристика

 order = np_order_repository.get_by_document_number(db, number)
!; | Статус стає REFUSED і підсвічується червоним.; order.error_message = str(exc)
 |
 | 3.; Критерій
 "apiKey": self.api_key,
 |
 | 5.; |-
| AC-19
| є собою помилки створення ЕН.; | Dashboard, список відправлень, картка замовлення.; | Вони підсвічуються помаранчевим.; | Телефон, ПІБ, прив'язка до контрагента.; | style="background:#ef9a9a;" | Критично
|-
| Повернення
| Посилки повертаються.; |-
| schedule
| jsonb
| Графік роботи.; | Ручна перевірка, нестандартна доставка.; |-
| Area
| Область.; 

</pre>
У відкритій документації API метод `getCities` у моделі `Address` описується як метод отримання довідника населених пунктів; там же зазначено рекомендацію зберігати копію довідників на стороні клієнта й оновлювати її раз на добу.; * Ref відділення;
* номер відділення;
* назву;
* адресу;
* місто;
* тип відділення;
* максимальну вагу;
* ознаку поштомата;
* графік роботи;
* координати;
* ознаку активності.; Офіційна сторінка інтеграції описує генерацію API Key у бізнес-кабінеті, а API-портал Nova Post окремо вказує функціональні можливості для бізнесу: обробка й відправлення замовлень, доступ до функцій Nova Post та інформації про посилки.;== 31.; Джерела ==
}
 "raw_request": command.model_dump(),

Приклад hash:
 "payer_type": "Recipient",

щоб передати партію посилок у Нову пошту.; |-
| is_active
| boolean
| Активність.; Код
!; Заборонено зберігати API Key у коді, Git, frontend-змінних або відкритих логах.; характеристика
|-
| id
| uuid
| ID інтеграції.; |-
| error_message
| text
| Помилка.; :contentReference [oaicite:1]{index=1}
 )
 |
 | 4.; API Нової пошти
API Нової пошти застосовується для автоматизації логістичних процесів бізнесу.; |-
| address
| text
| Адреса.; Тип
[[Категорія:Nova Post API]]
 entity_id=order.id,
=== 14.2.; Перевірка підключення ===
 {"DocumentNumber": number}

!; |-
| PhoneValidationError
| Некоректний телефон отримувача.; Замовлення
3.; |-
| latitude
| numeric
| Широта.; |-
| AC-15
| Відправлення доставлено.;</div>

щоб платформа автономно створила експрес-накладну без ручного введення в кабінеті Нової пошти.; | style="background:#ef9a9a;" | Критично
|}

=== 14.9.; актуалізація експрес-накладної ===

!; | платформа повертає успішний або помилковий статус.; |}

</div>

<div style="border-left: 6px solid #6a1b9a; background: #f3e5f5; padding: 12px 16px; margin: 16px 0;">

Довідник міст потрібен для вибору коректного `CityRef`.; |-
| ref
| varchar
| Ref міста в Новій пошті.; |-
| np_status
| varchar
| Оригінальний статус Нової пошти.; | Окрема шахматка повернень і статусів.; характеристика
 timeout_seconds: int = 30
</pre>
=== 17.2.; Довідник відділень і поштоматів ===
=== 5.3.; Доставка у поштомат ===
{| class="wikitable"
[[Категорія:Інтеграції]]
 def update_internet_document(self, ref: str, payload: "InternetDocumentPayload") -> "InternetDocumentResponse":
=== 21.4.; Синхронізація статусів ===
class NovaPoshtaClient:
 order.sent_at = utc_now()

=== 26.1.; інтеграційні функціональні можливості ===

=== 23.1.; Основні KPI ===
=== 5.2.; Доставка у відділення ===
async def sync_np_statuses(document_numbers: list [str], db: "Session") -> None:
9.; | ЕН додаються до реєстру.; характеристика

 called_method: str,
=== 14.7.; Розрахунок дати доставки ===
!; Тип задачі
POST /api/v1/nova-poshta/delivery/calculate-price
[[Категорія:API]]
!; "phone": "+380501112233"

{| class="wikitable"
щоб наклеїти його на посилку.; Замовлення доставляється у відділення Нової пошти.; характеристика

<pre>
7.; # Чи потрібно формувати реєстри?; |-
| updated_at
| timestamp
| Дата актуалізація.; Валідація, мапінг, дедублікація, черга
Замовлення доставляється кур'єром на адресу.; |-
| AC-2
| Адміністратор перевіряє підключення.; | Валідація параметрів вантажу.; | style="background:#eeeeee;" | Сірий
|-
| Очікує створення ЕН
| PENDING_CREATE
| Замовлення в черзі на створення ЕН.; |-
| raw_request
| jsonb
| Запит.; |-
| number
| varchar
| Номер відділення.; характеристика
Для реалізації задачі необхідно отримати:
!; |}

== 28.; Етапи реалізації ==

}
10.; Коментар

 "service_type": command.delivery.service_type,
 },
== 25.; Логування та аудит ==

{| class="wikitable"

== 8.; Типи доставки ==
 },
Нова пошта

=== 26.3.; Створення ЕН ===

 response = await nova_poshta_client.call_api(
=== 17.1.; Довідник міст ===
'''істотно:''' конкретний modelName, calledMethod і methodProperties потрібно брати з актуальної документації API Нової пошти.; |-
| Delivery Order
| Замовлення на доставку в K2 ERP.; |-
| recipient_name
| varchar
| ПІБ отримувача.; * Офіційна документація API Нової пошти в кабінеті / API-порталі.; "counterparty_ref": "sender-counterparty-ref",

 entity_type="np_delivery_order",
import httpx
<syntaxhighlight lang="json">

8.; Критерій

 v
=== 26.5.; Статуси ===

 db.commit()
== 21.; Приклад Python-логіки ==
== 16.; Валідація перед створенням ЕН ==

NOVA_POSHTA_RETRY_BACKOFF_SECONDS=5

[[Категорія:K2 ERP]]
=== 7.5.; Dashboard керівника ===


!; |-
| recipient_ref
| varchar
| Отримувач, якщо створений.; характеристика
|-
| id
| uuid
| ID події.; | style="background:#ffcc80;" | Важлива
|-
| Відділення  Поштомат
| WarehousePostomat
| Доставка в поштомат, якщо підтримується сценарієм.; |-
| API Event
| Подія інтеграції.; |-
| AC-3
| API Key неправильний.; |-
| Nova Poshta Client
| Python-клієнт для API Нової пошти.; |}

</div>

</pre>
== 5.; Основні бізнес-сценарії ==
 existing = np_order_repository.get_by_idempotency_key(
 retry_backoff_seconds: int = 5
|-
| AC-14
| Tracking API повертає новий статус.; |}

Етап 5.; ЕН і валідація

async with httpx.AsyncClient(timeout=self.timeout_seconds) as client:

!; |- | Print Service | Отримує PDF / маркування / друковані форми.; old_status=old_status,

15.; Приклад запиту на створення ЕН

"apiKey": "********",

Критично істотно: API Key потрібно зберігати тільки в зашифрованому вигляді або secret storage.; |- | recipient_warehouse_ref | varchar | Відділення / поштомат.; характеристика

GET /api/v1/nova-poshta/dashboard?date_from=2026-05-01&date_to=2026-05-31

"idempotency_key": command.idempotency_key,

7. User Story

def create_scan_sheet(self, document_refs: list [str]) -> "ScanSheetResponse":

POST /api/v1/nova-poshta/tracking/sync

- Mapping Layer Номер зберігається в K2 ERP.; |- Відділення 1 раз на добу або частіше - Синхронізація статусів Середній Статус стає DELIVERED і підсвічується зеленим.; |} Відмова, помилка API, неправильна адреса.; {| class="wikitable"
"city_ref": "sender-city-ref",

K2 ERP / Dashboard / складський облік / Менеджер

Перед створенням експрес-накладної платформа повинна перевірити:

pass

NOVA_POSHTA_RETRY_COUNT=3

payload={
  • перевіряє замовлення;
  • перевіряє отримувача;
  • перевіряє місто;
  • перевіряє відділення / адресу;
  • розраховує вартість доставки;
  • створює експрес-накладну;
  • зберігає номер ЕН;
  • передає номер ЕН назад у K2 ERP;
  • формує маркування для друку.; | style="background:#bbdefb;" | В роботі
Прибуло Повернути існуючу ЕН.; |- Tracking Status Статус доставки.; Тип
"cost": command.delivery.cost,
"sender": {
</div>
|-
| AC-1
| Адміністратор створює інтеграцію Нової пошти.; |-
| Друк маркування
| Хто надрукував, коли, формат.; |}

 data = response.json()

=== 11.2.; Основні компоненти Python-сервісу ===
== 18.; Дедублікація ==
POST /api/v1/nova-poshta/scan-sheets
 "recipient_warehouse_ref": command.recipient.warehouse_ref,
|-
| AC-11
| користувач системи натискає «Друк маркування».; |}

== 17.; Довідники Нової пошти ==

 pass
 def get_print_form(self, document_refs: list [str], format: str = "pdf") -> bytes:
POST /api/v1/nova-poshta/internet-documents/{document_id}/cancel
!;<pre>

* реалізувати dashboard API;
* реалізувати список проблемних відправлень;
* реалізувати фільтри;
* реалізувати експорт, якщо потрібно.; |-
| Повторна операційна дія
| Хто запустив, причина, результат.; |-
| AC-8
| API повертає номер ЕН.; |-
| ApiError
| API повернув помилку.; |-
| Common
| Загальні довідники.; |-
| status
| varchar
| Статус K2 ERP.; |-
| status
| varchar
| Статус.; |-
| style="background:#bbdefb;" | Блакитний
| #bbdefb
| операційна дія виконується або доставка в процесі.; | Черга, retry, dashboard помилок.; | Повернення, retry, проблемні статуси.; |-
| new_status
| varchar
| Новий статус.; | style="background:#c8e6c9;" | Норма
|-
| Маркування надруковано
| Готові до пакування відправлення.; | Валідація номера до відправки.; Статус K2 ERP
 order.delivered_at = utc_now()
 "backward_delivery": {
 called_method="getStatusDocuments",
!; |-
| API Layer
| REST API для прийому замовлень і команд із K2 ERP.; |-
| sent_at
| timestamp
| Дата створення ЕН.; | style="background:#c8e6c9;" | Зелений
|-
| Маркування надруковано
| MARKING_PRINTED
| Маркування або PDF отримано / надруковано.; |-
| settlement_type
| varchar
| Тип населеного пункту.; Статус
 "warehouse_ref": "recipient-warehouse-ref"
 "methodProperties": properties or {},
'''істотно:''' коди сервісів і доступність конкретних сценаріїв потрібно перевірити за довідниками API Нової пошти, оскільки правила можуть змінюватися.; !; |-
| Дублювання ЕН
| Повторний запит має змогу створити другу накладну.; response = await nova_poshta_client.call_api(
 payload=item,
 "weight": 2.5,
 event_type="NP_DOCUMENT_CREATED",
 retry_count: int = 3
!; |-
| entity_type
| varchar
| integration, order, document, scan_sheet, directory.; |}

=== 7.1.; Створення ЕН ===

<pre>

 audit_logger.log(
 self,
 |
 | 1.; Поле

 payload={"external_order_id": command.external_order_id},


!; |-
| Validation Layer
| Перевіряє отримувача, адресу, відділення, вагу, габарити, оплату.; |-
| Недоступність API
| ЕН не створюються.; K2 ERP створює замовлення.; |-
| City
| Місто / населений пункт з довідника Нової пошти.; Довідник
|-
| id
| uuid
| Внутрішній ID.; | Довідник міст оновлюється.; # Чи потрібна інтеграційні функціональні можливості з NovaPay?; Стан
 "contact_ref": "sender-contact-ref",

!; |-
| WarehouseNotFoundError
| Відділення або поштомат не знайдено.; | style="background:#ffcc80;" | Помаранчевий
|-
| Скасовано
| CANCELLED
| ЕН або замовлення скасовано.; !; |-
| SettlementTypeDescription
| Тип населеного пункту.; | Архів, чернетки.; !; |-
| document_hash
| Hash основних параметрів відправлення.; Показник

* наявність external_order_id;
* наявність idempotency_key;
* чи не розроблена вже ЕН для цього замовлення;
* API Key активний;
* місто відправника існує;
* місто отримувача існує;
* відділення або поштомат існує;
* відділення активне;
* телефон отримувача валідний;
* ПІБ отримувача заповнено;
* вага більше 0;
* кількість місць більше 0;
* оголошена вартість більше або дорівнює 0;
* тип сервісу сумісний із адресними даними;
* післяплата не перевищує правила бізнесу;
* платник доставки визначений;
* форма оплати визначена;
* характеристика вантажу заповнений.; | style="background:#ef9a9a;" | Червоний
|-
| Потребує повтору
| NEEDS_RETRY
| Технічна помилка, можна повторити.; Критерій

K2 ERP передає в Python-сервіс замовлення, інформаційні дані отримувача, місто, відділення або адресу, параметри вантажу та оплату.; |-
| Скасування ЕН
| Хто скасував, причина.; |}

 "external_order_id": "K2-ORDER-2026-000123",

!; Отримувач
 v
Замовлення доставляється у поштомат.; |-
| style="background:#ef9a9a;" | Червоний
| #ef9a9a
| Помилка або негативний результат.; Окремо варто відзначити який інтегрує K2 ERP / CRM / інтернет-магазин / WMS із API Нової пошти; додатково реалізовано розрахунку вартості доставки, синхронізації довідників, отримання статусів, друку маркувань і контролю відправлень.; |}

{| class="wikitable"

<syntaxhighlight lang="json">

!; |-
| default_contact_ref
| varchar
| Контакт за замовчуванням.; | style="background:#fff9c4;" | Контроль
|-
| Доставлено
| Успішні доставки.; 

* реалізувати 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;
* реалізувати обробку помилок.; |-
| is_active
| boolean
| Активність.; |-
| CityNotFoundError
| Місто не знайдено.; |-
| seats_amount
| integer
| Кількість місць.; |-
| style="background:#ffcc80;" | Помаранчевий
| #ffcc80
| Потрібна дія або є собою ризик.; Поле

== 9.; Статуси відправлень ==

[[Категорія:Логістика]]

=== 21.3.; Worker створення ЕН ===
== 2.; Область сфера застосування ==
 pass

 entity_type="np_delivery_order",

{| class="wikitable"
 async def call_api(
платформа повинна забезпечити:

'''Управлінський результат:''' менеджер і керівник повинні бачити, скільки замовлень передано в Нову пошту, скільки ЕН створено, які посилки доставлені, які очікують отримання, які повертаються, де є собою помилки адреси, оплати, ваги або статусу.; ЕН, статуси, маркування, реєстри
!; |-
| AC-10
| Відділення не знайдено.; |-
| ref
| varchar
| Ref відділення.; | Перевести в NEEDS_CORRECTION.; 
 "recipient_phone": command.recipient.phone,
pass
Міста 1 раз на добу - old_status varchar Попередній статус.; HTML

6.; |-

default_warehouse_ref varchar Відділення відправника.; характеристика
AC-7 style="background:#ffcc80;" | Помаранчевий
Помилка ERROR - AC-20 - raw_response jsonb Відповідь API.; №
payload={"delivery_order_id": str(order.id)},
; # Чи потрібно підтримувати міжнародну доставку?; ) - Sender Відправник.; Замовлення, замовник, адреса, вантаж

Як працівник складу,

"recipient": {
} - ScanSheet Реєстри прийому-передачі.; характеристика
  • зберігання налаштувань інтеграції;
  • отримання та актуалізація довідників Нової пошти;
  • пошук міст;
  • пошук відділень;
  • пошук поштоматів;
  • пошук вулиць;
  • створення контрагентів або використання існуючих;
  • створення контактних осіб;
  • створення адрес;
  • розрахунок вартості доставки;
  • розрахунок орієнтовної дати доставки;
  • створення експрес-накладної;
  • редагування експрес-накладної, якщо дозволено API;
  • видалення / скасування експрес-накладної, якщо дозволено API;
  • друк маркування;
  • формування реєстру відправлень;
  • отримання статусів відправлень;
  • синхронізацію статусів назад у K2 ERP;
  • журналювання всіх API-запитів;
  • dashboard для контролю логістики.; |-
Directory Sync Worker - provider varchar - created_at timestamp Статус стає RETURNING і підсвічується помаранчевим.; K2 ERP отримує номер ЕН.; | Idempotency key і перевірка external_order_id.; | Python-сервіс створює ЕН.; | Check-connection і повідомлення адміністратору.; Створюється запис delivery_order зі статусом PENDING_CREATE.; |- TimeoutError - Contact Person - DescriptionRu Назва російською, якщо доступна.; Коментар

</syntaxhighlight>

{{SEO
!; "cargo_type": "Parcel",

* реалізувати синхронізацію міст;
* реалізувати синхронізацію відділень;
* реалізувати пошук;
* реалізувати кешування;
* реалізувати регламентне актуалізація.; Tracking Worker оновлює статуси доставки.; |-
| style="background:#fff9c4;" | Жовтий
| #fff9c4
| Очікування або прибуття.;=== 26.4.; Друк і реєстри ===

 return

* інтернет-магазинів;
* CRM;
* ERP;
* WMS;
* складів;
* служб доставки;
* торгових компаній;
* дистриб'юторів;
* компаній, які створюють багато експрес-накладних;
* компаній, які хочуть контролювати доставку прямо з K2 ERP.; |-
| default_sender_ref
| varchar
| Відправник за замовчуванням.; |}

 },

# Який бізнес-кабінет і API Key використовуються?; |-
| np_document_number
| Номер ЕН / ТТН.; | Він бачить замовлення, ЕН, доставки, відмови, повернення та помилки.; # Чи потрібно автономно друкувати маркування після створення ЕН?; "cargo_type": command.delivery.cargo_type,

Як керівник, 

я хочу бачити статус доставки прямо в K2 ERP,

Ref Зупинити інтеграцію, повідомити адміністратора.; Конкретні моделі та методи потрібно звіряти з актуальною офіційною документацією API перед реалізацією production-версії.; Ключ
model_name="InternetDocument",

GET /api/v1/nova-poshta/internet-documents/{document_id}/print-form

|-
| 07.05.2026
| K2-ORDER-123
| -
| Іван Петренко
| style="background:#ef9a9a;" | Помилка
| Не знайдено відділення
| Виправити адресу
|-
| 07.05.2026
| K2-ORDER-124
| 20450000000000
| Олена Сидоренко
| style="background:#ef9a9a;" | Відмова
| Відмова отримувача
| Зв'язатися з клієнтом
|-
| 07.05.2026
| K2-ORDER-125
| 20450000000001
| ТОВ «Альфа»
| style="background:#ffcc80;" | Повернення
| Не отримано вчасно
| Контроль повернення
|}

POST /api/v1/nova-poshta/integrations

== 26. Acceptance Criteria ==

* зберігання API Key тільки у secret storage або в зашифрованому вигляді;
* заборону логування API Key;
* HTTPS для всіх API-запитів;
* перевірку SSL;
* рольову модель доступу;
* окремі права на створення ЕН;
* окремі права на скасування ЕН;
* окремі права на друк маркувань;
* окремі права на формування реєстрів;
* журнал усіх дій;
* захист від дублювання ЕН;
* маскування телефонів отримувачів у логах;
* контроль доступу до персональних даних.; | style="background:#fff9c4;" | Додаткова
|-
| Адреса → Адреса
| DoorsDoors
| Кур'єрська доставка від дверей до дверей.; |-
| api_key_encrypted
| text
| Зашифрований API Key.; class NovaPoshtaApiError(Exception):

=== Етап 8.; Production hardening ===

Синхронізуються:
=== 14.13.; Створення реєстру ===
 "payer": "Recipient"

 task_name="send_np_document",

; "modelName": "InternetDocument",
language: str = "ua"
]
"phone": "+380671112233",
До MVP входить: pass }, Як менеджер інтернет-магазину,

30.; Відкриті питання

called_method="save",
def get_document_delivery_date(self, payload: "DeliveryDatePayload") -> "DeliveryDateResponse":

платформа повинна логувати:

 model_name="TrackingDocument",
 }
=== Етап 7.; Dashboard та аудит ===

!; |-
| Description
| Назва українською.; |-
| backward_delivery_amount
| numeric
| Сума післяплати.; | Повторити фоново.; def create_internet_document(self, payload: "InternetDocumentPayload") -> "InternetDocumentResponse":
!; |-
| AuthError
| Невірний API Key.; 

 event_type="NP_STATUS_SYNCED",
=== 14.1.; Створення інтеграції ===

 "weight": command.delivery.weight,
!; Worker викликає API Нової пошти.; |-
| Створення ЕН
| Номер ЕН, Ref, дата, відповідь API.;</pre>

 for number in document_numbers

 "cost": 1500.00,

=== 21.2.; Створення ЕН ===
=== 14.12.; Синхронізація статусів ===
 audit_logger.log(
 def check_connection(self) -> "ConnectionStatus":
|-
| Address
| Робота з адресними довідниками.; | ЕН не створюється, статус NEEDS_CORRECTION.; # Чи потрібно створювати контрагентів через API?; Подія
 if order.status in ["CREATED", "DELIVERED"] and order.np_document_number:
!; Очікуваний результат
=== 12.1.; Призначення ===

Python-сервіс:

!; Де застосовується

[[Категорія:Python]]

[[Категорія:Нова пошта]]
Як комірник, 
 return existing

{| class="wikitable"

{{DISPLAYTITLE:Технічне завдання: Інтеграція з Новою поштою для Python}}
== 20.; Модель даних ==
 ) -> dict:

 )

Python-сервіс регулярно отримує статуси відправлень і оновлює K2 ERP.; |-
| Tracking Worker
| Оновлює статуси відправлень.; |-
| weight
| numeric
| Вага.; Компонент
</pre>

 if not data.get("success"):

 verify_ssl: bool = True
Потрібно передати:
<div style="border-left: 6px solid #1565c0; background: #e3f2fd; padding: 12px 16px; margin: 16px 0;">
== 11.; технічна архітектура рішення для бізнесу ==
=== 14.14. Dashboard ===
|-
| Чернетка
| DRAFT
| Замовлення є собою в K2 ERP, але ЕН ще не створено.; |-
| Друк маркування
| Високий
| Потрібно для складу.; Критерій
 def __init__(self, base_url: str, api_key: str, timeout_seconds: int = 30):
<pre>
щоб контролювати якість логістики, повернення, затримки та помилки.; continue

!; # Чи потрібна післяплата?; {| class="wikitable"

* неправильного API Key;
* помилок валідації;
* неправильного міста;
* неправильного відділення;
* некоректного телефону;
* ЕН, яка вже розроблена;
* ЕН, яка вже доставлена;
* ЕН, яка вже скасована.; | style="background:#fff9c4;" | Увага
|-
| ЕН створено
| Кількість створених ЕН.; |-
| idempotency_key
| Унікальний ключ конкретної спроби створення ЕН.;=== 14.6.; Розрахунок вартості доставки ===
|-
| Неправильний API Key
| інтеграційні функціональні можливості не працюватиме.; Поле
!; Очікуваний результат
 raise NovaPoshtaApiError(str(data.get("errors") or data))
!; :contentReference [oaicite:3]{index=3}
== 1.; Мета ==
=== 11.1.; Загальна схема ===
|-
| AC-18
| Менеджер відкриває dashboard.; |-
| created_at
| timestamp
| Дата створення.; | Перевести в NEEDS_CORRECTION.; payload = {

!; |-
| Scan Sheet
| Реєстр прийому-передачі.;=== Етап 4.; Довідники ===
<div style="border-left: 6px solid #f57c00; background: #fff3e0; padding: 12px 16px; margin: 16px 0;">
== 22.; Обробка помилок ==
async def create_np_document(command: "CreateNpDocumentCommand", db: "Session") -> "NpDeliveryOrder":
|-
| id
| uuid
| ID доставки.; |-
| style="background:#eeeeee;" | Сірий
| #eeeeee
| Чернетка, скасовано або неактивно.; |}

 "warehouse_ref": "sender-warehouse-ref",

платформа повинна не допускати дублювання ЕН.; | Отримання статусів за номерами ЕН.; # Чи потрібно показувати строк зберігання у відділенні?; Python-сервіс зберігає номер ЕН.; |-
| Помилка API
| Код, повідомлення, raw-відповідь.; |-
| Address
| Адреса для кур'єрської доставки.; | Його не можна вибрати для нових ЕН.; Тип помилки

== 4.; Передумови ==
"calledMethod": "save",

22.1.; Типи помилок

"recipient_name": command.recipient.full_name,
db.commit()
K2 ERP / CRM / Website / WMS

22.2.; Retry-логіка

np_validator.validate(command)
return data

3.; Основні функціональні можливості API Нової пошти

event_type="NP_DOCUMENT_QUEUED",
"Documents": [

NOVA_POSHTA_BASE_URL=https://api.novaposhta.ua/v2.0/json/

idempotency_key=command.idempotency_key,
"first_name": "Іван",
db.commit()
- Неправильний телефон - event_type varchar style="background:#bbdefb;" | Блакитний
Прийнято Новою поштою ACCEPTED_BY_NP Типи вантажу, типи сервісу, форми оплати тощо.; Причина