# SAP Business One Service Layer Connector Connector komunikuje výhradně přes SAP Business One Service Layer `/b1s/v1`. Hlavní vlastnosti: - login/logout přes Service Layer - správa `B1SESSION` a `ROUTEID` - automatický re-login po expiraci session - HTTP API s credentials předávanými v `X-SAP-B1-*` hlavičkách podle AppFactory pravidel - OData parametry `$select`, `$filter`, `$top`, `$skip`, `$orderby` - stránkování přes `odata.nextLink` a `@odata.nextLink` - retry pro dočasné chyby - zod validace konfigurace a hlavních response tvarů Bezpečnostní pravidla: - při knihovním použití se konfigurace může číst z environment variables - při HTTP API použití se SAP credentials posílají v request headers - hesla, cookies a session tokeny se nelogují - hesla a session tokeny se nevrací v běžných response - testy nepoužívají reálný SAP přístup - pro self-signed certifikáty je dostupné `rejectUnauthorized`, ale produkčně se doporučuje důvěryhodný certifikát HTTP API hlavičky: - `X-SAP-B1-BaseUrl` - `X-SAP-B1-CompanyDB` - `X-SAP-B1-Username` - `X-SAP-B1-Password` - `X-SAP-B1-Language` volitelně - `X-SAP-B1-Reject-Unauthorized` volitelně - `X-SAP-B1-Timeout-Ms` volitelně ## Detaily komunikace se Service Layer - **Login** – `POST /b1s/v1/Login` s `{ CompanyDB, UserName, Password, Language? }`. `Language` se posílá jako celé číslo (Service Layer očekává `Edm.Int32`); nenumerická hodnota se vynechá. Z odpovědi se čtou cookies `B1SESSION` a `ROUTEID` (s fallbackem na `SessionId` v body) a `SessionTimeout` (minuty) pro výpočet expirace. - **Autentizované requesty** – posílají `Cookie: B1SESSION=…; ROUTEID=…`. Při `401` connector jednou provede re-login a request zopakuje; re-login nesnižuje retry budget, takže funguje i při `SAP_B1_RETRY_COUNT=0`. - **Logout** – `POST /b1s/v1/Logout` se posílá **s aktivní session cookie**, jinak by Service Layer nevěděl, kterou session ukončit, a nechal by ji běžet až do timeoutu. - **Stránkování** – následuje `odata.nextLink` i `@odata.nextLink`. U absolutních nextLinků se zachová i query string (`$skip` apod.), takže `listAll` nezacyklí. ## Reverse proxy a Swagger Aplikace běží za AppFactory proxy na `/apps/` (Caddy `handle_path` prefix před předáním do containeru odstraní, takže container vidí routy bez prefixu a z requestu veřejnou cestu nelze odvodit). Stejný přístup jako sousední služba `idoklad`: - OpenAPI dokument se servíruje **pod stejným `/docs` prefixem** jako UI na `GET /docs/openapi.json` (plus alias `GET /openapi.json` pro přímý přístup). - Swagger UI načítá dokument přes **relativní** endpoint `openapi.json`, takže se v prohlížeči vyhodnotí jako `{prefix}/docs/openapi.json` lokálně i za proxy, bez hardcodování `/apps/`. - `servers[0].url` se nastaví z `ROOT_PATH` (fallback hlavička `X-Forwarded-Prefix`, nakonec `/`), takže Swagger `Try it out` volá `…/apps//api/`. | Kontrola | Lokálně (bez ROOT_PATH) | S `ROOT_PATH=/apps/sap-bo` | |---|---|---| | `GET /health` | 200 | 200 | | `GET /docs` (Swagger UI) | 200 | 200 | | `GET /docs/openapi.json` | 200 | 200 | | `servers[0].url` v OpenAPI | `/` | `/apps/sap-bo` |