Appearance
Nyitott katalógus – admin API (igények, tételek, árlista)
Ez a dokumentum a teljes / nyitott katalógus admin oldalán elérhető REST API-t írja le. Két fő prefix:
| Prefix | Szerep |
|---|---|
/api/v1/quotes | Igények (nyitott sáv), szerződés Excel import, scope meta, nyitott összesítő |
/api/v1/catalog | Katalógus sorok keresése, CRUD, delta ár import, facet regiszter |
Integration source of truth: OpenAPI (openapi.json / Redoc). Eltérés esetén az OpenAPI az irányadó. OpenAPI tag-ek: quotes, catalog.
Admin UI (referencia):
| Feladat | Menü / URL |
|---|---|
| Beérkező árajánlatkérés | Admin → Árajánlat → Nyitott igények — /admin?tab=quote-open-requests |
| Katalógus tételek, árlista | Admin → Árajánlat → Katalógus — nyitott / zárt scope alatt |
| Megrendelések | Admin → Árajánlat → Megrendelések — /admin?tab=quote-open-orders |
Kapcsolódó kód (áttekintés):
| Terület | Fő fájlok |
|---|---|
| Quote router | src/modules/quote/router.py |
| Katalógus REST | src/modules/quote/catalog_router.py |
| Nyitott sáv admin | src/modules/quote/open_lane_admin.py |
| Import jobok | src/modules/quote/catalog_import_jobs.py |
Kapcsolódó auth: 01-auth-jwt.md.
Hitelesítés és tenant
Minden végpont JWT-t igényel: Authorization: Bearer <token>.
| Szerepkör | Olvasás (GET) | Módosítás (POST/PATCH/PUT/DELETE) |
|---|---|---|
| VIEWER | Igen (lista, admin view) | Nem |
| EDITOR, TENANT_ADMIN | Igen | Igen |
| SYSTEM_ADMIN | Igen | Igen; X-Tenant-ID headerrel más tenant adatai is |
A tenant_id a JWT-ből jön; SYSTEM_ADMIN felülírhatja X-Tenant-ID-vel (ugyanaz a minta, mint a Booking modulnál).
1. Beérkező árajánlatkérés (nyitott sáv)
A nyitott katalógus widgetből beküldött igények az admin Nyitott igények listában jelennek meg. Az ügyintéző egy oldalon látja a megrendelő adatait és az áras ajánlattáblázatot (ugyanaz a modell, mint az ügyfél „Ajánlatom” fülén).
GET /api/v1/quotes/open-lane-requests
Beküldött nyitott katalógus igények listája.
Query: limit (default 200, max 500).
Válasz: { "items": [ … ] } — minden sor tartalmazza pl. a beküldés idejét, megrendelő nevét/e-mailjét, tételszámot, nettó összeget, állapotot, request_id-t.
Szerepkör: VIEWER+.
GET /api/v1/quotes/requests/{request_id}/open-lane-admin-view
Egy igény teljes admin modellje: megrendelő blokk + sorok árakkal (megnevezés, db, egységár, sor nettó, összesen).
Szerepkör: VIEWER+.
PATCH /api/v1/quotes/requests/{request_id}/open-lane-draft
Mentés: megrendelő adatok és/vagy tételsorok módosítása.
Request body (részleges):
json
{
"customer": {
"name": "Kiss János",
"email": "janos@example.com",
"phone": "+36…"
},
"line_items": [ … ],
"line_ops": [ … ]
}- customer: opcionális részleges patch.
- line_items: teljes sorlista felülírás (admin táblázat állapota).
- line_ops: strukturált sor-műveletek (pl. csere, törlés) — a nyitott sáv domain logikája szerint.
Válasz: frissített admin view modell.
Szerepkör: EDITOR+.
POST /api/v1/quotes/requests/{request_id}/open-lane-send
Árajánlat kiküldése e-mailben a megrendelőnek.
Request body:
json
{
"to": "janos@example.com",
"subject": "Árajánlat – …",
"dry_run": false,
"customer": { … },
"line_items": [ … ],
"staff_note_hu": "…",
"delivery_details_hu": "…"
}- dry_run:
trueesetén csak HTML előnézet — nem megy ki levél. - Ha to / subject hiányzik, a backend a megrendelő adataiból tölti.
Szerepkör: EDITOR+.
Flow: igény → szerkesztés → kiküldés
- Login – POST /auth/login → JWT.
- Lista – GET
/api/v1/quotes/open-lane-requests. - Részletek – GET
…/requests/{id}/open-lane-admin-view. - Szerkesztés – PATCH
…/open-lane-draft(db, termékcsere, új sor). - Küldés – POST
…/open-lane-send(dry_run: trueelőnézethez).
Python példa – nyitott igény lista
python
import requests
BASE_URL = "https://<your-api-host>"
headers = {"Authorization": f"Bearer {JWT}"}
r = requests.get(
f"{BASE_URL}/api/v1/quotes/open-lane-requests",
headers=headers,
params={"limit": 50},
)
for row in r.json().get("items", []):
print(row.get("request_id"), row.get("customer_name"), row.get("total_net_hu"))2. Árajánlati tételek – termék felzültés és szerkesztés
A katalógus minden sora SKU (catalog_item_id), megnevezés (title_hu), leírás (description) és facets JSON mezőkből áll. A nyitott katalógus widget és a gather/keresés az LLM terméktulajdonság mezőt használja a releváns termék kiválasztásához.
Facets mezők (fontosabb)
| Facet kulcs | Jelentés |
|---|---|
llm_termektulajdonsag | LLM-nek szánt tulajdonság-leírás (max ~2000 karakter) — felzültés / kereshetőség |
rovid_leiras | Rövid, emberi leírás (max ~800 karakter) |
tetel_tipus | munka | anyag | szolgaltatas | egyeb |
unit_code | Mértékegység (pl. db, m) |
unit_price_net | Nettó egységár (string, pl. "1950") |
vat_key | ÁFA kulcs (pl. "27") |
brand | Márka (opcionális) |
catalog_scope_id | Zárt scope azonosító; nyitott katalógusnál nincs (scope nélküli sor) |
A description mező tipikusan: llm_termektulajdonsag + újsor + rovid_leiras (ugyanaz, mint az Excel import és az admin űrlap mentése).
GET /api/v1/catalog/search
Katalógus sorok lapozott keresése.
Query (lényeg):
| Param | Leírás |
|---|---|
q | Szöveg (cím / leírás ILIKE) |
facet | Ismételhető: facet=kulcs=érték |
limit | Oldalméret (max 50) |
after_title_hu, after_id | Keyset lapozás |
open_catalog_only | true → csak nyitott (scope nélküli) sorok |
include_inactive | true → inaktív sorok is |
Válasz: { "items", "has_next", "next_after_title_hu", "next_after_id", "limit" }.
GET /api/v1/catalog/items/
Egy sor teljes adatai (staff).
POST /api/v1/catalog/items
Új katalógus sor.
Request body:
json
{
"catalog_item_id": "SKU-001",
"title_hu": "Csillárkapcsoló fehér",
"description": "Fehér csillárkapcsoló, 10A\nRövid leírás…",
"facets": {
"llm_termektulajdonsag": "Fehér csillárkapcsoló, 10A, fali szerelés",
"rovid_leiras": "Standard fehér kapcsoló",
"tetel_tipus": "anyag",
"unit_code": "db",
"unit_price_net": "1950",
"vat_key": "27"
},
"active": true
}PATCH /api/v1/catalog/items/
Részleges frissítés: title_hu, description, facets, active.
Példa – csak LLM tulajdonság frissítése:
json
{
"facets": {
"llm_termektulajdonsag": "Fehér csillárkapcsoló, 10A, IP20, fali"
}
}A facets patch merge viselkedésű a szolgáltatásban: a megadott kulcsok frissülnek, a többi megmarad.
POST /api/v1/catalog/items/bulk
Tömeges import (max 200 sor / kérés). Body: { "items": [ … ], "continue_on_error": false }.
Szerepkör (catalog CRUD): EDITOR+ (_staff).
3. Árlista és tételek módosítása (tömeges)
Szerződés Excel import (teljes / scope)
Nagy katalógus (millió+ tétel) tipikusan Excel szerződés sablonnal töltődik fel.
| Endpoint | Method | Leírás |
|---|---|---|
/api/v1/quotes/catalog/contract-template | GET | Üres sablon letöltése (.xlsx) |
/api/v1/quotes/catalog/import/start | POST | Háttér import (multipart: file, opc. catalog_scope_id, dry_run) → job_id |
/api/v1/quotes/catalog/import/status | GET | Job poll (job_id) |
/api/v1/quotes/catalog/import | POST | Szinkron import (script / teszt) |
- catalog_scope_id hiányzik → nyitott (teljes) katalógus sáv.
- catalog_scope_id megadva → zárt scope import (lásd GET
/api/v1/quotes/catalog/scopes).
GET /api/v1/quotes/catalog/open-summary — nyitott katalógus: item_count, last_import_at.
GET /api/v1/quotes/catalog/open/import-batches — import batch azonosítók listája.
Delta ár import (csak árváltozás)
Meglévő SKU-k nettó egységárának frissítése JSON-ból — teljes Excel újratöltés nélkül.
POST /api/v1/catalog/import-price-delta
json
{
"dry_run": true,
"items": [
{ "catalog_item_id": "SKU-001", "unit_price_net": "2100" },
{ "catalog_item_id": "SKU-002", "unit_price_net": "890" }
]
}Válasz:
json
{
"ok": true,
"dry_run": true,
"updated_count": 2,
"missing_count": 0,
"missing_skus": []
}- dry_run:
true→ szimuláció, DB nem változik. - missing_skus: nem található SKU-k listája.
Max 500 sor / kérés.
Python példa – delta ár (dry run)
python
import requests
BASE_URL = "https://<your-api-host>"
headers = {"Authorization": f"Bearer {JWT}", "Content-Type": "application/json"}
body = {
"dry_run": True,
"items": [
{"catalog_item_id": "ABC-123", "unit_price_net": "15000"},
],
}
r = requests.post(
f"{BASE_URL}/api/v1/catalog/import-price-delta",
headers=headers,
json=body,
)
print(r.json())4. Megrendelések (nyitott sáv, rövid)
Az ügyfél a widgetben Megrendelem után megrendelés keletkezik.
| Endpoint | Method | Leírás |
|---|---|---|
/api/v1/quotes/open-lane-orders | GET | Megrendelések listája |
/api/v1/quotes/requests/{request_id}/open-lane-order | PATCH | delivered: true — kiszállítva jelölés |
Admin UI: /admin?tab=quote-open-orders.
Zárt vs nyitott katalógus (meta)
| Nyitott (teljes) | Zárt scope | |
|---|---|---|
| Scope mező | Nincs catalog_scope_id a facetben | Van catalog_scope_id |
| Import | catalog_scope_id nélkül | catalog_scope_id=<scope> |
| Keresés szűrő | open_catalog_only=true | facet=catalog_scope_id=<scope> |
| Scope CRUD | — | /api/v1/quotes/catalog/scopes |
A nyitott katalógus public widget tokenje és a zárt katalógus tokenje külön admin fülön kezelhető — lásd 52-admin-public-widget-tokens.md és a quote public token admin UI-t.
További információ
- JWT auth: 01-auth-jwt.md
- Public widget flow: 21-flow-public-widget.md
- Endpoint matrix: 41-endpoint-matrix.md
- OpenAPI / Redoc: openapi.json, redoc — quotes és catalog tag-ek.