Убрали ПВЗ для КСЕ, и поправили формирование тарифа КСЕ
Deploy / deploy (push) Successful in 1m8s

This commit is contained in:
Раис Юсупалиев
2026-05-31 21:34:00 +03:00
parent 6c0f97adf6
commit c2757d24fc
8 changed files with 254 additions and 67 deletions
+80 -6
View File
@@ -7,7 +7,10 @@ import httpx
import structlog
from app.adapters.delivery_providers.base import DeliveryProvider
from app.adapters.delivery_providers.cse.constants import CSE_PROVIDER_NAME
from app.adapters.delivery_providers.cse.constants import (
CSE_PROVIDER_NAME,
delivery_type_requires_pvz,
)
from app.adapters.delivery_providers.cse.errors import (
CSEClientError,
CSEMappingError,
@@ -24,10 +27,12 @@ from app.adapters.delivery_providers.cse.order_mapper import (
build_calc_body_for_payment,
map_cse_save_order_request,
map_cse_save_order_response,
split_tariff_code,
)
from app.adapters.delivery_providers.cse.soap import (
Element,
build_envelope,
make_field,
parse_response,
)
from app.config import AdapterConfig
@@ -71,6 +76,27 @@ class CSEClient:
request_error_message="CSE calc request was rejected with status",
)
async def get_delivery_types(self) -> list[tuple[str, str]]:
"""Return available delivery schemes as (name, human label) pairs."""
body = {
"parameters": Element(
key="parameters",
items=[make_field("Reference", "DeliveryType")],
)
}
root = await self._post(
"GetReferenceData",
body,
request_error_message="CSE delivery types request was rejected with status",
)
result: list[tuple[str, str]] = []
for entry in root.items:
name = entry.value
if name:
result.append((name, entry.field_value("Information") or name))
return result
async def save_order(
self, request: InitPaymentRequest, order_uuid: str
) -> CSEOrderRegistrationResult:
@@ -183,6 +209,7 @@ class CSEProvider(DeliveryProvider):
def __init__(self, client: CSEClient, *, cache_ttl_seconds: int = 900) -> None:
self._client = client
self.cache_ttl_seconds = cache_ttl_seconds
self._delivery_types: list[tuple[str, str]] | None = None
@classmethod
def from_adapter_config(
@@ -200,7 +227,6 @@ class CSEProvider(DeliveryProvider):
payer=adapter_config.cse_payer,
payment_method=adapter_config.cse_payment_method,
shipping_method=adapter_config.cse_shipping_method,
urgency=adapter_config.cse_urgency,
),
timeout_seconds=adapter_config.cse_timeout_seconds,
retry_attempts=adapter_config.cse_retry_attempts,
@@ -211,23 +237,71 @@ class CSEProvider(DeliveryProvider):
async def get_prices(
self, request: DeliveryCalculationRequest
) -> list[DeliveryPrice]:
body = build_calc_body_for_calculation(request)
delivery_types = await self._resolve_delivery_types()
results = await asyncio.gather(
*(
self._prices_for_delivery_type(request, name, label)
for name, label in delivery_types
),
return_exceptions=True,
)
prices: list[DeliveryPrice] = []
errors: list[BaseException] = []
for result in results:
if isinstance(result, BaseException):
errors.append(result)
else:
prices.extend(result)
if not prices and errors:
raise errors[0]
return prices
async def _prices_for_delivery_type(
self,
request: DeliveryCalculationRequest,
delivery_type: str,
delivery_type_label: str,
) -> list[DeliveryPrice]:
body = build_calc_body_for_calculation(request, delivery_type)
root = await self._client.calc(body)
try:
return map_cse_calc_response(root)
return map_cse_calc_response(
root,
delivery_type=delivery_type,
delivery_type_label=delivery_type_label,
)
except CSEMappingError as exc:
raise CSEClientError("CSE calc response payload is invalid.") from exc
async def _resolve_delivery_types(self) -> list[tuple[str, str]]:
if self._delivery_types is None:
self._delivery_types = await self._client.get_delivery_types()
# Exclude schemes that require a pickup point (PVZ) at registration,
# since PVZ is not yet supported (only door-to-door is fulfillable).
usable = [
(name, label)
for name, label in self._delivery_types
if not delivery_type_requires_pvz(name, label)
]
# Fall back to the contract-default scheme (empty delivery_type) so
# calculation still works if no usable schemes are returned.
return usable or [("", "")]
async def get_payment_price(
self,
request: InitPaymentRequest,
) -> DeliveryPrice | None:
body = build_calc_body_for_payment(request)
tariff_code = request.system_data.tariff.tariff_code
delivery_type, _ = split_tariff_code(tariff_code)
body = build_calc_body_for_payment(request, delivery_type)
root = await self._client.calc(body)
try:
return map_cse_calc_response_for_tariff_code(
root,
tariff_code=request.system_data.tariff.tariff_code,
tariff_code=tariff_code,
)
except CSEMappingError as exc:
raise CSEClientError(