Wires the CRM (exoCRM GetOrders) into the dashboard as a locally persisted order queue instead of the previous static mockup: - CrmClient Protocol + ExoCrmClient/StubCrmClient for the CRM's signed JSON-RPC API - Order model + migration, synced from CRM on each queue view; soft-deleted orders stay hidden across re-syncs - GET/DELETE /api/v1/orders with "no receipt"/"receipt issued" tabs (the latter is empty until Checkbox fiscalization lands) - Dashboard: real order list, item-detail modal, tab switcher, one-click delete Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
47 lines
1.6 KiB
Python
47 lines
1.6 KiB
Python
"""Реальный клиент exoCRM (`GetOrders`)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import httpx
|
|
|
|
from app.core.config import Settings
|
|
from app.schemas.orders import OrderOut
|
|
from app.services.crm.checksum import compute_md5sum
|
|
from app.services.crm.client import CrmError
|
|
|
|
|
|
class ExoCrmClient:
|
|
def __init__(self, settings: Settings) -> None:
|
|
self._base_url = settings.crm_base_url
|
|
self._api_key = settings.crm_api_key
|
|
self._secret_key = settings.crm_secret_key
|
|
self._shop_key = settings.crm_shop_key
|
|
self._sid = settings.crm_sid
|
|
|
|
async def get_orders(self, *, status: str) -> list[OrderOut]:
|
|
body = {
|
|
"apikey": self._api_key,
|
|
"object": "Orders",
|
|
"method": "GetOrders",
|
|
"params": {
|
|
"sid": self._sid,
|
|
"key": self._shop_key,
|
|
"Status": status,
|
|
"ReturnGoods": True,
|
|
"ReturnTotals": True,
|
|
},
|
|
}
|
|
body["md5sum"] = compute_md5sum(body, self._secret_key)
|
|
|
|
async with httpx.AsyncClient(timeout=30) as client:
|
|
response = await client.post(self._base_url, json=body)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
|
|
if data.get("status") != "OK":
|
|
errors = data.get("errors") or {}
|
|
message = "; ".join(f"{code}: {text}" for code, text in errors.items())
|
|
raise CrmError(f"CRM вернула ошибку: {message or 'неизвестная ошибка'}")
|
|
|
|
return [OrderOut.model_validate(order) for order in data.get("result", [])]
|