@kreiseck/kasseneck-api 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/README.md +181 -27
  3. package/dist/cjs/client/aufrufe.d.ts +58 -4
  4. package/dist/cjs/client/aufrufe.js +185 -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 +10 -2
  14. package/dist/cjs/inventory/api.js +8 -1
  15. package/dist/cjs/inventory/endpunkte.d.ts +2 -1
  16. package/dist/cjs/inventory/endpunkte.js +2 -1
  17. package/dist/cjs/inventory/index.d.ts +5 -3
  18. package/dist/cjs/inventory/index.js +15 -3
  19. package/dist/cjs/inventory/lesen.d.ts +7 -1
  20. package/dist/cjs/inventory/lesen.js +75 -0
  21. package/dist/cjs/inventory/schreiben.d.ts +26 -1
  22. package/dist/cjs/inventory/schreiben.js +24 -10
  23. package/dist/cjs/inventory/typen.d.ts +156 -2
  24. package/dist/cjs/inventory/varianten.d.ts +67 -0
  25. package/dist/cjs/inventory/varianten.js +150 -0
  26. package/dist/cjs/inventory/vertrag.d.ts +40 -5
  27. package/dist/cjs/inventory/vertrag.js +51 -3
  28. package/dist/cjs/inventory/webhook.d.ts +5 -2
  29. package/dist/cjs/inventory/webhook.js +8 -2
  30. package/dist/cjs/invoice/endpunkte.d.ts +6 -0
  31. package/dist/cjs/invoice/endpunkte.js +13 -2
  32. package/dist/cjs/pos/texte.d.ts +11 -6
  33. package/dist/cjs/pos/texte.js +11 -6
  34. package/dist/cjs/stored/vokabular.d.ts +1 -1
  35. package/dist/cjs/stored/vokabular.js +1 -1
  36. package/dist/cjs/version.d.ts +1 -1
  37. package/dist/cjs/version.js +1 -1
  38. package/dist/esm/client/aufrufe.d.ts +58 -4
  39. package/dist/esm/client/aufrufe.js +183 -0
  40. package/dist/esm/client/errors.d.ts +32 -19
  41. package/dist/esm/client/errors.js +28 -17
  42. package/dist/esm/client/index.d.ts +2 -2
  43. package/dist/esm/client/index.js +1 -1
  44. package/dist/esm/client/transport.d.ts +27 -1
  45. package/dist/esm/client/transport.js +26 -28
  46. package/dist/esm/index.d.ts +1 -1
  47. package/dist/esm/index.js +1 -1
  48. package/dist/esm/inventory/api.d.ts +10 -2
  49. package/dist/esm/inventory/api.js +8 -1
  50. package/dist/esm/inventory/endpunkte.d.ts +2 -1
  51. package/dist/esm/inventory/endpunkte.js +2 -1
  52. package/dist/esm/inventory/index.d.ts +5 -3
  53. package/dist/esm/inventory/index.js +4 -2
  54. package/dist/esm/inventory/lesen.d.ts +7 -1
  55. package/dist/esm/inventory/lesen.js +74 -0
  56. package/dist/esm/inventory/schreiben.d.ts +26 -1
  57. package/dist/esm/inventory/schreiben.js +19 -11
  58. package/dist/esm/inventory/typen.d.ts +156 -2
  59. package/dist/esm/inventory/varianten.d.ts +67 -0
  60. package/dist/esm/inventory/varianten.js +142 -0
  61. package/dist/esm/inventory/vertrag.d.ts +40 -5
  62. package/dist/esm/inventory/vertrag.js +50 -2
  63. package/dist/esm/inventory/webhook.d.ts +5 -2
  64. package/dist/esm/inventory/webhook.js +9 -3
  65. package/dist/esm/invoice/endpunkte.d.ts +6 -0
  66. package/dist/esm/invoice/endpunkte.js +13 -2
  67. package/dist/esm/pos/texte.d.ts +11 -6
  68. package/dist/esm/pos/texte.js +11 -6
  69. package/dist/esm/stored/vokabular.d.ts +1 -1
  70. package/dist/esm/stored/vokabular.js +1 -1
  71. package/dist/esm/version.d.ts +1 -1
  72. package/dist/esm/version.js +1 -1
  73. package/fixtures/hobex-hps-codes.json +1 -1
  74. package/fixtures/invoice-api.schema.json +1 -1
  75. package/fixtures/invoice-texts.json +1 -1
  76. package/fixtures/pos-texts.json +1 -1
  77. package/fixtures/surface.json +85 -6
  78. package/fixtures/v3/antworten/belege.json +1 -1
  79. package/fixtures/v3/antworten/belegmail.json +1 -1
  80. package/fixtures/v3/antworten/kasse-belege.json +1 -1
  81. package/fixtures/v3/antworten/kasse.json +2 -2
  82. package/fixtures/v3/antworten/lager.json +2396 -4
  83. package/fixtures/v3/antworten/rechnungen.json +1 -1
  84. package/fixtures/v3/antworten/storno.json +1 -1
  85. package/fixtures/v3/stored/belege.json +1 -1
  86. package/fixtures/v3/stored/kasse.json +2 -2
  87. package/fixtures/v3/stored/rechnungen.json +1 -1
  88. package/fixtures/v3/v3-vokabular.json +151 -6
  89. package/fixtures/v3/zahlbetrag-faelle.json +1 -1
  90. 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
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
3
+ * reservieren, Varianten): 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, 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';
7
+ import type { AddVariantRequest, CreateVariantGroupRequest, UpdateVariantGroupRequest, VariantGroup, VariantGroupListQuery, VariantGroupPage, 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. */
@@ -57,5 +57,13 @@ export interface InventoryClient {
57
57
  getReservation(reservationId: string): Promise<Reservation>;
58
58
  listReservations(query?: ReservationListQuery): Promise<ReservationPage>;
59
59
  iterateReservations(query?: ReservationListQuery): AsyncGenerator<Reservation, void, undefined>;
60
+ createVariantGroup(request: CreateVariantGroupRequest): Promise<VariantGroup>;
61
+ /** Name, Vorgaben, neue Werte; oder `active: false` (Gruppe und alle Varianten stilllegen, endgueltig). */
62
+ updateVariantGroup(request: UpdateVariantGroupRequest): Promise<VariantGroup>;
63
+ /** Eine Variante mehr; Antwort: der Artikel wie `createArticle`. */
64
+ addVariant(request: AddVariantRequest): Promise<Article>;
65
+ getVariantGroup(variantGroupId: string): Promise<VariantGroup>;
66
+ listVariantGroups(query?: VariantGroupListQuery): Promise<VariantGroupPage>;
67
+ iterateVariantGroups(query?: VariantGroupListQuery): AsyncGenerator<VariantGroup, void, undefined>;
60
68
  }
61
69
  export declare function createInventoryClient(options: InventoryClientOptions): InventoryClient;
@@ -1,12 +1,13 @@
1
1
  /**
2
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
3
+ * reservieren, Varianten): 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
9
  import { changeStockCondition, createArticle, createReservation, deactivateArticle, extendReservation, getReservation, iterateReservations, listReservations, previewGoodsReceipt, receiveGoods, recordStockLoss, releaseReservation, reverseStockMovement, transferStock, updateArticle, } from './schreiben.js';
10
+ import { addVariant, createVariantGroup, getVariantGroup, iterateVariantGroups, listVariantGroups, updateVariantGroup, } from './varianten.js';
10
11
  export function createInventoryClient(options) {
11
12
  const rufen = createTransport({
12
13
  auth: inventoryKeyAuth({ apiKey: options.apiKey }),
@@ -47,5 +48,11 @@ export function createInventoryClient(options) {
47
48
  getReservation: (id) => getReservation(rufen, id),
48
49
  listReservations: (q) => listReservations(rufen, q),
49
50
  iterateReservations: (q) => iterateReservations(rufen, q),
51
+ createVariantGroup: (r) => createVariantGroup(rufen, r),
52
+ updateVariantGroup: (r) => updateVariantGroup(rufen, r),
53
+ addVariant: (r) => addVariant(rufen, r),
54
+ getVariantGroup: (id) => getVariantGroup(rufen, id),
55
+ listVariantGroups: (q) => listVariantGroups(rufen, q),
56
+ iterateVariantGroups: (q) => iterateVariantGroups(rufen, q),
50
57
  };
51
58
  }
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Die Aufrufe der Lager-API: Artikel, Standorte, Bestand und Bewegungen
3
3
  * lesen, Konto-Webhooks verwalten (Backend Stufe 5a). Die schreibenden
4
- * Aufrufe (Stufe 5b) stehen in `schreiben.ts` und teilen die Helfer hier.
4
+ * Aufrufe (Stufe 5b) stehen in `schreiben.ts`, die Variantengruppen (Stufe 5c)
5
+ * in `varianten.ts`; beide teilen die Helfer hier.
5
6
  *
6
7
  * Jede Funktion nimmt den Transport als ersten Parameter und ist einzeln
7
8
  * importierbar; die Fassade [createInventoryClient] bindet ihn nur einmal.
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Die Aufrufe der Lager-API: Artikel, Standorte, Bestand und Bewegungen
3
3
  * lesen, Konto-Webhooks verwalten (Backend Stufe 5a). Die schreibenden
4
- * Aufrufe (Stufe 5b) stehen in `schreiben.ts` und teilen die Helfer hier.
4
+ * Aufrufe (Stufe 5b) stehen in `schreiben.ts`, die Variantengruppen (Stufe 5c)
5
+ * in `varianten.ts`; beide teilen die Helfer hier.
5
6
  *
6
7
  * Jede Funktion nimmt den Transport als ersten Parameter und ist einzeln
7
8
  * importierbar; die Fassade [createInventoryClient] bindet ihn nur einmal.
@@ -2,7 +2,8 @@
2
2
  * `@kreiseck/kasseneck-api/inventory` – die Lager-API: Artikel, Standorte,
3
3
  * Bestand und Lagerprotokoll lesen, Konto-Webhooks verwalten und eingehende
4
4
  * Zustellungen pruefen (Backend Stufe 5a); Artikel anlegen und aendern,
5
- * Bestand buchen und Ware reservieren (Stufe 5b, seit 1.5.0).
5
+ * Bestand buchen und Ware reservieren (Stufe 5b, seit 1.5.0);
6
+ * Variantengruppen (Stufe 5c, seit 1.6.0).
6
7
  *
7
8
  * Ein eigener Unterpfad wie `invoice`: der `api_key` eines Kontos gehoert auf
8
9
  * einen **Server** (etwa das Backend eines Online-Shops) und soll nicht
@@ -16,6 +17,7 @@ export { inventoryKeyAuth, type InventoryKeyAuthOptions } from './auth.js';
16
17
  export { isInventoryError, isInventoryErrorCode, inventoryErrorCode, inventoryFieldErrors, inventoryRetryAfterSec, inventoryShortfalls, isInventoryWarningCode, type InventoryApiErrorCode, type InventoryFieldError, } from './fehler.js';
17
18
  export { createWebhook, deleteWebhook, getArticle, getStock, iterateArticles, iterateStock, iterateStockMovements, listArticles, listLocations, listStock, listStockMovements, listWebhookDeliveries, listWebhooks, lookupArticleByCode, rotateWebhookSecret, sendWebhookTest, updateWebhook, } from './endpunkte.js';
18
19
  export { changeStockCondition, createArticle, createReservation, deactivateArticle, extendReservation, getReservation, iterateReservations, listReservations, previewGoodsReceipt, receiveGoods, recordStockLoss, releaseReservation, reverseStockMovement, transferStock, updateArticle, } from './schreiben.js';
20
+ export { addVariant, createVariantGroup, getVariantGroup, iterateVariantGroups, listVariantGroups, updateVariantGroup, } from './varianten.js';
19
21
  export { verifyInventoryWebhookSignature, parseInventoryWebhookEvent, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_EVENT_HEADER, WEBHOOK_DELIVERY_HEADER, WEBHOOK_TOLERANCE_SEC, type VerifyInventoryWebhookOptions, } from './webhook.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';
22
+ export type { AddVariantRequest, Article, ArticleInput, ArticleListQuery, ArticleLookup, ArticlePage, ChangeStockConditionRequest, CreateArticleRequest, CreateInventoryWebhookOptions, CreateReservationRequest, CreateVariantGroupRequest, 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, UpdateVariantGroupRequest, VariantAttribute, VariantGroup, VariantGroupDefaults, VariantGroupDefaultsInput, VariantGroupListQuery, VariantGroupMember, VariantGroupPage, VariantInput, } from './typen.js';
23
+ 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, VARIANT_ATTRIBUTES_MAX, VARIANT_VALUES_MAX, VARIANT_MATRIX_MAX, VARIANT_GROUP_ACTIVE_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';
@@ -2,7 +2,8 @@
2
2
  * `@kreiseck/kasseneck-api/inventory` – die Lager-API: Artikel, Standorte,
3
3
  * Bestand und Lagerprotokoll lesen, Konto-Webhooks verwalten und eingehende
4
4
  * Zustellungen pruefen (Backend Stufe 5a); Artikel anlegen und aendern,
5
- * Bestand buchen und Ware reservieren (Stufe 5b, seit 1.5.0).
5
+ * Bestand buchen und Ware reservieren (Stufe 5b, seit 1.5.0);
6
+ * Variantengruppen (Stufe 5c, seit 1.6.0).
6
7
  *
7
8
  * Ein eigener Unterpfad wie `invoice`: der `api_key` eines Kontos gehoert auf
8
9
  * einen **Server** (etwa das Backend eines Online-Shops) und soll nicht
@@ -16,5 +17,6 @@ export { inventoryKeyAuth } from './auth.js';
16
17
  export { isInventoryError, isInventoryErrorCode, inventoryErrorCode, inventoryFieldErrors, inventoryRetryAfterSec, inventoryShortfalls, isInventoryWarningCode, } from './fehler.js';
17
18
  export { createWebhook, deleteWebhook, getArticle, getStock, iterateArticles, iterateStock, iterateStockMovements, listArticles, listLocations, listStock, listStockMovements, listWebhookDeliveries, listWebhooks, lookupArticleByCode, rotateWebhookSecret, sendWebhookTest, updateWebhook, } from './endpunkte.js';
18
19
  export { changeStockCondition, createArticle, createReservation, deactivateArticle, extendReservation, getReservation, iterateReservations, listReservations, previewGoodsReceipt, receiveGoods, recordStockLoss, releaseReservation, reverseStockMovement, transferStock, updateArticle, } from './schreiben.js';
20
+ export { addVariant, createVariantGroup, getVariantGroup, iterateVariantGroups, listVariantGroups, updateVariantGroup, } from './varianten.js';
19
21
  export { verifyInventoryWebhookSignature, parseInventoryWebhookEvent, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_EVENT_HEADER, WEBHOOK_DELIVERY_HEADER, WEBHOOK_TOLERANCE_SEC, } from './webhook.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';
22
+ 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, VARIANT_ATTRIBUTES_MAX, VARIANT_VALUES_MAX, VARIANT_MATRIX_MAX, VARIANT_GROUP_ACTIVE_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, GoodsReceiptPreviewLine, InventoryShortfall, InventoryWebhook, InventoryWebhookDelivery, InventoryWebhookTestDelivery, Location, Reservation, StockBelowMinimumEventData, StockChangedEventData, StockLevel, StockMovement, StockOperation, StockValue } from './typen.js';
15
+ import type { Article, GoodsReceiptPreviewLine, InventoryShortfall, InventoryWebhook, InventoryWebhookDelivery, InventoryWebhookTestDelivery, Location, Reservation, StockBelowMinimumEventData, StockChangedEventData, StockLevel, StockMovement, StockOperation, StockValue, VariantGroup } 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 {
@@ -38,6 +38,12 @@ export declare function vorschauZeile(ort: Ort, w: unknown): GoodsReceiptPreview
38
38
  export declare function reservierung(ort: Ort, w: unknown): Reservation;
39
39
  /** Die fehlenden Positionen aus `insufficient_available` (`data.details[]`); ein kaputter Eintrag faellt weg. */
40
40
  export declare function fehlmengen(roh: unknown): InventoryShortfall[];
41
+ /**
42
+ * Eine Variantengruppe. `attributes` und `variants` sind zugesagte Listen:
43
+ * fehlen sie, ist die Antwort kaputt (eine leere Liste hiesse „keine Merkmale“
44
+ * bzw. „keine Varianten“).
45
+ */
46
+ export declare function variantengruppe(ort: Ort, w: unknown): VariantGroup;
41
47
  /** Eine zugesagte Liste `data.<feld>`, Eintrag fuer Eintrag gelesen. */
42
48
  export declare function liste<T>(name: string, daten: unknown, feld: string, lesen: (ort: Ort, e: unknown) => T): T[];
43
49
  /** Der Cursor der naechsten Seite; `null` am Ende. Etwas anderes als Text oder `null` ist kaputt. */
@@ -381,6 +381,80 @@ export function fehlmengen(roh) {
381
381
  }
382
382
  return raus;
383
383
  }
