This commit is contained in:
JiriUhlir
2026-06-18 15:11:49 +02:00
parent 28596fe772
commit a5795fe344
5 changed files with 405 additions and 200 deletions
+79 -21
View File
@@ -115,41 +115,99 @@ class RaynetClient:
)
# ------------------------------------------------------------------ #
# Veřejné metody
# Generické CRUD nad libovolnou RAYNET entitou (resource)
#
# RAYNET má napříč celým API jednotné konvence:
# list GET /{resource}/
# detail GET /{resource}/{id}/
# create PUT /{resource}/
# update POST /{resource}/{id}/
# delete DELETE /{resource}/{id}/
# Tyto metody proto pokrývají celé RAYNET API (company, person, lead,
# businessCase, activity, product, offer, order, project, ...).
# ------------------------------------------------------------------ #
def list_records(self, resource: str, params: Optional[dict] = None) -> dict:
"""Vrátí seznam záznamů dané entity.
Args:
resource: název entity, např. ``"company"``, ``"person"``, ``"lead"``.
params: filtry / stránkování (``offset``, ``limit``, ``fulltext``, ...).
"""
return self._request("GET", f"/{self._res(resource)}/", params=params)
def get_record(self, resource: str, record_id: int | str) -> dict:
"""Vrátí detail jednoho záznamu."""
return self._request("GET", f"/{self._res(resource)}/{record_id}/")
def create_record(self, resource: str, data: dict) -> dict:
"""Vytvoří záznam (RAYNET používá pro create metodu PUT)."""
if not isinstance(data, dict):
raise ValueError("Parametr 'data' musí být slovník (dict).")
return self._request("PUT", f"/{self._res(resource)}/", json=data)
def update_record(self, resource: str, record_id: int | str, data: dict) -> dict:
"""Upraví záznam (RAYNET používá pro update metodu POST)."""
if not isinstance(data, dict):
raise ValueError("Parametr 'data' musí být slovník (dict).")
return self._request("POST", f"/{self._res(resource)}/{record_id}/", json=data)
def delete_record(self, resource: str, record_id: int | str) -> dict:
"""Smaže záznam."""
return self._request("DELETE", f"/{self._res(resource)}/{record_id}/")
def call(
self,
method: str,
path: str,
params: Optional[dict] = None,
json: Optional[Any] = None,
) -> dict:
"""Univerzální volání pro vnořené zdroje a speciální akce.
Příklady cest: ``/company/{id}/address/``,
``/company/{id}/lock``, ``/company/{id}/merge/{sourceId}/``.
"""
return self._request(method.upper(), path, params=params, json=json)
# ------------------------------------------------------------------ #
# Pojmenované zkratky pro nejčastější entity (tenké wrappery)
# ------------------------------------------------------------------ #
def create_company(self, data: dict) -> dict:
"""Vytvoří firmu (company) v RAYNET CRM.
RAYNET používá pro vytvoření záznamu HTTP metodu ``PUT`` na kolekci
``/company/`` (nikoli POST).
Args:
data: tělo požadavku dle RAYNET dokumentace. Povinná pole jsou
``name``, ``rating``, ``state`` a ``role``. Příklad kompletní
struktury viz :data:`EXAMPLE_COMPANY` níže.
Returns:
Parsovaná JSON odpověď serveru (obsahuje mj. ``id`` nové firmy).
Raises:
ValueError: pokud ``data`` nejsou slovník nebo chybí povinná pole.
RaynetAuthError: při chybě autentizace (401/403).
RaynetValidationError: při zamítnutí dat serverem (4xx).
RaynetError: při ostatních chybách (síť, 5xx, nevalidní JSON).
Povinná pole: ``name``, ``rating``, ``state``, ``role``.
Příklad struktury viz :data:`EXAMPLE_COMPANY` níže.
"""
if not isinstance(data, dict):
raise ValueError("Parametr 'data' musí být slovník (dict).")
missing = [f for f in ("name", "rating", "state", "role") if not data.get(f)]
missing = [f for f in ("name", "rating", "state", "role") if not (data or {}).get(f)]
if missing:
raise ValueError(
"Firma musí mít vyplněná povinná pole: " + ", ".join(missing) + "."
)
return self.create_record("company", data)
return self._request("PUT", "/company/", json=data)
def list_companies(self, **params: Any) -> dict:
return self.list_records("company", params or None)
def get_company(self, company_id: int | str) -> dict:
return self.get_record("company", company_id)
def update_company(self, company_id: int | str, data: dict) -> dict:
return self.update_record("company", company_id, data)
def delete_company(self, company_id: int | str) -> dict:
return self.delete_record("company", company_id)
# ------------------------------------------------------------------ #
# Interní HTTP vrstva
# ------------------------------------------------------------------ #
@staticmethod
def _res(resource: str) -> str:
"""Očistí název resource (bez lomítek), ať nejde sestavit divná URL."""
cleaned = (resource or "").strip().strip("/")
if not cleaned:
raise ValueError("Název resource nesmí být prázdný.")
return cleaned
def _request(self, method: str, path: str, **kwargs: Any) -> dict:
url = f"{self.base_url}/{path.lstrip('/')}"
kwargs.setdefault("timeout", self.timeout)