"""CDEK response mapper to unified delivery schema.""" from decimal import Decimal from typing import Any from app.schemas.response import DeliveryPrice class CDEKMappingError(ValueError): """Raised when CDEK response cannot be mapped.""" def map_cdek_response(payload: dict[str, Any]) -> list[DeliveryPrice]: tariffs = _get_tariffs(payload) payload_currency = payload.get("currency") return [ _map_tariff(tariff, payload_currency=payload_currency) for tariff in tariffs ] def map_cdek_response_for_tariff_code( payload: dict[str, Any], *, tariff_code: int, ) -> DeliveryPrice | None: tariff_codes = payload.get("tariff_codes") if not isinstance(tariff_codes, list): raise CDEKMappingError("CDEK response must include tariff_codes.") payload_currency = payload.get("currency") for tariff in tariff_codes: if not isinstance(tariff, dict): raise CDEKMappingError("CDEK tariff entry must be an object.") if _tariff_code_matches(tariff.get("tariff_code"), tariff_code): return _map_tariff(tariff, payload_currency=payload_currency) return None def _map_tariff( tariff: dict[str, Any], *, payload_currency: object, ) -> DeliveryPrice: service_name = tariff.get("tariff_name") or tariff.get("tariff_code") if service_name is None: raise CDEKMappingError("CDEK tariff_name is missing.") raw_price = tariff.get("delivery_sum") if raw_price is None: raise CDEKMappingError("CDEK delivery_sum is missing.") period_min = tariff.get("period_min") if period_min is None: raise CDEKMappingError("CDEK period_min is missing.") period_max = tariff.get("period_max", period_min) raw_currency = tariff.get("currency") or payload_currency or "RUB" try: return DeliveryPrice( provider="cdek", service_name=str(service_name), price=Decimal(str(raw_price)), currency=str(raw_currency).upper(), delivery_days_min=int(period_min), delivery_days_max=int(period_max), tariff_code=_extract_tariff_code(tariff.get("tariff_code")), bypass_parcel_type_filter=True, ) except (ArithmeticError, TypeError, ValueError) as exc: raise CDEKMappingError("CDEK response fields have invalid values.") from exc def _get_tariffs(payload: dict[str, Any]) -> list[dict[str, Any]]: tariff_codes = payload.get("tariff_codes") if not isinstance(tariff_codes, list) or not tariff_codes: raise CDEKMappingError("CDEK response must include non-empty tariff_codes.") tariffs: list[dict[str, Any]] = [] for tariff in tariff_codes: if not isinstance(tariff, dict): raise CDEKMappingError("CDEK tariff entry must be an object.") tariffs.append(tariff) return tariffs def _tariff_code_matches(value: object, expected_tariff_code: int) -> bool: if isinstance(value, bool) or value is None: return False try: return int(value) == expected_tariff_code except (TypeError, ValueError): return False def _extract_tariff_code(value: object) -> int | None: if isinstance(value, bool) or value is None: return None try: return int(value) except (TypeError, ValueError): return None