@kreiseck/kasseneck-api 1.5.0 → 1.6.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.
- package/CHANGELOG.md +124 -0
- package/README.md +181 -27
- package/dist/cjs/client/aufrufe.d.ts +58 -4
- package/dist/cjs/client/aufrufe.js +185 -1
- package/dist/cjs/client/errors.d.ts +32 -19
- package/dist/cjs/client/errors.js +28 -17
- package/dist/cjs/client/index.d.ts +2 -2
- package/dist/cjs/client/index.js +2 -1
- package/dist/cjs/client/transport.d.ts +27 -1
- package/dist/cjs/client/transport.js +25 -27
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/inventory/api.d.ts +10 -2
- package/dist/cjs/inventory/api.js +8 -1
- package/dist/cjs/inventory/endpunkte.d.ts +2 -1
- package/dist/cjs/inventory/endpunkte.js +2 -1
- package/dist/cjs/inventory/index.d.ts +5 -3
- package/dist/cjs/inventory/index.js +15 -3
- package/dist/cjs/inventory/lesen.d.ts +7 -1
- package/dist/cjs/inventory/lesen.js +75 -0
- package/dist/cjs/inventory/schreiben.d.ts +26 -1
- package/dist/cjs/inventory/schreiben.js +24 -10
- package/dist/cjs/inventory/typen.d.ts +156 -2
- package/dist/cjs/inventory/varianten.d.ts +67 -0
- package/dist/cjs/inventory/varianten.js +150 -0
- package/dist/cjs/inventory/vertrag.d.ts +40 -5
- package/dist/cjs/inventory/vertrag.js +51 -3
- package/dist/cjs/inventory/webhook.d.ts +5 -2
- package/dist/cjs/inventory/webhook.js +8 -2
- package/dist/cjs/invoice/endpunkte.d.ts +6 -0
- package/dist/cjs/invoice/endpunkte.js +13 -2
- package/dist/cjs/pos/texte.d.ts +11 -6
- package/dist/cjs/pos/texte.js +11 -6
- package/dist/cjs/stored/vokabular.d.ts +1 -1
- package/dist/cjs/stored/vokabular.js +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/client/aufrufe.d.ts +58 -4
- package/dist/esm/client/aufrufe.js +183 -0
- package/dist/esm/client/errors.d.ts +32 -19
- package/dist/esm/client/errors.js +28 -17
- package/dist/esm/client/index.d.ts +2 -2
- package/dist/esm/client/index.js +1 -1
- package/dist/esm/client/transport.d.ts +27 -1
- package/dist/esm/client/transport.js +26 -28
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/inventory/api.d.ts +10 -2
- package/dist/esm/inventory/api.js +8 -1
- package/dist/esm/inventory/endpunkte.d.ts +2 -1
- package/dist/esm/inventory/endpunkte.js +2 -1
- package/dist/esm/inventory/index.d.ts +5 -3
- package/dist/esm/inventory/index.js +4 -2
- package/dist/esm/inventory/lesen.d.ts +7 -1
- package/dist/esm/inventory/lesen.js +74 -0
- package/dist/esm/inventory/schreiben.d.ts +26 -1
- package/dist/esm/inventory/schreiben.js +19 -11
- package/dist/esm/inventory/typen.d.ts +156 -2
- package/dist/esm/inventory/varianten.d.ts +67 -0
- package/dist/esm/inventory/varianten.js +142 -0
- package/dist/esm/inventory/vertrag.d.ts +40 -5
- package/dist/esm/inventory/vertrag.js +50 -2
- package/dist/esm/inventory/webhook.d.ts +5 -2
- package/dist/esm/inventory/webhook.js +9 -3
- package/dist/esm/invoice/endpunkte.d.ts +6 -0
- package/dist/esm/invoice/endpunkte.js +13 -2
- package/dist/esm/pos/texte.d.ts +11 -6
- package/dist/esm/pos/texte.js +11 -6
- package/dist/esm/stored/vokabular.d.ts +1 -1
- package/dist/esm/stored/vokabular.js +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/fixtures/hobex-hps-codes.json +1 -1
- package/fixtures/invoice-api.schema.json +1 -1
- package/fixtures/invoice-texts.json +1 -1
- package/fixtures/pos-texts.json +1 -1
- package/fixtures/surface.json +85 -6
- package/fixtures/v3/antworten/belege.json +1 -1
- package/fixtures/v3/antworten/belegmail.json +1 -1
- package/fixtures/v3/antworten/kasse-belege.json +1 -1
- package/fixtures/v3/antworten/kasse.json +2 -2
- package/fixtures/v3/antworten/lager.json +2396 -4
- package/fixtures/v3/antworten/rechnungen.json +1 -1
- package/fixtures/v3/antworten/storno.json +1 -1
- package/fixtures/v3/stored/belege.json +1 -1
- package/fixtures/v3/stored/kasse.json +2 -2
- package/fixtures/v3/stored/rechnungen.json +1 -1
- package/fixtures/v3/v3-vokabular.json +151 -6
- package/fixtures/v3/zahlbetrag-faelle.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,130 @@ 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.6.0
|
|
8
|
+
|
|
9
|
+
Inventory API, variants: `./inventory` gains the five endpoints of backend
|
|
10
|
+
stage 5c. Reason: a shop sells the same apron in three sizes and two colours.
|
|
11
|
+
Until now it had to create six unrelated articles and keep their names, prices
|
|
12
|
+
and codes in step by hand; nothing told the shop or the register that they
|
|
13
|
+
belong together, and nothing stopped a second "M red". A variant group holds
|
|
14
|
+
what they share and guarantees that each combination exists once.
|
|
15
|
+
|
|
16
|
+
Additive at runtime; existing calls send the same bytes as in 1.5.1. Two
|
|
17
|
+
things change for code that relies on the old shape: the unions
|
|
18
|
+
`InventoryWebhookEvent`/`InventoryWebhookEventType`, `InventoryErrorCode`,
|
|
19
|
+
`InventoryEndpoint` and `ApiCall` gain members, so an exhaustive `switch` with a
|
|
20
|
+
`never` check (or a `Record<…>` over them) needs the new cases; and
|
|
21
|
+
`parseInventoryWebhookEvent` now returns an event for `variant_group.*` where
|
|
22
|
+
1.5.x returned `null`.
|
|
23
|
+
|
|
24
|
+
- **Variant groups**: `createVariantGroup` (with `createMatrix: true` every
|
|
25
|
+
combination of the values, at most 100, or the listed `variants[]`, at most
|
|
26
|
+
100; never both), `updateVariantGroup` (name, defaults as a partial update,
|
|
27
|
+
`addAttributeValues`, or `active: false` to deactivate the group and all its
|
|
28
|
+
variants for good), `getVariantGroup`, `listVariantGroups` and
|
|
29
|
+
`iterateVariantGroups` (sorted by `updatedAt` ascending, filters `active`
|
|
30
|
+
and `updatedSince`). `VariantGroup` carries `attributes` (1 to 3, each with
|
|
31
|
+
`key`, `label` and 1 to 30 `values`, in group order), `defaults`
|
|
32
|
+
(`unitPriceCents`, `vatRate`, `unit`, `groupId`, `stockTracked`), `active`,
|
|
33
|
+
`variants[]` (`articleId` and `variantAttributes` of every active variant)
|
|
34
|
+
and the times. The group answers carry no articles: read them with
|
|
35
|
+
`listArticles({ variantGroupId })`.
|
|
36
|
+
- **Variants are articles**: `addVariant` creates one more variant and answers
|
|
37
|
+
with the article as `createArticle` does. Each variant takes the article
|
|
38
|
+
fields of `createArticle`; fields it does not name are filled from the group
|
|
39
|
+
defaults at creation, the name defaults to "<group> <value1> <value2>" in
|
|
40
|
+
attribute order. `Article.variantGroupId` and `Article.variantAttributes`
|
|
41
|
+
are set only on variants; the keys of `variantAttributes` come sorted by code
|
|
42
|
+
point, the attribute order is in `VariantGroup.attributes`.
|
|
43
|
+
- **Idempotency**: the three writes take `idempotencyKey` (required in the
|
|
44
|
+
type and refused before sending without a valid one) and are in
|
|
45
|
+
`UNKNOWN_OUTCOME_CALLS`: after `outcome: 'unknown'` resend with the same key.
|
|
46
|
+
`getVariantGroup` and `listVariantGroups` are reads.
|
|
47
|
+
- **Checked before sending**, nothing else: the key, `variantGroupId`,
|
|
48
|
+
`createMatrix: true` together with `variants`, `variants` that is no list or
|
|
49
|
+
holds an entry without a `variantAttributes` object, integer prices,
|
|
50
|
+
quantities and purchase prices (also in `defaults` and in every variant), an
|
|
51
|
+
update without a change, `active` other than `false` or not alone,
|
|
52
|
+
`addAttributeValues` that is no object. The limits (3 attributes, 30 values,
|
|
53
|
+
matrix 100, 250 active variants per group) are left to the server, so it can
|
|
54
|
+
raise them; they are exported as `VARIANT_ATTRIBUTES_MAX`,
|
|
55
|
+
`VARIANT_VALUES_MAX`, `VARIANT_MATRIX_MAX`, `VARIANT_GROUP_ACTIVE_MAX`.
|
|
56
|
+
- **Events**: `variant_group.created` and `variant_group.updated` in
|
|
57
|
+
`INVENTORY_WEBHOOK_EVENTS` and `parseInventoryWebhookEvent`, carrying the
|
|
58
|
+
group as `getVariantGroup` returns it. `updated` fires only on a visible
|
|
59
|
+
change (new value, new or deactivated variant, name, defaults, deactivating
|
|
60
|
+
the group). Two deliveries may overtake each other: keep the one with the
|
|
61
|
+
later `updatedAt`.
|
|
62
|
+
- **Errors**: `INVENTORY_ERROR_CODES` appends `variant_group_not_found`,
|
|
63
|
+
`variant_already_exists` (with `field`, and `articleId` of the existing
|
|
64
|
+
variant), `invalid_variant_attributes` (with `field` and `errors[]`),
|
|
65
|
+
`variant_group_inactive` and `variant_limit`. `too_many_positions` now also
|
|
66
|
+
answers a variant request that would need more writes than fit into one
|
|
67
|
+
operation, with `field` (`variants`, `createMatrix`, or `externalIds` for
|
|
68
|
+
`addVariant`); nothing is written then.
|
|
69
|
+
- **Contract**: `fixtures/v3/` pulled from the backend (stage 5c); the
|
|
70
|
+
vocabulary of `./stored` regenerated from it (fingerprint only, no schema
|
|
71
|
+
change for stored documents).
|
|
72
|
+
|
|
73
|
+
## 1.5.1
|
|
74
|
+
|
|
75
|
+
Every call with an effect reports `outcome: 'unknown'` when it fails after
|
|
76
|
+
sending began: network error, timeout, HTTP 5xx, HTTP 200 with the `/v3`
|
|
77
|
+
marker but an empty, non-JSON or status-less body, and HTML with the marker.
|
|
78
|
+
Reason: until 1.5.0 only the six signing and money calls did; a goods receipt,
|
|
79
|
+
a reservation or `issueInvoice` came back as `'rejected'` ("did not happen")
|
|
80
|
+
although the server may have booked it. Whoever believed that and resent with
|
|
81
|
+
a **new** `idempotencyKey` booked twice.
|
|
82
|
+
|
|
83
|
+
A change to the safe side, no change on the wire; requests send the same body
|
|
84
|
+
as in 1.5.0 (only the `Kasseneck-Client` header carries the new version).
|
|
85
|
+
|
|
86
|
+
- **Which calls**: `UNKNOWN_OUTCOME_CALLS` (exported, sorted), also in
|
|
87
|
+
`fixtures/surface.json` as `unknownOutcomeCalls` for the Dart twin. New in it:
|
|
88
|
+
inventory writes (`createArticle`, `updateArticle`, `deactivateArticle`,
|
|
89
|
+
`receiveGoods`, `transferStock`, `recordStockLoss`, `changeStockCondition`,
|
|
90
|
+
`reverseStockMovement`), reservations (`createReservation`,
|
|
91
|
+
`extendReservation`, `releaseReservation`), inventory and partner webhooks
|
|
92
|
+
(create, update, delete, rotate the secret, test delivery), the invoice API
|
|
93
|
+
(`issueInvoice`, `cancelInvoice`, `createCreditNote`, `recordInvoicePayment`,
|
|
94
|
+
`createCustomer`, `updateCustomer`), invoice items and SEPA mandates
|
|
95
|
+
(`createInvoiceItem`, `updateInvoiceItem`, `withdrawInvoiceItem`,
|
|
96
|
+
`setCustomerMandate`, `revokeCustomerMandate`), the partner calls with an
|
|
97
|
+
effect (`createPartnerCustomer`, `sendPartnerCustomerFonLink`,
|
|
98
|
+
`requestCustomerSignature`, `createCustomerCashregister`,
|
|
99
|
+
`activateCashregister`, `reportCustomerContract`), and on the register
|
|
100
|
+
`pairRegisterDevice`, `unpairRegisterDevice`, `setMyKasseSettings`,
|
|
101
|
+
`setMyKasseLogo`, `setMyRegisterDeviceSettings`,
|
|
102
|
+
`setMyCashregisterStockLocation`, `createPrintJob`, `sendReceiptEmail`.
|
|
103
|
+
- **Which stay `'rejected'`**: reading calls, dry runs (`previewGoodsReceipt`,
|
|
104
|
+
`previewInvoice`, `issueInvoice` with `dryRun: true`), the register sign-in
|
|
105
|
+
sessions (`registerUserLogin`, `registerPinLogin`, `renewRegisterSession`,
|
|
106
|
+
`endRegisterSession`) and `createPaymentLinkStripe`: a repeat books nothing.
|
|
107
|
+
A timeout already during sign-in stays `'rejected'` as before: nothing was
|
|
108
|
+
sent.
|
|
109
|
+
- **What to do**: with an `idempotencyKey`, send the same request with the
|
|
110
|
+
**same** key; it takes effect once and returns the stored answer.
|
|
111
|
+
`createInvoiceItem` is recognised by `source` + `reference`: the same values
|
|
112
|
+
again are safe. Without a key (receipts, cancellations, money calls,
|
|
113
|
+
settings, webhooks, changing or withdrawing invoice items, mandates), read
|
|
114
|
+
the state first. The rule for receipts and payments is unchanged: look it up,
|
|
115
|
+
never resend.
|
|
116
|
+
- **Per call**: the transport takes a fifth argument `{ hasEffect }`
|
|
117
|
+
(`TransportCallOptions`). `true` marks a call with an effect that this
|
|
118
|
+
package does not know. `false` only counts together with
|
|
119
|
+
`params.dryRun === true` (a dry run under the name of the real call; the
|
|
120
|
+
package's own previews use it); without `dryRun: true` a call from the list
|
|
121
|
+
stays `'unknown'`, so no option can turn a real booking into `'rejected'`.
|
|
122
|
+
Without the option the list decides, and an unknown name counts as having no
|
|
123
|
+
effect.
|
|
124
|
+
- **Guard**: every call the package knows (`ALL_CALLS`, `PUBLIC_CALLS`,
|
|
125
|
+
`POS_CALLS`) is classified as with or without effect; a new call without a
|
|
126
|
+
classification fails the tests.
|
|
127
|
+
- `CALLS_WITH_EFFECT` of the register texts and `fixtures/pos-texts.json` are
|
|
128
|
+
unchanged; `messageOutcome` follows the transport first, so the register
|
|
129
|
+
shows the careful sentence for every call above.
|
|
130
|
+
|
|
7
131
|
## 1.5.0
|
|
8
132
|
|
|
9
133
|
Inventory API, write side and reservations: `./inventory` gains the 13
|
package/README.md
CHANGED
|
@@ -433,30 +433,42 @@ receipt email, and values outside a settings field's value list throw a
|
|
|
433
433
|
`KasseneckValidationError` before anything is sent, instead of being dropped
|
|
434
434
|
silently. For a layout option of 0.x the message names its English successor.
|
|
435
435
|
|
|
436
|
-
### `outcome: 'unknown'`: never
|
|
436
|
+
### `outcome: 'unknown'`: never resend blindly
|
|
437
437
|
|
|
438
438
|
`KasseneckApiError`, `KasseneckHttpError` and `KasseneckNetworkError` carry
|
|
439
439
|
`outcome`. `'rejected'` means the server turned the request down; whether
|
|
440
440
|
anything else is safe to do depends on the code, and on the money calls it
|
|
441
441
|
is only set for the codes listed below. `'unknown'` means the operation **may have been carried out**, for
|
|
442
|
-
`createReceipt` a signed receipt in the chain. Then never send it again:
|
|
443
|
-
the result back (`getReceipt`, `listMyReceipts`, the original of a
|
|
444
|
-
cancellation) and continue from there. `
|
|
445
|
-
|
|
442
|
+
`createReceipt` a signed receipt in the chain. Then never send it again blindly:
|
|
443
|
+
read the result back (`getReceipt`, `listMyReceipts`, the original of a
|
|
444
|
+
cancellation) and continue from there. A call with an `idempotencyKey` (or,
|
|
445
|
+
for invoice items, the same `source` and `reference`) is the exception: send
|
|
446
|
+
it again unchanged (see below).
|
|
447
|
+
`isOutcomeUnknown(error)` covers all three classes. The outcome is unknown for:
|
|
446
448
|
|
|
447
449
|
- `dialect_mismatch`, `receipt_outcome_unknown`, `cancellation_outcome_unknown`;
|
|
448
450
|
- `response_translation_failed`, unless `details.handled === false`;
|
|
449
451
|
- `response_unreadable`: a signing or money-moving call reported success,
|
|
450
452
|
but the response lacks what the call promises (no receipt, no reference, no
|
|
451
453
|
remaining quantities, no Hobex receipt, no captured payment intent);
|
|
452
|
-
- on
|
|
453
|
-
`
|
|
454
|
-
|
|
455
|
-
`
|
|
456
|
-
|
|
454
|
+
- on every call with an effect (`UNKNOWN_OUTCOME_CALLS`, also in
|
|
455
|
+
`fixtures/surface.json` as `unknownOutcomeCalls`): the signing calls
|
|
456
|
+
`createReceipt`, `cancelReceipt` and `financeWebService`, the money calls
|
|
457
|
+
`hobexPay` (`hobexPayApi`, charges a card), `hobexRefund`
|
|
458
|
+
(`hobexRefundApi`) and `stripeCaptureIntent`, and since 1.5.1 every other
|
|
459
|
+
call that books, issues, creates, changes, deletes or sends something:
|
|
460
|
+
inventory writes and reservations, webhooks, invoices, credit notes,
|
|
461
|
+
recorded payments, customers, invoice items and SEPA mandates, partner
|
|
462
|
+
businesses, register settings, pairing, print jobs and receipt emails.
|
|
463
|
+
There it is a network error or timeout after sending began, HTTP 5xx, and
|
|
464
|
+
HTTP 200 with the `Kasseneck-Api-Version: v3` marker but an empty,
|
|
457
465
|
non-JSON (also `text/html`) or status-less body (`KasseneckHttpError`,
|
|
458
466
|
`reason` `empty-body`, `not-json` or `missing-status`). HTML without the
|
|
459
|
-
marker stays `route_missing` with `'rejected'`: no function saw the call
|
|
467
|
+
marker stays `route_missing` with `'rejected'`: no function saw the call.
|
|
468
|
+
Reading calls and dry runs (`previewGoodsReceipt`, `previewInvoice`) stay
|
|
469
|
+
`'rejected'`, and so do the register sign-in sessions and
|
|
470
|
+
`createPaymentLinkStripe`: a repeat books nothing (a second short-lived
|
|
471
|
+
session, a second link nobody else has seen);
|
|
460
472
|
- on the money calls: every error envelope **without a code**, and every
|
|
461
473
|
code that is not one of the rejection codes below. The Hobex and Stripe
|
|
462
474
|
handlers also answer with a plain error message after the provider was
|
|
@@ -490,17 +502,33 @@ failed `hobexRefund` throws a `KasseneckApiError`; it never returns `false`,
|
|
|
490
502
|
because a `false` on an unclear outcome invites a second refund. Even a
|
|
491
503
|
`'rejected'` is no invitation to resend blindly: fix the cause first.
|
|
492
504
|
|
|
493
|
-
**Never retry
|
|
494
|
-
package.** A `fetch` passed in `options.fetch` (or a proxy or service
|
|
495
|
-
front of it) must not resend a request by itself after a network
|
|
496
|
-
timeout or a 5xx: a silent second send is a second signed receipt, a
|
|
497
|
-
charge or a second
|
|
498
|
-
instead (`getReceipt`, `listMyReceipts`, the Hobex
|
|
499
|
-
`transactionId`, the Stripe session).
|
|
500
|
-
|
|
501
|
-
`
|
|
502
|
-
`
|
|
503
|
-
`
|
|
505
|
+
**Never retry a call with an effect blindly, and never put a retrying layer
|
|
506
|
+
under the package.** A `fetch` passed in `options.fetch` (or a proxy or service
|
|
507
|
+
worker in front of it) must not resend a request by itself after a network
|
|
508
|
+
error, a timeout or a 5xx: a silent second send is a second signed receipt, a
|
|
509
|
+
second charge, a second refund or a second booking, and the package cannot
|
|
510
|
+
see it. Look the result up instead (`getReceipt`, `listMyReceipts`, the Hobex
|
|
511
|
+
transaction by its `transactionId`, the Stripe session).
|
|
512
|
+
|
|
513
|
+
**With an `idempotencyKey`** (inventory writes and reservations, `issueInvoice`,
|
|
514
|
+
`cancelInvoice`, `createCreditNote`, `recordInvoicePayment`, `createCustomer`
|
|
515
|
+
and `createPartnerCustomer` with a key) the safe retry after `'unknown'` is the
|
|
516
|
+
same request with the **same** key: it takes effect exactly once and returns
|
|
517
|
+
the stored answer (invoices and partner customers mark it with
|
|
518
|
+
`replayed: true`; inventory writes return the stored answer unchanged). Never a
|
|
519
|
+
new key: that books a second time. `createInvoiceItem` has no key; the server recognises a repeat by
|
|
520
|
+
`source` + `reference`, so the same request with the same values is safe
|
|
521
|
+
(`replayed: true`; other data gives `item_reference_conflict`). Without a key
|
|
522
|
+
(receipts, cancellations, money calls, settings, webhooks, `updateCustomer`,
|
|
523
|
+
`createCustomer` and `createPartnerCustomer` without one, `updateInvoiceItem`,
|
|
524
|
+
`withdrawInvoiceItem`, `setCustomerMandate`, `revokeCustomerMandate`) read the
|
|
525
|
+
state first (for invoice items `getInvoiceItem`) and only then decide.
|
|
526
|
+
|
|
527
|
+
A call through the open transport that this package does not know counts as
|
|
528
|
+
having no effect; say so with `transport(name, params, undefined, undefined,
|
|
529
|
+
{ hasEffect: true })`. `hasEffect: false` only counts together with
|
|
530
|
+
`params.dryRun === true` (a dry run under the name of the real call); without
|
|
531
|
+
it a call with an effect stays `'unknown'`.
|
|
504
532
|
|
|
505
533
|
```ts
|
|
506
534
|
import { isOutcomeUnknown, paymentsExpectedCents } from '@kreiseck/kasseneck-api';
|
|
@@ -944,7 +972,7 @@ process:
|
|
|
944
972
|
`hobexPay`, `hobexRefund` and `stripeCaptureIntent` move money. They are never
|
|
945
973
|
retried, neither by the app nor by a retrying `fetch` under the package: on
|
|
946
974
|
`isOutcomeUnknown(error)` look the payment up (see
|
|
947
|
-
[`outcome: 'unknown'`](#outcome-unknown-never-
|
|
975
|
+
[`outcome: 'unknown'`](#outcome-unknown-never-resend-blindly)).
|
|
948
976
|
- **Hobex HPS via Kasseneck Connect**, described below.
|
|
949
977
|
|
|
950
978
|
### Hobex HPS via Kasseneck Connect
|
|
@@ -1373,7 +1401,13 @@ try {
|
|
|
1373
1401
|
|
|
1374
1402
|
**After a timeout, retry with the same `idempotencyKey`**, never with a new one:
|
|
1375
1403
|
you then get the invoice that was already issued (`replayed: true`). The same
|
|
1376
|
-
key with different data gives `idempotency_conflict`.
|
|
1404
|
+
key with different data gives `idempotency_conflict`. Since 1.5.1 every invoice
|
|
1405
|
+
call with an effect (`issueInvoice`, `cancelInvoice`, `createCreditNote`,
|
|
1406
|
+
`recordInvoicePayment`, `createCustomer`, `updateCustomer`) reports
|
|
1407
|
+
`outcome: 'unknown'` after a timeout, a network error, HTTP 5xx or an
|
|
1408
|
+
unreadable answer (before: `'rejected'`); `previewInvoice` and the reading
|
|
1409
|
+
calls stay `'rejected'`. See
|
|
1410
|
+
[`outcome: 'unknown'`](#outcome-unknown-never-resend-blindly).
|
|
1377
1411
|
|
|
1378
1412
|
Validation errors arrive as `validation` with field paths
|
|
1379
1413
|
(`invoiceFieldErrors(error)` → `[{ field: 'items[0].vatRate', message }]`).
|
|
@@ -1448,7 +1482,8 @@ ledger, and get every stock change pushed by webhook within seconds, also the
|
|
|
1448
1482
|
ones made at the register in the shop. Since 1.5.0 also the write side:
|
|
1449
1483
|
create and update articles, book goods receipts, transfers, losses and
|
|
1450
1484
|
condition changes, and reserve stock at checkout (see
|
|
1451
|
-
[Shop: reserve and invoice](#shop-reserve-and-invoice))
|
|
1485
|
+
[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
|
|
1452
1487
|
the account and belongs on a **server**. Reading needs the module `lager`,
|
|
1453
1488
|
writing additionally the account switch *Lager-API schreiben*, which Kasseneck
|
|
1454
1489
|
turns on (always on in the test environment, `kr_test_…`; otherwise
|
|
@@ -1566,7 +1601,16 @@ Every write takes an `idempotencyKey` (1 to 120 characters). The same request
|
|
|
1566
1601
|
with the same key takes effect exactly once; repeating it returns the stored
|
|
1567
1602
|
answer of the first call, the same key with different content gives
|
|
1568
1603
|
`idempotency_conflict`. After a timeout or a network error, repeat with the
|
|
1569
|
-
**same** key, never with a new one.
|
|
1604
|
+
**same** key, never with a new one. Since 1.5.1 every write, reservation and
|
|
1605
|
+
webhook call reports `outcome: 'unknown'` in that case (also after HTTP 5xx or
|
|
1606
|
+
an unreadable answer; before: `'rejected'`), so `isOutcomeUnknown(error)` is
|
|
1607
|
+
the signal to resend writes and reservations with the same key;
|
|
1608
|
+
`previewGoodsReceipt` and the reading calls stay `'rejected'`. The webhook
|
|
1609
|
+
calls (`createWebhook`, `updateWebhook`, `deleteWebhook`,
|
|
1610
|
+
`rotateWebhookSecret`, `sendWebhookTest`) have no key: after `'unknown'` look
|
|
1611
|
+
the state up first (`listWebhooks`, `listWebhookDeliveries`) instead of
|
|
1612
|
+
resending, or you get a second webhook, a second new secret or a used-up test
|
|
1613
|
+
delivery. The client refuses to send a write without
|
|
1570
1614
|
a valid key, and checks before sending only what is certainly wrong without the
|
|
1571
1615
|
network (required ids, integer quantities, amounts and prices, the range of
|
|
1572
1616
|
`expiresInMinutes`); everything else the server decides and reports with its
|
|
@@ -1709,6 +1753,116 @@ function onDelivery(rawBody: Buffer) {
|
|
|
1709
1753
|
net without webhooks; the stock ledger shows reservations as movements of
|
|
1710
1754
|
type `reservation` with `quantityDelta: 0` and the change in `reservedDelta`.
|
|
1711
1755
|
|
|
1756
|
+
### Variants
|
|
1757
|
+
|
|
1758
|
+
A variant is an ordinary article with `variantGroupId` and
|
|
1759
|
+
`variantAttributes`: its own id, code, stock and tile at the register; it is
|
|
1760
|
+
read, booked, reserved and invoiced like any other article. The variant group
|
|
1761
|
+
holds what the variants share (name, attributes with their values, defaults
|
|
1762
|
+
for new variants) and guarantees that each combination exists only once. The
|
|
1763
|
+
writes take an `idempotencyKey` and the account switch *Lager-API schreiben*,
|
|
1764
|
+
like every other write.
|
|
1765
|
+
|
|
1766
|
+
```ts
|
|
1767
|
+
import { createInventoryClient, isInventoryError, parseInventoryWebhookEvent } from '@kreiseck/kasseneck-api/inventory';
|
|
1768
|
+
|
|
1769
|
+
const inventory = createInventoryClient({ apiKey: process.env.KASSENECK_API_KEY! });
|
|
1770
|
+
|
|
1771
|
+
// 1. Create the group with every combination (3 sizes × 2 colours = 6 variants).
|
|
1772
|
+
const apron = await inventory.createVariantGroup({
|
|
1773
|
+
idempotencyKey: 'shop-group-3001',
|
|
1774
|
+
name: 'Schürze',
|
|
1775
|
+
attributes: [
|
|
1776
|
+
{ key: 'size', label: 'Größe', values: ['S', 'M', 'L'] },
|
|
1777
|
+
{ key: 'colour', label: 'Farbe', values: ['rot', 'blau'] },
|
|
1778
|
+
],
|
|
1779
|
+
defaults: { unitPriceCents: 2490, vatRate: 20, stockTracked: true },
|
|
1780
|
+
createMatrix: true,
|
|
1781
|
+
});
|
|
1782
|
+
// apron.variants: [{ articleId, variantAttributes: { colour: 'rot', size: 'S' } }, …]
|
|
1783
|
+
|
|
1784
|
+
// 2. The answer carries ids only. Read the articles of the group (names
|
|
1785
|
+
// "Schürze S rot" …, own codes) and map them to the shop's products.
|
|
1786
|
+
for await (const article of inventory.iterateArticles({ variantGroupId: apron.id })) {
|
|
1787
|
+
await shop.linkVariant(article.variantAttributes!, article.id, article.internalCode);
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
// 3. A new size later: add the value, then the variants you want.
|
|
1791
|
+
await inventory.updateVariantGroup({
|
|
1792
|
+
idempotencyKey: 'shop-group-3001-xl',
|
|
1793
|
+
variantGroupId: apron.id,
|
|
1794
|
+
addAttributeValues: { size: ['S', 'M', 'L', 'XL'] }, // known values are skipped
|
|
1795
|
+
});
|
|
1796
|
+
try {
|
|
1797
|
+
await inventory.addVariant({
|
|
1798
|
+
idempotencyKey: 'shop-variant-3001-xl-rot',
|
|
1799
|
+
variantGroupId: apron.id,
|
|
1800
|
+
variantAttributes: { size: 'XL', colour: 'rot' },
|
|
1801
|
+
ean: '9001234567834', // optional: a foreign article with this code
|
|
1802
|
+
});
|
|
1803
|
+
} catch (error) {
|
|
1804
|
+
if (!isInventoryError(error, 'variant_already_exists')) throw error;
|
|
1805
|
+
// Exists already (error.details.articleId): link that one instead.
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
// 4. Webhooks: keep the group state with the latest updatedAt.
|
|
1809
|
+
function onDelivery(rawBody: Buffer) {
|
|
1810
|
+
const event = parseInventoryWebhookEvent(rawBody);
|
|
1811
|
+
if (event && !event.test && (event.type === 'variant_group.created' || event.type === 'variant_group.updated')) {
|
|
1812
|
+
return shop.saveGroupIfNewer(event.data.id, event.data, event.data.updatedAt);
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
```
|
|
1816
|
+
|
|
1817
|
+
- **Limits.** At most 3 attributes per group (keys `^[a-z0-9_]{1,32}$`,
|
|
1818
|
+
`__…__` is reserved), at most 30 values per attribute (1 to 30 characters,
|
|
1819
|
+
unique ignoring case), at most 100 combinations with `createMatrix` and at
|
|
1820
|
+
most 100 entries in `variants[]` per request, at most 250 active variants
|
|
1821
|
+
per group (`variant_limit`). The client does not check these before sending
|
|
1822
|
+
(the server may raise them); they are exported as
|
|
1823
|
+
`VARIANT_ATTRIBUTES_MAX`, `VARIANT_VALUES_MAX`, `VARIANT_MATRIX_MAX` and
|
|
1824
|
+
`VARIANT_GROUP_ACTIVE_MAX`. A request that would need more writes than fit
|
|
1825
|
+
into one operation (about 187 external ids with 100 variants) is refused as
|
|
1826
|
+
a whole with `too_many_positions` and `field` (`variants`, `createMatrix`,
|
|
1827
|
+
or `externalIds` for `addVariant`); nothing is written. Send fewer variants
|
|
1828
|
+
and add the rest with `addVariant`.
|
|
1829
|
+
- **Order.** `attributes` keeps the order of the group: it decides the default
|
|
1830
|
+
name "<group> <value1> <value2>" and the matrix (the first attribute runs
|
|
1831
|
+
outermost). `variantAttributes` on articles, in `variants[]` and in webhooks
|
|
1832
|
+
comes with its keys **sorted by code point**, not in attribute order; compare
|
|
1833
|
+
by key, never by position. Values are stored trimmed and in Unicode NFC; a
|
|
1834
|
+
variant's value must match a listed value exactly (case and spaces are not
|
|
1835
|
+
adjusted), otherwise `invalid_variant_attributes` names the `field`.
|
|
1836
|
+
- **Variants are articles.** `addVariant` answers with the article as
|
|
1837
|
+
`createArticle` does. Each variant takes the fields of `createArticle`;
|
|
1838
|
+
fields it does not name are filled from the group defaults **at creation
|
|
1839
|
+
only**: changing the group name or defaults later changes no existing
|
|
1840
|
+
variant (use `updateArticle`). `createArticle` and `updateArticle` refuse
|
|
1841
|
+
`variantGroupId` and `variantAttributes`; a variant is never moved to another
|
|
1842
|
+
group, and an existing article never becomes a variant.
|
|
1843
|
+
- **Deactivating.** `deactivateArticle` on one variant of an active group
|
|
1844
|
+
takes it out of the group's `variants[]` and frees its combination for a new
|
|
1845
|
+
variant.
|
|
1846
|
+
`updateVariantGroup({ active: false })` deactivates the group and every
|
|
1847
|
+
variant (codes and external ids become free), stands alone and is final; a
|
|
1848
|
+
deactivated group answers every other change and `addVariant` with
|
|
1849
|
+
`variant_group_inactive`. The answer comes when all variants are
|
|
1850
|
+
deactivated; after `outcome: 'unknown'` simply repeat it, also with a new
|
|
1851
|
+
key, it completes an interrupted run.
|
|
1852
|
+
- **After `unknown`.** As with every write: resend with the **same**
|
|
1853
|
+
`idempotencyKey`. A new key would create the group a second time (the
|
|
1854
|
+
combination check is per group). `variant_already_exists` on `addVariant`
|
|
1855
|
+
carries `articleId` of the existing variant.
|
|
1856
|
+
- **Events.** `variant_group.created` and `variant_group.updated` carry the
|
|
1857
|
+
group as `getVariantGroup` returns it (with `variants[]`, without articles).
|
|
1858
|
+
`updated` fires only on a visible change; creating a variant also sends
|
|
1859
|
+
`article.created`, deactivating the group one `variant_group.updated` and
|
|
1860
|
+
one `article.deactivated` per variant. Deliveries can overtake each other:
|
|
1861
|
+
keep a group state only if its `updatedAt` is later than the stored one.
|
|
1862
|
+
Without webhooks, `listVariantGroups({ updatedSince })` and
|
|
1863
|
+
`listArticles({ variantGroupId, updatedSince })` are sorted by `updatedAt`
|
|
1864
|
+
ascending and include the boundary.
|
|
1865
|
+
|
|
1712
1866
|
## Migrating from 0.x
|
|
1713
1867
|
|
|
1714
1868
|
1.0 is one breaking step: the wire, the exported names and the contract files
|
|
@@ -1784,7 +1938,7 @@ in machine form what both sides agreed on, among them:
|
|
|
1784
1938
|
|---|---|---|
|
|
1785
1939
|
| `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` |
|
|
1786
1940
|
| `stored/pos-settings-defaults.json` | the same defaults in the stored (internal, German) form (`betrieb`, `geraet`) | `npm run fixtures:kasse` |
|
|
1787
|
-
| `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` |
|
|
1941
|
+
| `surface.json` | base URLs (`baseUrls.public`, `baseUrls.pos`), the calls per path (`calls`, and the backend's `routes`), the calls with an effect whose outcome is `unknown` after a timeout, network error, 5xx or unreadable answer (`unknownOutcomeCalls`, sorted), 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` |
|
|
1788
1942
|
| `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` |
|
|
1789
1943
|
| `pos-texts.json` | the register's message catalogue | `npm run fixtures:texte` |
|
|
1790
1944
|
| `invoice-texts.json` | invoice texts in both languages | `npm run fixtures:rechnungstexte` |
|
|
@@ -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 } 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"];
|
|
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"];
|
|
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", "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"];
|
|
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"];
|
|
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
|
|
@@ -31,6 +31,60 @@ export declare const PUBLIC_CALLS: readonly ["createReceipt", "getReceipt", "can
|
|
|
31
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"];
|
|
32
32
|
export type PublicCall = typeof PUBLIC_CALLS[number];
|
|
33
33
|
export type PosCall = typeof POS_CALLS[number];
|
|
34
|
+
/**
|
|
35
|
+
* Die Aufrufe **mit Wirkung**, alphabetisch: sie legen etwas an, aendern oder
|
|
36
|
+
* loeschen es, buchen, signieren, bewegen Geld oder senden etwas hinaus
|
|
37
|
+
* (Mail, Druckjob, Probesendung). Scheitert einer, nachdem die Anfrage
|
|
38
|
+
* unterwegs war (Netzfehler, Zeitlimit, HTTP 5xx, unlesbare Erfolgsantwort,
|
|
39
|
+
* HTML mit Kennzeichen), meldet der Transport `outcome: 'unknown'`: der
|
|
40
|
+
* Vorgang kann ausgefuehrt sein.
|
|
41
|
+
*
|
|
42
|
+
* Bis 1.5.0 galt das nur fuer die sechs signierenden und geldbewegenden
|
|
43
|
+
* Aufrufe; ein Wareneingang oder eine Rechnung nach einem Zeitlimit kam als
|
|
44
|
+
* `'rejected'` an, und wer das glaubte und mit NEUEM Idempotenzschluessel
|
|
45
|
+
* neu sendete, buchte doppelt.
|
|
46
|
+
*
|
|
47
|
+
* Geht als `unknownOutcomeCalls` in den Vertrag (`fixtures/surface.json`);
|
|
48
|
+
* der Dart-Zwilling prueft seine Liste dagegen. Jeder Aufruf aus
|
|
49
|
+
* [ALL_CALLS], [PUBLIC_CALLS] und [POS_CALLS] steht entweder hier oder in
|
|
50
|
+
* [CALLS_WITHOUT_EFFECT] (Waechter `test/ausgang-einordnung.test.ts`).
|
|
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"];
|
|
53
|
+
/** Warum ein Aufruf keine Wirkung hat, die ein Zeitlimit offen lassen koennte. */
|
|
54
|
+
export type CallWithoutEffectReason = 'read' | 'repeatable';
|
|
55
|
+
/**
|
|
56
|
+
* Die Aufrufe **ohne Wirkung**, je mit Grund. Bei ihnen bleibt es bei
|
|
57
|
+
* `outcome: 'rejected'`, auch nach Zeitlimit, Netzfehler oder HTTP 5xx; eine
|
|
58
|
+
* Wiederholung bucht nichts doppelt:
|
|
59
|
+
*
|
|
60
|
+
* - `read`: reines Lesen (auch Berichte, Dateien, `generateFullReceiptId`,
|
|
61
|
+
* das nur einen Link-Schluessel ableitet, und `getCustomerCredentials`,
|
|
62
|
+
* dessen Abruf das Backend nur mitschreibt).
|
|
63
|
+
* - `repeatable`: legt etwas an, das ohne die verlorene Antwort niemand
|
|
64
|
+
* erreicht und das von selbst verfaellt, und bucht nichts. Die Sitzung der
|
|
65
|
+
* Kassen-Anmeldung (anmelden, verlaengern, abmelden: eine Wiederholung legt
|
|
66
|
+
* hoechstens eine weitere kurzlebige Sitzung an bzw. verlaengert oder
|
|
67
|
+
* beendet dieselbe noch einmal) und der Stripe-Zahlungslink
|
|
68
|
+
* (`createPaymentLinkStripe`: den Link kennt nur die Antwort, ein nie
|
|
69
|
+
* zugestellter Link wird nie bezahlt; Geld bewegt erst die Zahlung bzw.
|
|
70
|
+
* `stripeCaptureIntent`).
|
|
71
|
+
*
|
|
72
|
+
* Probelaeufe (`previewGoodsReceipt`, `previewInvoice`) teilen den Namen mit
|
|
73
|
+
* dem echten Aufruf und stehen darum nicht hier; die Huellen setzen fuer sie
|
|
74
|
+
* `hasEffect: false` beim Aufruf, das nur zusammen mit `dryRun: true` gilt
|
|
75
|
+
* (siehe `TransportCallOptions`).
|
|
76
|
+
*
|
|
77
|
+
* Paketintern; nicht Teil der Paketoberflaeche.
|
|
78
|
+
*/
|
|
79
|
+
export declare const CALLS_WITHOUT_EFFECT: Readonly<Record<string, CallWithoutEffectReason>>;
|
|
80
|
+
/**
|
|
81
|
+
* Hat dieser Aufruf Wirkung, ist sein Ausgang nach Zeitlimit, Netzfehler,
|
|
82
|
+
* HTTP 5xx oder unlesbarer Erfolgsantwort also unklar? `financeWebService`
|
|
83
|
+
* zaehlt mit jedem Vorgang. Ein Name, den dieses Paket nicht kennt (der
|
|
84
|
+
* offene Transport nimmt jeden), ist `false`; wer so einen Aufruf mit Wirkung
|
|
85
|
+
* absetzt, sagt es mit `hasEffect: true`.
|
|
86
|
+
*/
|
|
87
|
+
export declare function isUnknownOutcomeCall(name: string): boolean;
|
|
34
88
|
/** Einer der 28 Aufrufe des Kassenwegs. */
|
|
35
89
|
export declare function isPosCall(name: string): boolean;
|
|
36
90
|
/**
|
|
@@ -40,6 +94,6 @@ export declare function isPosCall(name: string): boolean;
|
|
|
40
94
|
*/
|
|
41
95
|
export declare function isPosOnlyCall(name: string): boolean;
|
|
42
96
|
/** Wie [KasseneckTransport], nur mit bekanntem Aufrufnamen. Nicht exportiert nach aussen. */
|
|
43
|
-
export type InternerTransport = <T = unknown>(functionName: ApiCall, params?: Record<string, unknown>, extraBodyFields?: TransportBodyFields, secretParams?: readonly string[]) => Promise<T>;
|
|
97
|
+
export type InternerTransport = <T = unknown>(functionName: ApiCall, params?: Record<string, unknown>, extraBodyFields?: TransportBodyFields, secretParams?: readonly string[], options?: TransportCallOptions) => Promise<T>;
|
|
44
98
|
/** Wie [KasseneckBinaryTransport], nur mit bekanntem Aufrufnamen. */
|
|
45
99
|
export type InternerBinaerTransport = (functionName: ApiCall, params?: Record<string, unknown>) => Promise<Uint8Array>;
|