Files
JiriUhlir e3dccc46d3 3
2026-06-18 15:59:55 +02:00

205 lines
8.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# RAYNET konektor
Stateless proxy nad [RAYNET CRM API v2](https://app.raynetcrm.com/api/doc/index-en.html).
Pokrývá celé RAYNET API díky jednotným REST konvencím.
## Přihlášení (společné pro celé připojení)
RAYNET API používá HTTP Basic Auth (email + API klíč) a hlavičku s názvem
instance. V této službě se předává **třemi hlavičkami u každého requestu**:
| Hlavička | Co to je | Kde to vzít |
|-----------------------|-------------------|-------------|
| `X-Api-Key` | API klíč (secret) | RAYNET CRM: **Nastavení → Klíč k API** |
| `X-Raynet-Email` | Email uživatele | Přihlašovací email do RAYNET |
| `X-Instance-Name` | Název instance | Identifikátor instance (subdoména účtu) |
> `X-Api-Key` je secret nikdy se neloguje, necommituje ani nevrací z endpointů
> (viz AGENTS.md). Tyto údaje jsou zobrazené i nahoře ve Swaggeru (`/docs`).
Base URL RAYNET: `https://app.raynet.cz/api/v2`.
## REST konvence RAYNET (platí pro celé API)
| Operace | RAYNET metoda + cesta |
|---------|------------------------------|
| List | `GET /{resource}/` |
| Detail | `GET /{resource}/{id}/` |
| Create | `PUT /{resource}/` |
| Update | `POST /{resource}/{id}/` |
| Delete | `DELETE /{resource}/{id}/` |
Příklady entit: `company`, `person`, `lead`, `businessCase`, `activity`,
`product`, `offer`, `order`, `project`, …
## Endpointy služby
Veřejně přes AppFactory reverse proxy: `https://services.csbot.cz/apps/<app-id>/...`
### Typované entity
Pro každou z těchto entit existuje plné CRUD se **strukturou objektu i odpovědí
viditelnou ve Swaggeru** (request modely, povinná pole, validace):
| Cesta | Entita | Povinná pole |
|---------------------------|--------------------|--------------|
| `/company` | Firma / klient | `name`, `rating`, `state`, `role` |
| `/person` | Kontaktní osoba | `lastName` |
| `/lead` | Lead / poptávka | `topic`, `priority` |
| `/businessCase` | Obchodní případ | `name`, `company` |
| `/offer` | Nabídka | `name`, `company`, `businessCase` |
| `/salesOrder` | Objednávka | `name`, `company`, `businessCase` |
| `/invoice` | Faktura | `company`, `currency`, `dueDate`, `issueDate`, `invoiceType`, `paymentType`, `taxableSupplyDate` |
| `/product` | Produkt | `code`, `name` |
| `/priceList` | Ceník | `name`, `code`, `currency`, `validFrom` |
| `/project` | Projekt | `name`, `company` |
| `/task` | Úkol | `title`, `priority`, `owner`, `resolver`, `deadline` |
| `/email` | E-mail (aktivita) | `title`, `priority`, `owner` |
| `/event` | Událost | `title`, `priority`, `owner` |
| `/meeting` | Schůzka | `title`, `priority`, `owner` |
| `/phoneCall` | Telefonát | `title`, `priority`, `owner` |
| `/letter` | Dopis | `title`, `priority`, `owner` |
| `/webhook` | Webhook | `url`, `events` |
Operace u každé entity:
| Metoda | Cesta | Popis |
|--------|--------------------|--------------------------------------|
| POST | `/{entita}` | Vytvoří záznam (validovaný objekt) |
| GET | `/{entita}` | Seznam (`offset`, `limit`, `fulltext` + libovolné RAYNET filtry) |
| GET | `/{entita}/{id}` | Detail |
| PUT | `/{entita}/{id}` | Částečná úprava (všechna pole volitelná) |
| DELETE | `/{entita}/{id}` | Smazání |
Enumy firmy: `rating` = `A`/`B`/`C`; `state` = `A_POTENTIAL`/`B_ACTUAL`/`C_DEFERRED`/`D_UNATTRACTIVE`;
`role` = `A_SUBSCRIBER`/`B_PARTNER`/`C_SUPPLIER`/`D_RIVAL`; `taxPayer` = `YES`/`NO`.
> Pole jsou v `camelCase` (tak je očekává RAYNET). Nevyjmenovaná pole jsou
> povolená (`extra="allow"`), takže lze poslat i pole, která model neuvádí.
### Generický průchod na zbytek API
Pro entity bez typovaného modelu zejména **uživatelé** (`userAccount`),
soubory (`file`), DMS dokumenty/složky, GDPR, hromadné e-maly a všechny
**číselníky** (`currency`, `legalForm`, `paymentTerm`, `taxRate`, `territory`,
`contactSource`, `companyCategory`, `productCategory`, `leadPhase`,
`businessCasePhase`, `offerStatus`, `salesOrderStatus`, `projectStatus`,
`maritalStatus`, `employeesNumber`, `economyActivity`, klasifikace 1/2/3, …):
| Metoda | Cesta | Mapuje se na RAYNET |
|--------|-----------------------------|-------------------------------|
| GET | `/api/{resource}` | `GET /{resource}/` (query params se předávají) |
| GET | `/api/{resource}/{id}` | `GET /{resource}/{id}/` |
| POST | `/api/{resource}` | `PUT /{resource}/` (create) |
| PUT | `/api/{resource}/{id}` | `POST /{resource}/{id}/` (update) |
| DELETE | `/api/{resource}/{id}` | `DELETE /{resource}/{id}/` |
### Vnořené zdroje a speciální akce
Pro kolekce a akce nad záznamem (`sub` = zbytek cesty, přesně dle RAYNET vč.
koncového lomítka u kolekcí):
| Metoda | Cesta | Příklad cíle |
|--------|----------------------------------------|--------------|
| GET | `/api/{resource}/{id}/{sub}` | `/invoice/{id}/pdfExport`, `/company/{id}/relationship/` |
| POST | `/api/{resource}/{id}/{sub}` | `/invoice/{id}/cancel`, `/company/{id}/lock`, `/company/{id}/merge/{srcId}/` |
| PUT | `/api/{resource}/{id}/{sub}` | `/company/{id}/address/`, `/invoice/{id}/payment/`, `/offer/{id}/item/` |
| DELETE | `/api/{resource}/{id}/{sub}` | `/company/{id}/address/5/` |
### Raw 100 % pokrytí
Pro jakoukoli cestu / metodu (i netypické, např. `PUT /invoice/creditNote`):
```text
POST /raw
{ "method": "PUT", "path": "/invoice/creditNote", "params": {...}, "data": {...} }
```
### Tvar odpovědí
- Create → `{ "success": true, "id": 123, "data": {...} }`
- Detail → `{ "success": true, "data": { ...objekt vč. id, rowInfo } }`
- Seznam → `{ "success": true, "totalCount": N, "data": [ ... ] }`
- Update / Delete → `{ "success": true }`
### Příklad těla `POST /company`
```json
{
"name": "ACME s.r.o.",
"rating": "A",
"state": "A_POTENTIAL",
"role": "A_SUBSCRIBER",
"regNumber": "12345678",
"taxNumber": "CZ12345678",
"taxPayer": "YES",
"addresses": [
{
"address": {
"name": "Sídlo klienta",
"street": "Francouzská 6167/5",
"city": "Ostrava",
"province": "Morava",
"zipCode": "708 00",
"country": "CZ"
},
"contactInfo": {
"email": "info@acme.cz",
"tel1": "+420 553 401 520",
"tel1Type": "recepce",
"www": "www.acme.cz"
}
}
],
"tags": ["import", "konektor"]
}
```
## Chybové stavy
| HTTP | Kdy |
|------|-----------------------------------------------------------|
| 400 | RAYNET odmítl data (nevalidní vstup) |
| 401 | chybný API klíč / email / instance (autentizace selhala) |
| 422 | nevalidní vstup (FastAPI validace nebo chybí povinné pole)|
| 502 | RAYNET nedostupný / chyba serveru / timeout |
## Použití konektoru přímo v Pythonu
```python
from app.raynet_client import RaynetClient, RaynetError
client = RaynetClient(api_key="...", email="user@firma.cz", instance_name="moje-instance")
try:
# pojmenovaná zkratka
company = client.create_company({
"name": "ACME s.r.o.", "rating": "A",
"state": "A_POTENTIAL", "role": "A_SUBSCRIBER",
})
# generické CRUD nad libovolnou entitou
leads = client.list_records("lead", {"limit": 50})
deal = client.get_record("businessCase", 123)
client.update_record("person", 42, {"lastName": "Novák"})
# speciální akce / vnořené zdroje
client.call("POST", f"/company/{company['id']}/lock")
except RaynetError as exc:
print("Chyba:", exc.message, exc.status_code)
```
`RaynetClient` drží `requests.Session` (Basic Auth + `X-Instance-Name`),
automaticky opakuje přechodné chyby (síť, 429, 5xx) a vyhazuje typované
výjimky `RaynetAuthError` / `RaynetValidationError` / `RaynetError`.
## Ověření po nasazení
```text
GET https://services.csbot.cz/apps/<app-id>/health
GET https://services.csbot.cz/apps/<app-id>/docs
```
Ve Swagger UI ověř, že `Try it out` volá endpointy přes `/apps/<app-id>` a že
jsou vyžadované hlavičky `X-Api-Key`, `X-Raynet-Email`, `X-Instance-Name`.
```