@kreiseck/kasseneck-api 1.3.0 → 1.5.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 +176 -0
- package/README.md +293 -1
- package/dist/cjs/client/aufrufe.d.ts +2 -2
- package/dist/cjs/client/aufrufe.js +58 -0
- package/dist/cjs/inventory/api.d.ts +61 -0
- package/dist/cjs/inventory/api.js +54 -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 +91 -0
- package/dist/cjs/inventory/endpunkte.js +290 -0
- package/dist/cjs/inventory/fehler.d.ts +43 -0
- package/dist/cjs/inventory/fehler.js +66 -0
- package/dist/cjs/inventory/index.d.ts +21 -0
- package/dist/cjs/inventory/index.js +94 -0
- package/dist/cjs/inventory/lesen.d.ts +45 -0
- package/dist/cjs/inventory/lesen.js +424 -0
- package/dist/cjs/inventory/schreiben.d.ts +83 -0
- package/dist/cjs/inventory/schreiben.js +315 -0
- package/dist/cjs/inventory/typen.d.ts +679 -0
- package/dist/cjs/inventory/typen.js +14 -0
- package/dist/cjs/inventory/vertrag.d.ts +136 -0
- package/dist/cjs/inventory/vertrag.js +291 -0
- package/dist/cjs/inventory/webhook.d.ts +52 -0
- package/dist/cjs/inventory/webhook.js +116 -0
- package/dist/cjs/invoice/index.d.ts +2 -2
- package/dist/cjs/invoice/index.js +2 -1
- package/dist/cjs/invoice/typen.d.ts +46 -2
- package/dist/cjs/invoice/vertrag.d.ts +19 -5
- package/dist/cjs/invoice/vertrag.js +37 -5
- package/dist/cjs/stored/vokabular.d.ts +1 -1
- package/dist/cjs/stored/vokabular.js +5 -3
- 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 +58 -0
- package/dist/esm/inventory/api.d.ts +61 -0
- package/dist/esm/inventory/api.js +51 -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 +91 -0
- package/dist/esm/inventory/endpunkte.js +267 -0
- package/dist/esm/inventory/fehler.d.ts +43 -0
- package/dist/esm/inventory/fehler.js +57 -0
- package/dist/esm/inventory/index.d.ts +21 -0
- package/dist/esm/inventory/index.js +20 -0
- package/dist/esm/inventory/lesen.d.ts +45 -0
- package/dist/esm/inventory/lesen.js +404 -0
- package/dist/esm/inventory/schreiben.d.ts +83 -0
- package/dist/esm/inventory/schreiben.js +298 -0
- package/dist/esm/inventory/typen.d.ts +679 -0
- package/dist/esm/inventory/typen.js +13 -0
- package/dist/esm/inventory/vertrag.d.ts +136 -0
- package/dist/esm/inventory/vertrag.js +288 -0
- package/dist/esm/inventory/webhook.d.ts +52 -0
- package/dist/esm/inventory/webhook.js +107 -0
- package/dist/esm/invoice/index.d.ts +2 -2
- package/dist/esm/invoice/index.js +1 -1
- package/dist/esm/invoice/typen.d.ts +46 -2
- package/dist/esm/invoice/vertrag.d.ts +19 -5
- package/dist/esm/invoice/vertrag.js +36 -4
- package/dist/esm/stored/vokabular.d.ts +1 -1
- package/dist/esm/stored/vokabular.js +5 -3
- 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-examples/credit-error-reservation.json +26 -0
- package/fixtures/invoice-api-examples/issue-error-reservation-article.json +25 -0
- package/fixtures/invoice-api-examples/issue-error-vat-id-risk.json +26 -0
- package/fixtures/invoice-api-examples/issue-reservation.json +24 -0
- package/fixtures/invoice-api-examples/issue-vat-id-risk.json +28 -0
- package/fixtures/invoice-api.schema.json +15 -2
- package/fixtures/invoice-texts.json +1 -1
- package/fixtures/pos-texts.json +1 -1
- package/fixtures/surface.json +306 -5
- 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 +3881 -0
- package/fixtures/v3/antworten/rechnungen.json +267 -44
- 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 +174 -18
- package/fixtures/v3/v3-vokabular.json +1007 -20
- package/fixtures/v3/zahlbetrag-faelle.json +2 -2
- package/package.json +14 -2
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fassade ueber den Aufrufen der Lager-API (lesen, Webhooks, schreiben,
|
|
3
|
+
* reservieren): Schluessel einmal binden, dann rufen. Wie [createInvoiceApi] bewusst keine Klasse; die Aufrufe sind freie
|
|
4
|
+
* Funktionen (endpunkte.ts) und bleiben einzeln importierbar.
|
|
5
|
+
*/
|
|
6
|
+
import { type FetchLike } from '../client/transport.js';
|
|
7
|
+
import type { Article, ChangeStockConditionRequest, CreateArticleRequest, CreateReservationRequest, DeactivateArticleRequest, ExtendReservationRequest, GoodsReceiptPreview, GoodsReceiptPreviewRequest, ReceiveGoodsRequest, RecordStockLossRequest, ReleaseReservationRequest, Reservation, ReservationListQuery, ReservationPage, ReverseStockMovementRequest, StockOperation, TransferStockRequest, UpdateArticleRequest, ArticleListQuery, ArticleLookup, ArticlePage, CreateInventoryWebhookOptions, InventoryWebhook, InventoryWebhookDelivery, InventoryWebhookList, InventoryWebhookPatch, InventoryWebhookTestResult, InventoryWebhookWithSecret, Location, StockLevel, StockListQuery, StockMovement, StockMovementPage, StockMovementQuery, StockPage, StockResult } from './typen.js';
|
|
8
|
+
import type { InventoryWebhookEventType } from './vertrag.js';
|
|
9
|
+
export interface InventoryClientOptions {
|
|
10
|
+
/** `api_key` des Kontos (`kr_live_…` / `kr_test_…`). Gehoert auf einen Server. */
|
|
11
|
+
apiKey: string;
|
|
12
|
+
/** Abweichende Basis-URL (eigener Proxy); muss auf `/v3` enden. Vorgabe `https://api.kasseneck.at/v3`. */
|
|
13
|
+
baseUrl?: string;
|
|
14
|
+
/** Zeitlimit je Aufruf in Millisekunden. */
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
/** Eigene `fetch`-Umsetzung (Tests, Proxys). */
|
|
17
|
+
fetch?: FetchLike;
|
|
18
|
+
}
|
|
19
|
+
export interface InventoryClient {
|
|
20
|
+
getArticle(articleId: string): Promise<Article>;
|
|
21
|
+
listArticles(query?: ArticleListQuery): Promise<ArticlePage>;
|
|
22
|
+
/** Alle Artikel der Abfrage ueber `nextCursor`: `for await (const a of client.iterateArticles())`. */
|
|
23
|
+
iterateArticles(query?: ArticleListQuery): AsyncGenerator<Article, void, undefined>;
|
|
24
|
+
lookupArticleByCode(lookup: ArticleLookup): Promise<Article>;
|
|
25
|
+
listLocations(): Promise<Location[]>;
|
|
26
|
+
getStock(articleId: string): Promise<StockResult>;
|
|
27
|
+
listStock(query?: StockListQuery): Promise<StockPage>;
|
|
28
|
+
iterateStock(query?: StockListQuery): AsyncGenerator<StockLevel, void, undefined>;
|
|
29
|
+
listStockMovements(query?: StockMovementQuery): Promise<StockMovementPage>;
|
|
30
|
+
iterateStockMovements(query?: StockMovementQuery): AsyncGenerator<StockMovement, void, undefined>;
|
|
31
|
+
createWebhook(options: CreateInventoryWebhookOptions): Promise<InventoryWebhookWithSecret>;
|
|
32
|
+
updateWebhook(webhookId: string, patch: InventoryWebhookPatch): Promise<InventoryWebhook>;
|
|
33
|
+
deleteWebhook(webhookId: string): Promise<{
|
|
34
|
+
webhookId: string;
|
|
35
|
+
deleted: boolean;
|
|
36
|
+
}>;
|
|
37
|
+
listWebhooks(): Promise<InventoryWebhookList>;
|
|
38
|
+
sendWebhookTest(webhookId: string, event: InventoryWebhookEventType | (string & {})): Promise<InventoryWebhookTestResult>;
|
|
39
|
+
rotateWebhookSecret(webhookId: string): Promise<InventoryWebhookWithSecret>;
|
|
40
|
+
listWebhookDeliveries(options?: {
|
|
41
|
+
webhookId?: string;
|
|
42
|
+
limit?: number;
|
|
43
|
+
}): Promise<InventoryWebhookDelivery[]>;
|
|
44
|
+
createArticle(request: CreateArticleRequest): Promise<Article>;
|
|
45
|
+
updateArticle(request: UpdateArticleRequest): Promise<Article>;
|
|
46
|
+
deactivateArticle(request: DeactivateArticleRequest): Promise<Article>;
|
|
47
|
+
receiveGoods(request: ReceiveGoodsRequest): Promise<StockOperation>;
|
|
48
|
+
/** `receiveGoods` mit `dryRun: true`: rechnet, schreibt nichts, Schluessel freigestellt. */
|
|
49
|
+
previewGoodsReceipt(request: GoodsReceiptPreviewRequest): Promise<GoodsReceiptPreview>;
|
|
50
|
+
transferStock(request: TransferStockRequest): Promise<StockOperation>;
|
|
51
|
+
recordStockLoss(request: RecordStockLossRequest): Promise<StockOperation>;
|
|
52
|
+
changeStockCondition(request: ChangeStockConditionRequest): Promise<StockOperation>;
|
|
53
|
+
reverseStockMovement(request: ReverseStockMovementRequest): Promise<StockOperation>;
|
|
54
|
+
createReservation(request: CreateReservationRequest): Promise<Reservation>;
|
|
55
|
+
extendReservation(request: ExtendReservationRequest): Promise<Reservation>;
|
|
56
|
+
releaseReservation(request: ReleaseReservationRequest): Promise<Reservation>;
|
|
57
|
+
getReservation(reservationId: string): Promise<Reservation>;
|
|
58
|
+
listReservations(query?: ReservationListQuery): Promise<ReservationPage>;
|
|
59
|
+
iterateReservations(query?: ReservationListQuery): AsyncGenerator<Reservation, void, undefined>;
|
|
60
|
+
}
|
|
61
|
+
export declare function createInventoryClient(options: InventoryClientOptions): InventoryClient;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Fassade ueber den Aufrufen der Lager-API (lesen, Webhooks, schreiben,
|
|
4
|
+
* reservieren): Schluessel einmal binden, dann rufen. Wie [createInvoiceApi] bewusst keine Klasse; die Aufrufe sind freie
|
|
5
|
+
* Funktionen (endpunkte.ts) und bleiben einzeln importierbar.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.createInventoryClient = createInventoryClient;
|
|
9
|
+
const transport_js_1 = require("../client/transport.js");
|
|
10
|
+
const auth_js_1 = require("./auth.js");
|
|
11
|
+
const endpunkte_js_1 = require("./endpunkte.js");
|
|
12
|
+
const schreiben_js_1 = require("./schreiben.js");
|
|
13
|
+
function createInventoryClient(options) {
|
|
14
|
+
const rufen = (0, transport_js_1.createTransport)({
|
|
15
|
+
auth: (0, auth_js_1.inventoryKeyAuth)({ apiKey: options.apiKey }),
|
|
16
|
+
baseUrl: options.baseUrl,
|
|
17
|
+
timeoutMs: options.timeoutMs,
|
|
18
|
+
fetch: options.fetch,
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
getArticle: (id) => (0, endpunkte_js_1.getArticle)(rufen, id),
|
|
22
|
+
listArticles: (q) => (0, endpunkte_js_1.listArticles)(rufen, q),
|
|
23
|
+
iterateArticles: (q) => (0, endpunkte_js_1.iterateArticles)(rufen, q),
|
|
24
|
+
lookupArticleByCode: (l) => (0, endpunkte_js_1.lookupArticleByCode)(rufen, l),
|
|
25
|
+
listLocations: () => (0, endpunkte_js_1.listLocations)(rufen),
|
|
26
|
+
getStock: (id) => (0, endpunkte_js_1.getStock)(rufen, id),
|
|
27
|
+
listStock: (q) => (0, endpunkte_js_1.listStock)(rufen, q),
|
|
28
|
+
iterateStock: (q) => (0, endpunkte_js_1.iterateStock)(rufen, q),
|
|
29
|
+
listStockMovements: (q) => (0, endpunkte_js_1.listStockMovements)(rufen, q),
|
|
30
|
+
iterateStockMovements: (q) => (0, endpunkte_js_1.iterateStockMovements)(rufen, q),
|
|
31
|
+
createWebhook: (o) => (0, endpunkte_js_1.createWebhook)(rufen, o),
|
|
32
|
+
updateWebhook: (id, patch) => (0, endpunkte_js_1.updateWebhook)(rufen, id, patch),
|
|
33
|
+
deleteWebhook: (id) => (0, endpunkte_js_1.deleteWebhook)(rufen, id),
|
|
34
|
+
listWebhooks: () => (0, endpunkte_js_1.listWebhooks)(rufen),
|
|
35
|
+
sendWebhookTest: (id, event) => (0, endpunkte_js_1.sendWebhookTest)(rufen, id, event),
|
|
36
|
+
rotateWebhookSecret: (id) => (0, endpunkte_js_1.rotateWebhookSecret)(rufen, id),
|
|
37
|
+
listWebhookDeliveries: (o) => (0, endpunkte_js_1.listWebhookDeliveries)(rufen, o),
|
|
38
|
+
createArticle: (r) => (0, schreiben_js_1.createArticle)(rufen, r),
|
|
39
|
+
updateArticle: (r) => (0, schreiben_js_1.updateArticle)(rufen, r),
|
|
40
|
+
deactivateArticle: (r) => (0, schreiben_js_1.deactivateArticle)(rufen, r),
|
|
41
|
+
receiveGoods: (r) => (0, schreiben_js_1.receiveGoods)(rufen, r),
|
|
42
|
+
previewGoodsReceipt: (r) => (0, schreiben_js_1.previewGoodsReceipt)(rufen, r),
|
|
43
|
+
transferStock: (r) => (0, schreiben_js_1.transferStock)(rufen, r),
|
|
44
|
+
recordStockLoss: (r) => (0, schreiben_js_1.recordStockLoss)(rufen, r),
|
|
45
|
+
changeStockCondition: (r) => (0, schreiben_js_1.changeStockCondition)(rufen, r),
|
|
46
|
+
reverseStockMovement: (r) => (0, schreiben_js_1.reverseStockMovement)(rufen, r),
|
|
47
|
+
createReservation: (r) => (0, schreiben_js_1.createReservation)(rufen, r),
|
|
48
|
+
extendReservation: (r) => (0, schreiben_js_1.extendReservation)(rufen, r),
|
|
49
|
+
releaseReservation: (r) => (0, schreiben_js_1.releaseReservation)(rufen, r),
|
|
50
|
+
getReservation: (id) => (0, schreiben_js_1.getReservation)(rufen, id),
|
|
51
|
+
listReservations: (q) => (0, schreiben_js_1.listReservations)(rufen, q),
|
|
52
|
+
iterateReservations: (q) => (0, schreiben_js_1.iterateReservations)(rufen, q),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anmeldung fuer die Lager-API: der `api_key` des Kontos als Bearer, ohne
|
|
3
|
+
* `cashregister-token` (gelesen wird am Konto, nicht an einer Kasse).
|
|
4
|
+
*
|
|
5
|
+
* **Der Schluessel gehoert auf einen Server**, etwa in das Backend eines
|
|
6
|
+
* Online-Shops, nie in ein Browser-Buendel.
|
|
7
|
+
*
|
|
8
|
+
* Geprueft wird nur, was ohne Netz sicher falsch ist: ein leerer Wert, ein
|
|
9
|
+
* Partner-Schluessel (`pk_…`) oder ein Kassen-Token (`cb_…`). Die Meldung
|
|
10
|
+
* nennt nie den Wert, nur seine Art.
|
|
11
|
+
*/
|
|
12
|
+
import type { KasseneckAuth } from '../client/auth.js';
|
|
13
|
+
export interface InventoryKeyAuthOptions {
|
|
14
|
+
/** `api_key` des Kontos, z. B. `kr_live_…` oder `kr_test_…`. */
|
|
15
|
+
apiKey: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function inventoryKeyAuth(options: InventoryKeyAuthOptions): KasseneckAuth;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Anmeldung fuer die Lager-API: der `api_key` des Kontos als Bearer, ohne
|
|
4
|
+
* `cashregister-token` (gelesen wird am Konto, nicht an einer Kasse).
|
|
5
|
+
*
|
|
6
|
+
* **Der Schluessel gehoert auf einen Server**, etwa in das Backend eines
|
|
7
|
+
* Online-Shops, nie in ein Browser-Buendel.
|
|
8
|
+
*
|
|
9
|
+
* Geprueft wird nur, was ohne Netz sicher falsch ist: ein leerer Wert, ein
|
|
10
|
+
* Partner-Schluessel (`pk_…`) oder ein Kassen-Token (`cb_…`). Die Meldung
|
|
11
|
+
* nennt nie den Wert, nur seine Art.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.inventoryKeyAuth = inventoryKeyAuth;
|
|
15
|
+
const errors_js_1 = require("../client/errors.js");
|
|
16
|
+
function inventoryKeyAuth(options) {
|
|
17
|
+
const schluessel = typeof options?.apiKey === 'string' ? options.apiKey.trim() : '';
|
|
18
|
+
if (!schluessel)
|
|
19
|
+
throw new errors_js_1.KasseneckAuthError('inventoryKeyAuth: apiKey fehlt');
|
|
20
|
+
if (/^pk_(live|test)_/i.test(schluessel)) {
|
|
21
|
+
throw new errors_js_1.KasseneckAuthError('inventoryKeyAuth: das ist ein Partner-Schluessel (pk_…); die Lager-API nimmt den api_key des Kontos (kr_…)');
|
|
22
|
+
}
|
|
23
|
+
if (/^cb_(live|test)_/i.test(schluessel)) {
|
|
24
|
+
throw new errors_js_1.KasseneckAuthError('inventoryKeyAuth: das ist ein Kassen-Token (cb_…); die Lager-API nimmt den api_key des Kontos (kr_…)');
|
|
25
|
+
}
|
|
26
|
+
return () => ({ headers: { Authorization: `Bearer ${schluessel}` }, params: {} });
|
|
27
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Die Aufrufe der Lager-API: Artikel, Standorte, Bestand und Bewegungen
|
|
3
|
+
* lesen, Konto-Webhooks verwalten (Backend Stufe 5a). Die schreibenden
|
|
4
|
+
* Aufrufe (Stufe 5b) stehen in `schreiben.ts` und teilen die Helfer hier.
|
|
5
|
+
*
|
|
6
|
+
* Jede Funktion nimmt den Transport als ersten Parameter und ist einzeln
|
|
7
|
+
* importierbar; die Fassade [createInventoryClient] bindet ihn nur einmal.
|
|
8
|
+
*
|
|
9
|
+
* **Geprueft wird hier nur, was ohne Netz sicher falsch ist** (leere Kennung,
|
|
10
|
+
* `limit` ausserhalb 1–200, eine Aenderung ohne Feld). Alles Fachliche prueft
|
|
11
|
+
* der Server und meldet es als `validation` mit `errors[]`; zwei Pruefungen
|
|
12
|
+
* hiessen zwei Wahrheiten.
|
|
13
|
+
*
|
|
14
|
+
* Lesen hat keine Wirkung: nach einem Zeitlimit darf derselbe Aufruf
|
|
15
|
+
* wiederholt werden. Bei `rate_limited` vorher `retryAfterSec` warten
|
|
16
|
+
* ([inventoryRetryAfterSec]).
|
|
17
|
+
*/
|
|
18
|
+
import type { ApiCall, InternerTransport } from '../client/aufrufe.js';
|
|
19
|
+
import { KasseneckValidationError } from '../client/errors.js';
|
|
20
|
+
import type { Article, ArticleListQuery, ArticleLookup, ArticlePage, CreateInventoryWebhookOptions, InventoryWebhook, InventoryWebhookDelivery, InventoryWebhookList, InventoryWebhookPatch, InventoryWebhookTestResult, InventoryWebhookWithSecret, Location, StockLevel, StockListQuery, StockMovement, StockMovementPage, StockMovementQuery, StockPage, StockResult } from './typen.js';
|
|
21
|
+
type Params = Record<string, unknown>;
|
|
22
|
+
export declare function anfragefehler(name: ApiCall, grund: string): KasseneckValidationError;
|
|
23
|
+
/** Eine Kennung, die gesendet werden muss: Text mit mindestens einem Zeichen ausser Leerraum. */
|
|
24
|
+
export declare function kennung(name: ApiCall, feld: string, wert: unknown): string;
|
|
25
|
+
/**
|
|
26
|
+
* Die Abfrage einer Liste als Parameter. Unbekannte Felder gehen unveraendert
|
|
27
|
+
* hinaus (der Server weist sie mit `validation` ab), `undefined` faellt weg.
|
|
28
|
+
*/
|
|
29
|
+
export declare function abfrage(name: ApiCall, query: object | undefined): Params;
|
|
30
|
+
/**
|
|
31
|
+
* Blaettert ueber alle Seiten, Eintrag fuer Eintrag. Derselbe Cursor zweimal
|
|
32
|
+
* waere eine Endlosschleife: dann endet die Schleife mit einem Antwortfehler.
|
|
33
|
+
*/
|
|
34
|
+
export declare function seitenweise<T>(name: ApiCall, start: string | undefined, seite: (cursor: string | undefined) => Promise<{
|
|
35
|
+
eintraege: T[];
|
|
36
|
+
nextCursor: string | null;
|
|
37
|
+
}>): AsyncGenerator<T, void, undefined>;
|
|
38
|
+
export declare function getArticle(transport: InternerTransport, articleId: string): Promise<Article>;
|
|
39
|
+
export declare function listArticles(transport: InternerTransport, query?: ArticleListQuery): Promise<ArticlePage>;
|
|
40
|
+
/** Alle Artikel der Abfrage, Seite fuer Seite ueber `nextCursor`. */
|
|
41
|
+
export declare function iterateArticles(transport: InternerTransport, query?: ArticleListQuery): AsyncGenerator<Article, void, undefined>;
|
|
42
|
+
/**
|
|
43
|
+
* Ein aktiver Artikel per Code (`number`, `ean` oder `internalCode`) oder per
|
|
44
|
+
* eigener Kennung aus `externalIds` (`{ externalSystem: 'shop', externalId: '4711' }`).
|
|
45
|
+
* Ein stillgelegter Artikel gilt als nicht gefunden (`article_not_found`).
|
|
46
|
+
*/
|
|
47
|
+
export declare function lookupArticleByCode(transport: InternerTransport, lookup: ArticleLookup): Promise<Article>;
|
|
48
|
+
/** Alle Standorte des Kontos, samt aufgeloesten (`active: false`) und dem Hauptstandort. */
|
|
49
|
+
export declare function listLocations(transport: InternerTransport): Promise<Location[]>;
|
|
50
|
+
/** Bestand eines Artikels je Standort. */
|
|
51
|
+
export declare function getStock(transport: InternerTransport, articleId: string): Promise<StockResult>;
|
|
52
|
+
export declare function listStock(transport: InternerTransport, query?: StockListQuery): Promise<StockPage>;
|
|
53
|
+
/**
|
|
54
|
+
* Alle Bestandszeilen der Abfrage, Seite fuer Seite. Die Werte (`values`)
|
|
55
|
+
* stehen je Seite in [listStock]; der Iterator liefert nur die Zeilen.
|
|
56
|
+
*/
|
|
57
|
+
export declare function iterateStock(transport: InternerTransport, query?: StockListQuery): AsyncGenerator<StockLevel, void, undefined>;
|
|
58
|
+
/** Das Lagerprotokoll, neueste zuerst. */
|
|
59
|
+
export declare function listStockMovements(transport: InternerTransport, query?: StockMovementQuery): Promise<StockMovementPage>;
|
|
60
|
+
export declare function iterateStockMovements(transport: InternerTransport, query?: StockMovementQuery): AsyncGenerator<StockMovement, void, undefined>;
|
|
61
|
+
/**
|
|
62
|
+
* Legt einen Webhook an (hoechstens 5 je Konto, `webhook_limit`).
|
|
63
|
+
* **Das Secret in der Antwort kommt nur dieses eine Mal**; sofort dorthin
|
|
64
|
+
* schreiben, wo der Empfaenger es liest, nicht in ein Protokoll.
|
|
65
|
+
*/
|
|
66
|
+
export declare function createWebhook(transport: InternerTransport, options: CreateInventoryWebhookOptions): Promise<InventoryWebhookWithSecret>;
|
|
67
|
+
/** Aendert nur die genannten Felder; `description: null` loescht die Beschreibung. */
|
|
68
|
+
export declare function updateWebhook(transport: InternerTransport, webhookId: string, patch: InventoryWebhookPatch): Promise<InventoryWebhook>;
|
|
69
|
+
export declare function deleteWebhook(transport: InternerTransport, webhookId: string): Promise<{
|
|
70
|
+
webhookId: string;
|
|
71
|
+
deleted: boolean;
|
|
72
|
+
}>;
|
|
73
|
+
/** Die Webhooks des Kontos und die Ereignisse, die es abonnieren kann. */
|
|
74
|
+
export declare function listWebhooks(transport: InternerTransport): Promise<InventoryWebhookList>;
|
|
75
|
+
/**
|
|
76
|
+
* Ein neues Secret fuer denselben Webhook. Ab der Antwort gilt nur noch das
|
|
77
|
+
* neue (keine Uebergangsfrist): erst speichern, dann weiterarbeiten.
|
|
78
|
+
*/
|
|
79
|
+
export declare function rotateWebhookSecret(transport: InternerTransport, webhookId: string): Promise<InventoryWebhookWithSecret>;
|
|
80
|
+
/**
|
|
81
|
+
* Eine Probe genau dieses Ereignisses an genau diesen Webhook, mit erfundener
|
|
82
|
+
* Nutzlast und `test: true` in der Huelle. Der Webhook muss das Ereignis
|
|
83
|
+
* abonnieren (`event_not_subscribed`) und aktiv sein (`webhook_inactive`).
|
|
84
|
+
*/
|
|
85
|
+
export declare function sendWebhookTest(transport: InternerTransport, webhookId: string, event: string): Promise<InventoryWebhookTestResult>;
|
|
86
|
+
/** Die letzten Zustellungen, neueste zuerst; mit `webhookId` nur die eines Webhooks. */
|
|
87
|
+
export declare function listWebhookDeliveries(transport: InternerTransport, options?: {
|
|
88
|
+
webhookId?: string;
|
|
89
|
+
limit?: number;
|
|
90
|
+
}): Promise<InventoryWebhookDelivery[]>;
|
|
91
|
+
export {};
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Die Aufrufe der Lager-API: Artikel, Standorte, Bestand und Bewegungen
|
|
4
|
+
* lesen, Konto-Webhooks verwalten (Backend Stufe 5a). Die schreibenden
|
|
5
|
+
* Aufrufe (Stufe 5b) stehen in `schreiben.ts` und teilen die Helfer hier.
|
|
6
|
+
*
|
|
7
|
+
* Jede Funktion nimmt den Transport als ersten Parameter und ist einzeln
|
|
8
|
+
* importierbar; die Fassade [createInventoryClient] bindet ihn nur einmal.
|
|
9
|
+
*
|
|
10
|
+
* **Geprueft wird hier nur, was ohne Netz sicher falsch ist** (leere Kennung,
|
|
11
|
+
* `limit` ausserhalb 1–200, eine Aenderung ohne Feld). Alles Fachliche prueft
|
|
12
|
+
* der Server und meldet es als `validation` mit `errors[]`; zwei Pruefungen
|
|
13
|
+
* hiessen zwei Wahrheiten.
|
|
14
|
+
*
|
|
15
|
+
* Lesen hat keine Wirkung: nach einem Zeitlimit darf derselbe Aufruf
|
|
16
|
+
* wiederholt werden. Bei `rate_limited` vorher `retryAfterSec` warten
|
|
17
|
+
* ([inventoryRetryAfterSec]).
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.anfragefehler = anfragefehler;
|
|
21
|
+
exports.kennung = kennung;
|
|
22
|
+
exports.abfrage = abfrage;
|
|
23
|
+
exports.seitenweise = seitenweise;
|
|
24
|
+
exports.getArticle = getArticle;
|
|
25
|
+
exports.listArticles = listArticles;
|
|
26
|
+
exports.iterateArticles = iterateArticles;
|
|
27
|
+
exports.lookupArticleByCode = lookupArticleByCode;
|
|
28
|
+
exports.listLocations = listLocations;
|
|
29
|
+
exports.getStock = getStock;
|
|
30
|
+
exports.listStock = listStock;
|
|
31
|
+
exports.iterateStock = iterateStock;
|
|
32
|
+
exports.listStockMovements = listStockMovements;
|
|
33
|
+
exports.iterateStockMovements = iterateStockMovements;
|
|
34
|
+
exports.createWebhook = createWebhook;
|
|
35
|
+
exports.updateWebhook = updateWebhook;
|
|
36
|
+
exports.deleteWebhook = deleteWebhook;
|
|
37
|
+
exports.listWebhooks = listWebhooks;
|
|
38
|
+
exports.rotateWebhookSecret = rotateWebhookSecret;
|
|
39
|
+
exports.sendWebhookTest = sendWebhookTest;
|
|
40
|
+
exports.listWebhookDeliveries = listWebhookDeliveries;
|
|
41
|
+
const errors_js_1 = require("../client/errors.js");
|
|
42
|
+
const lesen_js_1 = require("./lesen.js");
|
|
43
|
+
const vertrag_js_1 = require("./vertrag.js");
|
|
44
|
+
function anfragefehler(name, grund) {
|
|
45
|
+
return new errors_js_1.KasseneckValidationError(name, grund, 'request');
|
|
46
|
+
}
|
|
47
|
+
/** Eine Kennung, die gesendet werden muss: Text mit mindestens einem Zeichen ausser Leerraum. */
|
|
48
|
+
function kennung(name, feld, wert) {
|
|
49
|
+
if (typeof wert !== 'string' || wert.trim() === '')
|
|
50
|
+
throw anfragefehler(name, `${feld} fehlt`);
|
|
51
|
+
return wert;
|
|
52
|
+
}
|
|
53
|
+
/** Felder, die einen Zeitpunkt tragen: ein `Date` geht als ISO 8601 UTC hinaus. */
|
|
54
|
+
const ZEITFELDER = new Set(['updatedSince', 'changedSince', 'from', 'to']);
|
|
55
|
+
/**
|
|
56
|
+
* Die Abfrage einer Liste als Parameter. Unbekannte Felder gehen unveraendert
|
|
57
|
+
* hinaus (der Server weist sie mit `validation` ab), `undefined` faellt weg.
|
|
58
|
+
*/
|
|
59
|
+
function abfrage(name, query) {
|
|
60
|
+
if (query === undefined || query === null)
|
|
61
|
+
return {};
|
|
62
|
+
if (typeof query !== 'object' || Array.isArray(query))
|
|
63
|
+
throw anfragefehler(name, 'Abfrage muss ein Objekt sein');
|
|
64
|
+
const raus = {};
|
|
65
|
+
for (const [feld, w] of Object.entries(query)) {
|
|
66
|
+
if (w === undefined)
|
|
67
|
+
continue;
|
|
68
|
+
if (ZEITFELDER.has(feld) && w instanceof Date) {
|
|
69
|
+
if (Number.isNaN(w.getTime()))
|
|
70
|
+
throw anfragefehler(name, `${feld} ist kein gueltiger Zeitpunkt`);
|
|
71
|
+
raus[feld] = w.toISOString();
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
raus[feld] = w;
|
|
75
|
+
}
|
|
76
|
+
if (raus.limit !== undefined) {
|
|
77
|
+
const limit = raus.limit;
|
|
78
|
+
if (typeof limit !== 'number' || !Number.isInteger(limit) || limit < 1 || limit > vertrag_js_1.INVENTORY_LIST_LIMIT_MAX) {
|
|
79
|
+
throw anfragefehler(name, `limit muss eine ganze Zahl von 1 bis ${vertrag_js_1.INVENTORY_LIST_LIMIT_MAX} sein`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (raus.cursor !== undefined)
|
|
83
|
+
kennung(name, 'cursor', raus.cursor);
|
|
84
|
+
return raus;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Blaettert ueber alle Seiten, Eintrag fuer Eintrag. Derselbe Cursor zweimal
|
|
88
|
+
* waere eine Endlosschleife: dann endet die Schleife mit einem Antwortfehler.
|
|
89
|
+
*/
|
|
90
|
+
async function* seitenweise(name, start, seite) {
|
|
91
|
+
const gesehen = new Set();
|
|
92
|
+
// Auch der Startcursor zaehlt: nennt die erste Antwort ihn wieder, waere es dieselbe Seite.
|
|
93
|
+
if (start)
|
|
94
|
+
gesehen.add(start);
|
|
95
|
+
let cursor = start;
|
|
96
|
+
for (;;) {
|
|
97
|
+
const { eintraege, nextCursor } = await seite(cursor);
|
|
98
|
+
yield* eintraege;
|
|
99
|
+
if (nextCursor === null)
|
|
100
|
+
return;
|
|
101
|
+
if (gesehen.has(nextCursor))
|
|
102
|
+
throw (0, lesen_js_1.antwortfehler)(name, 'Antwort nennt denselben nextCursor zweimal');
|
|
103
|
+
gesehen.add(nextCursor);
|
|
104
|
+
cursor = nextCursor;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// ---- Artikel ------------------------------------------------------------------
|
|
108
|
+
async function getArticle(transport, articleId) {
|
|
109
|
+
const name = 'getArticle';
|
|
110
|
+
const daten = await transport(name, { articleId: kennung(name, 'articleId', articleId) });
|
|
111
|
+
return (0, lesen_js_1.artikel)({ name, pfad: 'article' }, (0, lesen_js_1.objekt)(daten)?.article);
|
|
112
|
+
}
|
|
113
|
+
async function listArticles(transport, query) {
|
|
114
|
+
const name = 'listArticles';
|
|
115
|
+
const daten = await transport(name, abfrage(name, query));
|
|
116
|
+
return { articles: (0, lesen_js_1.liste)(name, daten, 'articles', lesen_js_1.artikel), nextCursor: (0, lesen_js_1.naechsterCursor)(name, daten) };
|
|
117
|
+
}
|
|
118
|
+
/** Alle Artikel der Abfrage, Seite fuer Seite ueber `nextCursor`. */
|
|
119
|
+
function iterateArticles(transport, query) {
|
|
120
|
+
const { cursor, ...rest } = query ?? {};
|
|
121
|
+
return seitenweise('listArticles', cursor, async (c) => {
|
|
122
|
+
const s = await listArticles(transport, { ...rest, cursor: c });
|
|
123
|
+
return { eintraege: s.articles, nextCursor: s.nextCursor };
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Ein aktiver Artikel per Code (`number`, `ean` oder `internalCode`) oder per
|
|
128
|
+
* eigener Kennung aus `externalIds` (`{ externalSystem: 'shop', externalId: '4711' }`).
|
|
129
|
+
* Ein stillgelegter Artikel gilt als nicht gefunden (`article_not_found`).
|
|
130
|
+
*/
|
|
131
|
+
async function lookupArticleByCode(transport, lookup) {
|
|
132
|
+
const name = 'lookupArticleByCode';
|
|
133
|
+
let params;
|
|
134
|
+
if (typeof lookup === 'string') {
|
|
135
|
+
params = { code: kennung(name, 'code', lookup) };
|
|
136
|
+
}
|
|
137
|
+
else if (lookup !== null && typeof lookup === 'object' && !Array.isArray(lookup)) {
|
|
138
|
+
const l = lookup;
|
|
139
|
+
const extern = l.externalSystem !== undefined || l.externalId !== undefined;
|
|
140
|
+
if (l.code !== undefined && extern)
|
|
141
|
+
throw anfragefehler(name, 'entweder code oder externalSystem mit externalId');
|
|
142
|
+
params = extern
|
|
143
|
+
? { externalSystem: kennung(name, 'externalSystem', l.externalSystem), externalId: kennung(name, 'externalId', l.externalId) }
|
|
144
|
+
: { code: kennung(name, 'code', l.code) };
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
throw anfragefehler(name, 'Code als Text oder { code } bzw. { externalSystem, externalId } erwartet');
|
|
148
|
+
}
|
|
149
|
+
const daten = await transport(name, params);
|
|
150
|
+
return (0, lesen_js_1.artikel)({ name, pfad: 'article' }, (0, lesen_js_1.objekt)(daten)?.article);
|
|
151
|
+
}
|
|
152
|
+
// ---- Standorte und Bestand -----------------------------------------------------------
|
|
153
|
+
/** Alle Standorte des Kontos, samt aufgeloesten (`active: false`) und dem Hauptstandort. */
|
|
154
|
+
async function listLocations(transport) {
|
|
155
|
+
const name = 'listLocations';
|
|
156
|
+
return (0, lesen_js_1.liste)(name, await transport(name, {}), 'locations', lesen_js_1.standort);
|
|
157
|
+
}
|
|
158
|
+
/** Die Werte (`values`): fehlt das Feld, fehlt das Recht `costs` -> `null`, nie `[]`. */
|
|
159
|
+
function werte(name, daten) {
|
|
160
|
+
const roh = (0, lesen_js_1.objekt)(daten)?.values;
|
|
161
|
+
if (roh === undefined || roh === null)
|
|
162
|
+
return null;
|
|
163
|
+
return (0, lesen_js_1.liste)(name, daten, 'values', lesen_js_1.wert);
|
|
164
|
+
}
|
|
165
|
+
/** Bestand eines Artikels je Standort. */
|
|
166
|
+
async function getStock(transport, articleId) {
|
|
167
|
+
const name = 'getStock';
|
|
168
|
+
const daten = await transport(name, { articleId: kennung(name, 'articleId', articleId) });
|
|
169
|
+
return { stock: (0, lesen_js_1.liste)(name, daten, 'stock', lesen_js_1.bestand), values: werte(name, daten) };
|
|
170
|
+
}
|
|
171
|
+
async function listStock(transport, query) {
|
|
172
|
+
const name = 'listStock';
|
|
173
|
+
const daten = await transport(name, abfrage(name, query));
|
|
174
|
+
return { stock: (0, lesen_js_1.liste)(name, daten, 'stock', lesen_js_1.bestand), values: werte(name, daten), nextCursor: (0, lesen_js_1.naechsterCursor)(name, daten) };
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Alle Bestandszeilen der Abfrage, Seite fuer Seite. Die Werte (`values`)
|
|
178
|
+
* stehen je Seite in [listStock]; der Iterator liefert nur die Zeilen.
|
|
179
|
+
*/
|
|
180
|
+
function iterateStock(transport, query) {
|
|
181
|
+
const { cursor, ...rest } = query ?? {};
|
|
182
|
+
return seitenweise('listStock', cursor, async (c) => {
|
|
183
|
+
const s = await listStock(transport, { ...rest, cursor: c });
|
|
184
|
+
return { eintraege: s.stock, nextCursor: s.nextCursor };
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/** Das Lagerprotokoll, neueste zuerst. */
|
|
188
|
+
async function listStockMovements(transport, query) {
|
|
189
|
+
const name = 'listStockMovements';
|
|
190
|
+
const daten = await transport(name, abfrage(name, query));
|
|
191
|
+
return { movements: (0, lesen_js_1.liste)(name, daten, 'movements', lesen_js_1.bewegung), nextCursor: (0, lesen_js_1.naechsterCursor)(name, daten) };
|
|
192
|
+
}
|
|
193
|
+
function iterateStockMovements(transport, query) {
|
|
194
|
+
const { cursor, ...rest } = query ?? {};
|
|
195
|
+
return seitenweise('listStockMovements', cursor, async (c) => {
|
|
196
|
+
const s = await listStockMovements(transport, { ...rest, cursor: c });
|
|
197
|
+
return { eintraege: s.movements, nextCursor: s.nextCursor };
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
// ---- Webhooks ------------------------------------------------------------------
|
|
201
|
+
function mitSecret(name, daten) {
|
|
202
|
+
const o = (0, lesen_js_1.objekt)(daten);
|
|
203
|
+
const secret = o?.secret;
|
|
204
|
+
if (typeof secret !== 'string' || secret === '') {
|
|
205
|
+
throw (0, lesen_js_1.antwortfehler)(name, 'Antwort enthaelt kein secret; ohne es laesst sich keine Zustellung pruefen');
|
|
206
|
+
}
|
|
207
|
+
return { webhook: (0, lesen_js_1.webhook)({ name, pfad: 'webhook' }, o?.webhook), secret };
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Legt einen Webhook an (hoechstens 5 je Konto, `webhook_limit`).
|
|
211
|
+
* **Das Secret in der Antwort kommt nur dieses eine Mal**; sofort dorthin
|
|
212
|
+
* schreiben, wo der Empfaenger es liest, nicht in ein Protokoll.
|
|
213
|
+
*/
|
|
214
|
+
async function createWebhook(transport, options) {
|
|
215
|
+
const name = 'createWebhook';
|
|
216
|
+
const url = kennung(name, 'url', options?.url);
|
|
217
|
+
if (!Array.isArray(options.events) || options.events.length === 0) {
|
|
218
|
+
throw anfragefehler(name, 'events ist leer; ein Webhook ohne Ereignis bekaeme nie etwas');
|
|
219
|
+
}
|
|
220
|
+
const params = { url, events: options.events };
|
|
221
|
+
if (options.description !== undefined)
|
|
222
|
+
params.description = options.description;
|
|
223
|
+
return mitSecret(name, await transport(name, params));
|
|
224
|
+
}
|
|
225
|
+
/** Aendert nur die genannten Felder; `description: null` loescht die Beschreibung. */
|
|
226
|
+
async function updateWebhook(transport, webhookId, patch) {
|
|
227
|
+
const name = 'updateWebhook';
|
|
228
|
+
const id = kennung(name, 'webhookId', webhookId);
|
|
229
|
+
if (patch === null || typeof patch !== 'object' || Array.isArray(patch))
|
|
230
|
+
throw anfragefehler(name, 'patch muss ein Objekt sein');
|
|
231
|
+
const params = { webhookId: id };
|
|
232
|
+
for (const [feld, w] of Object.entries(patch))
|
|
233
|
+
if (w !== undefined)
|
|
234
|
+
params[feld] = w;
|
|
235
|
+
if (Object.keys(params).length === 1)
|
|
236
|
+
throw anfragefehler(name, 'patch nennt keine Aenderung');
|
|
237
|
+
const daten = await transport(name, params);
|
|
238
|
+
return (0, lesen_js_1.webhook)({ name, pfad: 'webhook' }, (0, lesen_js_1.objekt)(daten)?.webhook);
|
|
239
|
+
}
|
|
240
|
+
async function deleteWebhook(transport, webhookId) {
|
|
241
|
+
const name = 'deleteWebhook';
|
|
242
|
+
const id = kennung(name, 'webhookId', webhookId);
|
|
243
|
+
const o = (0, lesen_js_1.objekt)(await transport(name, { webhookId: id }));
|
|
244
|
+
return { webhookId: typeof o?.webhookId === 'string' && o.webhookId ? o.webhookId : id, deleted: o?.deleted === true };
|
|
245
|
+
}
|
|
246
|
+
/** Die Webhooks des Kontos und die Ereignisse, die es abonnieren kann. */
|
|
247
|
+
async function listWebhooks(transport) {
|
|
248
|
+
const name = 'listWebhooks';
|
|
249
|
+
const daten = await transport(name, {});
|
|
250
|
+
const ereignisse = (0, lesen_js_1.objekt)(daten)?.events;
|
|
251
|
+
return {
|
|
252
|
+
webhooks: (0, lesen_js_1.liste)(name, daten, 'webhooks', lesen_js_1.webhook),
|
|
253
|
+
events: Array.isArray(ereignisse) ? ereignisse.filter((e) => typeof e === 'string') : [],
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Ein neues Secret fuer denselben Webhook. Ab der Antwort gilt nur noch das
|
|
258
|
+
* neue (keine Uebergangsfrist): erst speichern, dann weiterarbeiten.
|
|
259
|
+
*/
|
|
260
|
+
async function rotateWebhookSecret(transport, webhookId) {
|
|
261
|
+
const name = 'rotateWebhookSecret';
|
|
262
|
+
return mitSecret(name, await transport(name, { webhookId: kennung(name, 'webhookId', webhookId) }));
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Eine Probe genau dieses Ereignisses an genau diesen Webhook, mit erfundener
|
|
266
|
+
* Nutzlast und `test: true` in der Huelle. Der Webhook muss das Ereignis
|
|
267
|
+
* abonnieren (`event_not_subscribed`) und aktiv sein (`webhook_inactive`).
|
|
268
|
+
*/
|
|
269
|
+
async function sendWebhookTest(transport, webhookId, event) {
|
|
270
|
+
const name = 'sendWebhookTest';
|
|
271
|
+
const id = kennung(name, 'webhookId', webhookId);
|
|
272
|
+
const ereignis = kennung(name, 'event', event);
|
|
273
|
+
const daten = await transport(name, { webhookId: id, event: ereignis });
|
|
274
|
+
const o = (0, lesen_js_1.objekt)(daten);
|
|
275
|
+
return {
|
|
276
|
+
eventId: typeof o?.eventId === 'string' ? o.eventId : '',
|
|
277
|
+
event: typeof o?.event === 'string' ? o.event : ereignis,
|
|
278
|
+
deliveries: (0, lesen_js_1.liste)(name, daten, 'deliveries', (ort, e) => (0, lesen_js_1.probeZustellung)(ort, e, id)),
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
/** Die letzten Zustellungen, neueste zuerst; mit `webhookId` nur die eines Webhooks. */
|
|
282
|
+
async function listWebhookDeliveries(transport, options = {}) {
|
|
283
|
+
const name = 'listWebhookDeliveries';
|
|
284
|
+
const params = {};
|
|
285
|
+
if (options.webhookId !== undefined)
|
|
286
|
+
params.webhookId = kennung(name, 'webhookId', options.webhookId);
|
|
287
|
+
if (options.limit !== undefined)
|
|
288
|
+
Object.assign(params, abfrage(name, { limit: options.limit }));
|
|
289
|
+
return (0, lesen_js_1.liste)(name, await transport(name, params), 'deliveries', lesen_js_1.zustellung);
|
|
290
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fehler der Lager-API auswerten: am Code, nie am Text.
|
|
3
|
+
*
|
|
4
|
+
* Es zaehlen die Codes der Lager-Endpunkte ([INVENTORY_ERROR_CODES]) und die,
|
|
5
|
+
* die Anmeldung und Rand auf jedem Aufruf erzeugen koennen
|
|
6
|
+
* ([INVENTORY_REQUEST_ERROR_CODES]). Ein fremder Code ist fuer diese Helfer
|
|
7
|
+
* kein Lager-Fehler: wer darauf verzweigt, tut es bewusst ueber
|
|
8
|
+
* `KasseneckApiError.code`.
|
|
9
|
+
*/
|
|
10
|
+
import type { KasseneckApiError } from '../client/errors.js';
|
|
11
|
+
import type { InventoryShortfall } from './typen.js';
|
|
12
|
+
import { type InventoryErrorCode, type InventoryRequestErrorCode, type InventoryWarningCode } from './vertrag.js';
|
|
13
|
+
/** Ein Code, den ein Lager-Aufruf liefern kann. */
|
|
14
|
+
export type InventoryApiErrorCode = InventoryErrorCode | InventoryRequestErrorCode;
|
|
15
|
+
export declare function isInventoryErrorCode(value: unknown): value is InventoryApiErrorCode;
|
|
16
|
+
/** Der Fehlercode eines geworfenen Fehlers; `undefined`, wenn es keiner der Lager-API ist. */
|
|
17
|
+
export declare function inventoryErrorCode(error: unknown): InventoryApiErrorCode | undefined;
|
|
18
|
+
/** Kurzform fuer `catch (e) { if (isInventoryError(e, 'article_not_found')) … }`. */
|
|
19
|
+
export declare function isInventoryError(error: unknown, code?: InventoryApiErrorCode): error is KasseneckApiError;
|
|
20
|
+
/** Ein Feldfehler aus `data.errors[]` einer `validation`-Antwort. */
|
|
21
|
+
export interface InventoryFieldError {
|
|
22
|
+
/** Feld der gesendeten Anfrage, z. B. `limit` oder `events`. */
|
|
23
|
+
field: string;
|
|
24
|
+
message: string;
|
|
25
|
+
}
|
|
26
|
+
/** Die Feldfehler einer `validation`-Antwort; leer, wenn es keine sind. */
|
|
27
|
+
export declare function inventoryFieldErrors(error: unknown): InventoryFieldError[];
|
|
28
|
+
/**
|
|
29
|
+
* Wie lange `rate_limited` noch gilt, in Sekunden (`data.retryAfterSec`,
|
|
30
|
+
* dasselbe wie die Kopfzeile `Retry-After`). `undefined`, wenn der Fehler kein
|
|
31
|
+
* `rate_limited` ist oder der Server keine Angabe macht. Die Grenze gilt je
|
|
32
|
+
* Konto (etwa 20 Anfragen je Sekunde, kurze Spitzen bis 40).
|
|
33
|
+
*/
|
|
34
|
+
export declare function inventoryRetryAfterSec(error: unknown): number | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Die Positionen, fuer die beim Reservieren der verfuegbare Bestand nicht
|
|
37
|
+
* reicht (`insufficient_available`, `data.details[]`): je Artikel und Standort
|
|
38
|
+
* angefragt und verfuegbar, in Tausendstel. Leer, wenn der Fehler ein anderer
|
|
39
|
+
* ist. Es fehlen nur diese Positionen; reserviert wurde nichts.
|
|
40
|
+
*/
|
|
41
|
+
export declare function inventoryShortfalls(error: unknown): InventoryShortfall[];
|
|
42
|
+
/** `true` fuer einen Hinweis-Code einer Buchung (`warnings[].code`); Hinweise sind nie Fehler. */
|
|
43
|
+
export declare function isInventoryWarningCode(value: unknown): value is InventoryWarningCode;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Fehler der Lager-API auswerten: am Code, nie am Text.
|
|
4
|
+
*
|
|
5
|
+
* Es zaehlen die Codes der Lager-Endpunkte ([INVENTORY_ERROR_CODES]) und die,
|
|
6
|
+
* die Anmeldung und Rand auf jedem Aufruf erzeugen koennen
|
|
7
|
+
* ([INVENTORY_REQUEST_ERROR_CODES]). Ein fremder Code ist fuer diese Helfer
|
|
8
|
+
* kein Lager-Fehler: wer darauf verzweigt, tut es bewusst ueber
|
|
9
|
+
* `KasseneckApiError.code`.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.isInventoryErrorCode = isInventoryErrorCode;
|
|
13
|
+
exports.inventoryErrorCode = inventoryErrorCode;
|
|
14
|
+
exports.isInventoryError = isInventoryError;
|
|
15
|
+
exports.inventoryFieldErrors = inventoryFieldErrors;
|
|
16
|
+
exports.inventoryRetryAfterSec = inventoryRetryAfterSec;
|
|
17
|
+
exports.inventoryShortfalls = inventoryShortfalls;
|
|
18
|
+
exports.isInventoryWarningCode = isInventoryWarningCode;
|
|
19
|
+
const fehlercodes_js_1 = require("../client/fehlercodes.js");
|
|
20
|
+
const lesen_js_1 = require("./lesen.js");
|
|
21
|
+
const vertrag_js_1 = require("./vertrag.js");
|
|
22
|
+
const BEKANNT = new Set([...vertrag_js_1.INVENTORY_ERROR_CODES, ...vertrag_js_1.INVENTORY_REQUEST_ERROR_CODES]);
|
|
23
|
+
function isInventoryErrorCode(value) {
|
|
24
|
+
return typeof value === 'string' && BEKANNT.has(value);
|
|
25
|
+
}
|
|
26
|
+
/** Der Fehlercode eines geworfenen Fehlers; `undefined`, wenn es keiner der Lager-API ist. */
|
|
27
|
+
function inventoryErrorCode(error) {
|
|
28
|
+
return (0, fehlercodes_js_1.bekannterCode)(error, BEKANNT);
|
|
29
|
+
}
|
|
30
|
+
/** Kurzform fuer `catch (e) { if (isInventoryError(e, 'article_not_found')) … }`. */
|
|
31
|
+
function isInventoryError(error, code) {
|
|
32
|
+
const gefunden = inventoryErrorCode(error);
|
|
33
|
+
return gefunden !== undefined && (code === undefined || gefunden === code);
|
|
34
|
+
}
|
|
35
|
+
/** Die Feldfehler einer `validation`-Antwort; leer, wenn es keine sind. */
|
|
36
|
+
function inventoryFieldErrors(error) {
|
|
37
|
+
return (0, fehlercodes_js_1.feldfehlerVon)(error);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Wie lange `rate_limited` noch gilt, in Sekunden (`data.retryAfterSec`,
|
|
41
|
+
* dasselbe wie die Kopfzeile `Retry-After`). `undefined`, wenn der Fehler kein
|
|
42
|
+
* `rate_limited` ist oder der Server keine Angabe macht. Die Grenze gilt je
|
|
43
|
+
* Konto (etwa 20 Anfragen je Sekunde, kurze Spitzen bis 40).
|
|
44
|
+
*/
|
|
45
|
+
function inventoryRetryAfterSec(error) {
|
|
46
|
+
if (inventoryErrorCode(error) !== 'rate_limited')
|
|
47
|
+
return undefined;
|
|
48
|
+
const wert = error.details['retryAfterSec'];
|
|
49
|
+
return typeof wert === 'number' && Number.isFinite(wert) && wert >= 0 ? wert : undefined;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Die Positionen, fuer die beim Reservieren der verfuegbare Bestand nicht
|
|
53
|
+
* reicht (`insufficient_available`, `data.details[]`): je Artikel und Standort
|
|
54
|
+
* angefragt und verfuegbar, in Tausendstel. Leer, wenn der Fehler ein anderer
|
|
55
|
+
* ist. Es fehlen nur diese Positionen; reserviert wurde nichts.
|
|
56
|
+
*/
|
|
57
|
+
function inventoryShortfalls(error) {
|
|
58
|
+
if (inventoryErrorCode(error) !== 'insufficient_available')
|
|
59
|
+
return [];
|
|
60
|
+
return (0, lesen_js_1.fehlmengen)(error.details['details']);
|
|
61
|
+
}
|
|
62
|
+
const HINWEISE = new Set(vertrag_js_1.INVENTORY_WARNING_CODES);
|
|
63
|
+
/** `true` fuer einen Hinweis-Code einer Buchung (`warnings[].code`); Hinweise sind nie Fehler. */
|
|
64
|
+
function isInventoryWarningCode(value) {
|
|
65
|
+
return typeof value === 'string' && HINWEISE.has(value);
|
|
66
|
+
}
|