- All frontend pages, labels, notices and errors; html lang=uk, uk-UA money format - Brand "Assistant System" in the top bar and page title - Backend error details returned to the UI (auth, orders, receipts, cash registers, Checkbox/CRM/NP errors) and CLI output - Tests updated for the new messages Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
48 lines
1.7 KiB
Python
48 lines
1.7 KiB
Python
"""Реальный клиент Nova Poshta (`TrackingDocument.getStatusDocuments`)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import httpx
|
|
|
|
from app.schemas.tracking import TrackingStatusOut
|
|
from app.services.nova_poshta.client import NovaPoshtaError
|
|
|
|
_API_URL = "https://api.novaposhta.ua/v2.0/json/"
|
|
|
|
# NP отклоняет запросы с более чем 100 накладными за раз.
|
|
_MAX_DOCUMENTS_PER_REQUEST = 100
|
|
|
|
|
|
class NpTrackingClient:
|
|
async def get_statuses(
|
|
self, *, api_key: str, waybill_numbers: list[str]
|
|
) -> list[TrackingStatusOut]:
|
|
if not waybill_numbers:
|
|
return []
|
|
if len(waybill_numbers) > _MAX_DOCUMENTS_PER_REQUEST:
|
|
raise NovaPoshtaError(
|
|
f"Забагато ТТН за один запит: {len(waybill_numbers)} "
|
|
f"(максимум {_MAX_DOCUMENTS_PER_REQUEST})"
|
|
)
|
|
|
|
body = {
|
|
"apiKey": api_key,
|
|
"modelName": "TrackingDocument",
|
|
"calledMethod": "getStatusDocuments",
|
|
"methodProperties": {
|
|
"Documents": [{"DocumentNumber": number, "Phone": ""} for number in waybill_numbers]
|
|
},
|
|
}
|
|
|
|
async with httpx.AsyncClient(timeout=30) as client:
|
|
response = await client.post(_API_URL, json=body)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
|
|
if not data.get("success"):
|
|
errors = data.get("errors") or []
|
|
message = "; ".join(str(error) for error in errors)
|
|
raise NovaPoshtaError(f"NP повернув помилку: {message or 'невідома помилка'}")
|
|
|
|
return [TrackingStatusOut.model_validate(item) for item in data.get("data", [])]
|