@kreiseck/kasseneck-api 1.2.2 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/README.md +119 -3
  3. package/dist/cjs/client/aufrufe.d.ts +2 -2
  4. package/dist/cjs/client/aufrufe.js +30 -0
  5. package/dist/cjs/inventory/api.d.ts +45 -0
  6. package/dist/cjs/inventory/api.js +38 -0
  7. package/dist/cjs/inventory/auth.d.ts +17 -0
  8. package/dist/cjs/inventory/auth.js +27 -0
  9. package/dist/cjs/inventory/endpunkte.d.ts +71 -0
  10. package/dist/cjs/inventory/endpunkte.js +285 -0
  11. package/dist/cjs/inventory/fehler.d.ts +33 -0
  12. package/dist/cjs/inventory/fehler.js +47 -0
  13. package/dist/cjs/inventory/index.d.ts +19 -0
  14. package/dist/cjs/inventory/index.js +64 -0
  15. package/dist/cjs/inventory/lesen.d.ts +38 -0
  16. package/dist/cjs/inventory/lesen.js +294 -0
  17. package/dist/cjs/inventory/typen.d.ts +319 -0
  18. package/dist/cjs/inventory/typen.js +14 -0
  19. package/dist/cjs/inventory/vertrag.d.ts +76 -0
  20. package/dist/cjs/inventory/vertrag.js +166 -0
  21. package/dist/cjs/inventory/webhook.d.ts +50 -0
  22. package/dist/cjs/inventory/webhook.js +110 -0
  23. package/dist/cjs/pos/artikel.d.ts +20 -0
  24. package/dist/cjs/pos/artikel.js +8 -0
  25. package/dist/cjs/pos/index.d.ts +1 -1
  26. package/dist/cjs/pos/index.js +2 -1
  27. package/dist/cjs/pos/texte.d.ts +41 -0
  28. package/dist/cjs/pos/texte.js +29 -1
  29. package/dist/cjs/stored/vokabular.d.ts +1 -1
  30. package/dist/cjs/stored/vokabular.js +1 -1
  31. package/dist/cjs/version.d.ts +1 -1
  32. package/dist/cjs/version.js +1 -1
  33. package/dist/esm/client/aufrufe.d.ts +2 -2
  34. package/dist/esm/client/aufrufe.js +30 -0
  35. package/dist/esm/inventory/api.d.ts +45 -0
  36. package/dist/esm/inventory/api.js +35 -0
  37. package/dist/esm/inventory/auth.d.ts +17 -0
  38. package/dist/esm/inventory/auth.js +24 -0
  39. package/dist/esm/inventory/endpunkte.d.ts +71 -0
  40. package/dist/esm/inventory/endpunkte.js +266 -0
  41. package/dist/esm/inventory/fehler.d.ts +33 -0
  42. package/dist/esm/inventory/fehler.js +40 -0
  43. package/dist/esm/inventory/index.d.ts +19 -0
  44. package/dist/esm/inventory/index.js +18 -0
  45. package/dist/esm/inventory/lesen.d.ts +38 -0
  46. package/dist/esm/inventory/lesen.js +278 -0
  47. package/dist/esm/inventory/typen.d.ts +319 -0
  48. package/dist/esm/inventory/typen.js +13 -0
  49. package/dist/esm/inventory/vertrag.d.ts +76 -0
  50. package/dist/esm/inventory/vertrag.js +163 -0
  51. package/dist/esm/inventory/webhook.d.ts +50 -0
  52. package/dist/esm/inventory/webhook.js +101 -0
  53. package/dist/esm/pos/artikel.d.ts +20 -0
  54. package/dist/esm/pos/artikel.js +8 -0
  55. package/dist/esm/pos/index.d.ts +1 -1
  56. package/dist/esm/pos/index.js +1 -1
  57. package/dist/esm/pos/texte.d.ts +41 -0
  58. package/dist/esm/pos/texte.js +28 -0
  59. package/dist/esm/stored/vokabular.d.ts +1 -1
  60. package/dist/esm/stored/vokabular.js +1 -1
  61. package/dist/esm/version.d.ts +1 -1
  62. package/dist/esm/version.js +1 -1
  63. package/fixtures/hobex-hps-codes.json +1 -1
  64. package/fixtures/invoice-api.schema.json +1 -1
  65. package/fixtures/invoice-texts.json +1 -1
  66. package/fixtures/pos-texts.json +36 -1
  67. package/fixtures/surface.json +161 -3
  68. package/fixtures/v3/README.md +9 -1
  69. package/fixtures/v3/antworten/belege.json +2 -2
  70. package/fixtures/v3/antworten/belegmail.json +2 -2
  71. package/fixtures/v3/antworten/kasse-belege.json +2 -2
  72. package/fixtures/v3/antworten/kasse.json +3 -3
  73. package/fixtures/v3/antworten/lager.json +1520 -0
  74. package/fixtures/v3/antworten/rechnungen.json +2 -2
  75. package/fixtures/v3/antworten/storno.json +2 -2
  76. package/fixtures/v3/stored/belege.json +2 -2
  77. package/fixtures/v3/stored/kasse.json +404 -4
  78. package/fixtures/v3/stored/rechnungen.json +2 -2
  79. package/fixtures/v3/v3-vokabular.json +423 -6
  80. package/fixtures/v3/zahlbetrag-faelle.json +2 -2
  81. package/package.json +14 -2
package/CHANGELOG.md CHANGED
@@ -4,6 +4,105 @@ Was vor 0.7.0 geschah, steht in der Commit-Historie (`git log`); ab hier wird
4
4
  es hier geführt. Ein Eintrag nennt die Änderung **und ihren Grund** —
5
5
  nur der Grund überlebt den nächsten Umbau.
6
6
 