384
+ // ---- Varianten (Stufe 5c) ------------------------------------------------------------
385
+ /** Eine Liste von Texten (Werte eines Merkmals); etwas anderes ist kaputt. */
386
+ function textliste(ort, feld, w) {
387
+ if (!Array.isArray(w) || !w.every((x) => typeof x === 'string')) {
388
+ throw antwortfehler(ort.name, `Antwort ist unbrauchbar (data.${ort.pfad}.${feld} ist keine Liste von Texten)`);
389
+ }
390
+ return [...w];
391
+ }
392
+ function merkmal(ort, w) {
393
+ const m = eintrag(ort, w);
394
+ return { key: kennung(ort, 'key', m.key), label: typeof m.label === 'string' ? m.label : '', values: textliste(ort, 'values', m.values) };
395
+ }
396
+ /**
397
+ * Vorgaben einer Gruppe: nur die Felder, die der Server sendet. Ein Preis als
398
+ * Bruchzahl ist kaputt (er fuellte sonst jede neue Variante falsch), ein Feld
399
+ * mit fremdem Typ ebenso.
400
+ */
401
+ function vorgaben(ort, w) {
402
+ if (w === undefined || w === null)
403
+ return {};
404
+ const v = objekt(w);
405
+ const vOrt = { name: ort.name, pfad: `${ort.pfad}.defaults` };
406
+ if (!v)
407
+ throw antwortfehler(ort.name, `Antwort ist unbrauchbar (data.${vOrt.pfad} ist kein Objekt)`);
408
+ const raus = {};
409
+ if (v.unitPriceCents !== undefined && v.unitPriceCents !== null)
410
+ raus.unitPriceCents = ganzzahl(vOrt, 'unitPriceCents', v.unitPriceCents);
411
+ if (v.vatRate !== undefined && v.vatRate !== null) {
412
+ if (typeof v.vatRate !== 'number' || !Number.isFinite(v.vatRate))
413
+ throw antwortfehler(ort.name, `Antwort enthaelt keinen USt-Satz (data.${vOrt.pfad}.vatRate)`);
414
+ raus.vatRate = v.vatRate;
415
+ }
416
+ for (const feld of ['unit', 'groupId']) {
417
+ const t = v[feld];
418
+ if (t === undefined || t === null)
419
+ continue;
420
+ if (typeof t !== 'string')
421
+ throw antwortfehler(ort.name, `Antwort ist unbrauchbar (data.${vOrt.pfad}.${feld} ist kein Text)`);
422
+ raus[feld] = t;
423
+ }
424
+ if (v.stockTracked !== undefined && v.stockTracked !== null) {
425
+ if (typeof v.stockTracked !== 'boolean')
426
+ throw antwortfehler(ort.name, `Antwort ist unbrauchbar (data.${vOrt.pfad}.stockTracked ist kein Wahrheitswert)`);
427
+ raus.stockTracked = v.stockTracked;
428
+ }
429
+ return raus;
430
+ }
431
+ function mitglied(ort, w) {
432
+ const x = eintrag(ort, w);
433
+ return { articleId: kennung(ort, 'articleId', x.articleId), variantAttributes: textAbbildung(x.variantAttributes) ?? {} };
434
+ }
435
+ /**
436
+ * Eine Variantengruppe. `attributes` und `variants` sind zugesagte Listen:
437
+ * fehlen sie, ist die Antwort kaputt (eine leere Liste hiesse „keine Merkmale“
438
+ * bzw. „keine Varianten“).
439
+ */
440
+ export function variantengruppe(ort, w) {
441
+ const g = eintrag(ort, w);
442
+ for (const feld of ['attributes', 'variants']) {
443
+ if (!Array.isArray(g[feld]))
444
+ throw antwortfehler(ort.name, `Antwort ist unbrauchbar (data.${ort.pfad}.${feld} ist keine Liste)`);
445
+ }
446
+ const unter = (feld, i) => ({ name: ort.name, pfad: `${ort.pfad}.${feld}[${i}]` });
447
+ return {
448
+ id: kennung(ort, 'id', g.id),
449
+ name: text(g.name),
450
+ attributes: g.attributes.map((m, i) => merkmal(unter('attributes', i), m)),
451
+ defaults: vorgaben(ort, g.defaults),
452
+ active: g.active !== false,
453
+ variants: g.variants.map((x, i) => mitglied(unter('variants', i), x)),
454
+ createdAt: text(g.createdAt),
455
+ updatedAt: text(g.updatedAt),
456
+ };
457
+ }
384
458
  // ---- Listen ------------------------------------------------------------------
