@kreiseck/kasseneck-api 1.7.1 → 1.10.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 (125) hide show
  1. package/CHANGELOG.md +113 -0
  2. package/README.md +170 -1
  3. package/dist/cjs/client/api.d.ts +5 -3
  4. package/dist/cjs/client/api.js +1 -0
  5. package/dist/cjs/client/aufrufe.d.ts +9 -7
  6. package/dist/cjs/client/aufrufe.js +60 -2
  7. package/dist/cjs/client/errors.js +3 -0
  8. package/dist/cjs/client/index.d.ts +2 -2
  9. package/dist/cjs/client/index.js +3 -1
  10. package/dist/cjs/client/reports.d.ts +26 -0
  11. package/dist/cjs/client/reports.js +47 -0
  12. package/dist/cjs/client/transport.d.ts +27 -3
  13. package/dist/cjs/client/transport.js +29 -3
  14. package/dist/cjs/index.d.ts +1 -1
  15. package/dist/cjs/index.js +4 -2
  16. package/dist/cjs/inventory/api.d.ts +21 -2
  17. package/dist/cjs/inventory/api.js +22 -3
  18. package/dist/cjs/inventory/fehler.d.ts +6 -0
  19. package/dist/cjs/inventory/fehler.js +12 -0
  20. package/dist/cjs/inventory/index.d.ts +6 -4
  21. package/dist/cjs/inventory/index.js +33 -3
  22. package/dist/cjs/inventory/inventur.d.ts +104 -0
  23. package/dist/cjs/inventory/inventur.js +245 -0
  24. package/dist/cjs/inventory/lesen.d.ts +20 -1
  25. package/dist/cjs/inventory/lesen.js +307 -0
  26. package/dist/cjs/inventory/typen.d.ts +410 -1
  27. package/dist/cjs/inventory/vertrag.d.ts +94 -8
  28. package/dist/cjs/inventory/vertrag.js +118 -5
  29. package/dist/cjs/invoice/index.d.ts +1 -1
  30. package/dist/cjs/invoice/typen.d.ts +12 -0
  31. package/dist/cjs/invoice/vertrag.d.ts +1 -1
  32. package/dist/cjs/invoice/vertrag.js +3 -0
  33. package/dist/cjs/models/cancellation.d.ts +1 -1
  34. package/dist/cjs/models/cancellation.js +3 -0
  35. package/dist/cjs/models/payment-errors.d.ts +1 -1
  36. package/dist/cjs/models/payment-errors.js +3 -0
  37. package/dist/cjs/models/receipt-email.d.ts +1 -1
  38. package/dist/cjs/models/receipt-email.js +3 -0
  39. package/dist/cjs/models/receipt-errors.d.ts +1 -1
  40. package/dist/cjs/models/receipt-errors.js +3 -0
  41. package/dist/cjs/pos/errors.d.ts +4 -3
  42. package/dist/cjs/pos/errors.js +24 -2
  43. package/dist/cjs/pos/index.d.ts +4 -1
  44. package/dist/cjs/pos/index.js +9 -2
  45. package/dist/cjs/pos/inventur.d.ts +104 -0
  46. package/dist/cjs/pos/inventur.js +117 -0
  47. package/dist/cjs/pos/texte.d.ts +82 -0
  48. package/dist/cjs/pos/texte.js +35 -0
  49. package/dist/cjs/register/errors.d.ts +1 -1
  50. package/dist/cjs/register/errors.js +3 -0
  51. package/dist/cjs/stored/vokabular.d.ts +1 -1
  52. package/dist/cjs/stored/vokabular.js +1 -1
  53. package/dist/cjs/version.d.ts +1 -1
  54. package/dist/cjs/version.js +1 -1
  55. package/dist/esm/client/api.d.ts +5 -3
  56. package/dist/esm/client/api.js +2 -1
  57. package/dist/esm/client/aufrufe.d.ts +9 -7
  58. package/dist/esm/client/aufrufe.js +60 -2
  59. package/dist/esm/client/errors.js +3 -0
  60. package/dist/esm/client/index.d.ts +2 -2
  61. package/dist/esm/client/index.js +2 -2
  62. package/dist/esm/client/reports.d.ts +26 -0
  63. package/dist/esm/client/reports.js +46 -0
  64. package/dist/esm/client/transport.d.ts +27 -3
  65. package/dist/esm/client/transport.js +28 -3
  66. package/dist/esm/index.d.ts +1 -1
  67. package/dist/esm/index.js +1 -1
  68. package/dist/esm/inventory/api.d.ts +21 -2
  69. package/dist/esm/inventory/api.js +23 -4
  70. package/dist/esm/inventory/fehler.d.ts +6 -0
  71. package/dist/esm/inventory/fehler.js +11 -0
  72. package/dist/esm/inventory/index.d.ts +6 -4
  73. package/dist/esm/inventory/index.js +5 -3
  74. package/dist/esm/inventory/inventur.d.ts +104 -0
  75. package/dist/esm/inventory/inventur.js +226 -0
  76. package/dist/esm/inventory/lesen.d.ts +20 -1
  77. package/dist/esm/inventory/lesen.js +301 -0
  78. package/dist/esm/inventory/typen.d.ts +410 -1
  79. package/dist/esm/inventory/vertrag.d.ts +94 -8
  80. package/dist/esm/inventory/vertrag.js +117 -4
  81. package/dist/esm/invoice/index.d.ts +1 -1
  82. package/dist/esm/invoice/typen.d.ts +12 -0
  83. package/dist/esm/invoice/vertrag.d.ts +1 -1
  84. package/dist/esm/invoice/vertrag.js +3 -0
  85. package/dist/esm/models/cancellation.d.ts +1 -1
  86. package/dist/esm/models/cancellation.js +3 -0
  87. package/dist/esm/models/payment-errors.d.ts +1 -1
  88. package/dist/esm/models/payment-errors.js +3 -0
  89. package/dist/esm/models/receipt-email.d.ts +1 -1
  90. package/dist/esm/models/receipt-email.js +3 -0
  91. package/dist/esm/models/receipt-errors.d.ts +1 -1
  92. package/dist/esm/models/receipt-errors.js +3 -0
  93. package/dist/esm/pos/errors.d.ts +4 -3
  94. package/dist/esm/pos/errors.js +24 -2
  95. package/dist/esm/pos/index.d.ts +4 -1
  96. package/dist/esm/pos/index.js +2 -1
  97. package/dist/esm/pos/inventur.d.ts +104 -0
  98. package/dist/esm/pos/inventur.js +109 -0
  99. package/dist/esm/pos/texte.d.ts +82 -0
  100. package/dist/esm/pos/texte.js +35 -0
  101. package/dist/esm/register/errors.d.ts +1 -1
  102. package/dist/esm/register/errors.js +3 -0
  103. package/dist/esm/stored/vokabular.d.ts +1 -1
  104. package/dist/esm/stored/vokabular.js +1 -1
  105. package/dist/esm/version.d.ts +1 -1
  106. package/dist/esm/version.js +1 -1
  107. package/fixtures/hobex-hps-codes.json +1 -1
  108. package/fixtures/invoice-api.schema.json +1 -1
  109. package/fixtures/invoice-texts.json +1 -1
  110. package/fixtures/pos-texts.json +94 -1
  111. package/fixtures/stocktake-quantity-cases.json +55 -0
  112. package/fixtures/surface.json +157 -8
  113. package/fixtures/v3/antworten/belege.json +1 -1
  114. package/fixtures/v3/antworten/belegmail.json +1 -1
  115. package/fixtures/v3/antworten/kasse-belege.json +1 -1
  116. package/fixtures/v3/antworten/kasse.json +2958 -3
  117. package/fixtures/v3/antworten/lager.json +1727 -3
  118. package/fixtures/v3/antworten/rechnungen.json +14 -6
  119. package/fixtures/v3/antworten/storno.json +1 -1
  120. package/fixtures/v3/stored/belege.json +1 -1
  121. package/fixtures/v3/stored/kasse.json +414 -3
  122. package/fixtures/v3/stored/rechnungen.json +1 -1
  123. package/fixtures/v3/v3-vokabular.json +530 -8
  124. package/fixtures/v3/zahlbetrag-faelle.json +1 -1
  125. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,119 @@ 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.10.0
