@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.
Files changed (105) hide show
  1. package/CHANGELOG.md +166 -0
  2. package/README.md +255 -36
  3. package/dist/cjs/client/aufrufe.d.ts +58 -4
  4. package/dist/cjs/client/aufrufe.js +196 -1
  5. package/dist/cjs/client/errors.d.ts +32 -19
  6. package/dist/cjs/client/errors.js +28 -17
  7. package/dist/cjs/client/index.d.ts +2 -2
  8. package/dist/cjs/client/index.js +2 -1
  9. package/dist/cjs/client/transport.d.ts +27 -1
  10. package/dist/cjs/client/transport.js +25 -27
  11. package/dist/cjs/index.d.ts +1 -1
  12. package/dist/cjs/index.js +3 -2
  13. package/dist/cjs/inventory/api.d.ts +19 -3
  14. package/dist/cjs/inventory/api.js +18 -2
  15. package/dist/cjs/inventory/endpunkte.d.ts +22 -2
  16. package/dist/cjs/inventory/endpunkte.js +6 -1
  17. package/dist/cjs/inventory/fehler.d.ts +11 -1
  18. package/dist/cjs/inventory/fehler.js +19 -0
  19. package/dist/cjs/inventory/index.d.ts +6 -4
  20. package/dist/cjs/inventory/index.js +32 -2
  21. package/dist/cjs/inventory/lesen.d.ts +8 -1
  22. package/dist/cjs/inventory/lesen.js +131 -1
  23. package/dist/cjs/inventory/schreiben.d.ts +86 -0
  24. package/dist/cjs/inventory/schreiben.js +320 -0
  25. package/dist/cjs/inventory/typen.d.ts +371 -11
  26. package/dist/cjs/inventory/vertrag.d.ts +76 -16
  27. package/dist/cjs/inventory/vertrag.js +138 -13
  28. package/dist/cjs/inventory/webhook.d.ts +3 -1
  29. package/dist/cjs/inventory/webhook.js +7 -1
  30. package/dist/cjs/invoice/endpunkte.d.ts +6 -0
  31. package/dist/cjs/invoice/endpunkte.js +13 -2
  32. package/dist/cjs/invoice/index.d.ts +2 -2
  33. package/dist/cjs/invoice/index.js +2 -1
  34. package/dist/cjs/invoice/typen.d.ts +46 -2
  35. package/dist/cjs/invoice/vertrag.d.ts +19 -5
  36. package/dist/cjs/invoice/vertrag.js +37 -5
  37. package/dist/cjs/pos/texte.d.ts +11 -6
  38. package/dist/cjs/pos/texte.js +11 -6
  39. package/dist/cjs/stored/vokabular.d.ts +1 -1
  40. package/dist/cjs/stored/vokabular.js +5 -3
  41. package/dist/cjs/version.d.ts +1 -1
  42. package/dist/cjs/version.js +1 -1
  43. package/dist/esm/client/aufrufe.d.ts +58 -4
  44. package/dist/esm/client/aufrufe.js +194 -0
  45. package/dist/esm/client/errors.d.ts +32 -19
  46. package/dist/esm/client/errors.js +28 -17
  47. package/dist/esm/client/index.d.ts +2 -2
  48. package/dist/esm/client/index.js +1 -1
  49. package/dist/esm/client/transport.d.ts +27 -1
  50. package/dist/esm/client/transport.js +26 -28
  51. package/dist/esm/index.d.ts +1 -1
  52. package/dist/esm/index.js +1 -1
  53. package/dist/esm/inventory/api.d.ts +19 -3
  54. package/dist/esm/inventory/api.js +18 -2
  55. package/dist/esm/inventory/endpunkte.d.ts +22 -2
  56. package/dist/esm/inventory/endpunkte.js +6 -5
  57. package/dist/esm/inventory/fehler.d.ts +11 -1
  58. package/dist/esm/inventory/fehler.js +18 -1
  59. package/dist/esm/inventory/index.d.ts +6 -4
  60. package/dist/esm/inventory/index.js +5 -3
  61. package/dist/esm/inventory/lesen.d.ts +8 -1
  62. package/dist/esm/inventory/lesen.js +127 -1
  63. package/dist/esm/inventory/schreiben.d.ts +86 -0
  64. package/dist/esm/inventory/schreiben.js +303 -0
  65. package/dist/esm/inventory/typen.d.ts +371 -11
  66. package/dist/esm/inventory/vertrag.d.ts +76 -16
  67. package/dist/esm/inventory/vertrag.js +137 -12
  68. package/dist/esm/inventory/webhook.d.ts +3 -1
  69. package/dist/esm/inventory/webhook.js +8 -2
  70. package/dist/esm/invoice/endpunkte.d.ts +6 -0
  71. package/dist/esm/invoice/endpunkte.js +13 -2
  72. package/dist/esm/invoice/index.d.ts +2 -2
  73. package/dist/esm/invoice/index.js +1 -1
  74. package/dist/esm/invoice/typen.d.ts +46 -2
  75. package/dist/esm/invoice/vertrag.d.ts +19 -5
  76. package/dist/esm/invoice/vertrag.js +36 -4
  77. package/dist/esm/pos/texte.d.ts +11 -6
  78. package/dist/esm/pos/texte.js +11 -6
  79. package/dist/esm/stored/vokabular.d.ts +1 -1
  80. package/dist/esm/stored/vokabular.js +5 -3
  81. package/dist/esm/version.d.ts +1 -1
  82. package/dist/esm/version.js +1 -1
  83. package/fixtures/hobex-hps-codes.json +1 -1
  84. package/fixtures/invoice-api-examples/credit-error-reservation.json +26 -0
  85. package/fixtures/invoice-api-examples/issue-error-reservation-article.json +25 -0
  86. package/fixtures/invoice-api-examples/issue-error-vat-id-risk.json +26 -0
  87. package/fixtures/invoice-api-examples/issue-reservation.json +24 -0
  88. package/fixtures/invoice-api-examples/issue-vat-id-risk.json +28 -0
  89. package/fixtures/invoice-api.schema.json +15 -2
  90. package/fixtures/invoice-texts.json +1 -1
  91. package/fixtures/pos-texts.json +1 -1
  92. package/fixtures/surface.json +206 -9
  93. package/fixtures/v3/antworten/belege.json +2 -2
  94. package/fixtures/v3/antworten/belegmail.json +2 -2
  95. package/fixtures/v3/antworten/kasse-belege.json +2 -2
  96. package/fixtures/v3/antworten/kasse.json +3 -3
  97. package/fixtures/v3/antworten/lager.json +2491 -130
  98. package/fixtures/v3/antworten/rechnungen.json +267 -44
  99. package/fixtures/v3/antworten/storno.json +2 -2
  100. package/fixtures/v3/stored/belege.json +2 -2
  101. package/fixtures/v3/stored/kasse.json +3 -3
  102. package/fixtures/v3/stored/rechnungen.json +174 -18
  103. package/fixtures/v3/v3-vokabular.json +593 -23
  104. package/fixtures/v3/zahlbetrag-faelle.json +2 -2
  105. 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 Beleg bzw. die Zahlung entstanden sein (Ausgang unklar, nachlesen).
