196 lines
6.8 KiB
Markdown
196 lines
6.8 KiB
Markdown
# 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.*`.
|