8
+
9
+ - New `getCashregisterReport(options)`: cash register report PDF (v2) for a closed month, a day up to today or a date range (`end` exclusive, max. 366 days). Reason: one successor for the monthly and daily report downloads, same rules as the customer panel.
10
+ - Deprecated `downloadMonthlyReport` and `downloadDailyReport`. Reason: the endpoints are deprecated; they keep working (closed periods now return the v2 report, the current month and today the previous layout).
11
+ - New error code `password_change_required` in the request error code lists. Reason: the backend /v3 contract already contains them since keck#638 (mandatory password change is rejected before the handler).
12
+ - `InvoiceVatIdProof` gains `afterSupplyDate` and `supplyDateProof` (new type `InvoiceSupplyDateProof`). Reason: the backend /v3 contract already contains them since keck#644 (proof relative to the date of supply).
13
+
14
+ ## 1.8.0
15
+
16
+ Stocktake (Lager-Kern stage 3): `./inventory` gains the twelve stocktake
17
+ endpoints of the inventory API, `./pos` the five calls for counting at the
18
+ register. Reason: a business that counts its stock had only the old
19
+ "set the stock to this number" adjustment, which knows no expected quantity
20
+ at the time of the count, no several counts per article, no blind count and
21
+ no record. The backend now runs a stocktake as its own process (count, review,
22
+ recount, close in parts, PDF record with the state of the ledger seal), and
23
+ shops, the web register and the app need it through the package.
24
+
25
+ Additive at runtime; existing calls send the same bytes as in 1.7.1. As in
26
+ 1.6.0, the unions `InventoryEndpoint`, `InventoryErrorCode`,
27
+ `InventoryWarningCode`, `PosErrorCode`, `ApiCall`, `PublicCall`, `PosCall`,
28
+ `MessageKey`, `LabelKey` and the error code unions derived from the
29
+ authentication codes (see Contract below) gain members, so an exhaustive `switch` with a
30
+ `never` check needs the new cases.
31
+
32
+ - **Inventory API**: `createStocktake`, `listStocktakes`/`iterateStocktakes`
33
+ (without `updatedSince` the most recently changed first; with `updatedSince`
34
+ sorted by `updatedAt` ascending and inclusive, like `listArticles`),
35
+ `getStocktake` (with `progress.counted`), `listStocktakeItems`/
36
+ `iterateStocktakeItems` (`openOnly`), `recordStocktakeCount`,
37
+ `voidStocktakeCount`, `listStocktakeCounts`/`iterateStocktakeCounts`,
38
+ `reviewStocktake`, `recountStocktake`, `closeStocktake` (answers
39
+ `{ stocktake, warnings }`), `cancelStocktake` and `getStocktakePdf`. Models
40
+ `Stocktake`, `StocktakeItem`, `StocktakeCount` and their parts; the result
41
+ fields of a closed stocktake (`totals`, `warnings`, `seal`, `checksum`,
42
+ `inventoryAsOf`, `pdf`) and the expected quantity of an item
43
+ (`expectedQuantity`, `differenceQuantity`, `needsCheck` …) are present only
44
+ when the server sends them: never before `review` (blind), values only with
45
+ `costs`. A missing count, quantity, round or list of counters, and an actor
46
+ that is not an object, are response errors, never `0` or "nobody".
47
+ `StocktakeItem.serialNumbers` is present only when the server sends it (the
48
+ answer of counting and voiding omits it), never invented as `[]`.
49
+ - **The record**: `getStocktakePdf` returns `{ kind: 'pdf', pdf }` (the bytes,
50
+ up to 9 MiB) or `{ kind: 'download', download: { url, expiresAt, sizeBytes,
51
+ sha256, fileName, contentType } }` (a signed link for 15 minutes above
52
+ that). It reads the answer as bytes like the report downloads and accepts
53
+ either a PDF or a success envelope. The transport for it is public:
54
+ `createPdfOrDataTransport(options)` at the package root (types
55
+ `KasseneckPdfOrDataTransport`, `PdfOrData`), so the free function
56
+ `getStocktakePdf(transport, stocktakeId)` works outside the client too, as
57
+ `getInvoicePdf` does with `createBinaryTransport`.
58
+ - **Counting at the register** (`./pos`, register path only):
59
+ `listMyStocktakes`, `listMyStocktakeItems`, `listMyStocktakeCounts`,
60
+ `recordMyStocktakeCount`, `voidMyStocktakeCount`, with the same models.
61
+ `parseQuantityMilli(text, unit, rule?)` turns the typed quantity into
62
+ thousandths without floating point (comma or point, at most three decimals;
63
+ a point with exactly three digits after a non-zero whole part, `'1.000'`,
64
+ is ambiguous and `null` for every unit; pieces, by the stored `rule` of the
65
+ article or else by the unit, whole numbers without separator only); its
66
+ cases are shared with the Dart twin in the new
67
+ `fixtures/stocktake-quantity-cases.json`.
68
+ Messages and labels `stocktake.*` for the counting screen in the catalogue
69
+ (`fixtures/pos-texts.json`).
70
+ - **Idempotency and outcome**: every write takes `idempotencyKey` (refused
71
+ before sending without a valid one). `createStocktake`, `recordStocktakeCount`,
72
+ `voidStocktakeCount`, `reviewStocktake`, `recountStocktake`, `closeStocktake`,
73
+ `cancelStocktake`, `recordMyStocktakeCount` and `voidMyStocktakeCount` are in
74
+ `UNKNOWN_OUTCOME_CALLS`: after `outcome: 'unknown'` resend with the **same**
75
+ key, a count is then counted once. The eight reads are in the list without
76
+ effect.
77
+ - **Checked before sending**, nothing else: the key, `stocktakeId`,
78
+ `articleId`, `countId`, `locationId`, `scope` as an object, an integer
79
+ `quantity`, a non-empty `reason`, a non-empty `items` list with `articleId`
80
+ for a recount, `serialNumbers` as a list, `uncountedAsZero` as a boolean.
81
+ The limits (5000 items, 200 per recount, 200 counts per item and round) are
82
+ left to the server and exported as `STOCKTAKE_ITEMS_MAX`,
83
+ `STOCKTAKE_RECOUNT_ITEMS_MAX`, `STOCKTAKE_COUNTS_PER_ITEM_MAX`.
84
+ - **Catalogues**: `STOCKTAKE_STATUSES`, `STOCKTAKE_TYPES`,
85
+ `STOCKTAKE_SCOPE_TYPES`, `STOCKTAKE_CHECK_REASONS`,
86
+ `STOCKTAKE_NOT_BOOKED_REASONS`, `STOCKTAKE_SOURCES`, `STOCKTAKE_ACTOR_TYPES`,
87
+ `STOCKTAKE_INVENTORY_AS_OF`, each the contract catalogue in its order.
88
+ - **Errors**: `INVENTORY_ERROR_CODES` appends `stocktake_not_found`,
89
+ `stocktake_not_open`, `stocktake_closed`, `stocktake_not_in_review`,
90
+ `stocktake_closing`, `stocktake_location_busy` (with `data.stocktakeId`, read
91
+ by the new `inventoryBusyStocktakeId(error)`), `stocktake_review_running`,
92
+ `stocktake_recount_open`, `article_not_in_scope`, `article_not_tracked`,
93
+ `count_not_found`, `count_already_voided`, `serial_already_counted`,
94
+ `too_many_counts` and `stocktake_not_closed`; `INVENTORY_WARNING_CODES`
95
+ appends `defect_capped`, `uncounted_items`, `not_booked` and
96
+ `recount_uncounted`. `POS_ERROR_CODES` gains the codes of the five register
97
+ calls.
98
+ - **Contract**: `fixtures/v3/` pulled from the backend at the state of the
99
+ stocktake (keck #633, #634); the vocabulary of `./stored` regenerated
100
+ (fingerprint only). The contract also lists `app_check_missing` and
101
+ `app_check_invalid` among the authentication codes (App Check of the admin
102
+ app, refused before any handler); every list derived from them gains both:
103
+ `RECEIPT_ERROR_CODES`, `CANCELLATION_ERROR_CODES`,
104
+ `RECEIPT_EMAIL_ERROR_CODES`, `PAYMENT_ERROR_CODES`, `REGISTER_ERROR_CODES`,
105
+ `POS_ERROR_CODES`, `INVOICE_REQUEST_ERROR_CODES`,
106
+ `INVENTORY_REQUEST_ERROR_CODES` (and their unions) and
107
+ `PAYMENT_CALL_REJECTED_CODES`, so they stay `rejected` on the money calls
108
+ (the Dart twin's `paymentCallRejectedCodes` follows). No call of this
109
+ package can receive them: the backend sends them only on three endpoints
110
+ of the admin app (App Check), none of which is public `/v3`, on the register
111
+ path or wrapped here; the lists follow the contract so that their guards
112
+ stay derived from it.
113
+ - **Counts**: `PUBLIC_CALLS` 92 → 104, `POS_CALLS` 28 → 33 (27 register-only
114
+ names).
115
+ - **Twin check**: the source fingerprint of `functions-kasse/kasse-settings-core.js`
116
+ in `test/fixtures/stored-zwillinge.json` follows the backend, which only added
117
+ functions after `mische` (card provider and auto-logout per device); the
118
+ behaviour comparison of `./stored` against the backend is unchanged and green.
119
+
7
120
  ## 1.7.1
8
121
 
9
122
  `ReceiptSheetLines` pins `letter-spacing` and `word-spacing` to 0. Reason:
package/README.md CHANGED
@@ -893,6 +893,48 @@ errors such as `location_not_found` and `location_inactive` are in
893
893
  `RETURN_DISPOSITION_LABELS` gives the label of each return choice
894
894
  (`labelText(RETURN_DISPOSITION_LABELS.restock)` is "Zurück ins Lager").
895
895
 
896
+ **Counting a stocktake at the register.** Five calls on the register path,
897
+ permissions `stocktakeCount` (count, void own counts) and `stocktakeClose`
898
+ (also void other people's counts; the expected quantity from `review` on).
899
+ Creating, reviewing and closing happen in the panel or through the inventory
900
+ API, not at the register.
901
+
902
+ ```ts
903
+ import { listMyStocktakes, listMyStocktakeItems, recordMyStocktakeCount, voidMyStocktakeCount, parseQuantityMilli, messageText, labelText } from '@kreiseck/kasseneck-api/pos';
904
+
905
+ const [open] = await listMyStocktakes(transport, { locationId: 'haupt' });
906
+ if (!open) showHint(messageText('stocktake.none_open'));
907
+ const { items } = await listMyStocktakeItems(transport, { stocktakeId: open!.id, openOnly: true });
908
+ const quantity = parseQuantityMilli('0,25', 'kg', article.quantityRule); // 250; null for invalid input
909
+ if (quantity === null) showHint(messageText('stocktake.quantity_invalid'));
910
+ const key = crypto.randomUUID(); // keep it for "Erneut senden"
911
+ const { count, item } = await recordMyStocktakeCount(transport, {
912
+ idempotencyKey: key, stocktakeId: open!.id, articleId: items[0]!.articleId, quantity: quantity!,
913
+ });
914
+ await voidMyStocktakeCount(transport, { idempotencyKey: `${key}-void`, stocktakeId: open!.id, countId: count.id, reason: 'Doppelt gezählt' });
915
+ ```
916
+
917
+ `parseQuantityMilli(text, unit, rule?)` turns the typed text into thousandths
918
+ without floating point: comma or point as decimal separator, at most three
919
+ decimals (trailing zeros do not count). A point followed by exactly three
920
+ digits after a non-zero whole part (`'1.000'`, `'12.500'`) is `null` for every
921
+ unit: in Austrian notation it is a thousands separator, on a keypad a decimal
922
+ point, and a factor of 1000 would be booked as a difference; with a comma it
923
+ is unambiguous (`'1,000'` is 1000, i.e. one unit). Pieces take whole numbers
924
+ without any separator only. Whether an article is counted in pieces comes
925
+ from `rule`, the stored quantity rule of the article (`PosArticle.quantityRule`,
926
+ `'piece'` or `'decimal'`), without it from the default of the unit
927
+ (`quantityRuleForUnit`: `Stk`, `g`, `ml` …, also when the unit is missing);
928
+ pass `'piece'` for a serial-number article. Anything else is `null`. Its cases are shared with the Dart twin in
929
+ `fixtures/stocktake-quantity-cases.json`. Counting works online only; after
930
+ `outcome: 'unknown'` resend the **same** count with the **same** key
931
+ (`labelText('stocktake.resend')`), it is counted exactly once. The texts of the
932
+ counting screen are in the catalogue as `stocktake.*`
933
+ (`messageText('stocktake.counted', { name, quantity })`,
934
+ `labelText('stocktake.progress', { counted, total })`); the error codes
935
+ (`stocktake_not_open`, `article_not_in_scope`, `count_already_voided` …) are in
936
+ `POS_ERROR_CODES`.
937
+
896
938
  `stockViewOf(perms)` (also exported from the package root) tells whether a
897
939
  register user may see locations and quantities: a missing `stockView` counts
898
940
  as granted, only an explicit `false` blocks it, and the other stock
@@ -1483,7 +1525,8 @@ ones made at the register in the shop. Since 1.5.0 also the write side:
1483
1525
  create and update articles, book goods receipts, transfers, losses and
1484
1526
  condition changes, and reserve stock at checkout (see
1485
1527
  [Shop: reserve and invoice](#shop-reserve-and-invoice)); since 1.6.0 variant
1486
- groups (sizes, colours, see [Variants](#variants)). Uses the `api_key` of
1528
+ groups (sizes, colours, see [Variants](#variants)); since 1.8.0 stocktakes
1529
+ (see [Stocktake](#stocktake)). Uses the `api_key` of
1487
1530
  the account and belongs on a **server**. Reading needs the module `lager`,
1488
1531
  writing additionally the account switch *Lager-API schreiben*, which Kasseneck
1489
1532
  turns on (always on in the test environment, `kr_test_…`; otherwise
@@ -1863,6 +1906,131 @@ function onDelivery(rawBody: Buffer) {
1863
1906
  `listArticles({ variantGroupId, updatedSince })` are sorted by `updatedAt`
1864
1907
  ascending and include the boundary.
1865
1908
 
1909
+ ### Stocktake
1910
+
1911
+ A stocktake counts the stock of one location: create it (scope, key date or
1912
+ perpetual, blind by default), count (several counts of the same article are
1913
+ added up, a wrong one is voided with a reason), review (only now the expected
1914
+ quantity and the difference appear), recount single items, close (books one
1915
+ movement `stocktake` per item and stores the stocktake record as PDF) or
1916
+ cancel. The same flow runs in the panel and, for counting, at the register
1917
+ (`./pos`, below). All writes, counting included, take an `idempotencyKey`
1918
+ and the account switch *Lager-API schreiben*; values (`…Cents`, `…Micros`)
1919
+ and the PDF with values need `costs`.
1920
+
1921
+ Example: Bäckerei Kornblum has 40 Kornspitz at the location `haupt`. At
1922
+ 10:00:00 the register sells 3, the stock movement is booked a few seconds
1923
+ late at 10:00:03. At 10:00:02 Livia Lindmayr counts 37 on the shelf.
1924
+
1925
+ ```ts
1926
+ import { createInventoryClient, inventoryBusyStocktakeId, isInventoryError } from '@kreiseck/kasseneck-api/inventory';
1927
+ import { parseQuantityMilli } from '@kreiseck/kasseneck-api/pos';
1928
+
1929
+ const inventory = createInventoryClient({ apiKey: process.env.KASSENECK_API_KEY! });
1930
+
1931
+ // 1. One open stocktake per location; reuse it if there is one.
1932
+ let stocktakeId: string;
1933
+ try {
1934
+ const created = await inventory.createStocktake({
1935
+ idempotencyKey: 'shop-stocktake-haupt-2026-12',
1936
+ locationId: 'haupt',
1937
+ scope: { type: 'groups', groupIds: ['gebaeck'] },
1938
+ type: 'key_date',
1939
+ keyDate: '2026-12-31', // blind: true is the default
1940
+ });
1941
+ stocktakeId = created.id; // status: 'counting'
1942
+ } catch (error) {
1943
+ const busy = inventoryBusyStocktakeId(error);
1944
+ if (!busy) throw error;
1945
+ stocktakeId = busy;
1946
+ }
1947
+
1948
+ // 2. Count. Quantities in thousandths: "37" pieces -> 37000, "0,25" kg -> 250.
1949
+ const kornspitz = await inventory.lookupArticleByCode('9001234567896');
1950
+ const { item } = await inventory.recordStocktakeCount({
1951
+ idempotencyKey: 'shelf-a-kornspitz-1', // after outcome 'unknown': resend with the SAME key
1952
+ stocktakeId,
1953
+ articleId: kornspitz.id,
1954
+ quantity: parseQuantityMilli('37', kornspitz.unit)!,
1955
+ });
1956
+ // item.quantity: 37000 (sum of the round), no expectedQuantity while counting
1957
+
1958
+ // 3. Review: computed in the background, poll until complete.
1959
+ await inventory.reviewStocktake({ idempotencyKey: 'review-1', stocktakeId });
1960
+ let stocktake = await inventory.getStocktake(stocktakeId);
1961
+ while (!stocktake.review?.complete) {
1962
+ await new Promise((r) => setTimeout(r, 2000));
1963
+ stocktake = await inventory.getStocktake(stocktakeId);
1964
+ }
1965
+ for await (const it of inventory.iterateStocktakeItems({ stocktakeId })) {
1966
+ // Kornspitz: expectedQuantity 37000, differenceQuantity 0 (the sale at
1967
+ // 10:00:00 was booked after the count, but it happened before it)
1968
+ if (it.needsCheck) console.log(it.articleId, it.checkReasons);
1969
+ }
1970
+
1971
+ // 4. Close (books in parts in the background), then fetch the record.
1972
+ const { warnings } = await inventory.closeStocktake({ idempotencyKey: 'close-1', stocktakeId });
1973
+ // … poll getStocktake until status === 'closed' …
1974
+ const pdf = await inventory.getStocktakePdf(stocktakeId);
1975
+ if (pdf.kind === 'pdf') await save('stocktake.pdf', pdf.pdf);
1976
+ else await download(pdf.download.url, pdf.download.sha256); // over 9 MiB: signed link, 15 minutes
1977
+ ```
1978
+
1979
+ - **Reference time.** The expected quantity of an item is the stock at the
1980
+ time of its last count (server time; the device clock never counts), taken
1981
+ from the stock ledger, including sales that happened before the count but
1982
+ were booked after it (within 3 days). In the example the expected quantity
1983
+ is 37, the difference 0, and closing changes nothing. Had the 3 Kornspitz
1984
+ been sold at 10:00:05, after the count, the expected quantity would be 40
1985
+ and the difference −3: closing books −3 on today's stock (37 after the
1986
+ sale), which leaves 34. Each piece is deducted exactly once.
1987
+ - **Blind.** Before `review` no response carries an expected quantity, a
1988
+ difference or `needsCheck`; the fields are absent, not `null`. With
1989
+ `blind: false` the items carry `bookStockNow` while counting: today's book
1990
+ stock, never the expected quantity at the reference time.
1991
+ - **Counting.** `quantity` in thousandths, `0` means counted empty. Pieces
1992
+ and serial-number articles take whole pieces only, serial-number articles
1993
+ exactly one serial number per piece (`serial_required`,
1994
+ `serial_already_counted`). Scope `all` adds a tracked article that was not
1995
+ listed (`addedLater`); scopes `groups` and `articles` answer
1996
+ `article_not_in_scope`. While counting or recounting, `voidStocktakeCount`
1997
+ with a reason takes a count back; the item is summed up again.
1998
+ - **Recount.** In `review`, `recountStocktake({ items, reason })` starts a new
1999
+ round for the named items (old counts stay, but no longer count); count
2000
+ them, then call `reviewStocktake` again. `closeStocktake` refuses with
2001
+ `stocktake_recount_open` while recounts are open.
2002
+ - **Closing.** Only from `review` (`stocktake_not_in_review`) and only once the
2003
+ review has finished computing: while `review.complete` is `false`,
2004
+ `closeStocktake` and `recountStocktake` answer `stocktake_review_running`
2005
+ (poll `getStocktake` and try again). Uncounted items
2006
+ are not booked and appear as "not counted" in the record; with
2007
+ `uncountedAsZero: true` they are booked as 0. The answer usually has
2008
+ `status: 'closing'` with `closing.parts` and `closing.bookedParts`; calling
2009
+ `closeStocktake` again while it is closing resumes it. After `closed`, the
2010
+ head carries `totals`, `warnings` (`uncounted_items`, `not_booked`,
2011
+ `defect_capped`), `seal` (the state of the stock ledger seal), `checksum`
2012
+ and `pdf`; `closeStocktake` itself may warn `recount_uncounted`. Each
2013
+ booking reaches webhooks as `stock.changed` with `cause: 'stocktake'`;
2014
+ there is no `stocktake.*` event.
2015
+ - **Lists.** `listStocktakes()` without `updatedSince` returns the most
2016
+ recently changed first (an open stocktake is not necessarily on top; filter
2017
+ with `status`). With `updatedSince` it is sorted by `updatedAt` ascending
2018
+ and includes the boundary, like `listArticles`: remember the largest
2019
+ `updatedAt` and ask again. `listStocktakeItems({ stocktakeId, openOnly })`
2020
+ and `listStocktakeCounts({ stocktakeId, articleId })` page with `cursor`;
2021
+ the `iterate…` variants follow `nextCursor` in the same order.
2022
+ - **The record.** `getStocktakePdf` exists only after closing
2023
+ (`stocktake_not_closed`, also for a cancelled stocktake). With `costs` it is
2024
+ the version with values, otherwise the one with quantities only. Up to
2025
+ 9 MiB the file comes in the answer (`kind: 'pdf'`), above that as a signed
2026
+ link for 15 minutes (`kind: 'download'`, with `sizeBytes` and `sha256`; check
2027
+ the downloaded file against `sha256`).
2028
+ - **Limits.** At most `STOCKTAKE_ITEMS_MAX` (5000) items per stocktake
2029
+ (`too_many_positions`; count larger stocks in several stocktakes one after
2030
+ another), `STOCKTAKE_RECOUNT_ITEMS_MAX` (200) items per recount and
2031
+ `STOCKTAKE_COUNTS_PER_ITEM_MAX` (200) counts per item and round
2032
+ (`too_many_counts`). The server checks them, not the client.
2033
+
1866
2034
  ## Migrating from 0.x
1867
2035
 
1868
2036
  1.0 is one breaking step: the wire, the exported names and the contract files
@@ -1946,6 +2114,7 @@ in machine form what both sides agreed on, among them:
1946
2114
  | `pos-message-cases.json` | error cases and the message each one must show in both registers | by hand |
1947
2115
  | `receipt-due-generated.json` | 1206 amounts due computed by the backend's own code, the reference for `receiptDueCents` | `node scripts/v3-zahlbetrag-generieren.mjs` |
1948
2116
  | `receipt-due-errors.json` | input the amount due cannot be computed from, with the `reason` of the `ReceiptDueError` each one throws | by hand |
2117
+ | `stocktake-quantity-cases.json` | typed quantities and the thousandths `parseQuantityMilli` makes of them (or `null`), per unit | by hand |
1949
2118
  | `v3/` | the backend's `/v3` contract (vocabulary, response cases, stored cases, amounts due), copied byte for byte | `node scripts/v3-vertrag-holen.mjs` |
1950
2119
  | `renames-1.0.json` | everything in these files that changed from 0.x to 1.0: paths (`files`), text catalogue keys (`texts`), placeholders, structural keys (`structure`), machine values (`values`), shape changes (`shapes`); rendered texts are unchanged | `npm run fixtures:umbenennung` |
1951
2120
 
@@ -2,7 +2,7 @@ import type { Cashregister, HobexReceipt, Receipt, ReportMonth, StripeUrlSession
2
2
  import { type CreateStripeLinkOptions, type StripeCaptureResult } from '../payments/stripe.js';
3
3
  import { type HobexPayOptions, type HobexRefundOptions } from '../payments/hobex.js';
4
4
  import { type TransportOptions } from './transport.js';
5
- import { type ReportV2, type ReportV2Options } from './reports.js';
5
+ import { type CashregisterReportPeriod, type ReportV2, type ReportV2Options } from './reports.js';
6
6
  import { type CashboxStatus, type SignatureStatus } from './status.js';
7
7
  import { type SendReceiptEmailOptions, type SendReceiptEmailResult, type ListMyReceiptsOptions, type ReceiptList, type ReceiptWithCompany, type SellReceiptOptions, type CancelReceiptOptions, type CancelReceiptResult } from './receipts.js';
8
8
  /**
@@ -54,9 +54,11 @@ export interface KasseneckApi {
54
54
  listMyCashregisters(): Promise<Cashregister[]>;
55
55
  /** Rohdaten eines Zeitraums: Belege und Firmendaten (`getReportV2`). */
56
56
  getReportV2(options: ReportV2Options): Promise<ReportV2>;
57
- /** Tagesbericht als PDF (Kalendertag nach Wiener Zeit). */
57
+ /** Kassenbericht als PDF (v2): abgeschlossener Monat, Tag oder Zeitraum (Endpunkt `getCashregisterReport`). */
58
+ getCashregisterReport(options: CashregisterReportPeriod): Promise<Uint8Array>;
59
+ /** @deprecated Since 1.10.0: use getCashregisterReport. Tagesbericht als PDF (Kalendertag nach Wiener Zeit). */
58
60
  downloadDailyReport(date: Date): Promise<Uint8Array>;
59
- /** Monatsbericht als PDF (Endpunkt `downloadReport`). */
61
+ /** @deprecated Since 1.10.0: use getCashregisterReport. Monatsbericht als PDF (Endpunkt `downloadReport`). */
60
62
  downloadMonthlyReport(reportMonth: ReportMonth): Promise<Uint8Array>;
61
63
  /** Betriebsstatus der Kasse bei FinanzOnline. */
62
64
  getCashboxStatus(): Promise<CashboxStatus>;
@@ -27,6 +27,7 @@ function createKasseneckApi(options) {
27
27
  sendReceiptEmail: (o) => (0, receipts_js_1.sendReceiptEmail)(rufen, o),
28
28
  listMyCashregisters: () => (0, cashregisters_js_1.listMyCashregisters)(rufen),
29
29
  getReportV2: (o) => (0, reports_js_1.getReportV2)(rufen, o),
30
+ getCashregisterReport: (options) => (0, reports_js_1.getCashregisterReport)(rufenBinaer, options),
30
31
  downloadDailyReport: (date) => (0, reports_js_1.downloadDailyReport)(rufenBinaer, date),
31
32
  downloadMonthlyReport: (reportMonth) => (0, reports_js_1.downloadMonthlyReport)(rufenBinaer, reportMonth),
32
33
  getCashboxStatus: () => (0, status_js_1.getCashboxStatus)(rufen),
@@ -12,8 +12,8 @@
12
12
  * weiterhin jeden `string`: wer einen Aufruf braucht, den dieses Paket nicht
13
13
  * umhuellt, muss ihn weiterhin absetzen koennen.
14
14
  */
15
- import type { TransportBodyFields, TransportCallOptions } 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", "getArticle", "listArticles", "lookupArticleByCode", "listLocations", "getStock", "listStock", "listStockMovements", "createWebhook", "updateWebhook", "deleteWebhook", "listWebhooks", "sendWebhookTest", "rotateWebhookSecret", "listWebhookDeliveries", "createArticle", "updateArticle", "deactivateArticle", "receiveGoods", "transferStock", "recordStockLoss", "changeStockCondition", "reverseStockMovement", "createReservation", "extendReservation", "releaseReservation", "getReservation", "listReservations", "createVariantGroup", "updateVariantGroup", "getVariantGroup", "listVariantGroups", "addVariant"];
15
+ import type { PdfOrData, TransportBodyFields, TransportCallOptions } 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", "getCashregisterReport", "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", "createArticle", "updateArticle", "deactivateArticle", "receiveGoods", "transferStock", "recordStockLoss", "changeStockCondition", "reverseStockMovement", "createReservation", "extendReservation", "releaseReservation", "getReservation", "listReservations", "createVariantGroup", "updateVariantGroup", "getVariantGroup", "listVariantGroups", "addVariant", "createStocktake", "listStocktakes", "getStocktake", "listStocktakeItems", "recordStocktakeCount", "voidStocktakeCount", "listStocktakeCounts", "reviewStocktake", "recountStocktake", "closeStocktake", "cancelStocktake", "getStocktakePdf", "listMyStocktakes", "listMyStocktakeItems", "listMyStocktakeCounts", "recordMyStocktakeCount", "voidMyStocktakeCount"];
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,14 +21,14 @@ 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", "getArticle", "listArticles", "lookupArticleByCode", "listLocations", "getStock", "listStock", "listStockMovements", "createWebhook", "updateWebhook", "deleteWebhook", "listWebhooks", "sendWebhookTest", "rotateWebhookSecret", "listWebhookDeliveries", "createArticle", "updateArticle", "deactivateArticle", "receiveGoods", "transferStock", "recordStockLoss", "changeStockCondition", "reverseStockMovement", "createReservation", "extendReservation", "releaseReservation", "getReservation", "listReservations", "createVariantGroup", "updateVariantGroup", "getVariantGroup", "listVariantGroups", "addVariant"];
24
+ export declare const PUBLIC_CALLS: readonly ["createReceipt", "getReceipt", "cancelReceipt", "sendReceiptEmail", "generateFullReceiptId", "downloadReceipt", "getFirstReceiptDate", "getReportV2", "downloadReport", "downloadDailyReport", "getCashregisterReport", "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", "createArticle", "updateArticle", "deactivateArticle", "receiveGoods", "transferStock", "recordStockLoss", "changeStockCondition", "reverseStockMovement", "createReservation", "extendReservation", "releaseReservation", "getReservation", "listReservations", "createVariantGroup", "updateVariantGroup", "getVariantGroup", "listVariantGroups", "addVariant", "createStocktake", "listStocktakes", "getStocktake", "listStocktakeItems", "recordStocktakeCount", "voidStocktakeCount", "listStocktakeCounts", "reviewStocktake", "recountStocktake", "closeStocktake", "cancelStocktake", "getStocktakePdf"];
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
28
28
  * `endpoints.register`. Sechs davon sind zugleich oeffentlich; die Kasse ruft
29
29
  * sie trotzdem ueber diesen Weg (ein Dialekt je Client, Nachtrag §5.2).
30
30
  */
31
- export declare const POS_CALLS: readonly ["pairRegisterDevice", "listRegisterUsersForDevice", "listRegisterSessionsForDevice", "registerUserLogin", "registerPinLogin", "renewRegisterSession", "endRegisterSession", "unpairRegisterDevice", "listMyCashregisters", "listMyReceipts", "getReceipt", "createReceipt", "generateFullReceiptId", "cancelReceipt", "sendReceiptEmail", "listMyArticleGroups", "listMyArticles", "getKasseSettings", "setMyKasseSettings", "setMyKasseLogo", "setMyRegisterDeviceSettings", "listMyPrinters", "createPrintJob", "getPrintJob", "listMyTipRecipients", "listMyStockLocations", "listMyStock", "setMyCashregisterStockLocation"];
31
+ export declare const POS_CALLS: readonly ["pairRegisterDevice", "listRegisterUsersForDevice", "listRegisterSessionsForDevice", "registerUserLogin", "registerPinLogin", "renewRegisterSession", "endRegisterSession", "unpairRegisterDevice", "listMyCashregisters", "listMyReceipts", "getReceipt", "createReceipt", "generateFullReceiptId", "cancelReceipt", "sendReceiptEmail", "listMyArticleGroups", "listMyArticles", "getKasseSettings", "setMyKasseSettings", "setMyKasseLogo", "setMyRegisterDeviceSettings", "listMyPrinters", "createPrintJob", "getPrintJob", "listMyTipRecipients", "listMyStockLocations", "listMyStock", "setMyCashregisterStockLocation", "listMyStocktakes", "listMyStocktakeItems", "listMyStocktakeCounts", "recordMyStocktakeCount", "voidMyStocktakeCount"];
32
32
  export type PublicCall = typeof PUBLIC_CALLS[number];
33
33
  export type PosCall = typeof POS_CALLS[number];
34
34
  /**
@@ -49,7 +49,7 @@ export type PosCall = typeof POS_CALLS[number];
49
49
  * [ALL_CALLS], [PUBLIC_CALLS] und [POS_CALLS] steht entweder hier oder in
50
50
  * [CALLS_WITHOUT_EFFECT] (Waechter `test/ausgang-einordnung.test.ts`).
51
51
  */
52
- export declare const UNKNOWN_OUTCOME_CALLS: readonly ["activateCashregister", "addVariant", "cancelInvoice", "cancelReceipt", "changeStockCondition", "createArticle", "createCreditNote", "createCustomer", "createCustomerCashregister", "createInvoiceItem", "createPartnerCustomer", "createPartnerWebhook", "createPrintJob", "createReceipt", "createReservation", "createVariantGroup", "createWebhook", "deactivateArticle", "deletePartnerWebhook", "deleteWebhook", "extendReservation", "financeWebService", "hobexPayApi", "hobexRefundApi", "issueInvoice", "pairRegisterDevice", "receiveGoods", "recordInvoicePayment", "recordStockLoss", "releaseReservation", "reportCustomerContract", "requestCustomerSignature", "reverseStockMovement", "revokeCustomerMandate", "rotatePartnerWebhookSecret", "rotateWebhookSecret", "sendPartnerCustomerFonLink", "sendPartnerWebhookTest", "sendReceiptEmail", "sendWebhookTest", "setCustomerMandate", "setMyCashregisterStockLocation", "setMyKasseLogo", "setMyKasseSettings", "setMyRegisterDeviceSettings", "stripeCaptureIntent", "transferStock", "unpairRegisterDevice", "updateArticle", "updateCustomer", "updateInvoiceItem", "updatePartnerWebhook", "updateVariantGroup", "updateWebhook", "withdrawInvoiceItem"];
52
+ export declare const UNKNOWN_OUTCOME_CALLS: readonly ["activateCashregister", "addVariant", "cancelInvoice", "cancelReceipt", "cancelStocktake", "changeStockCondition", "closeStocktake", "createArticle", "createCreditNote", "createCustomer", "createCustomerCashregister", "createInvoiceItem", "createPartnerCustomer", "createPartnerWebhook", "createPrintJob", "createReceipt", "createReservation", "createStocktake", "createVariantGroup", "createWebhook", "deactivateArticle", "deletePartnerWebhook", "deleteWebhook", "extendReservation", "financeWebService", "hobexPayApi", "hobexRefundApi", "issueInvoice", "pairRegisterDevice", "receiveGoods", "recordInvoicePayment", "recordMyStocktakeCount", "recordStockLoss", "recordStocktakeCount", "recountStocktake", "releaseReservation", "reportCustomerContract", "requestCustomerSignature", "reverseStockMovement", "reviewStocktake", "revokeCustomerMandate", "rotatePartnerWebhookSecret", "rotateWebhookSecret", "sendPartnerCustomerFonLink", "sendPartnerWebhookTest", "sendReceiptEmail", "sendWebhookTest", "setCustomerMandate", "setMyCashregisterStockLocation", "setMyKasseLogo", "setMyKasseSettings", "setMyRegisterDeviceSettings", "stripeCaptureIntent", "transferStock", "unpairRegisterDevice", "updateArticle", "updateCustomer", "updateInvoiceItem", "updatePartnerWebhook", "updateVariantGroup", "updateWebhook", "voidMyStocktakeCount", "voidStocktakeCount", "withdrawInvoiceItem"];
53
53
  /** Warum ein Aufruf keine Wirkung hat, die ein Zeitlimit offen lassen koennte. */
54
54
  export type CallWithoutEffectReason = 'read' | 'repeatable';
55
55
  /**
@@ -85,10 +85,10 @@ export declare const CALLS_WITHOUT_EFFECT: Readonly<Record<string, CallWithoutEf
85
85
  * absetzt, sagt es mit `hasEffect: true`.
86
86
  */
87
87
  export declare function isUnknownOutcomeCall(name: string): boolean;
88
- /** Einer der 28 Aufrufe des Kassenwegs. */
88
+ /** Einer der 33 Aufrufe des Kassenwegs. */
89
89
  export declare function isPosCall(name: string): boolean;
90
90
  /**
91
- * Nur ueber den Kassenweg erreichbar (22 Namen): unter `api.kasseneck.at/v3`
91
+ * Nur ueber den Kassenweg erreichbar (27 Namen): unter `api.kasseneck.at/v3`
92
92
  * gibt es sie nicht. Der Transport schickt sie darum ohne eigene Basis an
93
93
  * [POS_BASE_URL] statt an die oeffentliche Basis.
94
94
  */
@@ -97,3 +97,5 @@ export declare function isPosOnlyCall(name: string): boolean;
97
97
  export type InternerTransport = <T = unknown>(functionName: ApiCall, params?: Record<string, unknown>, extraBodyFields?: TransportBodyFields, secretParams?: readonly string[], options?: TransportCallOptions) => Promise<T>;
98
98
  /** Wie [KasseneckBinaryTransport], nur mit bekanntem Aufrufnamen. */
99
99
  export type InternerBinaerTransport = (functionName: ApiCall, params?: Record<string, unknown>) => Promise<Uint8Array>;
100
+ /** Wie `createPdfOrDataTransport` (transport.ts), nur mit bekanntem Aufrufnamen. */
101
+ export type InternerPdfOderDatenTransport = (functionName: ApiCall, params?: Record<string, unknown>) => Promise<PdfOrData>;
@@ -23,6 +23,7 @@ exports.ALL_CALLS = [
23
23
  'endRegisterSession',
24
24
  'financeWebService',
25
25
  'generateFullReceiptId',
26
+ 'getCashregisterReport',
26
27
  'getCustomer',
27
28
  'getCustomerCredentials',
28
29
  'getCustomerSignatureStatus',
@@ -111,6 +112,25 @@ exports.ALL_CALLS = [
111
112
  'getVariantGroup',
112
113
  'listVariantGroups',
113
114
  'addVariant',
115
+ // Lager-API Inventur (Lager-Kern Stufe 3, ./inventory)
116
+ 'createStocktake',
117
+ 'listStocktakes',
118
+ 'getStocktake',
119
+ 'listStocktakeItems',
120
+ 'recordStocktakeCount',
121
+ 'voidStocktakeCount',
122
+ 'listStocktakeCounts',
123
+ 'reviewStocktake',
124
+ 'recountStocktake',
125
+ 'closeStocktake',
126
+ 'cancelStocktake',
127
+ 'getStocktakePdf',
128
+ // Inventur zaehlen an der Kasse (Lager-Kern Stufe 3, ./pos)
129
+ 'listMyStocktakes',
130
+ 'listMyStocktakeItems',
131
+ 'listMyStocktakeCounts',
132
+ 'recordMyStocktakeCount',
133
+ 'voidMyStocktakeCount',
114
134
  ];
115
135
  /**
116
136
  * Die oeffentlichen Endpunkte unter `/v3` (`https://api.kasseneck.at/v3/<name>`),
@@ -129,6 +149,7 @@ exports.PUBLIC_CALLS = [
129
149
  'getReportV2',
130
150
  'downloadReport',
131
151
  'downloadDailyReport',
152
+ 'getCashregisterReport',
132
153
  'createPaymentLinkStripe',
133
154
  'stripeCaptureIntent',
134
155
  'hobexPayApi',
@@ -217,6 +238,19 @@ exports.PUBLIC_CALLS = [
217
238
  'getVariantGroup',
218
239
  'listVariantGroups',
219
240
  'addVariant',
241
+ // Lager-API Inventur (Lager-Kern Stufe 3), umhuellt in `./inventory`.
242
+ 'createStocktake',
243
+ 'listStocktakes',
244
+ 'getStocktake',
245
+ 'listStocktakeItems',
246
+ 'recordStocktakeCount',
247
+ 'voidStocktakeCount',
248
+ 'listStocktakeCounts',
249
+ 'reviewStocktake',
250
+ 'recountStocktake',
251
+ 'closeStocktake',
252
+ 'cancelStocktake',
253
+ 'getStocktakePdf',
220
254
  ];
221
255
  /**
222
256
  * Die Endpunkte des Kassenwegs (`https://kasse.kasseneck.at/api/v3/<name>`,
@@ -254,6 +288,12 @@ exports.POS_CALLS = [
254
288
  'listMyStockLocations',
255
289
  'listMyStock',
256
290
  'setMyCashregisterStockLocation',
291
+ // Inventur zaehlen (Lager-Kern Stufe 3): nur ueber den Kassenweg.
292
+ 'listMyStocktakes',
293
+ 'listMyStocktakeItems',
294
+ 'listMyStocktakeCounts',
295
+ 'recordMyStocktakeCount',
296
+ 'voidMyStocktakeCount',
257
297
  ];
258
298
  /**
259
299
  * Die Aufrufe **mit Wirkung**, alphabetisch: sie legen etwas an, aendern oder
@@ -278,7 +318,9 @@ exports.UNKNOWN_OUTCOME_CALLS = [
278
318
  'addVariant',
279
319
  'cancelInvoice',
280
320
  'cancelReceipt',
321
+ 'cancelStocktake',
281
322
  'changeStockCondition',
323
+ 'closeStocktake',
282
324
  'createArticle',
283
325
  'createCreditNote',
284
326
  'createCustomer',
@@ -289,6 +331,7 @@ exports.UNKNOWN_OUTCOME_CALLS = [
289
331
  'createPrintJob',
290
332
  'createReceipt',
291
333
  'createReservation',
334
+ 'createStocktake',
292
335
  'createVariantGroup',
293
336
  'createWebhook',
294
337
  'deactivateArticle',
@@ -302,11 +345,15 @@ exports.UNKNOWN_OUTCOME_CALLS = [
302
345
  'pairRegisterDevice',
303
346
  'receiveGoods',
304
347
  'recordInvoicePayment',
348
+ 'recordMyStocktakeCount',
305
349
  'recordStockLoss',
350
+ 'recordStocktakeCount',
351
+ 'recountStocktake',
306
352
  'releaseReservation',
307
353
  'reportCustomerContract',
308
354
  'requestCustomerSignature',
309
355
  'reverseStockMovement',
356
+ 'reviewStocktake',
310
357
  'revokeCustomerMandate',
311
358
  'rotatePartnerWebhookSecret',
312
359
  'rotateWebhookSecret',
@@ -328,6 +375,8 @@ exports.UNKNOWN_OUTCOME_CALLS = [
328
375
  'updatePartnerWebhook',
329
376
  'updateVariantGroup',
330
377
  'updateWebhook',
378
+ 'voidMyStocktakeCount',
379
+ 'voidStocktakeCount',
331
380
  'withdrawInvoiceItem',
332
381
  ];
333
382
  /**
@@ -362,6 +411,7 @@ exports.CALLS_WITHOUT_EFFECT = Object.freeze({
362
411
  createPaymentLinkStripe: 'repeatable',
363
412
  endRegisterSession: 'repeatable',
364
413
  generateFullReceiptId: 'read',
414
+ getCashregisterReport: 'read',
365
415
  getArticle: 'read',
366
416
  getCustomer: 'read',
367
417
  getCustomerCredentials: 'read',
@@ -382,6 +432,8 @@ exports.CALLS_WITHOUT_EFFECT = Object.freeze({
382
432
  getReportV2: 'read',
383
433
  getReservation: 'read',
384
434
  getStock: 'read',
435
+ getStocktake: 'read',
436
+ getStocktakePdf: 'read',
385
437
  getVariantGroup: 'read',
386
438
  hobexGetStatus: 'read',
387
439
  listArticles: 'read',
@@ -397,6 +449,9 @@ exports.CALLS_WITHOUT_EFFECT = Object.freeze({
397
449
  listMyReceipts: 'read',
398
450
  listMyStock: 'read',
399
451
  listMyStockLocations: 'read',
452
+ listMyStocktakeCounts: 'read',
453
+ listMyStocktakeItems: 'read',
454
+ listMyStocktakes: 'read',
400
455
  listMyTipRecipients: 'read',
401
456
  listPartnerCustomers: 'read',
402
457
  listPartnerWebhookDeliveries: 'read',
@@ -406,6 +461,9 @@ exports.CALLS_WITHOUT_EFFECT = Object.freeze({
406
461
  listReservations: 'read',
407
462
  listStock: 'read',
408
463
  listStockMovements: 'read',
464
+ listStocktakeCounts: 'read',
465
+ listStocktakeItems: 'read',
466
+ listStocktakes: 'read',
409
467
  listVariantGroups: 'read',
410
468
  listWebhookDeliveries: 'read',
411
469
  listWebhooks: 'read',
@@ -429,12 +487,12 @@ function isUnknownOutcomeCall(name) {
429
487
  const OEFFENTLICH = new Set(exports.PUBLIC_CALLS);
430
488
  const KASSENWEG = new Set(exports.POS_CALLS);
431
489
  const NUR_KASSE = new Set(exports.POS_CALLS.filter((name) => !OEFFENTLICH.has(name)));
432
- /** Einer der 28 Aufrufe des Kassenwegs. */
490
+ /** Einer der 33 Aufrufe des Kassenwegs. */
433
491
  function isPosCall(name) {
434
492
  return KASSENWEG.has(name);
435
493
  }
436
494
  /**
437
- * Nur ueber den Kassenweg erreichbar (22 Namen): unter `api.kasseneck.at/v3`
495
+ * Nur ueber den Kassenweg erreichbar (27 Namen): unter `api.kasseneck.at/v3`
438
496
  * gibt es sie nicht. Der Transport schickt sie darum ohne eigene Basis an
439
497
  * [POS_BASE_URL] statt an die oeffentliche Basis.
440
498
  */
@@ -280,7 +280,10 @@ exports.PAYMENT_CALL_REJECTED_CODES = Object.freeze([
280
280
  'account_not_found',
281
281
  'live_not_enabled',
282
282
  'api_not_approved', // Live-API ohne Freigabe (Entwicklerbereich): vor dem Handler abgewiesen
283
+ 'app_check_missing', // Admin-App ohne bzw. mit ungueltigem App Check: vor dem Handler abgewiesen
284
+ 'app_check_invalid',
283
285
  'unauthorized',
286
+ 'password_change_required', // Pflichtwechsel des Passworts offen: vor dem Handler abgewiesen
284
287
  'mfa_required',
285
288
  'user_verification_failed',
286
289
  'admin_required',
@@ -1,9 +1,9 @@
1
1
  export { type AuthCredentials, type KasseneckAuth, type ApiKeyAuthOptions, type RegisterUserAuthOptions, apiKeyAuth, registerUserAuth, } from './auth.js';
2
- export { DEFAULT_BASE_URL, POS_BASE_URL, DEFAULT_TIMEOUT_MS, type HttpResponseLike, type HttpRequestInit, type FetchLike, type TransportOptions, type TransportBodyFields, type TransportCallOptions, type KasseneckTransport, type KasseneckBinaryTransport, createTransport, createBinaryTransport, } from './transport.js';
2
+ export { DEFAULT_BASE_URL, POS_BASE_URL, DEFAULT_TIMEOUT_MS, type HttpResponseLike, type HttpRequestInit, type FetchLike, type TransportOptions, type TransportBodyFields, type TransportCallOptions, type KasseneckTransport, type KasseneckBinaryTransport, type KasseneckPdfOrDataTransport, type PdfOrData, createTransport, createBinaryTransport, createPdfOrDataTransport, } from './transport.js';
3
3
  export { ALL_CALLS, type ApiCall, PUBLIC_CALLS, POS_CALLS, UNKNOWN_OUTCOME_CALLS, type PublicCall, type PosCall, } from './aufrufe.js';
4
4
  export { KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, type ValidationScope, type KasseneckError, type HttpFailureReason, type CauseDigest, type ErrorOutcome, CLIENT_ERROR_CODES, type ClientErrorCode, isKasseneckApiError, isKasseneckAuthError, isKasseneckHttpError, isKasseneckNetworkError, isKasseneckValidationError, isOutcomeUnknown, } from './errors.js';
5
5
  export { type ReceiptCommonOptions, type SellReceiptOptions, type TipOptions, type TipRecipientShare, type CancelReceiptOptions, type ReceiptWithCompany, sellReceipt, sellReceiptWithCompany, paymentsExpectedCents, cardRefundReference, receiptLayoutFromResult, cancelReceipt, type CancelReceiptResult, zeroReceipt, getReceipt, getReceiptWithCompany, generateFullReceiptId, getFirstReceiptDate, listMyReceipts, type ListMyReceiptsOptions, type ReceiptList, type ReceiptListStats, checkVoucherCombinationError, type SendReceiptEmailOptions, type SendReceiptEmailResult, sendReceiptEmail, } from './receipts.js';
6
6
  export { listMyCashregisters } from './cashregisters.js';
7
- export { downloadDailyReport, downloadMonthlyReport, getReportV2, type ReportV2, type ReportV2Metadata, type ReportV2Options } from './reports.js';
7
+ export { downloadDailyReport, downloadMonthlyReport, getCashregisterReport, getReportV2, type CashregisterReportPeriod, type ReportV2, type ReportV2Metadata, type ReportV2Options } from './reports.js';
8
8
  export { type CashboxStatus, type SignatureStatus, getCashboxStatus, getSignatureStatus, } from './status.js';
9
9
  export { type KasseneckApi, createKasseneckApi } from './api.js';