174
- return new KasseneckNetworkError(fehlerName, abbruch.signal.aborted, zeitlimitMs, causeDigest(ursache, geheimnisse), UNKNOWN_OUTCOME_CALLS.has(functionName) ? 'unknown' : 'rejected');
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 && UNKNOWN_OUTCOME_CALLS.has(functionName) ? 'unknown' : 'rejected';
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 Beleg bzw. die Zahlung dann entstanden sein: unlesbarer Rumpf,
235
+ // Wirkung kann der Vorgang dann ausgefuehrt sein: unlesbarer Rumpf,
237
236
  // Ausgang unklar, statt `route_missing`.
238
- if (UNKNOWN_OUTCOME_CALLS.has(functionName) && traegtKennzeichen(antwort)) {
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
- const unlesbar = UNKNOWN_OUTCOME_CALLS.has(functionName) ? 'unknown' : 'rejected';
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.
@@ -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: Schluessel einmal binden, dann
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: Schluessel einmal binden, dann
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 { type InventoryErrorCode, type InventoryRequestErrorCode } from './vertrag.js';
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 { INVENTORY_ERROR_CODES, INVENTORY_REQUEST_ERROR_CODES, } from './vertrag.js';
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
- ? { sellable: ganzzahl(nachherOrt, 'sellable', nachher.sellable), defective: ganzzahl(nachherOrt, 'defective', nachher.defective) }
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) {