Files
lux_fiscal/backend/app/services/nova_poshta/np_client.py
lauadminandClaude Opus 5.5 b8f2fe6b6e Translate UI and user-facing messages to Ukrainian (#5)
- 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>
2026-09-25 15:27:39 +03:00

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", [])]