385
459
  /** Eine zugesagte Liste `data.<feld>`, Eintrag fuer Eintrag gelesen. */
386
460
  export function liste(name, daten, feld, lesen) {
@@ -23,9 +23,33 @@
23
23
  * **Wiederholen:** nach einem Zeitlimit oder Netzfehler denselben Aufruf mit
24
24
  * **demselben** `idempotencyKey` noch einmal senden. Er wirkt genau einmal und
25
25
  * liefert die gespeicherte Antwort; ein neuer Schluessel buchte ein zweites Mal.
26
+ * Darum meldet jeder schreibende Aufruf in diesen Faellen (auch HTTP 5xx und
27
+ * unlesbare Antwort) `outcome: 'unknown'`, nie `'rejected'`. Lesen und der
28
+ * Probelauf (`previewGoodsReceipt`) bleiben `'rejected'`.
26
29
  */
27
- import type { InternerTransport } from '../client/aufrufe.js';
30
+ import type { ApiCall, InternerTransport } from '../client/aufrufe.js';
28
31
  import type { Article, ChangeStockConditionRequest, CreateArticleRequest, CreateReservationRequest, DeactivateArticleRequest, ExtendReservationRequest, GoodsReceiptPreview, GoodsReceiptPreviewRequest, ReceiveGoodsRequest, RecordStockLossRequest, ReleaseReservationRequest, Reservation, ReservationListQuery, ReservationPage, ReverseStockMovementRequest, StockOperation, TransferStockRequest, UpdateArticleRequest } from './typen.js';
32
+ type Params = Record<string, unknown>;
33
+ /** Die Anfrage als flache Kopie ohne `undefined`; der Aufrufer behaelt sein Objekt. Paketintern, auch fuer `varianten.ts`. */
34
+ export declare function anfrage(name: ApiCall, request: unknown): Params;
35
+ /**
36
+ * `idempotencyKey`: Text mit 1–120 Zeichen, nicht nur Leerraum. Er wird nie
37
+ * getrimmt oder gekuerzt: ein veraenderter Schluessel waere ein anderer.
38
+ */
39
+ export declare function schluessel(name: ApiCall, p: Params, { pflicht }: {
40
+ pflicht: boolean;
41
+ }): void;
42
+ /** Eine Ganzzahl (Tausendstel, Cent, Mikro-Euro); fehlt sie, nur wenn sie darf. `null` nur, wo es leert. */
43
+ export declare function ganz(name: ApiCall, feld: string, w: unknown, { pflicht, leerbar }?: {
44
+ pflicht?: boolean | undefined;
45
+ leerbar?: boolean | undefined;
46
+ }): void;
47
+ /**
48
+ * Zahlenfelder eines Artikels; `null` leert sie (bzw. heisst bei der Anlage
49
+ * „nicht angegeben“). `praefix` nennt die Stelle in der Anfrage (`variants[2].`).
50
+ */
51
+ export declare function artikelZahlen(name: ApiCall, p: Params, praefix?: string): void;
52
+ export declare const artikelAus: (name: ApiCall, daten: unknown) => Article;
29
53
  /**
30
54
  * Legt einen Artikel an. Mit `ean` ein Fremdartikel mit diesem Code (gueltige
31
55
  * Pruefziffer, frei im Konto), sonst vergibt der Server den naechsten eigenen
@@ -81,3 +105,4 @@ export declare function getReservation(transport: InternerTransport, reservation
81
105
  export declare function listReservations(transport: InternerTransport, query?: ReservationListQuery): Promise<ReservationPage>;
82
106
  /** Alle Reservierungen der Abfrage, Seite fuer Seite ueber `nextCursor`. */
83
107
  export declare function iterateReservations(transport: InternerTransport, query?: ReservationListQuery): AsyncGenerator<Reservation, void, undefined>;
108
+ export {};
@@ -23,13 +23,16 @@
23
23
  * **Wiederholen:** nach einem Zeitlimit oder Netzfehler denselben Aufruf mit
24
24
  * **demselben** `idempotencyKey` noch einmal senden. Er wirkt genau einmal und
25
25
  * liefert die gespeicherte Antwort; ein neuer Schluessel buchte ein zweites Mal.
26
+ * Darum meldet jeder schreibende Aufruf in diesen Faellen (auch HTTP 5xx und
27
+ * unlesbare Antwort) `outcome: 'unknown'`, nie `'rejected'`. Lesen und der
28
+ * Probelauf (`previewGoodsReceipt`) bleiben `'rejected'`.
26
29
  */
27
30
  import { abfrage, anfragefehler, kennung, seitenweise } from './endpunkte.js';
28
31
  import { artikel, liste, naechsterCursor, objekt, reservierung, vorgang, vorschauZeile } from './lesen.js';
29
32
  import { INVENTORY_IDEMPOTENCY_KEY_MAX, RESERVATION_MINUTES_MAX, RESERVATION_MINUTES_MIN } from './vertrag.js';
30
33
  // ---- Pruefung vor dem Senden ------------------------------------------------------
31
- /** Die Anfrage als flache Kopie ohne `undefined`; der Aufrufer behaelt sein Objekt. */
32
- function anfrage(name, request) {
34
+ /** Die Anfrage als flache Kopie ohne `undefined`; der Aufrufer behaelt sein Objekt. Paketintern, auch fuer `varianten.ts`. */
35
+ export function anfrage(name, request) {
33
36
  if (request === null || typeof request !== 'object' || Array.isArray(request)) {
34
37
  throw anfragefehler(name, 'Anfrage muss ein Objekt sein');
35
38
  }
@@ -43,7 +46,7 @@ function anfrage(name, request) {
43
46
  * `idempotencyKey`: Text mit 1–120 Zeichen, nicht nur Leerraum. Er wird nie
44
47
  * getrimmt oder gekuerzt: ein veraenderter Schluessel waere ein anderer.
45
48
  */
46
- function schluessel(name, p, { pflicht }) {
49
+ export function schluessel(name, p, { pflicht }) {
47
50
  const w = p.idempotencyKey;
48
51
  if (w === undefined || w === null) {
49
52
  if (pflicht) {
@@ -58,7 +61,7 @@ function schluessel(name, p, { pflicht }) {
58
61
  }
59
62
  }
60
63
  /** Eine Ganzzahl (Tausendstel, Cent, Mikro-Euro); fehlt sie, nur wenn sie darf. `null` nur, wo es leert. */
61
- function ganz(name, feld, w, { pflicht = false, leerbar = false } = {}) {
64
+ export function ganz(name, feld, w, { pflicht = false, leerbar = false } = {}) {
62
65
  if (w === undefined || (w === null && leerbar)) {
63
66
  if (pflicht)
64
67
  throw anfragefehler(name, `${feld} fehlt`);
@@ -104,19 +107,22 @@ function positionen(name, w, { pflicht, menge }, weiter = () => { }) {
104
107
  });
105
108
  }
106
109
  // ---- Artikel ------------------------------------------------------------------
107
- /** Zahlenfelder eines Artikels; `null` leert sie (bzw. heisst bei der Anlage „nicht angegeben“). */
108
- function artikelZahlen(name, p) {
110
+ /**
111
+ * Zahlenfelder eines Artikels; `null` leert sie (bzw. heisst bei der Anlage
112
+ * „nicht angegeben“). `praefix` nennt die Stelle in der Anfrage (`variants[2].`).
113
+ */
114
+ export function artikelZahlen(name, p, praefix = '') {
109
115
  for (const feld of ['unitPriceCents', 'minStock', 'purchasePriceMicros'])
110
- ganz(name, feld, p[feld], { leerbar: true });
116
+ ganz(name, `${praefix}${feld}`, p[feld], { leerbar: true });
111
117
  const jeStandort = p.minStockByLocation;
112
118
  if (jeStandort === undefined || jeStandort === null)
113
119
  return;
114
120
  if (typeof jeStandort !== 'object' || Array.isArray(jeStandort))
115
- throw anfragefehler(name, 'minStockByLocation muss ein Objekt { standort: Tausendstel } sein');
121
+ throw anfragefehler(name, `${praefix}minStockByLocation muss ein Objekt { standort: Tausendstel } sein`);
116
122
  for (const [standort, w] of Object.entries(jeStandort))
117
- ganz(name, `minStockByLocation.${standort}`, w, { leerbar: true });
123
+ ganz(name, `${praefix}minStockByLocation.${standort}`, w, { leerbar: true });
118
124
  }
119
- const artikelAus = (name, daten) => artikel({ name, pfad: 'article' }, objekt(daten)?.article);
125
+ export const artikelAus = (name, daten) => artikel({ name, pfad: 'article' }, objekt(daten)?.article);
120
126
  /**
121
127
  * Legt einen Artikel an. Mit `ean` ein Fremdartikel mit diesem Code (gueltige
122
128
  * Pruefziffer, frei im Konto), sonst vergibt der Server den naechsten eigenen
@@ -197,7 +203,9 @@ export async function previewGoodsReceipt(transport, request) {
197
203
  delete p.idempotencyKey;
198
204
  schluessel(name, p, { pflicht: false });
199
205
  eingangZahlen(name, p);
200
- const daten = await transport(name, { ...p, dryRun: true });
206
+ // Ein Probelauf schreibt nichts: nach einem Zeitlimit bleibt er `rejected`,
207
+ // obwohl `receiveGoods` sonst Wirkung hat.
208
+ const daten = await transport(name, { ...p, dryRun: true }, undefined, undefined, { hasEffect: false });
201
209
  return { preview: liste(name, daten, 'preview', vorschauZeile) };
202
210
  }
203
211
  const stueckPositionen = (name, p) => positionen(name, p.items, { pflicht: true, menge: 'pflicht' });