7
+ ## 1.4.0
8
+
9
+ Inventory API, read side and account webhooks: new subpath `./inventory`.
10
+ Reason: since stage 5a the backend offers articles, locations, stock and the
11
+ stock ledger under `/v3` with the account's `api_key`, plus webhooks that
12
+ report every stock change within seconds. A shop that shows stock or keeps
13
+ its own copy needs a typed client and, above all, a signature check it
14
+ cannot get wrong.
15
+
16
+ Additive, no breaking change; existing calls send and read the same bytes as
17
+ in 1.3.0.
18
+
19
+ - **`createInventoryClient({ apiKey })`** (`./inventory`, server only, base
20
+ `https://api.kasseneck.at/v3`): `getArticle`, `listArticles`,
21
+ `lookupArticleByCode` (code as text or `{ code }`, or
22
+ `{ externalSystem, externalId }`), `listLocations`, `getStock`, `listStock`,
23
+ `listStockMovements`, and the async iterators `iterateArticles`,
24
+ `iterateStock`, `iterateStockMovements` that follow `nextCursor` until
25
+ `null` (the same cursor twice throws instead of looping). Webhook management:
26
+ `createWebhook`, `updateWebhook`, `deleteWebhook`, `listWebhooks`,
27
+ `sendWebhookTest`, `rotateWebhookSecret`, `listWebhookDeliveries`. Every call
28
+ is also exported as a free function taking the transport.
29
+ - **Models**: `Article` (incl. `stockLocationIds`; `purchasePriceMicros` only
30
+ with the account permission `costs`, otherwise the field is absent, not
31
+ `null`), `StockLevel` (`onHand`, `reserved`, `available`, `defective`,
32
+ `sequence`, `updatedAt`), `StockValue`, `StockMovement`, `Location`,
33
+ `InventoryWebhook` (`consecutiveFailures`), `InventoryWebhookDelivery`
34
+ (`deliveryId`; status `delivered`, `pending`, `failed`, `dropped`); the same
35
+ names as for partner webhooks. Quantities are integer thousandths, money
36
+ integer cents, purchase prices integer micro-euros; `available` may be
37
+ negative. A fractional or missing quantity, amount or `sequence` in a
38
+ response throws `KasseneckValidationError` with `scope: 'response'`, as for
39
+ register stock since 1.2.0. A `Date` in `updatedSince`, `changedSince`,
40
+ `from` or `to` goes out as ISO 8601 UTC.
41
+ - **Incoming webhooks**: `verifyInventoryWebhookSignature(secret, header, rawBody,
42
+ { toleranceSec = 300, now })` resolves to `true` or `false` and never
43
+ throws: HMAC-SHA256 over `"<t>.<raw body>"`, constant-time comparison,
44
+ 300 seconds in both directions, several `v1=` parts allowed; checked against
45
+ the backend's test vector (t=1700000000). Asynchronous because it uses
46
+ WebCrypto, as `./partner` does. `parseInventoryWebhookEvent(rawBody)` returns a typed
47
+ `InventoryWebhookEvent` for `stock.changed` (`cause`, `movementId`),
48
+ `stock.below_minimum` (when `onHand` drops below the minimum stock set for
49
+ the location; the article's `minStock` alone never triggers it, the same rule
50
+ as `listStock({ belowMinimum: true })`) and `article.created|updated|deactivated`, with
51
+ `accountId` instead of `partnerId` in the envelope; an event type this
52
+ version does not know returns `null`, a body that is no envelope throws.
53
+ Both carry `Inventory` in their name on purpose: `./partner` has a
54
+ `verifyWebhookSignature` with an options object that resolves to
55
+ `{ ok, reason }`, and an object is truthy, so a mix-up in plain JavaScript
56
+ would accept every delivery.
57
+ - **Errors** through the existing classes: `INVENTORY_ERROR_CODES`
58
+ (`rate_limited` with `retryAfterSec`, also after 20 `sendWebhookTest` per
59
+ account and calendar day in Vienna, `inventory_api_not_enabled`,
60
+ `module_inactive`, `article_not_found`, `invalid_cursor`, `webhook_limit`
61
+ and the other webhook codes …), `INVENTORY_REQUEST_ERROR_CODES`, `isInventoryError`,
62
+ `inventoryErrorCode`, `inventoryFieldErrors`, `inventoryRetryAfterSec`.
63
+ - **Lists as data**: `INVENTORY_ENDPOINTS`, `INVENTORY_WEBHOOK_EVENTS`,
64
+ `INVENTORY_WEBHOOK_ENVELOPE_FIELDS`, `LOCATION_TYPES`,
65
+ `STOCK_MOVEMENT_TYPES`, `STOCK_MOVEMENT_SOURCES`, `STOCK_CONDITIONS`,
66
+ `STOCK_CHANGE_CAUSES`, `WEBHOOK_DELIVERY_STATUSES`, each held against the
67
+ backend contract. A goods receipt is `goods_receipt` (movement type and
68
+ cause), opening stock taken over is `takeover` (also as cause); `receipt`
69
+ only ever means a sales receipt (`source.type`).
70
+ - **Contract**: `fixtures/v3/` pulled again from the backend (the 14 new
71
+ endpoints, catalogs and events, and `antworten/lager.json` with real
72
+ responses and delivered webhook events that the tests read); `PUBLIC_CALLS` and `ALL_CALLS` gain the 14
73
+ names; `surface.json` gains the key `inventory` with the lists above.
74
+
75
+ ## 1.3.0
76
+
77
+ Article codes on `PosArticle` and the stock words of the register in the
78
+ shared catalogue. Reason: the backend already sends `number`, `ean`,
79
+ `internalCode` and `stockTracked` per article in `listMyArticles` under
80
+ `/api/v3`, but the package dropped them, so the browser register could not
81
+ search by scanned code nor tell a stock-tracked article without guessing. The
82
+ stock labels lived locally in the browser register; the browser register and
83
+ the register app have to use the same words.
84
+
85
+ Additive, no breaking change; requests send the same bytes as in 1.2.2.
86
+
87
+ - **`PosArticle`** gains `number`, `ean`, `internalCode` (`string | null`) and
88
+ `stockTracked` (`boolean | null`). Optional on the type like
89
+ `stockLocationIds`, so existing object literals keep compiling; the reader
90
+ `fromPosArticlePayload` always sets them. Texts pass through unchanged
91
+ (leading zeros, case, spaces); an empty or whitespace-only text and a
92
+ value of the wrong type become `null`. `stockTracked: null` means the
93
+ response carries no statement (older backends), not `false`. `./stored`
94
+ (`fromStoredArticle`) returns the same fields.
95
+ - **Labels** (`LABELS`, `labelText`): `stock.all_articles`, `stock.location`,
96
+ `stock.default_location`, `stock.resolved`, `stock.where_to`,
97
+ `stock.available`, `stock.return_restock`, `stock.return_defective`,
98
+ `stock.return_disposed`. New `RETURN_DISPOSITION_LABELS` (`./pos`) maps each
99
+ `ReturnDisposition` to its label key.
100
+ - **Message** (`MESSAGES`, `messageText`): `cancellation.input_rejected`, for
101
+ a cancellation whose reason, note or lines the server rejected.
102
+ - **`fixtures/pos-texts.json`**: the new keys and a new top-level key
103
+ `returnDispositionLabels` after `labels`. `surface.json` and the other
104
+ contract files change only in their version.
105
+
7
106
  ## 1.2.2
