"""Схема статуса ТТН Nova Poshta (`TrackingDocument.getStatusDocuments`). Поля валидируются из "сырых" PascalCase-ключей ответа NP через `Field(alias=...)`, как и `OrderOut` для CRM. Суммы остаются строками "как есть" от NP — в integer-копейки переводится только на границе с персистентной моделью. """ from __future__ import annotations from typing import Any from pydantic import BaseModel, ConfigDict, Field, model_validator class TrackingStatusOut(BaseModel): model_config = ConfigDict(populate_by_name=True) number: str = Field(alias="Number") status: str = Field(alias="Status") status_code: str = Field(alias="StatusCode") payment_method: str | None = Field(default=None, alias="PaymentMethod") scheduled_delivery_date: str | None = Field(default=None, alias="ScheduledDeliveryDate") actual_delivery_date: str | None = Field(default=None, alias="ActualDeliveryDate") # Чистая сумма к перечислению продавцу за товар — поле `AfterpaymentOnGoodsCost` # ("Контроль оплати" в кабинете NP). В отличие от `AmountToPay`/ # `ExpressWaybillAmountToPay` (сколько получатель должен заплатить НП прямо # сейчас — включает стоимость доставки и комиссию НП и обнуляется после # оплаты), это поле — зафиксированная при создании ТТН сумма за товар без # доставки и комиссии, и не меняется по ходу доставки. `AmountToPay`/ # `ExpressWaybillAmountToPay` — запасной вариант на случай, если NP для # какого-то типа накладной не возвращает `AfterpaymentOnGoodsCost`. cod_amount: str | None = Field(default=None) # Статус оплаты аналогично раздвоен на `PaymentStatus`/`ExpressWaybillPaymentStatus`. payment_status: str | None = Field(default=None) @model_validator(mode="before") @classmethod def _fold_express_fields(cls, data: Any) -> Any: if not isinstance(data, dict): return data data = dict(data) afterpayment = data.get("AfterpaymentOnGoodsCost") fallback = data.get("AmountToPay") or data.get("ExpressWaybillAmountToPay") or None data.setdefault("cod_amount", str(afterpayment) if afterpayment else fallback) data.setdefault( "payment_status", data.get("PaymentStatus") or data.get("ExpressWaybillPaymentStatus") or None, ) return data