# 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í). Proto: - OpenAPI `servers` obsahuje `ROOT_PATH` (`/apps/`), takže Swagger `Try it out` volá `…/apps//api/`. - Swagger UI načítá OpenAPI dokument z `ROOT_PATH + /openapi.json`, ne z kořene domény. - Lokálně bez `ROOT_PATH` se vše chová relativně ke kořeni (`/openapi.json`, server `/`).