Each cash register stores its own encrypted NP API key. Status polling uses register keys and binds an order to the register whose key sees the TTN as its own (PhoneSender present); ETTN receipts are created from that register. Migration 0008 moves the old NOVA_POSHTA_API_KEY into the default register. Closes #3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 lines
1.7 KiB
Python
47 lines
1.7 KiB
Python
"""Фикстурный клиент Nova Poshta для тестов — не ходит в сеть."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from app.schemas.tracking import TrackingStatusOut
|
|
|
|
_FIXTURE_STATUSES: dict[str, dict] = {
|
|
"20450123456789": {
|
|
"Number": "20450123456789",
|
|
"Status": "Відправлення отримано",
|
|
"StatusCode": "9",
|
|
"PaymentMethod": "Cash",
|
|
"ScheduledDeliveryDate": "22-09-2026 18:00:00",
|
|
"ActualDeliveryDate": "22-09-2026 15:30:00",
|
|
"AmountToPay": "1200.00",
|
|
"AfterpaymentOnGoodsCost": 1200,
|
|
"PaymentStatus": "Paid",
|
|
"PhoneSender": "380501112233",
|
|
}
|
|
}
|
|
|
|
|
|
class StubNovaPoshtaClient:
|
|
"""`statuses` — ответы NP по ТТН; `by_key` — отдельные ответы для конкретных
|
|
ключей API (кабинет отправителя видит свои ТТН полностью, чужие — урезанно)."""
|
|
|
|
def __init__(
|
|
self,
|
|
statuses: dict[str, dict] | None = None,
|
|
*,
|
|
by_key: dict[str, dict[str, dict]] | None = None,
|
|
) -> None:
|
|
self._statuses = statuses if statuses is not None else _FIXTURE_STATUSES
|
|
self._by_key = by_key or {}
|
|
self.calls: list[tuple[str, list[str]]] = []
|
|
|
|
async def get_statuses(
|
|
self, *, api_key: str, waybill_numbers: list[str]
|
|
) -> list[TrackingStatusOut]:
|
|
self.calls.append((api_key, list(waybill_numbers)))
|
|
statuses = self._by_key.get(api_key, self._statuses)
|
|
return [
|
|
TrackingStatusOut.model_validate(statuses[number])
|
|
for number in waybill_numbers
|
|
if number in statuses
|
|
]
|