Files
polstrin-sap/README.md
T
JiriUhlir fea25d7429 first
2026-07-15 09:03:28 +02:00

196 lines
6.8 KiB
Markdown
Raw 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.
# POLSTRIN SAP Business One Service Layer Connector
Node.js + TypeScript connector pro SAP Business One Service Layer REST/OData API, dedikovaný instalaci **POLSTRIN DESIGN s.r.o.** (`https://ws.polstrin.cz:50000`, SAP B1 10.0, verze `1000310`). Používá pouze Service Layer (`/b1s/v1`), ne SAP DI API. Vznikl jako kopie obecné služby `sap-bo`; hlavní rozdíly:
- SAP credentials se **nepředávají v hlavičkách**, ale čtou se z environment variables (AppFactory secrets, viz AGENTS.md „Secrets v parametrech“).
- Jedna sdílená Service Layer session přežívá mezi requesty (re-login při expiraci/401 řeší `SessionManager`).
- Volitelná ochrana `/api` rout sdíleným klíčem: když je nastavený secret `API_KEY`, každý request musí poslat hlavičku `X-Api-Key`.
- Generické endpointy `/api/entities/...` pro práci s libovolným entity setem — hlavně pro UDO tabulky POLSTRIN addonů (`U_ADN_*`, `U_DFX_*`, `U_PVT_*`, `U_VCZ_*`, `VYROBNI_PLAN`, `VYROBNI_DAVKA`). Detaily v [documentation/polstrin-specifika.md](documentation/polstrin-specifika.md).
Součástí repozitáře je AppFactory HTTP wrapper s endpointy:
- `GET /`
- `GET /health`
- `GET /docs`
- `GET /openapi.json`
- `POST /api/session/login` (ověří spojení, vrací verzi Service Layeru a session timeout)
- `POST /api/session/logout`
- `GET /api/system/info` (verze SAP, dostupné entity sety, UDF/UDT/UDO, admin info)
- `GET /api/entities` (seznam všech entity setů)
- `GET|POST /api/entities/{entitySet}`, `GET /api/entities/{entitySet}/all`
- `GET|PATCH|DELETE /api/entities/{entitySet}/{id}` (`?idType=number` pro číselné klíče)
- `GET /api/<resource>`
- `GET /api/<resource>/all`
- `GET /api/<resource>/{id}`
- `POST /api/<resource>`
- `PATCH /api/<resource>/{id}`
- `DELETE /api/<resource>/{id}` pouze pro obecně mazatelné resource
## Instalace
```bash
npm install
npm run build
npm test
```
## Konfigurace (secrets přes environment variables)
Všechny SAP credentials se nastavují přes AppFactory portál jako variables/secrets; aplikace je čte z environment variables. Nikdy se nepředávají v requestech, nelogují se a necommitují. Lokálně vytvoř `.env` podle `.env.example`:
```env
SAP_B1_BASE_URL=https://ws.polstrin.cz:50000
SAP_B1_COMPANY_DB=<secret>
SAP_B1_USERNAME=<secret>
SAP_B1_PASSWORD=<secret>
SAP_B1_LANGUAGE=
SAP_B1_TIMEOUT_MS=30000
SAP_B1_REJECT_UNAUTHORIZED=true
SAP_B1_RETRY_COUNT=2
SAP_B1_RETRY_DELAY_MS=250
API_KEY=<volitelny secret>
```
`SAP_B1_BASE_URL` může být buď root Service Layer hostu, nebo přímo URL končící `/b1s/v1`. Pro self-signed certifikáty lze v interním prostředí nastavit `SAP_B1_REJECT_UNAUTHORIZED=false`; v produkci preferuj důvěryhodný certifikát a ponech `true`.
## Autentizace HTTP API
SAP credentials jsou vnitřní secret služby — klienti je neposílají. Když je nastavený secret `API_KEY`, musí každý request na `/api/...` obsahovat hlavičku:
```http
X-Api-Key: <hodnota API_KEY>
```
Bez nastaveného `API_KEY` jsou `/api` routy otevřené (vhodné jen pro interní síť). Ve Swaggeru (`/docs`) se klíč vyplňuje přes `Authorize`.
## Použití
### Login a logout
```ts
import { SapBusinessOneServiceLayer, loadSapB1ConfigFromEnv } from "./src";
const sap = new SapBusinessOneServiceLayer(loadSapB1ConfigFromEnv());
await sap.login();
await sap.logout();
```
Login volá `POST /b1s/v1/Login`, uloží cookies `B1SESSION` a `ROUTEID` a posílá je v dalších requestech. Při expiraci session a odpovědi `401` connector jednou provede re-login a request zopakuje.
### Vypsání Business Partners
```ts
const partners = await sap.businessPartners.list({
select: ["CardCode", "CardName", "CardType"],
filter: "CardType eq 'cCustomer'",
top: 50,
orderby: "CardName asc"
});
console.log(partners.value);
```
### Načtení všech záznamů přes nextLink
```ts
const allItems = await sap.items.listAll({
select: ["ItemCode", "ItemName"],
top: 100
});
```
Connector podporuje starší `odata.nextLink` i novější `@odata.nextLink`.
### Vytvoření objednávky
```ts
const order = await sap.orders.create({
CardCode: "C001",
DocDueDate: "2026-07-15",
DocumentLines: [
{
ItemCode: "A00001",
Quantity: 2,
UnitPrice: 100
}
]
});
```
### Aktualizace položky
```ts
await sap.items.update("A00001", {
ItemName: "Updated item name"
});
```
## Resource moduly
Implementované resource moduly:
- `businessPartners`
- `items`
- `orders`
- `invoices`
- `purchaseOrders`
- `deliveryNotes`
- `stockTransfers`
Každý modul má:
- `list(query?)`
- `listAll(query?)`
- `get(id)`
- `create(data)`
- `update(id, data)`
- `delete(id)` pouze tam, kde je povolené mazání
U marketing dokumentů (`Orders`, `Invoices`, `PurchaseOrders`, `DeliveryNotes`) a skladových převodek je delete v connectoru záměrně blokovaný. SAP Business One obvykle řeší rušení dokumentů storno/cancel operacemi podle typu dokladu a nastavení firmy.
## Zpracování chyb
Connector převádí chyby na `SapB1Error`:
- `status` HTTP status
- `code` SAP error code, pokud jej Service Layer vrátí
- `message` bezpečná chybová zpráva
- `retryable` příznak pro dočasné chyby
Retry se používá pro `408`, `429` a `5xx`. Citlivé hodnoty jako heslo, cookies a session tokeny se při logování redigují.
## Testy
Testy používají mockované HTTP odpovědi přes axios adapter nebo fake klienty. Nevolají reálný SAP.
```bash
npm test
```
Pokryté oblasti:
- autentizace a cookies
- logout
- automatický re-login po `401`
- OData query parametry
- resource URL builder
## AppFactory
Aplikace poslouchá na `0.0.0.0` a portu `PORT` s výchozí hodnotou `3000`. `ROOT_PATH` se používá pro dokumentaci a testovací requesty za reverse proxy, například `/apps/polstrin-sap`.
`/docs` je Swagger UI servírované přímo jako HTML (stejně jako sousední `google-service`),
bez statického middleware proto nevzniká redirect `/docs``/docs/`, který by za proxy
zahodil prefix. Assety se načítají z CDN, spec URL je `ROOT_PATH + /openapi.json`. V Swaggeru
použij `Authorize` pro vyplnění `X-Api-Key` (pokud je `API_KEY` nastavený) a potom `Try it out`
u konkrétní operace. OpenAPI `servers` se nastaví z `ROOT_PATH` (jinak `/`), takže za proxy
volá například `/apps/polstrin-sap/api/business-partners`, ne root doménu.
## TODO ověřit v konkrétní instalaci SAP Business One
- Přesné enum hodnoty a povinná pole pro jednotlivé entity se mohou lišit podle lokalizace, add-onů a verze SAP Business One.
- U rušení dokladů ověř konkrétní Service Layer akce dostupné pro daný typ dokladu a firemní nastavení.
- U velkých datasetů ověř server-side limity stránkování a maximální povolené `$top`.
- Ověř, zda konkrétní instalace vrací OData metadata ve starším formátu `odata.*` nebo novějším `@odata.*`.