8
107
 
9
108
  The receipt fixtures, goldens and tests carried the serial number of a real
package/README.md CHANGED
@@ -49,6 +49,7 @@ models, same enum values, checked against each other in tests.
49
49
  - [Card payments](#card-payments)
50
50
  - [Partner API (`./partner`)](#partner-api-partner)
51
51
  - [Invoice API (`./invoice`)](#invoice-api-invoice)
52
+ - [Inventory API (`./inventory`)](#inventory-api-inventory)
52
53
  - [Migrating from 0.x](#migrating-from-0x)
53
54
  - [Development](#development)
54
55
  - [Contract files for the twin packages](#contract-files-for-the-twin-packages)
@@ -211,6 +212,7 @@ adapter:
211
212
  | `…/stored` | Stored Firestore documents (inner form, German) as the same English models the `/v3` wire returns: receipts with company and layout, register settings, articles. For clients that read Firestore directly, such as the admin panel. |
212
213
  | `…/invoice` | Invoice API: create and search customers, issue finalised invoices, credit notes and cancellation, PDF and e-invoice XML, the contract as data. **Belongs on a server.** |
213
214
  | `…/invoice/calc` | Pure calculation core for invoice totals (integers, no transport, no dependency beyond types). Safe to run in the browser. |
215
+ | `…/inventory` | Inventory API: read articles, locations, stock and the stock ledger, manage account webhooks, verify and parse incoming stock and article events. **Belongs on a server.** |
214
216
  | `…/react` | Thin React adapter that renders a receipt layout or a receipt sheet. Needs React. |
215
217
  | `…/fixtures/*` | Golden receipts (JSON): inputs `receipts/<name>.json`, promised line output `expected/<name>.lines.json`, `manifest.json` with checksums. The backend, the browser register and the Flutter package check against the same files. |
216
218
 
@@ -408,6 +410,7 @@ the received body.
408
410
  | `POS_ERROR_CODES` | `isPosError` (`…/pos`) | settings, articles, printers, tip recipients |
409
411
  | `PARTNER_ERROR_CODES` + `PARTNER_REQUEST_ERROR_CODES` | `isPartnerError` (`…/partner`) | partner API |
410
412
  | `INVOICE_ERROR_CODES` + `INVOICE_REQUEST_ERROR_CODES` | `isInvoiceError` (`…/invoice`) | invoice API |
413
+ | `INVENTORY_ERROR_CODES` + `INVENTORY_REQUEST_ERROR_CODES` | `isInventoryError` (`…/inventory`) | inventory API |
411
414
 
412
415
  Every group has the same helpers: `is…ErrorCode(value)`, `…ErrorCode(error)`
413
416
  (the code if the group knows it), `is…Error(error, code?)` (a type guard; without
@@ -823,7 +826,9 @@ sending a German value.
823
826
 
824
827
  The rest of `…/pos`: `listMyArticles` and `listMyArticleGroups` for the tiles
825
828
  (`visible`, `quantityRule: 'piece' | 'decimal'`, `askQuantity`,
826
- `maxQuantity`), `listMyPrinters`, `createPrintJob` and `getPrintJob` for
829
+ `maxQuantity`; for scanner search `number`, `ean` and `internalCode`, passed
830
+ through unchanged and `null` when empty; `stockTracked`, `null` when the
831
+ response says nothing), `listMyPrinters`, `createPrintJob` and `getPrintJob` for
827
832
  network printers (poll until `isPrintJobFinished(job)`; an unknown state is
828
833
  `'unknown'` and ends the polling), `listMyTipRecipients`, `setMyPosLogo`, and
829
834
  the register's text catalogue (`MESSAGES`, `LABELS`, `messageText`,
@@ -855,7 +860,10 @@ names none), registers `stockLocationId` (absent for the default location;
855
860
  only the result of `setMyCashregisterStockLocation` uses `null` for it), and
856
861
  `listRegisterUsersForDevice` returns `cashregister.stockLocationId`;
857
862
  errors such as `location_not_found` and `location_inactive` are in
858
- `POS_ERROR_CODES`.
863
+ `POS_ERROR_CODES`. The register's stock words are in the catalogue as
864
+ `stock.*` labels (`labelText('stock.where_to')`), and
865
+ `RETURN_DISPOSITION_LABELS` gives the label of each return choice
866
+ (`labelText(RETURN_DISPOSITION_LABELS.restock)` is "Zurück ins Lager").
859
867
 
860
868
  `stockViewOf(perms)` (also exported from the package root) tells whether a
861
869
  register user may see locations and quantities: a missing `stockView` counts
@@ -1412,6 +1420,114 @@ but € 23.49 with the core and on the invoice. It stays unchanged for existing
1412
1420
  callers; use `calculateInvoice` or `previewInvoice` in new code. Test cases for
1413
1421
  the old formula: `fixtures/invoice-totals.json`.
1414
1422
 
1423
+ ## Inventory API (`./inventory`)
1424
+
1425
+ For online shops and other systems that show or mirror the stock of a
1426
+ Kasseneck account: read articles, locations, stock per location and the stock
1427
+ ledger, and get every stock change pushed by webhook within seconds, also the
1428
+ ones made at the register in the shop. Uses the `api_key` of the account and
1429
+ belongs on a **server**. Reading needs the module `lager`; purchase prices and
1430
+ stock values appear only when the account has the permission `costs`
1431
+ (otherwise the fields are absent, not `null`).
1432
+
1433
+ **Integers with a fixed scale:** quantities in thousandths of the base unit
1434
+ (`1000` = 1 piece, `250` = 0.250 kg), money in cents, purchase prices in
1435
+ micro-euros. `available = onHand − reserved` and may be negative: the register
1436
+ never refuses a sale. A fractional quantity in a response throws
1437
+ `KasseneckValidationError` with `scope: 'response'`; it is never read as `0`.
1438
+
1439
+ ```ts
1440
+ import express from 'express';
1441
+ import { createInventoryClient, verifyInventoryWebhookSignature, parseInventoryWebhookEvent } from '@kreiseck/kasseneck-api/inventory';
1442
+
1443
+ const inventory = createInventoryClient({ apiKey: process.env.KASSENECK_API_KEY! });
1444
+
1445
+ // 1. Read: an article by its EAN, then its stock per location.
1446
+ const article = await inventory.lookupArticleByCode('9001234567896');
1447
+ const { stock } = await inventory.getStock(article.id);
1448
+ // stock[0]: { articleId, locationId, onHand: 12000, reserved: 2000, available: 10000, defective: 0, sequence: 42, updatedAt }
1449
+
1450
+ // 2. Initial sync, page by page over nextCursor.
1451
+ for await (const row of inventory.iterateStock()) {
1452
+ await shop.saveStock(row.articleId, row.locationId, row.available, row.sequence);
1453
+ }
1454
+
1455
+ // 3. Subscribe once. The secret is shown only in this response.
1456
+ const { secret } = await inventory.createWebhook({
1457
+ url: 'https://shop.example.com/kasseneck-webhook',
1458
+ events: ['stock.changed', 'stock.below_minimum'],
1459
+ description: 'Bäckerei Kornblum online shop',
1460
+ });
1461
+
1462
+ // 4. Receive. express.raw BEFORE any JSON parser: the signature covers the bytes as received.
1463
+ const app = express();
1464
+ app.post('/kasseneck-webhook', express.raw({ type: '*/*' }), async (req, res) => {
1465
+ // await is required: the check is asynchronous, and a forgotten await
1466
+ // yields a Promise, which is truthy, so every delivery would pass.
1467
+ if (!(await verifyInventoryWebhookSignature(secret, req.header('X-Kasseneck-Signature'), req.body))) {
1468
+ return res.sendStatus(400);
1469
+ }
1470
+ let event;
1471
+ try {
1472
+ event = parseInventoryWebhookEvent(req.body); // throws on a malformed envelope
1473
+ } catch {
1474
+ return res.sendStatus(400);
1475
+ }
1476
+ res.sendStatus(200); // answer within 10 s, work afterwards
1477
+ if (!event || event.test) return; // unknown type of a later version, or a test delivery
1478
+ if (event.type === 'stock.changed') {
1479
+ // State, not delta: keep it only if sequence is higher than the stored one.
1480
+ await shop.saveStockIfNewer(event.data.articleId, event.data.locationId, event.data.available, event.data.sequence);
1481
+ }
1482
+ });
1483
+ ```
1484
+
1485
+ - **Signature.** `verifyInventoryWebhookSignature(secret, header, rawBody, { toleranceSec, now })`
1486
+ resolves to `true` or `false` and never throws. It is the same procedure as
1487
+ for partner webhooks: `X-Kasseneck-Signature: t=<unix seconds>,v1=<hex>`
1488
+ with HMAC-SHA256 over `"<t>.<raw body>"`, compared in constant time, and a
1489
+ window of 300 seconds in both directions against replays. It is asynchronous
1490
+ because it uses WebCrypto: always `await` it, a forgotten `await` leaves a
1491
+ Promise, which is truthy, and lets every delivery through. The name differs
1492
+ on purpose from `verifyWebhookSignature` in `./partner`, which takes an
1493
+ options object and resolves to `{ ok, reason }`. After `rotateWebhookSecret`
1494
+ only the new secret is valid; pass both during your own switch-over
1495
+ (`secret` may be a list, one match is enough).
1496
+ - **Parsing.** `parseInventoryWebhookEvent(rawBody)` returns `null` for an
1497
+ event type this version does not know (answer 2xx and skip it) and throws
1498
+ `KasseneckValidationError` on a body that is no envelope or carries a
1499
+ fractional quantity; verify first, then parse inside `try`.
1500
+ - **Events.** `stock.changed` carries the current state of one article at one
1501
+ location (`onHand`, `reserved`, `available`, `defective`, `sequence`,
1502
+ `updatedAt`) plus `cause` (`sale`, `invoice`, `goods_receipt`, `transfer`,
1503
+ `takeover` …) and `movementId`; changes within 10 seconds are combined into
1504
+ one delivery. `stock.below_minimum` fires once when `onHand` drops below the
1505
+ minimum stock set for the location; `minStock` in the payload is that
1506
+ threshold. The article's own `minStock` never triggers it, and
1507
+ `listStock({ belowMinimum: true })` follows the same rule. In movements,
1508
+ `goods_receipt` is a goods receipt; `receipt` only ever means a sales receipt
1509
+ (`source.type`).
1510
+ `article.created`, `article.updated` and `article.deactivated` carry the
1511
+ article as `getArticle` returns it, without purchase prices. Deduplicate on
1512
+ `event.id`; deliveries are retried after 1 min, 5 min, 30 min, 2 h and 12 h.
1513
+ - **Safety net without webhooks.** `listStock({ changedSince })` and
1514
+ `listArticles({ updatedSince })` are sorted by `updatedAt` ascending and
1515
+ include the boundary, so remembering the last `updatedAt` and asking again
1516
+ loses nothing. Lists take `limit` (1–200, default 50) and `cursor`.
1517
+ - **Test deliveries.** `sendWebhookTest` sends a recognisably invented payload
1518
+ with `test: true` in the envelope. At most 20 per account and calendar day in
1519
+ Vienna (live and test environment count separately; rejected calls do not
1520
+ count); after that `rate_limited` with the wait until midnight in Vienna.
1521
+ Deliveries carry `deliveryId` (the header `X-Kasseneck-Delivery`), webhooks
1522
+ `consecutiveFailures`, the same names as for partner webhooks.
1523
+ - **Errors.** `rate_limited` (about 20 requests per second per account, or the
1524
+ daily limit of `sendWebhookTest`) carries the wait in
1525
+ `inventoryRetryAfterSec(error)`. `inventory_api_not_enabled`,
1526
+ `module_inactive`, `article_not_found`, `invalid_cursor`,
1527
+ `webhook_not_found`, `webhook_limit` (5 per account),
1528
+ `invalid_webhook_url`, `event_not_subscribed` and `webhook_inactive` are
1529
+ decided on the code with `isInventoryError(error, code)`.
1530
+
1415
1531
  ## Migrating from 0.x
1416
1532
 
1417
1533
  1.0 is one breaking step: the wire, the exported names and the contract files
@@ -1487,7 +1603,7 @@ in machine form what both sides agreed on, among them:
1487
1603
  |---|---|---|
1488
1604
  | `pos-settings-defaults.json` | field names and defaults of the register settings as sent on `/api/v3` (`business`, `device`), derived from the backend contract in `fixtures/v3/` | `npm run fixtures:kasse` |
1489
1605
  | `stored/pos-settings-defaults.json` | the same defaults in the stored (internal, German) form (`betrieb`, `geraet`) | `npm run fixtures:kasse` |
1490
- | `surface.json` | base URLs (`baseUrls.public`, `baseUrls.pos`), the calls per path (`calls`, and the backend's `routes`), settings value lists (`enums`, keyed by field), other register lists (`pos`), register error codes, permission keys, shortcut actions, partner and invoice lists | `npm run fixtures:oberflaeche` |
1606
+ | `surface.json` | base URLs (`baseUrls.public`, `baseUrls.pos`), the calls per path (`calls`, and the backend's `routes`), settings value lists (`enums`, keyed by field), other register lists (`pos`), register error codes, permission keys, shortcut actions, partner, invoice and inventory lists | `npm run fixtures:oberflaeche` |
1491
1607
  | `hobex-hps-codes.json` | measured HPS result codes, their meaning and whether they settle an outcome (the contract behind `isConclusive`) | `npm run fixtures:hobex-hps-codes` |
1492
1608
  | `pos-texts.json` | the register's message catalogue | `npm run fixtures:texte` |
1493
1609
  | `invoice-texts.json` | invoice texts in both languages | `npm run fixtures:rechnungstexte` |
@@ -13,7 +13,7 @@
13
13
  * umhuellt, muss ihn weiterhin absetzen koennen.
14
14
  */
15
15
  import type { TransportBodyFields } from './transport.js';
16
- export declare const ALL_CALLS: readonly ["activateCashregister", "cancelInvoice", "cancelReceipt", "createCreditNote", "createCustomer", "createCustomerCashregister", "createPartnerCustomer", "checkPartnerCustomerEmail", "createPartnerWebhook", "createPaymentLinkStripe", "createPrintJob", "createReceipt", "deletePartnerWebhook", "downloadDailyReport", "downloadReport", "endRegisterSession", "financeWebService", "generateFullReceiptId", "getCustomer", "getCustomerCredentials", "getCustomerSignatureStatus", "getFirstReceiptDate", "getInvoice", "getInvoicePdf", "getInvoiceSetupStatus", "getInvoiceXml", "getKasseSettings", "getPartnerCustomer", "getPartnerInfo", "getPrintJob", "getReceipt", "getReportV2", "hobexPayApi", "hobexRefundApi", "issueInvoice", "listCustomerCashregisters", "listInvoices", "listBrands", "listMyArticleGroups", "listMyArticles", "listMyCashregisters", "listMyPrinters", "listMyReceipts", "listMyStock", "listMyStockLocations", "listMyTipRecipients", "listPartnerCustomers", "listPartnerWebhookDeliveries", "listPartnerWebhooks", "listRegisterUsersForDevice", "listRegisterSessionsForDevice", "pairRegisterDevice", "recordInvoicePayment", "registerPinLogin", "registerUserLogin", "renewRegisterSession", "reportCustomerContract", "requestCustomerSignature", "searchCustomers", "sendPartnerCustomerFonLink", "sendPartnerWebhookTest", "sendReceiptEmail", "setMyCashregisterStockLocation", "setMyKasseLogo", "setMyKasseSettings", "setMyRegisterDeviceSettings", "stripeCaptureIntent", "unpairRegisterDevice", "rotatePartnerWebhookSecret", "updateCustomer", "updatePartnerWebhook"];
16
+ export declare const ALL_CALLS: readonly ["activateCashregister", "cancelInvoice", "cancelReceipt", "createCreditNote", "createCustomer", "createCustomerCashregister", "createPartnerCustomer", "checkPartnerCustomerEmail", "createPartnerWebhook", "createPaymentLinkStripe", "createPrintJob", "createReceipt", "deletePartnerWebhook", "downloadDailyReport", "downloadReport", "endRegisterSession", "financeWebService", "generateFullReceiptId", "getCustomer", "getCustomerCredentials", "getCustomerSignatureStatus", "getFirstReceiptDate", "getInvoice", "getInvoicePdf", "getInvoiceSetupStatus", "getInvoiceXml", "getKasseSettings", "getPartnerCustomer", "getPartnerInfo", "getPrintJob", "getReceipt", "getReportV2", "hobexPayApi", "hobexRefundApi", "issueInvoice", "listCustomerCashregisters", "listInvoices", "listBrands", "listMyArticleGroups", "listMyArticles", "listMyCashregisters", "listMyPrinters", "listMyReceipts", "listMyStock", "listMyStockLocations", "listMyTipRecipients", "listPartnerCustomers", "listPartnerWebhookDeliveries", "listPartnerWebhooks", "listRegisterUsersForDevice", "listRegisterSessionsForDevice", "pairRegisterDevice", "recordInvoicePayment", "registerPinLogin", "registerUserLogin", "renewRegisterSession", "reportCustomerContract", "requestCustomerSignature", "searchCustomers", "sendPartnerCustomerFonLink", "sendPartnerWebhookTest", "sendReceiptEmail", "setMyCashregisterStockLocation", "setMyKasseLogo", "setMyKasseSettings", "setMyRegisterDeviceSettings", "stripeCaptureIntent", "unpairRegisterDevice", "rotatePartnerWebhookSecret", "updateCustomer", "updatePartnerWebhook", "getArticle", "listArticles", "lookupArticleByCode", "listLocations", "getStock", "listStock", "listStockMovements", "createWebhook", "updateWebhook", "deleteWebhook", "listWebhooks", "sendWebhookTest", "rotateWebhookSecret", "listWebhookDeliveries"];
17
17
  export type ApiCall = typeof ALL_CALLS[number];
18
18
  /**
19
19
  * Die oeffentlichen Endpunkte unter `/v3` (`https://api.kasseneck.at/v3/<name>`),
@@ -21,7 +21,7 @@ export type ApiCall = typeof ALL_CALLS[number];
21
21
  * (`fixtures/v3/v3-vokabular.json`, `endpoints.public`, umbenannt nach
22
22
  * `names`). Ein Test haelt beide Listen deckungsgleich.
23
23
  */
24
- export declare const PUBLIC_CALLS: readonly ["createReceipt", "getReceipt", "cancelReceipt", "sendReceiptEmail", "generateFullReceiptId", "downloadReceipt", "getFirstReceiptDate", "getReportV2", "downloadReport", "downloadDailyReport", "createPaymentLinkStripe", "stripeCaptureIntent", "hobexPayApi", "hobexRefundApi", "hobexGetStatus", "financeWebService", "listMyTipRecipients", "getPartnerInfo", "createPartnerCustomer", "checkPartnerCustomerEmail", "listPartnerCustomers", "getPartnerCustomer", "sendPartnerCustomerFonLink", "createPartnerWebhook", "updatePartnerWebhook", "deletePartnerWebhook", "listPartnerWebhooks", "sendPartnerWebhookTest", "rotatePartnerWebhookSecret", "listPartnerWebhookDeliveries", "requestCustomerSignature", "getCustomerSignatureStatus", "createCustomerCashregister", "activateCashregister", "listCustomerCashregisters", "getCustomerCredentials", "reportCustomerContract", "getPartnerBilling", "getPartnerBillingMonth", "createCustomer", "getCustomer", "updateCustomer", "searchCustomers", "issueInvoice", "cancelInvoice", "createCreditNote", "getInvoice", "listInvoices", "getInvoicePdf", "getInvoiceXml", "getInvoiceSetupStatus", "listBrands", "recordInvoicePayment", "createInvoiceItem", "updateInvoiceItem", "withdrawInvoiceItem", "getInvoiceItem", "listInvoiceItems", "setCustomerMandate", "revokeCustomerMandate"];
24
+ export declare const PUBLIC_CALLS: readonly ["createReceipt", "getReceipt", "cancelReceipt", "sendReceiptEmail", "generateFullReceiptId", "downloadReceipt", "getFirstReceiptDate", "getReportV2", "downloadReport", "downloadDailyReport", "createPaymentLinkStripe", "stripeCaptureIntent", "hobexPayApi", "hobexRefundApi", "hobexGetStatus", "financeWebService", "listMyTipRecipients", "getPartnerInfo", "createPartnerCustomer", "checkPartnerCustomerEmail", "listPartnerCustomers", "getPartnerCustomer", "sendPartnerCustomerFonLink", "createPartnerWebhook", "updatePartnerWebhook", "deletePartnerWebhook", "listPartnerWebhooks", "sendPartnerWebhookTest", "rotatePartnerWebhookSecret", "listPartnerWebhookDeliveries", "requestCustomerSignature", "getCustomerSignatureStatus", "createCustomerCashregister", "activateCashregister", "listCustomerCashregisters", "getCustomerCredentials", "reportCustomerContract", "getPartnerBilling", "getPartnerBillingMonth", "createCustomer", "getCustomer", "updateCustomer", "searchCustomers", "issueInvoice", "cancelInvoice", "createCreditNote", "getInvoice", "listInvoices", "getInvoicePdf", "getInvoiceXml", "getInvoiceSetupStatus", "listBrands", "recordInvoicePayment", "createInvoiceItem", "updateInvoiceItem", "withdrawInvoiceItem", "getInvoiceItem", "listInvoiceItems", "setCustomerMandate", "revokeCustomerMandate", "getArticle", "listArticles", "lookupArticleByCode", "listLocations", "getStock", "listStock", "listStockMovements", "createWebhook", "updateWebhook", "deleteWebhook", "listWebhooks", "sendWebhookTest", "rotateWebhookSecret", "listWebhookDeliveries"];
25
25
  /**
26
26
  * Die Endpunkte des Kassenwegs (`https://kasse.kasseneck.at/api/v3/<name>`,
27
27
  * Web-Kasse: gleicher Ursprung `/api/v3`), in der Reihenfolge von
@@ -75,6 +75,21 @@ exports.ALL_CALLS = [
75
75
  'rotatePartnerWebhookSecret',
76
76
  'updateCustomer',
77
77
  'updatePartnerWebhook',
78
+ // Lager-API (Stufe 5a, ./inventory)
79
+ 'getArticle',
80
+ 'listArticles',
81
+ 'lookupArticleByCode',
82
+ 'listLocations',
83
+ 'getStock',
84
+ 'listStock',
85
+ 'listStockMovements',
86
+ 'createWebhook',
87
+ 'updateWebhook',
88
+ 'deleteWebhook',
89
+ 'listWebhooks',
90
+ 'sendWebhookTest',
91
+ 'rotateWebhookSecret',
92
+ 'listWebhookDeliveries',
78
93
  ];
79
94
  /**
80
95
  * Die oeffentlichen Endpunkte unter `/v3` (`https://api.kasseneck.at/v3/<name>`),
@@ -146,6 +161,21 @@ exports.PUBLIC_CALLS = [
146
161
  'listInvoiceItems',
147
162
  'setCustomerMandate',
148
163
  'revokeCustomerMandate',
164
+ // Lager-API lesen und Konto-Webhooks (Backend Stufe 5a), umhuellt in `./inventory`.
165
+ 'getArticle',
166
+ 'listArticles',
167
+ 'lookupArticleByCode',
168
+ 'listLocations',
169
+ 'getStock',
170
+ 'listStock',
171
+ 'listStockMovements',
172
+ 'createWebhook',
173
+ 'updateWebhook',
174
+ 'deleteWebhook',
175
+ 'listWebhooks',
176
+ 'sendWebhookTest',
177
+ 'rotateWebhookSecret',
178
+ 'listWebhookDeliveries',
149
179
  ];
150
180
  /**
151
181
  * Die Endpunkte des Kassenwegs (`https://kasse.kasseneck.at/api/v3/<name>`,
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Fassade ueber den Aufrufen der Lager-API: Schluessel einmal binden, dann
3
+ * rufen. Wie [createInvoiceApi] bewusst keine Klasse; die Aufrufe sind freie
4
+ * Funktionen (endpunkte.ts) und bleiben einzeln importierbar.
5
+ */
6
+ import { type FetchLike } from '../client/transport.js';
7
+ import type { Article, ArticleListQuery, ArticleLookup, ArticlePage, CreateInventoryWebhookOptions, InventoryWebhook, InventoryWebhookDelivery, InventoryWebhookList, InventoryWebhookPatch, InventoryWebhookTestResult, InventoryWebhookWithSecret, Location, StockLevel, StockListQuery, StockMovement, StockMovementPage, StockMovementQuery, StockPage, StockResult } from './typen.js';
8
+ import type { InventoryWebhookEventType } from './vertrag.js';
9
+ export interface InventoryClientOptions {
10
+ /** `api_key` des Kontos (`kr_live_…` / `kr_test_…`). Gehoert auf einen Server. */
11
+ apiKey: string;
12
+ /** Abweichende Basis-URL (eigener Proxy); muss auf `/v3` enden. Vorgabe `https://api.kasseneck.at/v3`. */
13
+ baseUrl?: string;
14
+ /** Zeitlimit je Aufruf in Millisekunden. */
15
+ timeoutMs?: number;
16
+ /** Eigene `fetch`-Umsetzung (Tests, Proxys). */
17
+ fetch?: FetchLike;
18
+ }
19
+ export interface InventoryClient {
20
+ getArticle(articleId: string): Promise<Article>;
21
+ listArticles(query?: ArticleListQuery): Promise<ArticlePage>;
22
+ /** Alle Artikel der Abfrage ueber `nextCursor`: `for await (const a of client.iterateArticles())`. */
23
+ iterateArticles(query?: ArticleListQuery): AsyncGenerator<Article, void, undefined>;
24
+ lookupArticleByCode(lookup: ArticleLookup): Promise<Article>;
25
+ listLocations(): Promise<Location[]>;
26
+ getStock(articleId: string): Promise<StockResult>;
27
+ listStock(query?: StockListQuery): Promise<StockPage>;
28
+ iterateStock(query?: StockListQuery): AsyncGenerator<StockLevel, void, undefined>;
29
+ listStockMovements(query?: StockMovementQuery): Promise<StockMovementPage>;
30
+ iterateStockMovements(query?: StockMovementQuery): AsyncGenerator<StockMovement, void, undefined>;
31
+ createWebhook(options: CreateInventoryWebhookOptions): Promise<InventoryWebhookWithSecret>;
32
+ updateWebhook(webhookId: string, patch: InventoryWebhookPatch): Promise<InventoryWebhook>;
33
+ deleteWebhook(webhookId: string): Promise<{
34
+ webhookId: string;
35
+ deleted: boolean;
36
+ }>;
37
+ listWebhooks(): Promise<InventoryWebhookList>;
38
+ sendWebhookTest(webhookId: string, event: InventoryWebhookEventType | (string & {})): Promise<InventoryWebhookTestResult>;
39
+ rotateWebhookSecret(webhookId: string): Promise<InventoryWebhookWithSecret>;
40
+ listWebhookDeliveries(options?: {
41
+ webhookId?: string;
42
+ limit?: number;
43
+ }): Promise<InventoryWebhookDelivery[]>;
44
+ }
45
+ export declare function createInventoryClient(options: InventoryClientOptions): InventoryClient;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ /**
3
+ * Fassade ueber den Aufrufen der Lager-API: Schluessel einmal binden, dann
4
+ * rufen. Wie [createInvoiceApi] bewusst keine Klasse; die Aufrufe sind freie
5
+ * Funktionen (endpunkte.ts) und bleiben einzeln importierbar.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.createInventoryClient = createInventoryClient;
9
+ const transport_js_1 = require("../client/transport.js");
10
+ const auth_js_1 = require("./auth.js");
11
+ const endpunkte_js_1 = require("./endpunkte.js");
12
+ function createInventoryClient(options) {
13
+ const rufen = (0, transport_js_1.createTransport)({
14
+ auth: (0, auth_js_1.inventoryKeyAuth)({ apiKey: options.apiKey }),
15
+ baseUrl: options.baseUrl,
16
+ timeoutMs: options.timeoutMs,
17
+ fetch: options.fetch,
18
+ });
19
+ return {
20
+ getArticle: (id) => (0, endpunkte_js_1.getArticle)(rufen, id),
21
+ listArticles: (q) => (0, endpunkte_js_1.listArticles)(rufen, q),
22
+ iterateArticles: (q) => (0, endpunkte_js_1.iterateArticles)(rufen, q),
23
+ lookupArticleByCode: (l) => (0, endpunkte_js_1.lookupArticleByCode)(rufen, l),
24
+ listLocations: () => (0, endpunkte_js_1.listLocations)(rufen),
25
+ getStock: (id) => (0, endpunkte_js_1.getStock)(rufen, id),
26
+ listStock: (q) => (0, endpunkte_js_1.listStock)(rufen, q),
27
+ iterateStock: (q) => (0, endpunkte_js_1.iterateStock)(rufen, q),
28
+ listStockMovements: (q) => (0, endpunkte_js_1.listStockMovements)(rufen, q),
29
+ iterateStockMovements: (q) => (0, endpunkte_js_1.iterateStockMovements)(rufen, q),
30
+ createWebhook: (o) => (0, endpunkte_js_1.createWebhook)(rufen, o),
31
+ updateWebhook: (id, patch) => (0, endpunkte_js_1.updateWebhook)(rufen, id, patch),
32
+ deleteWebhook: (id) => (0, endpunkte_js_1.deleteWebhook)(rufen, id),
33
+ listWebhooks: () => (0, endpunkte_js_1.listWebhooks)(rufen),
34
+ sendWebhookTest: (id, event) => (0, endpunkte_js_1.sendWebhookTest)(rufen, id, event),
35
+ rotateWebhookSecret: (id) => (0, endpunkte_js_1.rotateWebhookSecret)(rufen, id),
36
+ listWebhookDeliveries: (o) => (0, endpunkte_js_1.listWebhookDeliveries)(rufen, o),
37
+ };
38
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Anmeldung fuer die Lager-API: der `api_key` des Kontos als Bearer, ohne
3
+ * `cashregister-token` (gelesen wird am Konto, nicht an einer Kasse).
4
+ *
5
+ * **Der Schluessel gehoert auf einen Server**, etwa in das Backend eines
6
+ * Online-Shops, nie in ein Browser-Buendel.
7
+ *
8
+ * Geprueft wird nur, was ohne Netz sicher falsch ist: ein leerer Wert, ein
9
+ * Partner-Schluessel (`pk_…`) oder ein Kassen-Token (`cb_…`). Die Meldung
10
+ * nennt nie den Wert, nur seine Art.
11
+ */
12
+ import type { KasseneckAuth } from '../client/auth.js';
13
+ export interface InventoryKeyAuthOptions {
14
+ /** `api_key` des Kontos, z. B. `kr_live_…` oder `kr_test_…`. */
15
+ apiKey: string;
16
+ }
17
+ export declare function inventoryKeyAuth(options: InventoryKeyAuthOptions): KasseneckAuth;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ /**
3
+ * Anmeldung fuer die Lager-API: der `api_key` des Kontos als Bearer, ohne
4
+ * `cashregister-token` (gelesen wird am Konto, nicht an einer Kasse).
5
+ *
6
+ * **Der Schluessel gehoert auf einen Server**, etwa in das Backend eines
7
+ * Online-Shops, nie in ein Browser-Buendel.
8
+ *
9
+ * Geprueft wird nur, was ohne Netz sicher falsch ist: ein leerer Wert, ein
10
+ * Partner-Schluessel (`pk_…`) oder ein Kassen-Token (`cb_…`). Die Meldung
11
+ * nennt nie den Wert, nur seine Art.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.inventoryKeyAuth = inventoryKeyAuth;
15
+ const errors_js_1 = require("../client/errors.js");
16
+ function inventoryKeyAuth(options) {
17
+ const schluessel = typeof options?.apiKey === 'string' ? options.apiKey.trim() : '';
18
+ if (!schluessel)
19
+ throw new errors_js_1.KasseneckAuthError('inventoryKeyAuth: apiKey fehlt');
20
+ if (/^pk_(live|test)_/i.test(schluessel)) {
21
+ throw new errors_js_1.KasseneckAuthError('inventoryKeyAuth: das ist ein Partner-Schluessel (pk_…); die Lager-API nimmt den api_key des Kontos (kr_…)');
22
+ }
23
+ if (/^cb_(live|test)_/i.test(schluessel)) {
24
+ throw new errors_js_1.KasseneckAuthError('inventoryKeyAuth: das ist ein Kassen-Token (cb_…); die Lager-API nimmt den api_key des Kontos (kr_…)');
25
+ }
26
+ return () => ({ headers: { Authorization: `Bearer ${schluessel}` }, params: {} });
27
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Die Aufrufe der Lager-API: Artikel, Standorte, Bestand und Bewegungen
3
+ * lesen, Konto-Webhooks verwalten (Backend Stufe 5a).
4
+ *
5
+ * Jede Funktion nimmt den Transport als ersten Parameter und ist einzeln
6
+ * importierbar; die Fassade [createInventoryClient] bindet ihn nur einmal.
7
+ *
8
+ * **Geprueft wird hier nur, was ohne Netz sicher falsch ist** (leere Kennung,
9
+ * `limit` ausserhalb 1–200, eine Aenderung ohne Feld). Alles Fachliche prueft
10
+ * der Server und meldet es als `validation` mit `errors[]`; zwei Pruefungen
11
+ * hiessen zwei Wahrheiten.
12
+ *
13
+ * Lesen hat keine Wirkung: nach einem Zeitlimit darf derselbe Aufruf
14
+ * wiederholt werden. Bei `rate_limited` vorher `retryAfterSec` warten
15
+ * ([inventoryRetryAfterSec]).
16
+ */
17
+ import type { InternerTransport } from '../client/aufrufe.js';
18
+ import type { Article, ArticleListQuery, ArticleLookup, ArticlePage, CreateInventoryWebhookOptions, InventoryWebhook, InventoryWebhookDelivery, InventoryWebhookList, InventoryWebhookPatch, InventoryWebhookTestResult, InventoryWebhookWithSecret, Location, StockLevel, StockListQuery, StockMovement, StockMovementPage, StockMovementQuery, StockPage, StockResult } from './typen.js';
19
+ export declare function getArticle(transport: InternerTransport, articleId: string): Promise<Article>;
20
+ export declare function listArticles(transport: InternerTransport, query?: ArticleListQuery): Promise<ArticlePage>;
21
+ /** Alle Artikel der Abfrage, Seite fuer Seite ueber `nextCursor`. */
22
+ export declare function iterateArticles(transport: InternerTransport, query?: ArticleListQuery): AsyncGenerator<Article, void, undefined>;
23
+ /**
24
+ * Ein aktiver Artikel per Code (`number`, `ean` oder `internalCode`) oder per
25
+ * eigener Kennung aus `externalIds` (`{ externalSystem: 'shop', externalId: '4711' }`).
26
+ * Ein stillgelegter Artikel gilt als nicht gefunden (`article_not_found`).
27
+ */
28
+ export declare function lookupArticleByCode(transport: InternerTransport, lookup: ArticleLookup): Promise<Article>;
29
+ /** Alle Standorte des Kontos, samt aufgeloesten (`active: false`) und dem Hauptstandort. */
30
+ export declare function listLocations(transport: InternerTransport): Promise<Location[]>;
31
+ /** Bestand eines Artikels je Standort. */
32
+ export declare function getStock(transport: InternerTransport, articleId: string): Promise<StockResult>;
33
+ export declare function listStock(transport: InternerTransport, query?: StockListQuery): Promise<StockPage>;
34
+ /**
35
+ * Alle Bestandszeilen der Abfrage, Seite fuer Seite. Die Werte (`values`)
36
+ * stehen je Seite in [listStock]; der Iterator liefert nur die Zeilen.
37
+ */
38
+ export declare function iterateStock(transport: InternerTransport, query?: StockListQuery): AsyncGenerator<StockLevel, void, undefined>;
39
+ /** Das Lagerprotokoll, neueste zuerst. */
40
+ export declare function listStockMovements(transport: InternerTransport, query?: StockMovementQuery): Promise<StockMovementPage>;
41
+ export declare function iterateStockMovements(transport: InternerTransport, query?: StockMovementQuery): AsyncGenerator<StockMovement, void, undefined>;
42
+ /**
43
+ * Legt einen Webhook an (hoechstens 5 je Konto, `webhook_limit`).
44
+ * **Das Secret in der Antwort kommt nur dieses eine Mal**; sofort dorthin
45
+ * schreiben, wo der Empfaenger es liest, nicht in ein Protokoll.
46
+ */
47
+ export declare function createWebhook(transport: InternerTransport, options: CreateInventoryWebhookOptions): Promise<InventoryWebhookWithSecret>;
48
+ /** Aendert nur die genannten Felder; `description: null` loescht die Beschreibung. */
49
+ export declare function updateWebhook(transport: InternerTransport, webhookId: string, patch: InventoryWebhookPatch): Promise<InventoryWebhook>;
50
+ export declare function deleteWebhook(transport: InternerTransport, webhookId: string): Promise<{
51
+ webhookId: string;
52
+ deleted: boolean;
53
+ }>;
54
+ /** Die Webhooks des Kontos und die Ereignisse, die es abonnieren kann. */
55
+ export declare function listWebhooks(transport: InternerTransport): Promise<InventoryWebhookList>;
56
+ /**
57
+ * Ein neues Secret fuer denselben Webhook. Ab der Antwort gilt nur noch das
58
+ * neue (keine Uebergangsfrist): erst speichern, dann weiterarbeiten.
59
+ */
60
+ export declare function rotateWebhookSecret(transport: InternerTransport, webhookId: string): Promise<InventoryWebhookWithSecret>;
61
+ /**
62
+ * Eine Probe genau dieses Ereignisses an genau diesen Webhook, mit erfundener
63
+ * Nutzlast und `test: true` in der Huelle. Der Webhook muss das Ereignis
64
+ * abonnieren (`event_not_subscribed`) und aktiv sein (`webhook_inactive`).
65
+ */
66
+ export declare function sendWebhookTest(transport: InternerTransport, webhookId: string, event: string): Promise<InventoryWebhookTestResult>;
67
+ /** Die letzten Zustellungen, neueste zuerst; mit `webhookId` nur die eines Webhooks. */
68
+ export declare function listWebhookDeliveries(transport: InternerTransport, options?: {
69
+ webhookId?: string;
70
+ limit?: number;
71
+ }): Promise<InventoryWebhookDelivery[]>;