@kreiseck/kasseneck-api 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -0
- package/README.md +112 -1
- package/dist/cjs/client/aufrufe.d.ts +2 -2
- package/dist/cjs/client/aufrufe.js +30 -0
- package/dist/cjs/inventory/api.d.ts +45 -0
- package/dist/cjs/inventory/api.js +38 -0
- package/dist/cjs/inventory/auth.d.ts +17 -0
- package/dist/cjs/inventory/auth.js +27 -0
- package/dist/cjs/inventory/endpunkte.d.ts +71 -0
- package/dist/cjs/inventory/endpunkte.js +285 -0
- package/dist/cjs/inventory/fehler.d.ts +33 -0
- package/dist/cjs/inventory/fehler.js +47 -0
- package/dist/cjs/inventory/index.d.ts +19 -0
- package/dist/cjs/inventory/index.js +64 -0
- package/dist/cjs/inventory/lesen.d.ts +38 -0
- package/dist/cjs/inventory/lesen.js +294 -0
- package/dist/cjs/inventory/typen.d.ts +319 -0
- package/dist/cjs/inventory/typen.js +14 -0
- package/dist/cjs/inventory/vertrag.d.ts +76 -0
- package/dist/cjs/inventory/vertrag.js +166 -0
- package/dist/cjs/inventory/webhook.d.ts +50 -0
- package/dist/cjs/inventory/webhook.js +110 -0
- 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 +2 -2
- package/dist/esm/client/aufrufe.js +30 -0
- package/dist/esm/inventory/api.d.ts +45 -0
- package/dist/esm/inventory/api.js +35 -0
- package/dist/esm/inventory/auth.d.ts +17 -0
- package/dist/esm/inventory/auth.js +24 -0
- package/dist/esm/inventory/endpunkte.d.ts +71 -0
- package/dist/esm/inventory/endpunkte.js +266 -0
- package/dist/esm/inventory/fehler.d.ts +33 -0
- package/dist/esm/inventory/fehler.js +40 -0
- package/dist/esm/inventory/index.d.ts +19 -0
- package/dist/esm/inventory/index.js +18 -0
- package/dist/esm/inventory/lesen.d.ts +38 -0
- package/dist/esm/inventory/lesen.js +278 -0
- package/dist/esm/inventory/typen.d.ts +319 -0
- package/dist/esm/inventory/typen.js +13 -0
- package/dist/esm/inventory/vertrag.d.ts +76 -0
- package/dist/esm/inventory/vertrag.js +163 -0
- package/dist/esm/inventory/webhook.d.ts +50 -0
- package/dist/esm/inventory/webhook.js +101 -0
- 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 +161 -3
- package/fixtures/v3/README.md +9 -1
- package/fixtures/v3/antworten/belege.json +2 -2
- package/fixtures/v3/antworten/belegmail.json +2 -2
- package/fixtures/v3/antworten/kasse-belege.json +2 -2
- package/fixtures/v3/antworten/kasse.json +3 -3
- package/fixtures/v3/antworten/lager.json +1520 -0
- package/fixtures/v3/antworten/rechnungen.json +2 -2
- package/fixtures/v3/antworten/storno.json +2 -2
- package/fixtures/v3/stored/belege.json +2 -2
- package/fixtures/v3/stored/kasse.json +404 -4
- package/fixtures/v3/stored/rechnungen.json +2 -2
- package/fixtures/v3/v3-vokabular.json +423 -6
- package/fixtures/v3/zahlbetrag-faelle.json +2 -2
- package/package.json +14 -2
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Der Vertrag der Lager-API (Backend Stufe 5a) als Daten: Endpunkte,
|
|
3
|
+
* Wertkataloge, Ereignisse und Fehlercodes, englisch wie am Draht `/v3`.
|
|
4
|
+
*
|
|
5
|
+
* Quelle ist der Vertrags-Export des Backends (`fixtures/v3/v3-vokabular.json`):
|
|
6
|
+
* `endpoints.public`, die Kataloge `STANDORT_TYP`, `BEWEGUNG_ART`,
|
|
7
|
+
* `BEWEGUNG_QUELLE`, `LAGER_ZUSTAND`, `LAGER_URSACHE`, `ZUSTELLUNG` und
|
|
8
|
+
* `events`. `test/inventory.test.ts` haelt jede Liste deckungsgleich mit
|
|
9
|
+
* dieser Datei; nichts hier wird geraten.
|
|
10
|
+
*/
|
|
11
|
+
/** Die 14 Endpunkte, in der Reihenfolge von `endpoints.public`. */
|
|
12
|
+
export const INVENTORY_ENDPOINTS = [
|
|
13
|
+
'getArticle',
|
|
14
|
+
'listArticles',
|
|
15
|
+
'lookupArticleByCode',
|
|
16
|
+
'listLocations',
|
|
17
|
+
'getStock',
|
|
18
|
+
'listStock',
|
|
19
|
+
'listStockMovements',
|
|
20
|
+
'createWebhook',
|
|
21
|
+
'updateWebhook',
|
|
22
|
+
'deleteWebhook',
|
|
23
|
+
'listWebhooks',
|
|
24
|
+
'sendWebhookTest',
|
|
25
|
+
'rotateWebhookSecret',
|
|
26
|
+
'listWebhookDeliveries',
|
|
27
|
+
];
|
|
28
|
+
/** Art eines Standorts (Katalog `STANDORT_TYP`). */
|
|
29
|
+
export const LOCATION_TYPES = ['warehouse', 'store', 'vehicle', 'other'];
|
|
30
|
+
/**
|
|
31
|
+
* Art einer Lagerbewegung (Katalog `BEWEGUNG_ART`); zugleich der Filter `type`.
|
|
32
|
+
* `goods_receipt` ist der Wareneingang, `takeover` der uebernommene Anfangsbestand
|
|
33
|
+
* (auch per Import). `receipt` gibt es hier nicht: das ist der Kassenbeleg (Quelle).
|
|
34
|
+
*/
|
|
35
|
+
export const STOCK_MOVEMENT_TYPES = [
|
|
36
|
+
'sale',
|
|
37
|
+
'goods_receipt',
|
|
38
|
+
'loss',
|
|
39
|
+
'return',
|
|
40
|
+
'transfer_out',
|
|
41
|
+
'transfer_in',
|
|
42
|
+
'condition_out',
|
|
43
|
+
'condition_in',
|
|
44
|
+
'stocktake',
|
|
45
|
+
'adjustment',
|
|
46
|
+
'takeover',
|
|
47
|
+
'reversal',
|
|
48
|
+
'revaluation',
|
|
49
|
+
'method_change',
|
|
50
|
+
];
|
|
51
|
+
/**
|
|
52
|
+
* Woher eine Bewegung kommt (Katalog `BEWEGUNG_QUELLE`); zugleich der Filter
|
|
53
|
+
* `source`. `receipt` ist der Kassenbeleg wie ueberall in der API (der
|
|
54
|
+
* Wareneingang ist die Bewegungsart `goods_receipt`).
|
|
55
|
+
*/
|
|
56
|
+
export const STOCK_MOVEMENT_SOURCES = [
|
|
57
|
+
'receipt',
|
|
58
|
+
'invoice',
|
|
59
|
+
'cancellation',
|
|
60
|
+
'credit_note',
|
|
61
|
+
'panel',
|
|
62
|
+
'register',
|
|
63
|
+
'api',
|
|
64
|
+
'stocktake',
|
|
65
|
+
'system',
|
|
66
|
+
];
|
|
67
|
+
/** Zustand der Ware an einer Bewegung (Katalog `LAGER_ZUSTAND`). */
|
|
68
|
+
export const STOCK_CONDITIONS = ['sellable', 'defective'];
|
|
69
|
+
/**
|
|
70
|
+
* Ursache eines `stock.changed` (Katalog `LAGER_URSACHE`), abgeleitet aus der
|
|
71
|
+
* juengsten Bewegung mit Mengenwirkung. `other`: keine Regel passt oder es
|
|
72
|
+
* gibt keine Bewegung (dann ist `movementId` `null`).
|
|
73
|
+
*/
|
|
74
|
+
export const STOCK_CHANGE_CAUSES = [
|
|
75
|
+
'sale',
|
|
76
|
+
'invoice',
|
|
77
|
+
'credit_note',
|
|
78
|
+
'cancellation',
|
|
79
|
+
'goods_receipt',
|
|
80
|
+
'transfer',
|
|
81
|
+
'loss',
|
|
82
|
+
'condition',
|
|
83
|
+
'reversal',
|
|
84
|
+
'reservation',
|
|
85
|
+
'stocktake',
|
|
86
|
+
'takeover',
|
|
87
|
+
'other',
|
|
88
|
+
];
|
|
89
|
+
/** Stand einer Zustellung (Katalog `ZUSTELLUNG`, derselbe wie bei Partner-Webhooks). */
|
|
90
|
+
export const WEBHOOK_DELIVERY_STATUSES = ['delivered', 'pending', 'failed', 'dropped'];
|
|
91
|
+
/**
|
|
92
|
+
* Die Ereignisse, die ein Konto-Webhook abonnieren kann (Stufe 5a). Spaetere
|
|
93
|
+
* Stufen ergaenzen `reservation.*` und `variant_group.*`.
|
|
94
|
+
*/
|
|
95
|
+
export const INVENTORY_WEBHOOK_EVENTS = [
|
|
96
|
+
'stock.changed',
|
|
97
|
+
'stock.below_minimum',
|
|
98
|
+
'article.created',
|
|
99
|
+
'article.updated',
|
|
100
|
+
'article.deactivated',
|
|
101
|
+
];
|
|
102
|
+
/**
|
|
103
|
+
* Die Felder der Huelle jeder Zustellung, in der Reihenfolge am Draht. Statt
|
|
104
|
+
* `partnerId` (Partner-Webhooks) traegt sie `accountId`; `test` steht nur auf
|
|
105
|
+
* Probesendungen.
|
|
106
|
+
*/
|
|
107
|
+
export const INVENTORY_WEBHOOK_ENVELOPE_FIELDS = ['id', 'type', 'createdAt', 'accountId', 'test', 'data'];
|
|
108
|
+
/** Hoechstzahl der Webhooks je Konto (`webhook_limit`, wie bei Partner-Webhooks). */
|
|
109
|
+
export const INVENTORY_WEBHOOK_LIMIT = 5;
|
|
110
|
+
/** Groesstes `limit` einer Liste; ohne Angabe liefert der Server 50. */
|
|
111
|
+
export const INVENTORY_LIST_LIMIT_MAX = 200;
|
|
112
|
+
/**
|
|
113
|
+
* Die Codes, die die Lager-Endpunkte selbst senden. `validation` traegt
|
|
114
|
+
* `errors: [{ field, message }]`, `rate_limited` traegt `retryAfterSec`
|
|
115
|
+
* (dazu die Kopfzeile `Retry-After`) – auch bei `sendWebhookTest` nach 20
|
|
116
|
+
* Probesendungen je Wiener Kalendertag (dann bis Mitternacht in Wien).
|
|
117
|
+
*/
|
|
118
|
+
export const INVENTORY_ERROR_CODES = [
|
|
119
|
+
'validation',
|
|
120
|
+
'invalid_cursor',
|
|
121
|
+
'article_not_found',
|
|
122
|
+
'webhook_not_found',
|
|
123
|
+
'webhook_limit',
|
|
124
|
+
'invalid_webhook_url',
|
|
125
|
+
'event_not_subscribed',
|
|
126
|
+
'webhook_inactive',
|
|
127
|
+
'inventory_api_not_enabled',
|
|
128
|
+
'module_inactive',
|
|
129
|
+
'rate_limited',
|
|
130
|
+
'server_error',
|
|
131
|
+
];
|
|
132
|
+
/**
|
|
133
|
+
* Codes, die Anmeldung und Rand auf jedem Lager-Aufruf erzeugen koennen,
|
|
134
|
+
* soweit sie nicht schon in [INVENTORY_ERROR_CODES] stehen: `errorCodes.auth`
|
|
135
|
+
* ohne die des Partner-Zugangs und `errorCodes.edge` (sortiert), zuletzt
|
|
136
|
+
* `route_missing` (Code des Pakets). Dieselbe Ableitung wie bei der
|
|
137
|
+
* Rechnungs-API.
|
|
138
|
+
*/
|
|
139
|
+
export const INVENTORY_REQUEST_ERROR_CODES = [
|
|
140
|
+
'account_not_found',
|
|
141
|
+
'admin_required',
|
|
142
|
+
'api_not_approved',
|
|
143
|
+
'cashregister_not_assigned',
|
|
144
|
+
'cashregister_not_found',
|
|
145
|
+
'cashregister_token_invalid',
|
|
146
|
+
'cashregister_token_missing',
|
|
147
|
+
'dialect_mismatch',
|
|
148
|
+
'internal_translation_error',
|
|
149
|
+
'live_not_enabled',
|
|
150
|
+
'method_not_allowed',
|
|
151
|
+
'mfa_required',
|
|
152
|
+
'not_found',
|
|
153
|
+
'register_user_no_business',
|
|
154
|
+
'register_user_not_allowed',
|
|
155
|
+
'register_user_not_found',
|
|
156
|
+
'response_translation_failed',
|
|
157
|
+
'session_expired',
|
|
158
|
+
'session_other_cashregister',
|
|
159
|
+
'unauthorized',
|
|
160
|
+
'user_disabled',
|
|
161
|
+
'user_verification_failed',
|
|
162
|
+
'route_missing',
|
|
163
|
+
];
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eingehende Konto-Webhooks der Lager-API: Signatur pruefen, Ereignis lesen.
|
|
3
|
+
*
|
|
4
|
+
* Dasselbe Verfahren wie bei Partner-Webhooks (Backend
|
|
5
|
+
* `gemeinsam/webhook-core.js`, `signaturKopf`/`pruefeSignatur`): Kopf
|
|
6
|
+
* `X-Kasseneck-Signature: t=<unix-sekunden>,v1=<hex>` mit
|
|
7
|
+
* `v1 = HMAC-SHA256(secret, "<t>.<roher Rumpf>")`, Zeitfenster 300 Sekunden in
|
|
8
|
+
* beide Richtungen, zeitkonstanter Vergleich, mehrere `v1=`-Anteile erlaubt.
|
|
9
|
+
* Die Pruefung selbst liegt in `partner/webhook-signatur.ts` und wird hier nur
|
|
10
|
+
* mit der Form `(secret, kopf, rumpf, optionen)` angeboten.
|
|
11
|
+
*
|
|
12
|
+
* Reihenfolge im Empfaenger: **erst pruefen, dann lesen**, und dabei den
|
|
13
|
+
* **rohen** Rumpf nehmen (in Express `express.raw({ type: '*\/*' })` vor jedem
|
|
14
|
+
* JSON-Parser).
|
|
15
|
+
*/
|
|
16
|
+
import type { InventoryWebhookEvent } from './typen.js';
|
|
17
|
+
export { WEBHOOK_SIGNATURE_HEADER, WEBHOOK_EVENT_HEADER, WEBHOOK_DELIVERY_HEADER, WEBHOOK_TOLERANCE_SEC, } from '../partner/webhook-signatur.js';
|
|
18
|
+
export interface VerifyInventoryWebhookOptions {
|
|
19
|
+
/** Erlaubte Abweichung des Zeitstempels in Sekunden, in beide Richtungen; Vorgabe 300. */
|
|
20
|
+
toleranceSec?: number;
|
|
21
|
+
/** Jetzt: ein `Date` oder Millisekunden seit 1970 (wie `Date.now()`). Vorgabe: die Systemuhr. */
|
|
22
|
+
now?: Date | number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Prueft die Signatur einer Zustellung. `true` nur, wenn Kopf, Zeitfenster
|
|
26
|
+
* und HMAC stimmen; jede schlechte Eingabe und jede Ausnahme ist `false`,
|
|
27
|
+
* nie ein Wurf.
|
|
28
|
+
*
|
|
29
|
+
* **Asynchron**, weil die Pruefung WebCrypto (`crypto.subtle`) benutzt: das
|
|
30
|
+
* Paket hat keine Laufzeitabhaengigkeit und laeuft auch im Browser.
|
|
31
|
+
*
|
|
32
|
+
* @param secret das Secret aus `createWebhook`/`rotateWebhookSecret`; eine
|
|
33
|
+
* Liste erlaubt den Wechsel (es reicht, wenn eines passt)
|
|
34
|
+
* @param header der Wert von `X-Kasseneck-Signature`, unveraendert
|
|
35
|
+
* @param rawBody der **rohe** Rumpf (Text oder Bytes), nicht `JSON.parse` + `stringify`
|
|
36
|
+
*/
|
|
37
|
+
export declare function verifyInventoryWebhookSignature(secret: string | readonly string[], header: string | null | undefined, rawBody: string | Uint8Array, options?: VerifyInventoryWebhookOptions): Promise<boolean>;
|
|
38
|
+
/**
|
|
39
|
+
* Liest eine Zustellung als typisiertes Ereignis. Vorher die Signatur pruefen
|
|
40
|
+
* ([verifyInventoryWebhookSignature]).
|
|
41
|
+
*
|
|
42
|
+
* - Ein Ereignis, das diese Paketversion nicht kennt (etwa `reservation.*`
|
|
43
|
+
* einer spaeteren Stufe), ergibt `null`: mit 2xx antworten und uebergehen.
|
|
44
|
+
* - Ein Rumpf, der keine Huelle ist, oder eine Bruchzahl in einer Menge wirft
|
|
45
|
+
* `KasseneckValidationError` (`scope: 'response'`).
|
|
46
|
+
*
|
|
47
|
+
* **Entdoppeln** auf `event.id`; **Stand statt Aenderung**: einen gespeicherten
|
|
48
|
+
* Bestand nur ueberschreiben, wenn `data.sequence` groesser ist.
|
|
49
|
+
*/
|
|
50
|
+
export declare function parseInventoryWebhookEvent(rawBody: string | Uint8Array): InventoryWebhookEvent | null;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eingehende Konto-Webhooks der Lager-API: Signatur pruefen, Ereignis lesen.
|
|
3
|
+
*
|
|
4
|
+
* Dasselbe Verfahren wie bei Partner-Webhooks (Backend
|
|
5
|
+
* `gemeinsam/webhook-core.js`, `signaturKopf`/`pruefeSignatur`): Kopf
|
|
6
|
+
* `X-Kasseneck-Signature: t=<unix-sekunden>,v1=<hex>` mit
|
|
7
|
+
* `v1 = HMAC-SHA256(secret, "<t>.<roher Rumpf>")`, Zeitfenster 300 Sekunden in
|
|
8
|
+
* beide Richtungen, zeitkonstanter Vergleich, mehrere `v1=`-Anteile erlaubt.
|
|
9
|
+
* Die Pruefung selbst liegt in `partner/webhook-signatur.ts` und wird hier nur
|
|
10
|
+
* mit der Form `(secret, kopf, rumpf, optionen)` angeboten.
|
|
11
|
+
*
|
|
12
|
+
* Reihenfolge im Empfaenger: **erst pruefen, dann lesen**, und dabei den
|
|
13
|
+
* **rohen** Rumpf nehmen (in Express `express.raw({ type: '*\/*' })` vor jedem
|
|
14
|
+
* JSON-Parser).
|
|
15
|
+
*/
|
|
16
|
+
import { KasseneckValidationError } from '../client/errors.js';
|
|
17
|
+
import { verifyWebhookSignature as pruefeSignatur } from '../partner/webhook-signatur.js';
|
|
18
|
+
import { artikel, bestandGeaendert, objekt, unterMindestbestand } from './lesen.js';
|
|
19
|
+
import { INVENTORY_WEBHOOK_EVENTS } from './vertrag.js';
|
|
20
|
+
export { WEBHOOK_SIGNATURE_HEADER, WEBHOOK_EVENT_HEADER, WEBHOOK_DELIVERY_HEADER, WEBHOOK_TOLERANCE_SEC, } from '../partner/webhook-signatur.js';
|
|
21
|
+
/**
|
|
22
|
+
* Prueft die Signatur einer Zustellung. `true` nur, wenn Kopf, Zeitfenster
|
|
23
|
+
* und HMAC stimmen; jede schlechte Eingabe und jede Ausnahme ist `false`,
|
|
24
|
+
* nie ein Wurf.
|
|
25
|
+
*
|
|
26
|
+
* **Asynchron**, weil die Pruefung WebCrypto (`crypto.subtle`) benutzt: das
|
|
27
|
+
* Paket hat keine Laufzeitabhaengigkeit und laeuft auch im Browser.
|
|
28
|
+
*
|
|
29
|
+
* @param secret das Secret aus `createWebhook`/`rotateWebhookSecret`; eine
|
|
30
|
+
* Liste erlaubt den Wechsel (es reicht, wenn eines passt)
|
|
31
|
+
* @param header der Wert von `X-Kasseneck-Signature`, unveraendert
|
|
32
|
+
* @param rawBody der **rohe** Rumpf (Text oder Bytes), nicht `JSON.parse` + `stringify`
|
|
33
|
+
*/
|
|
34
|
+
export async function verifyInventoryWebhookSignature(secret, header, rawBody, options = {}) {
|
|
35
|
+
try {
|
|
36
|
+
const jetzt = options.now instanceof Date ? options.now.getTime() : options.now;
|
|
37
|
+
const nowSec = typeof jetzt === 'number' && Number.isFinite(jetzt) ? Math.floor(jetzt / 1000) : undefined;
|
|
38
|
+
const r = await pruefeSignatur({
|
|
39
|
+
secret,
|
|
40
|
+
signatureHeader: header,
|
|
41
|
+
body: rawBody,
|
|
42
|
+
...(nowSec === undefined ? {} : { nowSec }),
|
|
43
|
+
...(options.toleranceSec === undefined ? {} : { toleranceSec: options.toleranceSec }),
|
|
44
|
+
});
|
|
45
|
+
return r.ok;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const BEKANNT = new Set(INVENTORY_WEBHOOK_EVENTS);
|
|
52
|
+
function kaputt(grund) {
|
|
53
|
+
return new KasseneckValidationError('parseInventoryWebhookEvent', grund, 'response');
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Liest eine Zustellung als typisiertes Ereignis. Vorher die Signatur pruefen
|
|
57
|
+
* ([verifyInventoryWebhookSignature]).
|
|
58
|
+
*
|
|
59
|
+
* - Ein Ereignis, das diese Paketversion nicht kennt (etwa `reservation.*`
|
|
60
|
+
* einer spaeteren Stufe), ergibt `null`: mit 2xx antworten und uebergehen.
|
|
61
|
+
* - Ein Rumpf, der keine Huelle ist, oder eine Bruchzahl in einer Menge wirft
|
|
62
|
+
* `KasseneckValidationError` (`scope: 'response'`).
|
|
63
|
+
*
|
|
64
|
+
* **Entdoppeln** auf `event.id`; **Stand statt Aenderung**: einen gespeicherten
|
|
65
|
+
* Bestand nur ueberschreiben, wenn `data.sequence` groesser ist.
|
|
66
|
+
*/
|
|
67
|
+
export function parseInventoryWebhookEvent(rawBody) {
|
|
68
|
+
const text = typeof rawBody === 'string' ? rawBody : new TextDecoder('utf-8').decode(rawBody);
|
|
69
|
+
let roh;
|
|
70
|
+
try {
|
|
71
|
+
roh = JSON.parse(text);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
throw kaputt('Rumpf ist kein JSON');
|
|
75
|
+
}
|
|
76
|
+
const e = objekt(roh);
|
|
77
|
+
if (!e)
|
|
78
|
+
throw kaputt('Rumpf ist kein Ereignis (kein Objekt)');
|
|
79
|
+
const { id, type, createdAt, accountId, data } = e;
|
|
80
|
+
if (typeof id !== 'string' || id === '' || typeof type !== 'string' || type === '')
|
|
81
|
+
throw kaputt('Ereignis ohne id oder type');
|
|
82
|
+
if (typeof createdAt !== 'number' || !Number.isFinite(createdAt))
|
|
83
|
+
throw kaputt('Ereignis ohne createdAt');
|
|
84
|
+
if (typeof accountId !== 'string' || accountId === '')
|
|
85
|
+
throw kaputt('Ereignis ohne accountId');
|
|
86
|
+
if (!BEKANNT.has(type))
|
|
87
|
+
return null;
|
|
88
|
+
const ort = { name: 'parseInventoryWebhookEvent', pfad: 'data' };
|
|
89
|
+
if (!objekt(data))
|
|
90
|
+
throw kaputt('Ereignis ohne data');
|
|
91
|
+
// Nur ein ausdrueckliches `true` ist eine Probe; im Zweifel der Ernstfall.
|
|
92
|
+
const huelle = { id, type: type, createdAt, accountId, test: e.test === true };
|
|
93
|
+
switch (huelle.type) {
|
|
94
|
+
case 'stock.changed':
|
|
95
|
+
return { ...huelle, type: huelle.type, data: bestandGeaendert(ort, data) };
|
|
96
|
+
case 'stock.below_minimum':
|
|
97
|
+
return { ...huelle, type: huelle.type, data: unterMindestbestand(ort, data) };
|
|
98
|
+
default:
|
|
99
|
+
return { ...huelle, type: huelle.type, data: artikel(ort, data) };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Fingerabdruck des Vertrags-Exports, aus dem diese Datei stammt (`_quelle.sha256`). */
|
|
2
|
-
export declare const VOKABULAR_QUELLE = "
|
|
2
|
+
export declare const VOKABULAR_QUELLE = "79931a40ccaea45777da4713bba475c2f74e1fe7d6264f294cecd321964f9ded";
|
|
3
3
|
/** Schema-Notation des Vertrags: Blatt 'aussen': 'innen', Objekt { __: 'innen', ... }, Liste [ { __: 'innen', ... } ]. */
|
|
4
4
|
export type SchemaEintrag = string | SchemaObjekt | readonly [SchemaObjekt];
|
|
5
5
|
export interface SchemaObjekt {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Erzeugt von scripts/stored-vokabular.mjs aus fixtures/v3/v3-vokabular.json.
|
|
2
2
|
// Nicht von Hand aendern: test/stored.test.ts vergleicht mit dem Vertrag.
|
|
3
3
|
/** Fingerabdruck des Vertrags-Exports, aus dem diese Datei stammt (`_quelle.sha256`). */
|
|
4
|
-
export const VOKABULAR_QUELLE = "
|
|
4
|
+
export const VOKABULAR_QUELLE = "79931a40ccaea45777da4713bba475c2f74e1fe7d6264f294cecd321964f9ded";
|
|
5
5
|
/** Schema je Endpunkt (aussen -> innen) und Wertverweise auf die Kataloge. */
|
|
6
6
|
export const SCHEMAS = {
|
|
7
7
|
"getReceipt": {
|
package/dist/esm/version.d.ts
CHANGED
package/dist/esm/version.js
CHANGED
package/fixtures/pos-texts.json
CHANGED
package/fixtures/surface.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
2
|
+
"version": "1.4.0",
|
|
3
3
|
"baseUrls": {
|
|
4
4
|
"public": "https://api.kasseneck.at/v3",
|
|
5
5
|
"pos": "https://kasse.kasseneck.at/api/v3"
|
|
@@ -54,7 +54,21 @@
|
|
|
54
54
|
"stripeCaptureIntent",
|
|
55
55
|
"rotatePartnerWebhookSecret",
|
|
56
56
|
"updateCustomer",
|
|
57
|
-
"updatePartnerWebhook"
|
|
57
|
+
"updatePartnerWebhook",
|
|
58
|
+
"getArticle",
|
|
59
|
+
"listArticles",
|
|
60
|
+
"lookupArticleByCode",
|
|
61
|
+
"listLocations",
|
|
62
|
+
"getStock",
|
|
63
|
+
"listStock",
|
|
64
|
+
"listStockMovements",
|
|
65
|
+
"createWebhook",
|
|
66
|
+
"updateWebhook",
|
|
67
|
+
"deleteWebhook",
|
|
68
|
+
"listWebhooks",
|
|
69
|
+
"sendWebhookTest",
|
|
70
|
+
"rotateWebhookSecret",
|
|
71
|
+
"listWebhookDeliveries"
|
|
58
72
|
],
|
|
59
73
|
"pos": [
|
|
60
74
|
"cancelReceipt",
|
|
@@ -148,7 +162,21 @@
|
|
|
148
162
|
"getInvoiceItem",
|
|
149
163
|
"listInvoiceItems",
|
|
150
164
|
"setCustomerMandate",
|
|
151
|
-
"revokeCustomerMandate"
|
|
165
|
+
"revokeCustomerMandate",
|
|
166
|
+
"getArticle",
|
|
167
|
+
"listArticles",
|
|
168
|
+
"lookupArticleByCode",
|
|
169
|
+
"listLocations",
|
|
170
|
+
"getStock",
|
|
171
|
+
"listStock",
|
|
172
|
+
"listStockMovements",
|
|
173
|
+
"createWebhook",
|
|
174
|
+
"updateWebhook",
|
|
175
|
+
"deleteWebhook",
|
|
176
|
+
"listWebhooks",
|
|
177
|
+
"sendWebhookTest",
|
|
178
|
+
"rotateWebhookSecret",
|
|
179
|
+
"listWebhookDeliveries"
|
|
152
180
|
],
|
|
153
181
|
"pos": [
|
|
154
182
|
"pairRegisterDevice",
|
|
@@ -927,5 +955,135 @@
|
|
|
927
955
|
"domesticReverseCharge",
|
|
928
956
|
"outsideScope"
|
|
929
957
|
]
|
|
958
|
+
},
|
|
959
|
+
"inventory": {
|
|
960
|
+
"inventoryEndpoints": [
|
|
961
|
+
"getArticle",
|
|
962
|
+
"listArticles",
|
|
963
|
+
"lookupArticleByCode",
|
|
964
|
+
"listLocations",
|
|
965
|
+
"getStock",
|
|
966
|
+
"listStock",
|
|
967
|
+
"listStockMovements",
|
|
968
|
+
"createWebhook",
|
|
969
|
+
"updateWebhook",
|
|
970
|
+
"deleteWebhook",
|
|
971
|
+
"listWebhooks",
|
|
972
|
+
"sendWebhookTest",
|
|
973
|
+
"rotateWebhookSecret",
|
|
974
|
+
"listWebhookDeliveries"
|
|
975
|
+
],
|
|
976
|
+
"inventoryErrorCodes": [
|
|
977
|
+
"validation",
|
|
978
|
+
"invalid_cursor",
|
|
979
|
+
"article_not_found",
|
|
980
|
+
"webhook_not_found",
|
|
981
|
+
"webhook_limit",
|
|
982
|
+
"invalid_webhook_url",
|
|
983
|
+
"event_not_subscribed",
|
|
984
|
+
"webhook_inactive",
|
|
985
|
+
"inventory_api_not_enabled",
|
|
986
|
+
"module_inactive",
|
|
987
|
+
"rate_limited",
|
|
988
|
+
"server_error"
|
|
989
|
+
],
|
|
990
|
+
"inventoryRequestErrorCodes": [
|
|
991
|
+
"account_not_found",
|
|
992
|
+
"admin_required",
|
|
993
|
+
"api_not_approved",
|
|
994
|
+
"cashregister_not_assigned",
|
|
995
|
+
"cashregister_not_found",
|
|
996
|
+
"cashregister_token_invalid",
|
|
997
|
+
"cashregister_token_missing",
|
|
998
|
+
"dialect_mismatch",
|
|
999
|
+
"internal_translation_error",
|
|
1000
|
+
"live_not_enabled",
|
|
1001
|
+
"method_not_allowed",
|
|
1002
|
+
"mfa_required",
|
|
1003
|
+
"not_found",
|
|
1004
|
+
"register_user_no_business",
|
|
1005
|
+
"register_user_not_allowed",
|
|
1006
|
+
"register_user_not_found",
|
|
1007
|
+
"response_translation_failed",
|
|
1008
|
+
"session_expired",
|
|
1009
|
+
"session_other_cashregister",
|
|
1010
|
+
"unauthorized",
|
|
1011
|
+
"user_disabled",
|
|
1012
|
+
"user_verification_failed",
|
|
1013
|
+
"route_missing"
|
|
1014
|
+
],
|
|
1015
|
+
"inventoryWebhookEnvelopeFields": [
|
|
1016
|
+
"id",
|
|
1017
|
+
"type",
|
|
1018
|
+
"createdAt",
|
|
1019
|
+
"accountId",
|
|
1020
|
+
"test",
|
|
1021
|
+
"data"
|
|
1022
|
+
],
|
|
1023
|
+
"inventoryWebhookEvents": [
|
|
1024
|
+
"stock.changed",
|
|
1025
|
+
"stock.below_minimum",
|
|
1026
|
+
"article.created",
|
|
1027
|
+
"article.updated",
|
|
1028
|
+
"article.deactivated"
|
|
1029
|
+
],
|
|
1030
|
+
"locationTypes": [
|
|
1031
|
+
"warehouse",
|
|
1032
|
+
"store",
|
|
1033
|
+
"vehicle",
|
|
1034
|
+
"other"
|
|
1035
|
+
],
|
|
1036
|
+
"stockChangeCauses": [
|
|
1037
|
+
"sale",
|
|
1038
|
+
"invoice",
|
|
1039
|
+
"credit_note",
|
|
1040
|
+
"cancellation",
|
|
1041
|
+
"goods_receipt",
|
|
1042
|
+
"transfer",
|
|
1043
|
+
"loss",
|
|
1044
|
+
"condition",
|
|
1045
|
+
"reversal",
|
|
1046
|
+
"reservation",
|
|
1047
|
+
"stocktake",
|
|
1048
|
+
"takeover",
|
|
1049
|
+
"other"
|
|
1050
|
+
],
|
|
1051
|
+
"stockConditions": [
|
|
1052
|
+
"sellable",
|
|
1053
|
+
"defective"
|
|
1054
|
+
],
|
|
1055
|
+
"stockMovementSources": [
|
|
1056
|
+
"receipt",
|
|
1057
|
+
"invoice",
|
|
1058
|
+
"cancellation",
|
|
1059
|
+
"credit_note",
|
|
1060
|
+
"panel",
|
|
1061
|
+
"register",
|
|
1062
|
+
"api",
|
|
1063
|
+
"stocktake",
|
|
1064
|
+
"system"
|
|
1065
|
+
],
|
|
1066
|
+
"stockMovementTypes": [
|
|
1067
|
+
"sale",
|
|
1068
|
+
"goods_receipt",
|
|
1069
|
+
"loss",
|
|
1070
|
+
"return",
|
|
1071
|
+
"transfer_out",
|
|
1072
|
+
"transfer_in",
|
|
1073
|
+
"condition_out",
|
|
1074
|
+
"condition_in",
|
|
1075
|
+
"stocktake",
|
|
1076
|
+
"adjustment",
|
|
1077
|
+
"takeover",
|
|
1078
|
+
"reversal",
|
|
1079
|
+
"revaluation",
|
|
1080
|
+
"method_change"
|
|
1081
|
+
],
|
|
1082
|
+
"webhookDeliveryStatuses": [
|
|
1083
|
+
"delivered",
|
|
1084
|
+
"pending",
|
|
1085
|
+
"failed",
|
|
1086
|
+
"dropped"
|
|
1087
|
+
]
|
|
930
1088
|
}
|
|
931
1089
|
}
|
package/fixtures/v3/README.md
CHANGED
|
@@ -17,6 +17,7 @@ Erzeugt von Jest-Tests in zwei Codebases (jede übersetzt mit ihrem eigenen Rand
|
|
|
17
17
|
| `functions/test/unit/v3-vertrag-export.test.js` | `v3-vokabular.json`, `antworten/belege.json`, `antworten/kasse-belege.json`, `antworten/storno.json`, `antworten/belegmail.json`, `antworten/rechnungen.json`, `stored/belege.json`, `stored/rechnungen.json`, `zahlbetrag-faelle.json` |
|
|
18
18
|
| `functions/test/unit/v3-vertrag-export-kassenweg.test.js` | Teil `default` von `antworten/kasse.json` und `stored/kasse.json` (6 Beleg-Endpunkte der Kasse) |
|
|
19
19
|
| `functions-kasse/test/unit/v3-vertrag-export.test.js` | Teil `kasse` derselben zwei Dateien (die übrigen 19 Kassen-Endpunkte) |
|
|
20
|
+
| `functions-kasse/test/unit/v3-vertrag-export-lager.test.js` | `antworten/lager.json` (Lager-API, Stufe 5a) |
|
|
20
21
|
|
|
21
22
|
Fest injiziert, damit zwei Läufe dieselben Bytes liefern: eine Uhr für alle Welten
|
|
22
23
|
(26.09.2026 08:00 UTC), `crypto.randomBytes`/`randomUUID`, fortlaufende Dokument-IDs
|
|
@@ -46,6 +47,7 @@ bleiben verschieden:
|
|
|
46
47
|
| `fullReceiptId` (auch im Text) | `000…0.000…0<8 hex>` |
|
|
47
48
|
| `statusPassword`, Token in `statusUrl` (gespeichert: `public_password`, `public_token`) | `EXAM-<4 hex>`, `000…0<8 hex>` |
|
|
48
49
|
| Kopplungscode (`code` bei `pairRegisterDevice`, `register_pairings/<CODE>`) | `EXMP<4 Zeichen>` (Alphabet ohne 0/1/I/O) |
|
|
50
|
+
| Webhook-Secret (`secret` bei `createWebhook`/`rotateWebhookSecret`, auch im Text) | `whsec_EXAMPLE<8 hex>AAAA…` (38 Zeichen) |
|
|
49
51
|
| ungültige Eingaben dieser Felder | `INVALID_EXAMPLE_<8 hex>` |
|
|
50
52
|
|
|
51
53
|
In `stored/` stehen Schlüssel, Hashes und Salze als `<geheim>`. Ein Test prüft jede Datei
|
|
@@ -90,7 +92,7 @@ Code-Änderung zusammen einchecken.
|
|
|
90
92
|
äußere Codes) und je Quelle: Rand (`edge`), Anmeldung (`auth`),
|
|
91
93
|
`receiptMessages`, Kassen-Handler (`registerHandlers`, je Endpunkt in
|
|
92
94
|
`registerHandlersByEndpoint`), Fälle der Kassen-Welt (`registerCases`), Storno,
|
|
93
|
-
Zahlungen, Belegmail, Rechnung, Partner. Jeder Code, der irgendwo in `antworten/`
|
|
95
|
+
Zahlungen, Belegmail, Rechnung, Partner, Lager-API (`inventory`). Jeder Code, der irgendwo in `antworten/`
|
|
94
96
|
vorkommt, steht in `all` (Test).
|
|
95
97
|
- `noticeCodes`: Hinweis-Codes (`notice[].code` der Rechnungs-API), keine Fehler.
|
|
96
98
|
- `schemas`: je Endpunkt der Eintrag des Vokabulars (Notation außen → innen);
|
|
@@ -109,6 +111,12 @@ Code-Änderung zusammen einchecken.
|
|
|
109
111
|
Liste, Storno, Gutschrift, Zahlung, Fehler).
|
|
110
112
|
- **`antworten/kasse.json`**: alle 25 Kassen-Endpunkte unter `/api/v3`, je Fall
|
|
111
113
|
(englischer Name) Methode, Aufrufer, Parameter, HTTP-Status, Kopfzeilen und Antwort.
|
|
114
|
+
- **`antworten/lager.json`**: Lager-API unter `/v3` (Kanal `api`) in Ablaufreihenfolge an
|
|
115
|
+
einem Konto (Bäckerei Kornblum, Standort `haupt`): Artikel, Standorte, Bestand, Bewegungen,
|
|
116
|
+
mit und ohne Schalter `lagerApi.kosten`, Konto-Webhooks verwalten samt Fehlern
|
|
117
|
+
(`webhook_limit`, `rate_limited` der Tagesgrenze für Probesendungen …). Dazu
|
|
118
|
+
`webhookEvents`: die zugestellten Konto-Webhooks (`stock.changed`, `stock.below_minimum`,
|
|
119
|
+
`article.*`), Hülle wie gesendet.
|
|
112
120
|
- **`stored/`**: die inneren Firestore-Dokumente (deutsch, ohne Geheimnisse), aus denen
|
|
113
121
|
die Antworten entstanden; für `./stored` (gespeicherte Form → englisches Modell).
|
|
114
122
|
- **`zahlbetrag-faelle.json`**: Rechenfälle für `receiptDueCents(items, vouchers,
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"_hinweis": "Vertrags-Export /v3, erzeugt aus den echten Handlern (npm run vertrag:v3 in functions/ und functions-kasse/). Nicht von Hand pflegen.",
|
|
3
3
|
"_quelle": {
|
|
4
4
|
"sha256": "61892b91e6a8a0f273dcfdeb63809d92d98fb837a3c0baa782f03b29dd3b8b7a",
|
|
5
|
-
"inputsSha256": "
|
|
6
|
-
"backendPackage": "@kreiseck/kasseneck-api@0.
|
|
5
|
+
"inputsSha256": "4fec6d58dd069e6d980bcab1d9883380d06e6fe8ba2a5e0f05d772b7720955c2",
|
|
6
|
+
"backendPackage": "@kreiseck/kasseneck-api@0.32.2",
|
|
7
7
|
"inputs": [
|
|
8
8
|
"docs/api/fehlercodes.json",
|
|
9
9
|
"functions-kasse/test/unit/fixtures/kassen-codes-v3.js",
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"_hinweis": "Vertrags-Export /v3, erzeugt aus den echten Handlern (npm run vertrag:v3 in functions/ und functions-kasse/). Nicht von Hand pflegen.",
|
|
3
3
|
"_quelle": {
|
|
4
4
|
"sha256": "265bcf3e14cdea33ec3c4df399eb487d40c0d7793ee23d2ee12bcf664bcad550",
|
|
5
|
-
"inputsSha256": "
|
|
6
|
-
"backendPackage": "@kreiseck/kasseneck-api@0.
|
|
5
|
+
"inputsSha256": "4fec6d58dd069e6d980bcab1d9883380d06e6fe8ba2a5e0f05d772b7720955c2",
|
|
6
|
+
"backendPackage": "@kreiseck/kasseneck-api@0.32.2",
|
|
7
7
|
"inputs": [
|
|
8
8
|
"docs/api/fehlercodes.json",
|
|
9
9
|
"functions-kasse/test/unit/fixtures/kassen-codes-v3.js",
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"_hinweis": "Vertrags-Export /v3, erzeugt aus den echten Handlern (npm run vertrag:v3 in functions/ und functions-kasse/). Nicht von Hand pflegen.",
|
|
3
3
|
"_quelle": {
|
|
4
4
|
"sha256": "aad7147db385e4a6d88ba5fb59d24c04e7e1f01195778aa70ccdc68fb90adcd7",
|
|
5
|
-
"inputsSha256": "
|
|
6
|
-
"backendPackage": "@kreiseck/kasseneck-api@0.
|
|
5
|
+
"inputsSha256": "4fec6d58dd069e6d980bcab1d9883380d06e6fe8ba2a5e0f05d772b7720955c2",
|
|
6
|
+
"backendPackage": "@kreiseck/kasseneck-api@0.32.2",
|
|
7
7
|
"inputs": [
|
|
8
8
|
"docs/api/fehlercodes.json",
|
|
9
9
|
"functions-kasse/test/unit/fixtures/kassen-codes-v3.js",
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"default": {
|
|
5
5
|
"sha256": "bf1e7c100e328517c72d5badf31904183efe22d1fddec308e2fe2722068854bc",
|
|
6
6
|
"head": [],
|
|
7
|
-
"inputsSha256": "
|
|
8
|
-
"backendPackage": "@kreiseck/kasseneck-api@0.
|
|
7
|
+
"inputsSha256": "91fa28cc05dd8f34575b8ea622bd7e3f145bbd25a8e97ad8ecf582b9df69078d",
|
|
8
|
+
"backendPackage": "@kreiseck/kasseneck-api@0.32.2",
|
|
9
9
|
"inputs": [
|
|
10
10
|
"functions-kasse/test/unit/fixtures/kassen-welt.js",
|
|
11
11
|
"functions/gemeinsam/api-rand.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"channel",
|
|
25
25
|
"note"
|
|
26
26
|
],
|
|
27
|
-
"inputsSha256": "
|
|
27
|
+
"inputsSha256": "f8c6cfbda74bdcd5f3cc9542009698699dec89175ea233f53ee0dea8f007e043",
|
|
28
28
|
"backendPackage": "@kreiseck/kasseneck-api@0.14.0",
|
|
29
29
|
"inputs": [
|
|
30
30
|
"functions-kasse/gemeinsam/api-rand.js",
|