@kreiseck/kasseneck-api 1.4.0 → 1.5.1
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 +166 -0
- package/README.md +255 -36
- package/dist/cjs/client/aufrufe.d.ts +58 -4
- package/dist/cjs/client/aufrufe.js +196 -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 +19 -3
- package/dist/cjs/inventory/api.js +18 -2
- package/dist/cjs/inventory/endpunkte.d.ts +22 -2
- package/dist/cjs/inventory/endpunkte.js +6 -1
- package/dist/cjs/inventory/fehler.d.ts +11 -1
- package/dist/cjs/inventory/fehler.js +19 -0
- package/dist/cjs/inventory/index.d.ts +6 -4
- package/dist/cjs/inventory/index.js +32 -2
- package/dist/cjs/inventory/lesen.d.ts +8 -1
- package/dist/cjs/inventory/lesen.js +131 -1
- package/dist/cjs/inventory/schreiben.d.ts +86 -0
- package/dist/cjs/inventory/schreiben.js +320 -0
- package/dist/cjs/inventory/typen.d.ts +371 -11
- package/dist/cjs/inventory/vertrag.d.ts +76 -16
- package/dist/cjs/inventory/vertrag.js +138 -13
- package/dist/cjs/inventory/webhook.d.ts +3 -1
- package/dist/cjs/inventory/webhook.js +7 -1
- package/dist/cjs/invoice/endpunkte.d.ts +6 -0
- package/dist/cjs/invoice/endpunkte.js +13 -2
- 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/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 +5 -3
- 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 +194 -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 +19 -3
- package/dist/esm/inventory/api.js +18 -2
- package/dist/esm/inventory/endpunkte.d.ts +22 -2
- package/dist/esm/inventory/endpunkte.js +6 -5
- package/dist/esm/inventory/fehler.d.ts +11 -1
- package/dist/esm/inventory/fehler.js +18 -1
- package/dist/esm/inventory/index.d.ts +6 -4
- package/dist/esm/inventory/index.js +5 -3
- package/dist/esm/inventory/lesen.d.ts +8 -1
- package/dist/esm/inventory/lesen.js +127 -1
- package/dist/esm/inventory/schreiben.d.ts +86 -0
- package/dist/esm/inventory/schreiben.js +303 -0
- package/dist/esm/inventory/typen.d.ts +371 -11
- package/dist/esm/inventory/vertrag.d.ts +76 -16
- package/dist/esm/inventory/vertrag.js +137 -12
- package/dist/esm/inventory/webhook.d.ts +3 -1
- package/dist/esm/inventory/webhook.js +8 -2
- package/dist/esm/invoice/endpunkte.d.ts +6 -0
- package/dist/esm/invoice/endpunkte.js +13 -2
- 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/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 +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 +206 -9
- 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 +2491 -130
- 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 +3 -3
- package/fixtures/v3/stored/rechnungen.json +174 -18
- package/fixtures/v3/v3-vokabular.json +593 -23
- package/fixtures/v3/zahlbetrag-faelle.json +2 -2
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isRegisterUserAuth } from './auth.js';
|
|
2
|
-
import { isPosCall, isPosOnlyCall } from './aufrufe.js';
|
|
2
|
+
import { isPosCall, isPosOnlyCall, isUnknownOutcomeCall } from './aufrufe.js';
|
|
3
3
|
import { PACKAGE_VERSION } from '../version.js';
|
|
4
4
|
import { KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, causeDigest, fehlerDetails, } from './errors.js';
|
|
5
5
|
/**
|
|
@@ -36,6 +36,12 @@ import { KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNet
|
|
|
36
36
|
* **Kein Wiederholen fehlgeschlagener Aufrufe.** Ein Beleg ist nicht folgenlos
|
|
37
37
|
* wiederholbar; ohne entschiedene Idempotenz waere ein automatischer zweiter
|
|
38
38
|
* Versuch ein zweiter Beleg.
|
|
39
|
+
*
|
|
40
|
+
* **Ausgang je Aufruf.** Ob ein Scheitern nach dem Senden `outcome: 'unknown'`
|
|
41
|
+
* traegt, haengt am Aufruf: mit Wirkung ([UNKNOWN_OUTCOME_CALLS] in
|
|
42
|
+
* aufrufe.ts) ja, Lesen und Probelauf nein. Ein Probelauf traegt denselben
|
|
43
|
+
* Namen wie der echte Aufruf; die Huelle sagt es darum beim Aufruf
|
|
44
|
+
* (`hasEffect: false`, [TransportCallOptions]).
|
|
39
45
|
*/
|
|
40
46
|
/** Basis-URL der oeffentlichen API (Produktion). */
|
|
41
47
|
export const DEFAULT_BASE_URL = 'https://api.kasseneck.at/v3';
|
|
@@ -56,23 +62,6 @@ const VERSION_WERT = 'v3';
|
|
|
56
62
|
const KASSENECK_HOSTS = new Set(['api.kasseneck.at', 'kasse.kasseneck.at']);
|
|
57
63
|
/** Die 1.x-Linie spricht nur `/v3`: jede Basis endet so (`/v3` oder `/api/v3`). */
|
|
58
64
|
const V3_ENDE = /\/v3$/;
|
|
59
|
-
/**
|
|
60
|
-
* Aufrufe mit Wirkung, die nie blind wiederholt werden duerfen: sie signieren
|
|
61
|
-
* (`createReceipt`, `cancelReceipt`), loesen bei FinanzOnline etwas aus
|
|
62
|
-
* (`financeWebService`) oder bewegen Geld (`hobexPayApi` belastet eine Karte,
|
|
63
|
-
* `hobexRefundApi` erstattet, `stripeCaptureIntent` zieht eine vorgemerkte
|
|
64
|
-
* Zahlung ein). Scheitert einer, nachdem die Anfrage unterwegs war (Netz,
|
|
65
|
-
* Zeitlimit, HTTP 5xx, unlesbare Erfolgsantwort, HTML mit Kennzeichen), ist
|
|
66
|
-
* sein Ausgang offen.
|
|
67
|
-
*/
|
|
68
|
-
const UNKNOWN_OUTCOME_CALLS = new Set([
|
|
69
|
-
'createReceipt',
|
|
70
|
-
'cancelReceipt',
|
|
71
|
-
'financeWebService',
|
|
72
|
-
'hobexPayApi',
|
|
73
|
-
'hobexRefundApi',
|
|
74
|
-
'stripeCaptureIntent',
|
|
75
|
-
]);
|
|
76
65
|
/**
|
|
77
66
|
* Produkte, die das Backend in `Kasseneck-Client` zaehlt (Positivliste,
|
|
78
67
|
* Nachtrag §6); alles andere zaehlte dort als `ungueltig`. Das Paket weist
|
|
@@ -89,7 +78,7 @@ const CLIENT_MAX = 64;
|
|
|
89
78
|
export const DEFAULT_TIMEOUT_MS = 30_000;
|
|
90
79
|
export function createTransport(options) {
|
|
91
80
|
const kern = createCore(options);
|
|
92
|
-
return (functionName, params, extraBodyFields, secretParams) => kern(functionName, params, extraBodyFields, secretParams, alsText, jsonAuswerten);
|
|
81
|
+
return (functionName, params, extraBodyFields, secretParams, callOptions) => kern(functionName, params, extraBodyFields, secretParams, callOptions, alsText, jsonAuswerten);
|
|
93
82
|
}
|
|
94
83
|
/**
|
|
95
84
|
* Zweiter Einstiegspunkt fuer die Bericht-Downloads. Er liest die Antwort als
|
|
@@ -101,7 +90,7 @@ export function createTransport(options) {
|
|
|
101
90
|
*/
|
|
102
91
|
export function createBinaryTransport(options) {
|
|
103
92
|
const kern = createCore(options);
|
|
104
|
-
return (functionName, params) => kern(functionName, params, undefined, undefined, alsBytes, pdfAuswerten);
|
|
93
|
+
return (functionName, params) => kern(functionName, params, undefined, undefined, undefined, alsBytes, pdfAuswerten);
|
|
105
94
|
}
|
|
106
95
|
/**
|
|
107
96
|
* Gemeinsamer Kern beider Einstiegspunkte: Anmeldung, Zeitlimit, Anfrage und
|
|
@@ -125,12 +114,21 @@ function createCore(options) {
|
|
|
125
114
|
* (Berichte, Zahlungen, FinanzOnline), geht an die oeffentliche Basis.
|
|
126
115
|
*/
|
|
127
116
|
const basisFuer = (functionName) => isPosOnlyCall(functionName) || (kassenweg && isPosCall(functionName)) ? kassenBasis : oeffentlicheBasis;
|
|
128
|
-
return async function aufrufen(functionName, params = {}, extraBodyFields, secretParams, lesen, auswerten) {
|
|
117
|
+
return async function aufrufen(functionName, params = {}, extraBodyFields, secretParams, callOptions, lesen, auswerten) {
|
|
129
118
|
// Die URL nennt die Backend-Funktion, die Fehler nennen den **Vorgang**:
|
|
130
119
|
// `financeWebService` fuehrt ein Dutzend verschiedener Vorgaenge unter einem
|
|
131
120
|
// Endpunkt, und ein Fehler, der nur "financeWebService" sagt, verschweigt
|
|
132
121
|
// dem Aufrufer, welcher davon scheiterte.
|
|
133
122
|
const fehlerName = extraBodyFields?.method ? `${functionName}/${extraBodyFields.method}` : functionName;
|
|
123
|
+
// Ausgang eines Scheiterns nach dem Senden: offen, wenn der Aufruf Wirkung
|
|
124
|
+
// hat. `hasEffect: true` hebt einen fremden Aufruf auf `unknown`.
|
|
125
|
+
// `hasEffect: false` senkt einen Aufruf mit Wirkung nur, wenn er wirklich
|
|
126
|
+
// ein Probelauf ist (`dryRun === true`, so streng prueft auch das
|
|
127
|
+
// Backend): sonst liefe ein echter Beleg oder eine Buchung nach einem
|
|
128
|
+
// Zeitlimit als `rejected`, und genau das fuehrt zur Doppelbuchung.
|
|
129
|
+
const probelauf = callOptions?.hasEffect === false && params['dryRun'] === true;
|
|
130
|
+
const wirkung = callOptions?.hasEffect === true || (isUnknownOutcomeCall(functionName) && !probelauf);
|
|
131
|
+
const nachDemSenden = wirkung ? 'unknown' : 'rejected';
|
|
134
132
|
// Das Zeitlimit laeuft ab HIER — es deckt die Anmeldung mit ab. Haengt die
|
|
135
133
|
// Token-Erneuerung auf flauem Netz, haette der Aufruf sonst weder Ergebnis
|
|
136
134
|
// noch Fehler, und die Kasse stuende still.
|
|
@@ -170,8 +168,9 @@ function createCore(options) {
|
|
|
170
168
|
}
|
|
171
169
|
// Bis hierher kam keine verwertbare Antwort: Netz weg oder Zeitlimit.
|
|
172
170
|
// Die Anfrage war schon unterwegs: bei einem Aufruf mit Wirkung kann
|
|
173
|
-
// der
|
|
174
|
-
|
|
171
|
+
// der Vorgang ausgefuehrt sein (Beleg, Zahlung, Buchung, Rechnung;
|
|
172
|
+
// Ausgang unklar).
|
|
173
|
+
return new KasseneckNetworkError(fehlerName, abbruch.signal.aborted, zeitlimitMs, causeDigest(ursache, geheimnisse), nachDemSenden);
|
|
175
174
|
};
|
|
176
175
|
const basis = basisFuer(functionName);
|
|
177
176
|
const url = `${basis}/${encodeURIComponent(functionName)}`;
|
|
@@ -225,7 +224,7 @@ function createCore(options) {
|
|
|
225
224
|
throw fehler;
|
|
226
225
|
}
|
|
227
226
|
// 5xx auf einem Aufruf mit Wirkung: der Handler kann gelaufen sein.
|
|
228
|
-
const ausgang = antwort.status >= 500
|
|
227
|
+
const ausgang = antwort.status >= 500 ? nachDemSenden : 'rejected';
|
|
229
228
|
throw new KasseneckHttpError(fehlerName, antwort.status, inhaltstyp, 'server-error', ausgang);
|
|
230
229
|
}
|
|
231
230
|
// HTTP 200 mit HTML: die Auffangregel der Single-Page-App hat den Aufruf
|
|
@@ -233,9 +232,9 @@ function createCore(options) {
|
|
|
233
232
|
if (inhaltstyp !== undefined && /^\s*text\/html\b/i.test(inhaltstyp)) {
|
|
234
233
|
// Mit Kennzeichen hat der `/v3`-Rand den Aufruf gesehen (etwa ein
|
|
235
234
|
// Proxy, der nur den Inhaltstyp umschreibt). Bei einem Aufruf mit
|
|
236
|
-
// Wirkung kann der
|
|
235
|
+
// Wirkung kann der Vorgang dann ausgefuehrt sein: unlesbarer Rumpf,
|
|
237
236
|
// Ausgang unklar, statt `route_missing`.
|
|
238
|
-
if (
|
|
237
|
+
if (nachDemSenden === 'unknown' && traegtKennzeichen(antwort)) {
|
|
239
238
|
throw new KasseneckHttpError(fehlerName, antwort.status, inhaltstyp, 'not-json', 'unknown');
|
|
240
239
|
}
|
|
241
240
|
throw new KasseneckApiError(fehlerName, 'Route fehlt: die Antwort ist eine HTML-Seite statt des Backends', {}, 'route_missing');
|
|
@@ -253,8 +252,7 @@ function createCore(options) {
|
|
|
253
252
|
// Ab hier kam HTTP 200 mit Kennzeichen: der `/v3`-Rand hat den Aufruf
|
|
254
253
|
// gesehen. Ist der Rumpf dann unlesbar (gekuerzt von einem Proxy,
|
|
255
254
|
// abgebrochene Verbindung), kann ein Handler mit Wirkung gelaufen sein.
|
|
256
|
-
|
|
257
|
-
return auswerten(koerper, fehlerName, antwort.status, inhaltstyp, geheimnisse, unlesbar);
|
|
255
|
+
return auswerten(koerper, fehlerName, antwort.status, inhaltstyp, geheimnisse, nachDemSenden);
|
|
258
256
|
}
|
|
259
257
|
finally {
|
|
260
258
|
// Ohne Abraeumen haelt der Wecker den Node-Prozess bis zum Zeitlimit wach.
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { ReceiptType, type ReceiptTypeKey, VatRate, type VatRateKey, KeckPaymentMethod, type KeckPaymentMethodKey, CreditCardProvider, type CreditCardProviderKey, VoucherType, type VoucherTypeKey, VoucherAction, type VoucherActionKey, StripeLinkMode, type StripeLinkModeKey, } from './enums/index.js';
|
|
2
2
|
export { type ReceiptItem, type ReceiptItemPayload, type ReceiptItemPayloadRead, toReceiptItemPayload, fromReceiptItemPayload, receiptItemTotalCents, receiptItemIsValid, negateReceiptItem, type TipRecipient, isTipItem, type Voucher, type VoucherPayload, toVoucherPayload, fromVoucherPayload, voucherIsValid, type Receipt, type RegistrationInfo, type ReceiptPayload, type ReceiptPayloadRead, toReceiptPayload, fromReceiptPayload, receiptSubSumCents, receiptSumCents, type CancellationOf, type CancellationItem, type Cancellation, type CancellationReason, type CancellationErrorCode, type CancellationStatus, type ReturnDisposition, RETURN_DISPOSITIONS, CANCELLATION_REASONS, CANCELLATION_STATUSES, CANCELLATION_ERROR_CODES, CANCELLATION_RESERVATION_MS, isCancellationReason, isReturnDisposition, isCancellationErrorCode, cancellationErrorCode, isCancellationError, cancellationFieldErrors, type CancellationFieldError, type ReceiptPayment, type ReceiptPaymentPayload, type ReceiptPaymentInput, fromReceiptPaymentPayload, toReceiptPaymentPayload, type PaymentErrorCode, PAYMENT_ERROR_CODES, isPaymentErrorCode, paymentErrorCode, isPaymentError, paymentFieldErrors, type PaymentFieldError, type ReceiptEmailErrorCode, type ReceiptEmailVia, RECEIPT_EMAIL_ERROR_CODES, RECEIPT_EMAIL_SEND_ERROR_CODES, type ReceiptEmailSendErrorCode, RECEIPT_EMAIL_VIAS, isReceiptEmailErrorCode, receiptEmailErrorCode, isReceiptEmailError, receiptEmailFieldErrors, type ReceiptEmailFieldError, type ReceiptErrorCode, type ReceiptFieldError, RECEIPT_ERROR_CODES, isReceiptErrorCode, receiptErrorCode, isReceiptError, receiptFieldErrors, remainingQuantities, type ReceiptCompany, type ReceiptCompanyPayload, fromReceiptCompanyPayload, receiptCompanyTaxInfo, type Cashregister, type CashregisterOnboarding, type CashregisterPayload, type CashregisterOnboardingPayload, fromCashregisterPayload, type ReceiptSummary, type ReceiptSummaryPayload, fromReceiptSummaryPayload, type ZeroKind, ZERO_KINDS, isZeroKind, type ReportMonth, reportMonthFromDate, previousReportMonth, nextReportMonth, reportMonthKey, reportMonthReadable, type StripeUrlSession, type StripeUrlSessionPayload, toStripeUrlSessionPayload, fromStripeUrlSessionPayload, type HobexReceipt, type HobexReceiptPayload, toHobexReceiptPayload, fromHobexReceiptPayload, hobexReceiptToCardPaymentData, hobexReceiptNeedsSignature, } from './models/index.js';
|
|
3
|
-
export { type AuthCredentials, type KasseneckAuth, type ApiKeyAuthOptions, type RegisterUserAuthOptions, apiKeyAuth, registerUserAuth, DEFAULT_BASE_URL, POS_BASE_URL, DEFAULT_TIMEOUT_MS, type HttpResponseLike, type HttpRequestInit, type FetchLike, type TransportOptions, type TransportBodyFields, type KasseneckTransport, type KasseneckBinaryTransport, ALL_CALLS, type ApiCall, PUBLIC_CALLS, POS_CALLS, type PublicCall, type PosCall, createTransport, createBinaryTransport, KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, type ValidationScope, type KasseneckError, type HttpFailureReason, type CauseDigest, type ErrorOutcome, CLIENT_ERROR_CODES, type ClientErrorCode, isKasseneckApiError, isKasseneckAuthError, isKasseneckHttpError, isKasseneckNetworkError, isKasseneckValidationError, isOutcomeUnknown, type ReceiptCommonOptions, type SellReceiptOptions, type TipOptions, type TipRecipientShare, type CancelReceiptOptions, type CancelReceiptResult, type ReceiptWithCompany, sellReceipt, sellReceiptWithCompany, paymentsExpectedCents, cardRefundReference, receiptLayoutFromResult, cancelReceipt, zeroReceipt, getReceipt, getReceiptWithCompany, generateFullReceiptId, getFirstReceiptDate, listMyReceipts, type ListMyReceiptsOptions, type ReceiptList, type ReceiptListStats, listMyCashregisters, checkVoucherCombinationError, type SendReceiptEmailOptions, type SendReceiptEmailResult, sendReceiptEmail, downloadDailyReport, downloadMonthlyReport, getReportV2, type ReportV2, type ReportV2Metadata, type ReportV2Options, type CashboxStatus, type SignatureStatus, getCashboxStatus, getSignatureStatus, type KasseneckApi, createKasseneckApi, } from './client/index.js';
|
|
3
|
+
export { type AuthCredentials, type KasseneckAuth, type ApiKeyAuthOptions, type RegisterUserAuthOptions, apiKeyAuth, registerUserAuth, DEFAULT_BASE_URL, POS_BASE_URL, DEFAULT_TIMEOUT_MS, type HttpResponseLike, type HttpRequestInit, type FetchLike, type TransportOptions, type TransportBodyFields, type TransportCallOptions, type KasseneckTransport, type KasseneckBinaryTransport, ALL_CALLS, type ApiCall, PUBLIC_CALLS, POS_CALLS, UNKNOWN_OUTCOME_CALLS, type PublicCall, type PosCall, createTransport, createBinaryTransport, KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, type ValidationScope, type KasseneckError, type HttpFailureReason, type CauseDigest, type ErrorOutcome, CLIENT_ERROR_CODES, type ClientErrorCode, isKasseneckApiError, isKasseneckAuthError, isKasseneckHttpError, isKasseneckNetworkError, isKasseneckValidationError, isOutcomeUnknown, type ReceiptCommonOptions, type SellReceiptOptions, type TipOptions, type TipRecipientShare, type CancelReceiptOptions, type CancelReceiptResult, type ReceiptWithCompany, sellReceipt, sellReceiptWithCompany, paymentsExpectedCents, cardRefundReference, receiptLayoutFromResult, cancelReceipt, zeroReceipt, getReceipt, getReceiptWithCompany, generateFullReceiptId, getFirstReceiptDate, listMyReceipts, type ListMyReceiptsOptions, type ReceiptList, type ReceiptListStats, listMyCashregisters, checkVoucherCombinationError, type SendReceiptEmailOptions, type SendReceiptEmailResult, sendReceiptEmail, downloadDailyReport, downloadMonthlyReport, getReportV2, type ReportV2, type ReportV2Metadata, type ReportV2Options, type CashboxStatus, type SignatureStatus, getCashboxStatus, getSignatureStatus, type KasseneckApi, createKasseneckApi, } from './client/index.js';
|
|
4
4
|
export { type ReceiptDueTip, type ReceiptDueTipRecipient, type ReceiptDueOptions, type ReceiptDueBuckets, type ReceiptDueBreakdown, type ReceiptDueErrorReason, receiptDueCents, receiptDueBreakdown, ReceiptDueError, RECEIPT_DUE_ERROR_REASONS, isReceiptDueError, } from './receipt/due.js';
|
|
5
5
|
export { parseServerTimeStamp, toViennaWallClock, type ViennaWallClock } from './vienna-time.js';
|
|
6
6
|
export { type PosBusinessSettings, type PosDeviceSettings, type PosSettings, type ArticleGroup, type PosArticle, POS_BUSINESS_DEFAULTS, POS_DEVICE_DEFAULTS, mergePosSettings, fromArticleGroupPayload, fromPosArticlePayload, listMyArticleGroups, listMyArticles, getPosSettings, setMyPosSettings, setMyRegisterDeviceSettings, distributeDiscount, cancelScopeOf, receiptsScopeOf, stockViewOf, } from './pos/index.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { ReceiptType, VatRate, KeckPaymentMethod, CreditCardProvider, VoucherType, VoucherAction, StripeLinkMode, } from './enums/index.js';
|
|
2
2
|
export { toReceiptItemPayload, fromReceiptItemPayload, receiptItemTotalCents, receiptItemIsValid, negateReceiptItem, isTipItem, toVoucherPayload, fromVoucherPayload, voucherIsValid, toReceiptPayload, fromReceiptPayload, receiptSubSumCents, receiptSumCents, RETURN_DISPOSITIONS, CANCELLATION_REASONS, CANCELLATION_STATUSES, CANCELLATION_ERROR_CODES, CANCELLATION_RESERVATION_MS, isCancellationReason, isReturnDisposition, isCancellationErrorCode, cancellationErrorCode, isCancellationError, cancellationFieldErrors, fromReceiptPaymentPayload, toReceiptPaymentPayload, PAYMENT_ERROR_CODES, isPaymentErrorCode, paymentErrorCode, isPaymentError, paymentFieldErrors, RECEIPT_EMAIL_ERROR_CODES, RECEIPT_EMAIL_SEND_ERROR_CODES, RECEIPT_EMAIL_VIAS, isReceiptEmailErrorCode, receiptEmailErrorCode, isReceiptEmailError, receiptEmailFieldErrors, RECEIPT_ERROR_CODES, isReceiptErrorCode, receiptErrorCode, isReceiptError, receiptFieldErrors, remainingQuantities, fromReceiptCompanyPayload, receiptCompanyTaxInfo, fromCashregisterPayload, fromReceiptSummaryPayload, ZERO_KINDS, isZeroKind, reportMonthFromDate, previousReportMonth, nextReportMonth, reportMonthKey, reportMonthReadable, toStripeUrlSessionPayload, fromStripeUrlSessionPayload, toHobexReceiptPayload, fromHobexReceiptPayload, hobexReceiptToCardPaymentData, hobexReceiptNeedsSignature, } from './models/index.js';
|
|
3
|
-
export { apiKeyAuth, registerUserAuth, DEFAULT_BASE_URL, POS_BASE_URL, DEFAULT_TIMEOUT_MS, ALL_CALLS, PUBLIC_CALLS, POS_CALLS, createTransport, createBinaryTransport, KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, CLIENT_ERROR_CODES, isKasseneckApiError, isKasseneckAuthError, isKasseneckHttpError, isKasseneckNetworkError, isKasseneckValidationError, isOutcomeUnknown, sellReceipt, sellReceiptWithCompany, paymentsExpectedCents, cardRefundReference, receiptLayoutFromResult, cancelReceipt, zeroReceipt, getReceipt, getReceiptWithCompany, generateFullReceiptId, getFirstReceiptDate, listMyReceipts, listMyCashregisters, checkVoucherCombinationError, sendReceiptEmail, downloadDailyReport, downloadMonthlyReport, getReportV2, getCashboxStatus, getSignatureStatus, createKasseneckApi, } from './client/index.js';
|
|
3
|
+
export { apiKeyAuth, registerUserAuth, DEFAULT_BASE_URL, POS_BASE_URL, DEFAULT_TIMEOUT_MS, ALL_CALLS, PUBLIC_CALLS, POS_CALLS, UNKNOWN_OUTCOME_CALLS, createTransport, createBinaryTransport, KasseneckApiError, KasseneckAuthError, KasseneckHttpError, KasseneckNetworkError, KasseneckValidationError, CLIENT_ERROR_CODES, isKasseneckApiError, isKasseneckAuthError, isKasseneckHttpError, isKasseneckNetworkError, isKasseneckValidationError, isOutcomeUnknown, sellReceipt, sellReceiptWithCompany, paymentsExpectedCents, cardRefundReference, receiptLayoutFromResult, cancelReceipt, zeroReceipt, getReceipt, getReceiptWithCompany, generateFullReceiptId, getFirstReceiptDate, listMyReceipts, listMyCashregisters, checkVoucherCombinationError, sendReceiptEmail, downloadDailyReport, downloadMonthlyReport, getReportV2, getCashboxStatus, getSignatureStatus, createKasseneckApi, } from './client/index.js';
|
|
4
4
|
export { receiptDueCents, receiptDueBreakdown, ReceiptDueError, RECEIPT_DUE_ERROR_REASONS, isReceiptDueError, } from './receipt/due.js';
|
|
5
5
|
export { parseServerTimeStamp, toViennaWallClock } from './vienna-time.js';
|
|
6
6
|
export { POS_BUSINESS_DEFAULTS, POS_DEVICE_DEFAULTS, mergePosSettings, fromArticleGroupPayload, fromPosArticlePayload, listMyArticleGroups, listMyArticles, getPosSettings, setMyPosSettings, setMyRegisterDeviceSettings, distributeDiscount, cancelScopeOf, receiptsScopeOf, stockViewOf, } from './pos/index.js';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Fassade ueber den Aufrufen der Lager-API
|
|
3
|
-
* rufen. Wie [createInvoiceApi] bewusst keine Klasse; die Aufrufe sind freie
|
|
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
4
|
* Funktionen (endpunkte.ts) und bleiben einzeln importierbar.
|
|
5
5
|
*/
|
|
6
6
|
import { type FetchLike } from '../client/transport.js';
|
|
7
|
-
import type { Article, ArticleListQuery, ArticleLookup, ArticlePage, CreateInventoryWebhookOptions, InventoryWebhook, InventoryWebhookDelivery, InventoryWebhookList, InventoryWebhookPatch, InventoryWebhookTestResult, InventoryWebhookWithSecret, Location, StockLevel, StockListQuery, StockMovement, StockMovementPage, StockMovementQuery, StockPage, StockResult } from './typen.js';
|
|
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
8
|
import type { InventoryWebhookEventType } from './vertrag.js';
|
|
9
9
|
export interface InventoryClientOptions {
|
|
10
10
|
/** `api_key` des Kontos (`kr_live_…` / `kr_test_…`). Gehoert auf einen Server. */
|
|
@@ -41,5 +41,21 @@ export interface InventoryClient {
|
|
|
41
41
|
webhookId?: string;
|
|
42
42
|
limit?: number;
|
|
43
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>;
|
|
44
60
|
}
|
|
45
61
|
export declare function createInventoryClient(options: InventoryClientOptions): InventoryClient;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Fassade ueber den Aufrufen der Lager-API
|
|
3
|
-
* rufen. Wie [createInvoiceApi] bewusst keine Klasse; die Aufrufe sind freie
|
|
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
4
|
* Funktionen (endpunkte.ts) und bleiben einzeln importierbar.
|
|
5
5
|
*/
|
|
6
6
|
import { createTransport } from '../client/transport.js';
|
|
7
7
|
import { inventoryKeyAuth } from './auth.js';
|
|
8
8
|
import { createWebhook, deleteWebhook, getArticle, getStock, iterateArticles, iterateStock, iterateStockMovements, listArticles, listLocations, listStock, listStockMovements, listWebhookDeliveries, listWebhooks, lookupArticleByCode, rotateWebhookSecret, sendWebhookTest, updateWebhook, } from './endpunkte.js';
|
|
9
|
+
import { changeStockCondition, createArticle, createReservation, deactivateArticle, extendReservation, getReservation, iterateReservations, listReservations, previewGoodsReceipt, receiveGoods, recordStockLoss, releaseReservation, reverseStockMovement, transferStock, updateArticle, } from './schreiben.js';
|
|
9
10
|
export function createInventoryClient(options) {
|
|
10
11
|
const rufen = createTransport({
|
|
11
12
|
auth: inventoryKeyAuth({ apiKey: options.apiKey }),
|
|
@@ -31,5 +32,20 @@ export function createInventoryClient(options) {
|
|
|
31
32
|
sendWebhookTest: (id, event) => sendWebhookTest(rufen, id, event),
|
|
32
33
|
rotateWebhookSecret: (id) => rotateWebhookSecret(rufen, id),
|
|
33
34
|
listWebhookDeliveries: (o) => listWebhookDeliveries(rufen, o),
|
|
35
|
+
createArticle: (r) => createArticle(rufen, r),
|
|
36
|
+
updateArticle: (r) => updateArticle(rufen, r),
|
|
37
|
+
deactivateArticle: (r) => deactivateArticle(rufen, r),
|
|
38
|
+
receiveGoods: (r) => receiveGoods(rufen, r),
|
|
39
|
+
previewGoodsReceipt: (r) => previewGoodsReceipt(rufen, r),
|
|
40
|
+
transferStock: (r) => transferStock(rufen, r),
|
|
41
|
+
recordStockLoss: (r) => recordStockLoss(rufen, r),
|
|
42
|
+
changeStockCondition: (r) => changeStockCondition(rufen, r),
|
|
43
|
+
reverseStockMovement: (r) => reverseStockMovement(rufen, r),
|
|
44
|
+
createReservation: (r) => createReservation(rufen, r),
|
|
45
|
+
extendReservation: (r) => extendReservation(rufen, r),
|
|
46
|
+
releaseReservation: (r) => releaseReservation(rufen, r),
|
|
47
|
+
getReservation: (id) => getReservation(rufen, id),
|
|
48
|
+
listReservations: (q) => listReservations(rufen, q),
|
|
49
|
+
iterateReservations: (q) => iterateReservations(rufen, q),
|
|
34
50
|
};
|
|
35
51
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Die Aufrufe der Lager-API: Artikel, Standorte, Bestand und Bewegungen
|
|
3
|
-
* lesen, Konto-Webhooks verwalten (Backend Stufe 5a).
|
|
3
|
+
* lesen, Konto-Webhooks verwalten (Backend Stufe 5a). Die schreibenden
|
|
4
|
+
* Aufrufe (Stufe 5b) stehen in `schreiben.ts` und teilen die Helfer hier.
|
|
4
5
|
*
|
|
5
6
|
* Jede Funktion nimmt den Transport als ersten Parameter und ist einzeln
|
|
6
7
|
* importierbar; die Fassade [createInventoryClient] bindet ihn nur einmal.
|
|
@@ -14,8 +15,26 @@
|
|
|
14
15
|
* wiederholt werden. Bei `rate_limited` vorher `retryAfterSec` warten
|
|
15
16
|
* ([inventoryRetryAfterSec]).
|
|
16
17
|
*/
|
|
17
|
-
import type { InternerTransport } from '../client/aufrufe.js';
|
|
18
|
+
import type { ApiCall, InternerTransport } from '../client/aufrufe.js';
|
|
19
|
+
import { KasseneckValidationError } from '../client/errors.js';
|
|
18
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>;
|
|
19
38
|
export declare function getArticle(transport: InternerTransport, articleId: string): Promise<Article>;
|
|
20
39
|
export declare function listArticles(transport: InternerTransport, query?: ArticleListQuery): Promise<ArticlePage>;
|
|
21
40
|
/** Alle Artikel der Abfrage, Seite fuer Seite ueber `nextCursor`. */
|
|
@@ -69,3 +88,4 @@ export declare function listWebhookDeliveries(transport: InternerTransport, opti
|
|
|
69
88
|
webhookId?: string;
|
|
70
89
|
limit?: number;
|
|
71
90
|
}): Promise<InventoryWebhookDelivery[]>;
|
|
91
|
+
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Die Aufrufe der Lager-API: Artikel, Standorte, Bestand und Bewegungen
|
|
3
|
-
* lesen, Konto-Webhooks verwalten (Backend Stufe 5a).
|
|
3
|
+
* lesen, Konto-Webhooks verwalten (Backend Stufe 5a). Die schreibenden
|
|
4
|
+
* Aufrufe (Stufe 5b) stehen in `schreiben.ts` und teilen die Helfer hier.
|
|
4
5
|
*
|
|
5
6
|
* Jede Funktion nimmt den Transport als ersten Parameter und ist einzeln
|
|
6
7
|
* importierbar; die Fassade [createInventoryClient] bindet ihn nur einmal.
|
|
@@ -17,11 +18,11 @@
|
|
|
17
18
|
import { KasseneckValidationError } from '../client/errors.js';
|
|
18
19
|
import { antwortfehler, artikel, bestand, bewegung, liste, naechsterCursor, objekt, probeZustellung, standort, webhook, wert, zustellung, } from './lesen.js';
|
|
19
20
|
import { INVENTORY_LIST_LIMIT_MAX } from './vertrag.js';
|
|
20
|
-
function anfragefehler(name, grund) {
|
|
21
|
+
export function anfragefehler(name, grund) {
|
|
21
22
|
return new KasseneckValidationError(name, grund, 'request');
|
|
22
23
|
}
|
|
23
24
|
/** Eine Kennung, die gesendet werden muss: Text mit mindestens einem Zeichen ausser Leerraum. */
|
|
24
|
-
function kennung(name, feld, wert) {
|
|
25
|
+
export function kennung(name, feld, wert) {
|
|
25
26
|
if (typeof wert !== 'string' || wert.trim() === '')
|
|
26
27
|
throw anfragefehler(name, `${feld} fehlt`);
|
|
27
28
|
return wert;
|
|
@@ -32,7 +33,7 @@ const ZEITFELDER = new Set(['updatedSince', 'changedSince', 'from', 'to']);
|
|
|
32
33
|
* Die Abfrage einer Liste als Parameter. Unbekannte Felder gehen unveraendert
|
|
33
34
|
* hinaus (der Server weist sie mit `validation` ab), `undefined` faellt weg.
|
|
34
35
|
*/
|
|
35
|
-
function abfrage(name, query) {
|
|
36
|
+
export function abfrage(name, query) {
|
|
36
37
|
if (query === undefined || query === null)
|
|
37
38
|
return {};
|
|
38
39
|
if (typeof query !== 'object' || Array.isArray(query))
|
|
@@ -63,7 +64,7 @@ function abfrage(name, query) {
|
|
|
63
64
|
* Blaettert ueber alle Seiten, Eintrag fuer Eintrag. Derselbe Cursor zweimal
|
|
64
65
|
* waere eine Endlosschleife: dann endet die Schleife mit einem Antwortfehler.
|
|
65
66
|
*/
|
|
66
|
-
async function* seitenweise(name, start, seite) {
|
|
67
|
+
export async function* seitenweise(name, start, seite) {
|
|
67
68
|
const gesehen = new Set();
|
|
68
69
|
// Auch der Startcursor zaehlt: nennt die erste Antwort ihn wieder, waere es dieselbe Seite.
|
|
69
70
|
if (start)
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* `KasseneckApiError.code`.
|
|
9
9
|
*/
|
|
10
10
|
import type { KasseneckApiError } from '../client/errors.js';
|
|
11
|
-
import
|
|
11
|
+
import type { InventoryShortfall } from './typen.js';
|
|
12
|
+
import { type InventoryErrorCode, type InventoryRequestErrorCode, type InventoryWarningCode } from './vertrag.js';
|
|
12
13
|
/** Ein Code, den ein Lager-Aufruf liefern kann. */
|
|
13
14
|
export type InventoryApiErrorCode = InventoryErrorCode | InventoryRequestErrorCode;
|
|
14
15
|
export declare function isInventoryErrorCode(value: unknown): value is InventoryApiErrorCode;
|
|
@@ -31,3 +32,12 @@ export declare function inventoryFieldErrors(error: unknown): InventoryFieldErro
|
|
|
31
32
|
* Konto (etwa 20 Anfragen je Sekunde, kurze Spitzen bis 40).
|
|
32
33
|
*/
|
|
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;
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* `KasseneckApiError.code`.
|
|
9
9
|
*/
|
|
10
10
|
import { bekannterCode, feldfehlerVon } from '../client/fehlercodes.js';
|
|
11
|
-
import {
|
|
11
|
+
import { fehlmengen } from './lesen.js';
|
|
12
|
+
import { INVENTORY_ERROR_CODES, INVENTORY_REQUEST_ERROR_CODES, INVENTORY_WARNING_CODES, } from './vertrag.js';
|
|
12
13
|
const BEKANNT = new Set([...INVENTORY_ERROR_CODES, ...INVENTORY_REQUEST_ERROR_CODES]);
|
|
13
14
|
export function isInventoryErrorCode(value) {
|
|
14
15
|
return typeof value === 'string' && BEKANNT.has(value);
|
|
@@ -38,3 +39,19 @@ export function inventoryRetryAfterSec(error) {
|
|
|
38
39
|
const wert = error.details['retryAfterSec'];
|
|
39
40
|
return typeof wert === 'number' && Number.isFinite(wert) && wert >= 0 ? wert : undefined;
|
|
40
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Die Positionen, fuer die beim Reservieren der verfuegbare Bestand nicht
|
|
44
|
+
* reicht (`insufficient_available`, `data.details[]`): je Artikel und Standort
|
|
45
|
+
* angefragt und verfuegbar, in Tausendstel. Leer, wenn der Fehler ein anderer
|
|
46
|
+
* ist. Es fehlen nur diese Positionen; reserviert wurde nichts.
|
|
47
|
+
*/
|
|
48
|
+
export function inventoryShortfalls(error) {
|
|
49
|
+
if (inventoryErrorCode(error) !== 'insufficient_available')
|
|
50
|
+
return [];
|
|
51
|
+
return fehlmengen(error.details['details']);
|
|
52
|
+
}
|
|
53
|
+
const HINWEISE = new Set(INVENTORY_WARNING_CODES);
|
|
54
|
+
/** `true` fuer einen Hinweis-Code einer Buchung (`warnings[].code`); Hinweise sind nie Fehler. */
|
|
55
|
+
export function isInventoryWarningCode(value) {
|
|
56
|
+
return typeof value === 'string' && HINWEISE.has(value);
|
|
57
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `@kreiseck/kasseneck-api/inventory` – die Lager-API: Artikel, Standorte,
|
|
3
3
|
* Bestand und Lagerprotokoll lesen, Konto-Webhooks verwalten und eingehende
|
|
4
|
-
* Zustellungen pruefen (Backend Stufe 5a)
|
|
4
|
+
* Zustellungen pruefen (Backend Stufe 5a); Artikel anlegen und aendern,
|
|
5
|
+
* Bestand buchen und Ware reservieren (Stufe 5b, seit 1.5.0).
|
|
5
6
|
*
|
|
6
7
|
* Ein eigener Unterpfad wie `invoice`: der `api_key` eines Kontos gehoert auf
|
|
7
8
|
* einen **Server** (etwa das Backend eines Online-Shops) und soll nicht
|
|
@@ -12,8 +13,9 @@
|
|
|
12
13
|
*/
|
|
13
14
|
export { createInventoryClient, type InventoryClient, type InventoryClientOptions } from './api.js';
|
|
14
15
|
export { inventoryKeyAuth, type InventoryKeyAuthOptions } from './auth.js';
|
|
15
|
-
export { isInventoryError, isInventoryErrorCode, inventoryErrorCode, inventoryFieldErrors, inventoryRetryAfterSec, type InventoryApiErrorCode, type InventoryFieldError, } from './fehler.js';
|
|
16
|
+
export { isInventoryError, isInventoryErrorCode, inventoryErrorCode, inventoryFieldErrors, inventoryRetryAfterSec, inventoryShortfalls, isInventoryWarningCode, type InventoryApiErrorCode, type InventoryFieldError, } from './fehler.js';
|
|
16
17
|
export { createWebhook, deleteWebhook, getArticle, getStock, iterateArticles, iterateStock, iterateStockMovements, listArticles, listLocations, listStock, listStockMovements, listWebhookDeliveries, listWebhooks, lookupArticleByCode, rotateWebhookSecret, sendWebhookTest, updateWebhook, } from './endpunkte.js';
|
|
18
|
+
export { changeStockCondition, createArticle, createReservation, deactivateArticle, extendReservation, getReservation, iterateReservations, listReservations, previewGoodsReceipt, receiveGoods, recordStockLoss, releaseReservation, reverseStockMovement, transferStock, updateArticle, } from './schreiben.js';
|
|
17
19
|
export { verifyInventoryWebhookSignature, parseInventoryWebhookEvent, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_EVENT_HEADER, WEBHOOK_DELIVERY_HEADER, WEBHOOK_TOLERANCE_SEC, type VerifyInventoryWebhookOptions, } from './webhook.js';
|
|
18
|
-
export type { Article, ArticleListQuery, ArticleLookup, ArticlePage, CreateInventoryWebhookOptions, InventoryWebhook, InventoryWebhookDelivery, InventoryWebhookEnvelope, InventoryWebhookEvent, InventoryWebhookList, InventoryWebhookPatch, InventoryWebhookTestDelivery, InventoryWebhookTestResult, InventoryWebhookWithSecret, Location, LocationAddress, StockBelowMinimumEventData, StockChangedEventData, StockLevel, StockListQuery, StockMovement, StockMovementLot, StockMovementPage, StockMovementQuery, StockMovementSourceRef, StockPage, StockResult, StockValue, } from './typen.js';
|
|
19
|
-
export { INVENTORY_ENDPOINTS, INVENTORY_ERROR_CODES, INVENTORY_REQUEST_ERROR_CODES, INVENTORY_WEBHOOK_EVENTS, INVENTORY_WEBHOOK_ENVELOPE_FIELDS, INVENTORY_WEBHOOK_LIMIT, INVENTORY_LIST_LIMIT_MAX, LOCATION_TYPES, STOCK_MOVEMENT_TYPES, STOCK_MOVEMENT_SOURCES, STOCK_CONDITIONS, STOCK_CHANGE_CAUSES, WEBHOOK_DELIVERY_STATUSES, type InventoryEndpoint, type InventoryErrorCode, type InventoryRequestErrorCode, type InventoryWebhookEventType, type LocationType, type StockMovementType, type StockMovementSource, type StockCondition, type StockChangeCause, type WebhookDeliveryStatus, } from './vertrag.js';
|
|
20
|
+
export type { Article, ArticleInput, ArticleListQuery, ArticleLookup, ArticlePage, ChangeStockConditionRequest, CreateArticleRequest, CreateInventoryWebhookOptions, CreateReservationRequest, DeactivateArticleRequest, ExtendReservationRequest, GoodsReceiptItem, GoodsReceiptPreview, GoodsReceiptPreviewLine, GoodsReceiptPreviewRequest, InventoryShortfall, InventoryWarning, InventoryWebhook, InventoryWebhookDelivery, InventoryWebhookEnvelope, InventoryWebhookEvent, InventoryWebhookList, InventoryWebhookPatch, InventoryWebhookTestDelivery, InventoryWebhookTestResult, InventoryWebhookWithSecret, LandedCost, Location, LocationAddress, ReceiveGoodsRequest, RecordStockLossRequest, ReleaseReservationItem, ReleaseReservationRequest, Reservation, ReservationItem, ReservationItemInput, ReservationListQuery, ReservationPage, ReverseStockMovementRequest, StockBelowMinimumEventData, StockChangedEventData, StockItem, StockLevel, StockListQuery, StockMovement, StockMovementLot, StockMovementPage, StockMovementQuery, StockMovementSourceRef, StockOperation, StockPage, StockResult, StockValue, TransferStockRequest, UpdateArticleRequest, } from './typen.js';
|
|
21
|
+
export { INVENTORY_ENDPOINTS, INVENTORY_ERROR_CODES, INVENTORY_REQUEST_ERROR_CODES, INVENTORY_WEBHOOK_EVENTS, INVENTORY_WEBHOOK_ENVELOPE_FIELDS, INVENTORY_WEBHOOK_LIMIT, INVENTORY_LIST_LIMIT_MAX, LOCATION_TYPES, STOCK_MOVEMENT_TYPES, STOCK_MOVEMENT_SOURCES, STOCK_CONDITIONS, STOCK_CHANGE_CAUSES, WEBHOOK_DELIVERY_STATUSES, INVENTORY_WARNING_CODES, STOCK_KINDS, STOCK_LOSS_REASONS, WITHDRAWAL_TYPES, LANDED_COST_TYPES, LANDED_COST_ALLOCATIONS, RESERVATION_STATUSES, INVENTORY_IDEMPOTENCY_KEY_MAX, RESERVATION_MINUTES_MIN, RESERVATION_MINUTES_MAX, type InventoryEndpoint, type InventoryErrorCode, type InventoryRequestErrorCode, type InventoryWebhookEventType, type LocationType, type StockMovementType, type StockMovementSource, type StockCondition, type StockChangeCause, type WebhookDeliveryStatus, type InventoryWarningCode, type StockKind, type StockLossReason, type WithdrawalType, type LandedCostType, type LandedCostAllocation, type ReservationStatus, } from './vertrag.js';
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `@kreiseck/kasseneck-api/inventory` – die Lager-API: Artikel, Standorte,
|
|
3
3
|
* Bestand und Lagerprotokoll lesen, Konto-Webhooks verwalten und eingehende
|
|
4
|
-
* Zustellungen pruefen (Backend Stufe 5a)
|
|
4
|
+
* Zustellungen pruefen (Backend Stufe 5a); Artikel anlegen und aendern,
|
|
5
|
+
* Bestand buchen und Ware reservieren (Stufe 5b, seit 1.5.0).
|
|
5
6
|
*
|
|
6
7
|
* Ein eigener Unterpfad wie `invoice`: der `api_key` eines Kontos gehoert auf
|
|
7
8
|
* einen **Server** (etwa das Backend eines Online-Shops) und soll nicht
|
|
@@ -12,7 +13,8 @@
|
|
|
12
13
|
*/
|
|
13
14
|
export { createInventoryClient } from './api.js';
|
|
14
15
|
export { inventoryKeyAuth } from './auth.js';
|
|
15
|
-
export { isInventoryError, isInventoryErrorCode, inventoryErrorCode, inventoryFieldErrors, inventoryRetryAfterSec, } from './fehler.js';
|
|
16
|
+
export { isInventoryError, isInventoryErrorCode, inventoryErrorCode, inventoryFieldErrors, inventoryRetryAfterSec, inventoryShortfalls, isInventoryWarningCode, } from './fehler.js';
|
|
16
17
|
export { createWebhook, deleteWebhook, getArticle, getStock, iterateArticles, iterateStock, iterateStockMovements, listArticles, listLocations, listStock, listStockMovements, listWebhookDeliveries, listWebhooks, lookupArticleByCode, rotateWebhookSecret, sendWebhookTest, updateWebhook, } from './endpunkte.js';
|
|
18
|
+
export { changeStockCondition, createArticle, createReservation, deactivateArticle, extendReservation, getReservation, iterateReservations, listReservations, previewGoodsReceipt, receiveGoods, recordStockLoss, releaseReservation, reverseStockMovement, transferStock, updateArticle, } from './schreiben.js';
|
|
17
19
|
export { verifyInventoryWebhookSignature, parseInventoryWebhookEvent, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_EVENT_HEADER, WEBHOOK_DELIVERY_HEADER, WEBHOOK_TOLERANCE_SEC, } from './webhook.js';
|
|
18
|
-
export { INVENTORY_ENDPOINTS, INVENTORY_ERROR_CODES, INVENTORY_REQUEST_ERROR_CODES, INVENTORY_WEBHOOK_EVENTS, INVENTORY_WEBHOOK_ENVELOPE_FIELDS, INVENTORY_WEBHOOK_LIMIT, INVENTORY_LIST_LIMIT_MAX, LOCATION_TYPES, STOCK_MOVEMENT_TYPES, STOCK_MOVEMENT_SOURCES, STOCK_CONDITIONS, STOCK_CHANGE_CAUSES, WEBHOOK_DELIVERY_STATUSES, } from './vertrag.js';
|
|
20
|
+
export { INVENTORY_ENDPOINTS, INVENTORY_ERROR_CODES, INVENTORY_REQUEST_ERROR_CODES, INVENTORY_WEBHOOK_EVENTS, INVENTORY_WEBHOOK_ENVELOPE_FIELDS, INVENTORY_WEBHOOK_LIMIT, INVENTORY_LIST_LIMIT_MAX, LOCATION_TYPES, STOCK_MOVEMENT_TYPES, STOCK_MOVEMENT_SOURCES, STOCK_CONDITIONS, STOCK_CHANGE_CAUSES, WEBHOOK_DELIVERY_STATUSES, INVENTORY_WARNING_CODES, STOCK_KINDS, STOCK_LOSS_REASONS, WITHDRAWAL_TYPES, LANDED_COST_TYPES, LANDED_COST_ALLOCATIONS, RESERVATION_STATUSES, INVENTORY_IDEMPOTENCY_KEY_MAX, RESERVATION_MINUTES_MIN, RESERVATION_MINUTES_MAX, } from './vertrag.js';
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* wenn der Server sie sendet: „fehlt“ heisst dort „kein Recht“, nicht „leer“.
|
|
13
13
|
*/
|
|
14
14
|
import { KasseneckValidationError } from '../client/errors.js';
|
|
15
|
-
import type { Article, InventoryWebhook, InventoryWebhookDelivery, InventoryWebhookTestDelivery, Location, StockBelowMinimumEventData, StockChangedEventData, StockLevel, StockMovement, StockValue } from './typen.js';
|
|
15
|
+
import type { Article, GoodsReceiptPreviewLine, InventoryShortfall, InventoryWebhook, InventoryWebhookDelivery, InventoryWebhookTestDelivery, Location, Reservation, StockBelowMinimumEventData, StockChangedEventData, StockLevel, StockMovement, StockOperation, StockValue } from './typen.js';
|
|
16
16
|
type Roh = Record<string, unknown>;
|
|
17
17
|
/** Ein Leser bekommt den Vorgang (fuer die Meldung) und den Pfad im Rumpf. */
|
|
18
18
|
export interface Ort {
|
|
@@ -31,6 +31,13 @@ export declare function zustellung(ort: Ort, w: unknown): InventoryWebhookDelive
|
|
|
31
31
|
export declare function probeZustellung(ort: Ort, w: unknown, webhookId: string): InventoryWebhookTestDelivery;
|
|
32
32
|
export declare function bestandGeaendert(ort: Ort, w: unknown): StockChangedEventData;
|
|
33
33
|
export declare function unterMindestbestand(ort: Ort, w: unknown): StockBelowMinimumEventData;
|
|
34
|
+
/** Antwort einer Buchung; ohne `operationId` ist nicht belegt, dass gebucht wurde. */
|
|
35
|
+
export declare function vorgang(name: string, daten: unknown): StockOperation;
|
|
36
|
+
/** Eine Zeile der Wareneingangs-Vorschau; Werte nur, wenn der Server sie sendet (Recht `costs`). */
|
|
37
|
+
export declare function vorschauZeile(ort: Ort, w: unknown): GoodsReceiptPreviewLine;
|
|
38
|
+
export declare function reservierung(ort: Ort, w: unknown): Reservation;
|
|
39
|
+
/** Die fehlenden Positionen aus `insufficient_available` (`data.details[]`); ein kaputter Eintrag faellt weg. */
|
|
40
|
+
export declare function fehlmengen(roh: unknown): InventoryShortfall[];
|
|
34
41
|
/** Eine zugesagte Liste `data.<feld>`, Eintrag fuer Eintrag gelesen. */
|
|
35
42
|
export declare function liste<T>(name: string, daten: unknown, feld: string, lesen: (ort: Ort, e: unknown) => T): T[];
|
|
36
43
|
/** Der Cursor der naechsten Seite; `null` am Ende. Etwas anderes als Text oder `null` ist kaputt. */
|
|
@@ -59,6 +59,30 @@ function textAbbildung(w) {
|
|
|
59
59
|
raus[k] = v;
|
|
60
60
|
return raus;
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Mengen je Standort (`minStockByLocation`): jeder Wert eine Ganzzahl. Fehlt
|
|
64
|
+
* das Feld (Server vor Stufe 5b), gilt „keiner“ (`{}`).
|
|
65
|
+
*/
|
|
66
|
+
function mengenJeStandort(ort, feld, w) {
|
|
67
|
+
if (w === undefined || w === null)
|
|
68
|
+
return {};
|
|
69
|
+
const o = objekt(w);
|
|
70
|
+
if (!o)
|
|
71
|
+
throw antwortfehler(ort.name, `Antwort ist unbrauchbar (data.${ort.pfad}.${feld} ist kein Objekt)`);
|
|
72
|
+
const raus = {};
|
|
73
|
+
for (const [k, v] of Object.entries(o))
|
|
74
|
+
raus[k] = ganzzahl(ort, `${feld}.${k}`, v);
|
|
75
|
+
return raus;
|
|
76
|
+
}
|
|
77
|
+
/** Eine Liste von Kennungen (`movementIds`, `lotIds`); fehlt sie, ist sie leer. */
|
|
78
|
+
function kennungsliste(ort, feld, w) {
|
|
79
|
+
if (w === undefined || w === null)
|
|
80
|
+
return [];
|
|
81
|
+
if (!Array.isArray(w) || !w.every((x) => typeof x === 'string')) {
|
|
82
|
+
throw antwortfehler(ort.name, `Antwort ist unbrauchbar (data.${ort.pfad}${ort.pfad ? '.' : ''}${feld} ist keine Liste von Kennungen)`);
|
|
83
|
+
}
|
|
84
|
+
return [...w];
|
|
85
|
+
}
|
|
62
86
|
// ---- Artikel ------------------------------------------------------------------
|
|
63
87
|
export function artikel(ort, w) {
|
|
64
88
|
const a = eintrag(ort, w);
|
|
@@ -76,6 +100,7 @@ export function artikel(ort, w) {
|
|
|
76
100
|
const raus = {
|
|
77
101
|
id: kennung(ort, 'id', a.id),
|
|
78
102
|
name: text(a.name),
|
|
103
|
+
description: text(a.description),
|
|
79
104
|
unitPriceCents: ganzzahlOderNull(ort, 'unitPriceCents', a.unitPriceCents),
|
|
80
105
|
vatRate: typeof vatRate === 'number' ? vatRate : null,
|
|
81
106
|
unit: text(a.unit),
|
|
@@ -85,8 +110,10 @@ export function artikel(ort, w) {
|
|
|
85
110
|
groupId: text(a.groupId),
|
|
86
111
|
revenueGroupId: text(a.revenueGroupId),
|
|
87
112
|
stockTracked: a.stockTracked === true,
|
|
113
|
+
stockKind: textOderNull(a.stockKind),
|
|
88
114
|
stockLocationIds: standorte,
|
|
89
115
|
minStock: ganzzahlOderNull(ort, 'minStock', a.minStock),
|
|
116
|
+
minStockByLocation: mengenJeStandort(ort, 'minStockByLocation', a.minStockByLocation),
|
|
90
117
|
active: a.active !== false,
|
|
91
118
|
createdAt: text(a.createdAt),
|
|
92
119
|
updatedAt: text(a.updatedAt),
|
|
@@ -173,8 +200,14 @@ export function bewegung(ort, w) {
|
|
|
173
200
|
locationId: text(b.locationId),
|
|
174
201
|
condition: text(b.condition),
|
|
175
202
|
quantityDelta: ganzzahl(ort, 'quantityDelta', b.quantityDelta),
|
|
203
|
+
// Server vor Stufe 5b senden das Feld nicht: dort aenderte keine Bewegung `reserved`.
|
|
204
|
+
reservedDelta: b.reservedDelta === undefined ? 0 : ganzzahl(ort, 'reservedDelta', b.reservedDelta),
|
|
176
205
|
stockAfter: nachher
|
|
177
|
-
? {
|
|
206
|
+
? {
|
|
207
|
+
sellable: ganzzahl(nachherOrt, 'sellable', nachher.sellable),
|
|
208
|
+
defective: ganzzahl(nachherOrt, 'defective', nachher.defective),
|
|
209
|
+
reserved: ganzzahlOderNull(nachherOrt, 'reserved', nachher.reserved),
|
|
210
|
+
}
|
|
178
211
|
: null,
|
|
179
212
|
operationId: text(b.operationId),
|
|
180
213
|
source: quelle
|
|
@@ -255,6 +288,99 @@ export function unterMindestbestand(ort, w) {
|
|
|
255
288
|
minStock: ganzzahl(ort, 'minStock', d.minStock),
|
|
256
289
|
};
|
|
257
290
|
}
|
|
291
|
+
// ---- Schreiben (Stufe 5b) ------------------------------------------------------------
|
|
292
|
+
function warnung(ort, w) {
|
|
293
|
+
const h = eintrag(ort, w);
|
|
294
|
+
if (typeof h.code !== 'string' || h.code === '')
|
|
295
|
+
throw antwortfehler(ort.name, `Hinweis ohne Code (data.${ort.pfad}.code)`);
|
|
296
|
+
return {
|
|
297
|
+
code: h.code,
|
|
298
|
+
articleId: textOderNull(h.articleId),
|
|
299
|
+
locationId: textOderNull(h.locationId),
|
|
300
|
+
message: typeof h.message === 'string' ? h.message : '',
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
/** Antwort einer Buchung; ohne `operationId` ist nicht belegt, dass gebucht wurde. */
|
|
304
|
+
export function vorgang(name, daten) {
|
|
305
|
+
const d = objekt(daten);
|
|
306
|
+
if (!d)
|
|
307
|
+
throw antwortfehler(name, 'Antwort ist unbrauchbar (data ist kein Objekt)');
|
|
308
|
+
const ort = { name, pfad: '' };
|
|
309
|
+
if (typeof d.operationId !== 'string' || d.operationId === '') {
|
|
310
|
+
throw antwortfehler(name, 'Antwort enthaelt keine Kennung (data.operationId fehlt)');
|
|
311
|
+
}
|
|
312
|
+
const hinweise = d.warnings === undefined || d.warnings === null ? [] : d.warnings;
|
|
313
|
+
if (!Array.isArray(hinweise))
|
|
314
|
+
throw antwortfehler(name, 'Antwort ist unbrauchbar (data.warnings ist keine Liste)');
|
|
315
|
+
return {
|
|
316
|
+
operationId: d.operationId,
|
|
317
|
+
movementIds: kennungsliste(ort, 'movementIds', d.movementIds),
|
|
318
|
+
lotIds: kennungsliste(ort, 'lotIds', d.lotIds),
|
|
319
|
+
warnings: hinweise.map((h, i) => warnung({ name, pfad: `warnings[${i}]` }, h)),
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
/** Eine Zeile der Wareneingangs-Vorschau; Werte nur, wenn der Server sie sendet (Recht `costs`). */
|
|
323
|
+
export function vorschauZeile(ort, w) {
|
|
324
|
+
const z = eintrag(ort, w);
|
|
325
|
+
const serien = z.serialNumbers === undefined || z.serialNumbers === null ? [] : z.serialNumbers;
|
|
326
|
+
if (!Array.isArray(serien) || !serien.every((x) => typeof x === 'string')) {
|
|
327
|
+
throw antwortfehler(ort.name, `Antwort ist unbrauchbar (data.${ort.pfad}.serialNumbers ist keine Liste)`);
|
|
328
|
+
}
|
|
329
|
+
const raus = {
|
|
330
|
+
articleId: kennung(ort, 'articleId', z.articleId),
|
|
331
|
+
quantity: ganzzahl(ort, 'quantity', z.quantity),
|
|
332
|
+
expiresOn: textOderNull(z.expiresOn),
|
|
333
|
+
batch: textOderNull(z.batch),
|
|
334
|
+
serialNumbers: [...serien],
|
|
335
|
+
priceFromArticle: z.priceFromArticle === true,
|
|
336
|
+
};
|
|
337
|
+
for (const feld of ['baseCents', 'landedCostCents', 'valueCents', 'unitCostMicros']) {
|
|
338
|
+
if (hat(z, feld))
|
|
339
|
+
raus[feld] = ganzzahlOderNull(ort, feld, z[feld]);
|
|
340
|
+
}
|
|
341
|
+
return raus;
|
|
342
|
+
}
|
|
343
|
+
function reservierungsPosition(ort, w) {
|
|
344
|
+
const p = eintrag(ort, w);
|
|
345
|
+
return {
|
|
346
|
+
articleId: kennung(ort, 'articleId', p.articleId),
|
|
347
|
+
locationId: kennung(ort, 'locationId', p.locationId),
|
|
348
|
+
quantity: ganzzahl(ort, 'quantity', p.quantity),
|
|
349
|
+
redeemed: ganzzahl(ort, 'redeemed', p.redeemed),
|
|
350
|
+
released: ganzzahl(ort, 'released', p.released),
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
export function reservierung(ort, w) {
|
|
354
|
+
const r = eintrag(ort, w);
|
|
355
|
+
if (!Array.isArray(r.items))
|
|
356
|
+
throw antwortfehler(ort.name, `Antwort ist unbrauchbar (data.${ort.pfad}.items ist keine Liste)`);
|
|
357
|
+
return {
|
|
358
|
+
id: kennung(ort, 'id', r.id),
|
|
359
|
+
status: textOderNull(r.status),
|
|
360
|
+
reference: text(r.reference),
|
|
361
|
+
items: r.items.map((p, i) => reservierungsPosition({ name: ort.name, pfad: `${ort.pfad}.items[${i}]` }, p)),
|
|
362
|
+
expiresAt: text(r.expiresAt),
|
|
363
|
+
createdAt: text(r.createdAt),
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
/** Die fehlenden Positionen aus `insufficient_available` (`data.details[]`); ein kaputter Eintrag faellt weg. */
|
|
367
|
+
export function fehlmengen(roh) {
|
|
368
|
+
if (!Array.isArray(roh))
|
|
369
|
+
return [];
|
|
370
|
+
const raus = [];
|
|
371
|
+
for (const e of roh) {
|
|
372
|
+
const o = objekt(e);
|
|
373
|
+
if (!o)
|
|
374
|
+
continue;
|
|
375
|
+
const { articleId, locationId, requested, available } = o;
|
|
376
|
+
if (typeof articleId !== 'string' || typeof locationId !== 'string')
|
|
377
|
+
continue;
|
|
378
|
+
if (!Number.isSafeInteger(requested) || !Number.isSafeInteger(available))
|
|
379
|
+
continue;
|
|
380
|
+
raus.push({ articleId, locationId, requested: requested, available: available });
|
|
381
|
+
}
|
|
382
|
+
return raus;
|
|
383
|
+
}
|
|
258
384
|
// ---- Listen ------------------------------------------------------------------
|
|
259
385
|
/** Eine zugesagte Liste `data.<feld>`, Eintrag fuer Eintrag gelesen. */
|
|
260
386
|
export function liste(name, daten, feld, lesen) {
|