@kreiseck/kasseneck-api 1.16.0 → 1.17.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 (70) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/cjs/client/receipts.js +8 -0
  3. package/dist/cjs/client/reports.d.ts +10 -9
  4. package/dist/cjs/client/reports.js +10 -9
  5. package/dist/cjs/index.d.ts +1 -1
  6. package/dist/cjs/models/voucher.d.ts +46 -4
  7. package/dist/cjs/models/voucher.js +58 -11
  8. package/dist/cjs/pos/artikel.d.ts +9 -0
  9. package/dist/cjs/pos/artikel.js +1 -0
  10. package/dist/cjs/pos/gutschein.d.ts +107 -2
  11. package/dist/cjs/pos/gutschein.js +124 -4
  12. package/dist/cjs/pos/index.d.ts +1 -1
  13. package/dist/cjs/pos/index.js +7 -3
  14. package/dist/cjs/pos/texte.d.ts +39 -0
  15. package/dist/cjs/pos/texte.js +22 -0
  16. package/dist/cjs/receipt/due.d.ts +20 -9
  17. package/dist/cjs/receipt/due.js +1 -0
  18. package/dist/cjs/receipt/gutschein-plan.d.ts +23 -7
  19. package/dist/cjs/receipt/gutschein-plan.js +67 -2
  20. package/dist/cjs/receipt/index.d.ts +1 -1
  21. package/dist/cjs/stored/draht.js +10 -2
  22. package/dist/cjs/stored/vokabular.d.ts +1 -1
  23. package/dist/cjs/stored/vokabular.js +84 -3
  24. package/dist/cjs/version.d.ts +1 -1
  25. package/dist/cjs/version.js +1 -1
  26. package/dist/esm/client/receipts.js +8 -0
  27. package/dist/esm/client/reports.d.ts +10 -9
  28. package/dist/esm/client/reports.js +10 -9
  29. package/dist/esm/index.d.ts +1 -1
  30. package/dist/esm/models/voucher.d.ts +46 -4
  31. package/dist/esm/models/voucher.js +56 -11
  32. package/dist/esm/pos/artikel.d.ts +9 -0
  33. package/dist/esm/pos/artikel.js +1 -0
  34. package/dist/esm/pos/gutschein.d.ts +107 -2
  35. package/dist/esm/pos/gutschein.js +123 -3
  36. package/dist/esm/pos/index.d.ts +1 -1
  37. package/dist/esm/pos/index.js +2 -2
  38. package/dist/esm/pos/texte.d.ts +39 -0
  39. package/dist/esm/pos/texte.js +22 -0
  40. package/dist/esm/receipt/due.d.ts +20 -9
  41. package/dist/esm/receipt/due.js +1 -0
  42. package/dist/esm/receipt/gutschein-plan.d.ts +23 -7
  43. package/dist/esm/receipt/gutschein-plan.js +68 -3
  44. package/dist/esm/receipt/index.d.ts +1 -1
  45. package/dist/esm/stored/draht.js +10 -2
  46. package/dist/esm/stored/vokabular.d.ts +1 -1
  47. package/dist/esm/stored/vokabular.js +84 -3
  48. package/dist/esm/version.d.ts +1 -1
  49. package/dist/esm/version.js +1 -1
  50. package/fixtures/hobex-hps-codes.json +1 -1
  51. package/fixtures/invoice-api.schema.json +1 -1
  52. package/fixtures/invoice-texts.json +1 -1
  53. package/fixtures/pos-texts.json +43 -2
  54. package/fixtures/receipt-due-voucher-generated.json +485 -483
  55. package/fixtures/surface.json +17 -1
  56. package/fixtures/v3/README.md +8 -1
  57. package/fixtures/v3/antworten/belege.json +27 -12
  58. package/fixtures/v3/antworten/belegmail.json +4 -1
  59. package/fixtures/v3/antworten/berichte.json +151 -0
  60. package/fixtures/v3/antworten/kasse-belege.json +27 -12
  61. package/fixtures/v3/antworten/kasse.json +366 -9
  62. package/fixtures/v3/antworten/lager.json +1 -1
  63. package/fixtures/v3/antworten/rechnungen.json +4 -1
  64. package/fixtures/v3/antworten/storno.json +4 -1
  65. package/fixtures/v3/stored/belege.json +4 -1
  66. package/fixtures/v3/stored/kasse.json +2 -2
  67. package/fixtures/v3/stored/rechnungen.json +4 -1
  68. package/fixtures/v3/v3-vokabular.json +417 -10
  69. package/fixtures/v3/zahlbetrag-faelle.json +29 -10
  70. package/package.json +1 -1
@@ -4,7 +4,7 @@
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.KATALOGE = exports.ARTIKEL_FELDER = exports.SCHEMAS = exports.VOKABULAR_QUELLE = void 0;
6
6
  /** Fingerabdruck des Vertrags-Exports, aus dem diese Datei stammt (`_quelle.sha256`). */
7
- exports.VOKABULAR_QUELLE = "d11de425770bc431be9766199e4c9b3e712eb8e0eea84658f771a0f79d98e90e";
7
+ exports.VOKABULAR_QUELLE = "3088cb472f3fef3ed4ff969bf0d37d051363714096616a9263270c58266bde14";
8
8
  /** Schema je Endpunkt (aussen -> innen) und Wertverweise auf die Kataloge. */
9
9
  exports.SCHEMAS = {
10
10
  "getReceipt": {
@@ -54,9 +54,12 @@ exports.SCHEMAS = {
54
54
  "faceValueCents": "nennwertCents",
55
55
  "quantity": "stueck",
56
56
  "articleName": "artikelName",
57
+ "typeId": "sorteId",
58
+ "typeName": "sorteName",
57
59
  "validity": {
58
60
  "__": "gueltigkeit",
59
61
  "pattern": "muster",
62
+ "redeemableYears": "jahre",
60
63
  "redeemableUntil": "einloesbarBis",
61
64
  "refundableUntil": "rueckzahlbarBis",
62
65
  "validUntil": "gueltigBis"
@@ -204,20 +207,72 @@ exports.SCHEMAS = {
204
207
  "vouchers": {
205
208
  "__": "gutscheine",
206
209
  "sale": "verkauf",
210
+ "typeSale": "sortenVerkauf",
207
211
  "valueVoucherType": "wertArt",
208
212
  "vatRateBp": "satzBp",
209
213
  "label": {
210
214
  "__": "etikett",
211
215
  "size": "groesse",
216
+ "rotation": "drehung",
212
217
  "fields": {
213
218
  "__": "felder",
214
219
  "business": "betrieb",
215
220
  "value": "wert",
216
221
  "validity": "gueltigkeit",
217
- "checkPage": "pruefseite"
222
+ "checkPage": "pruefseite",
223
+ "designation": "bezeichnung"
218
224
  },
219
225
  "freeText": "freitext"
220
- }
226
+ },
227
+ "labelDefault": {
228
+ "__": "etikettStandard",
229
+ "size": "groesse",
230
+ "rotation": "drehung",
231
+ "fields": {
232
+ "__": "felder",
233
+ "business": "betrieb",
234
+ "value": "wert",
235
+ "validity": "gueltigkeit",
236
+ "checkPage": "pruefseite",
237
+ "designation": "bezeichnung"
238
+ },
239
+ "freeText": "freitext"
240
+ },
241
+ "types": [
242
+ {
243
+ "__": "sorten",
244
+ "kind": "art",
245
+ "vatRateBp": "satzBp",
246
+ "amount": {
247
+ "__": "betrag",
248
+ "mode": "modus"
249
+ },
250
+ "validity": {
251
+ "__": "gueltigkeit",
252
+ "pattern": "muster",
253
+ "years": "jahre"
254
+ },
255
+ "payout": "auszahlung",
256
+ "label": {
257
+ "__": "etikett",
258
+ "size": "groesse",
259
+ "rotation": "drehung",
260
+ "fields": {
261
+ "__": "felder",
262
+ "business": "betrieb",
263
+ "value": "wert",
264
+ "validity": "gueltigkeit",
265
+ "checkPage": "pruefseite",
266
+ "designation": "bezeichnung"
267
+ },
268
+ "freeText": "freitext"
269
+ },
270
+ "order": "reihenfolge",
271
+ "active": "aktiv",
272
+ "soldCount": "verkauft"
273
+ }
274
+ ],
275
+ "serviceArticles": "leistungsArtikel"
221
276
  }
222
277
  },
223
278
  "werte": {
@@ -272,6 +327,18 @@ exports.SCHEMAS = {
272
327
  "vouchers.valueVoucherType": {
273
328
  "mehrzweck": "multi_purpose",
274
329
  "einzweck": "single_purpose"
330
+ },
331
+ "vouchers.types[].kind": {
332
+ "$catalog": "GUTSCHEIN_ART"
333
+ },
334
+ "vouchers.types[].amount.mode": {
335
+ "$catalog": "GUTSCHEIN_BETRAG_MODUS"
336
+ },
337
+ "vouchers.types[].validity.pattern": {
338
+ "$catalog": "GUTSCHEIN_SORTE_MUSTER"
339
+ },
340
+ "vouchers.types[].payout": {
341
+ "$catalog": "GUTSCHEIN_AUSZAHLUNG"
275
342
  }
276
343
  }
277
344
  },
@@ -282,6 +349,7 @@ exports.SCHEMAS = {
282
349
  "__": "articles",
283
350
  "quantityRule": "mengenregel",
284
351
  "askQuantity": "mengeFragen",
352
+ "serviceVoucher": "gutscheinLeistung",
285
353
  "maxQuantity": "maxMenge",
286
354
  "tile": {
287
355
  "__": "kasse",
@@ -324,6 +392,7 @@ exports.ARTIKEL_FELDER = [
324
392
  "askQuantity",
325
393
  "maxQuantity",
326
394
  "revenueGroupId",
395
+ "serviceVoucher",
327
396
  "active",
328
397
  "groupId",
329
398
  "tile",
@@ -484,11 +553,23 @@ exports.KATALOGE = {
484
553
  "leistung": "service",
485
554
  "aktion": "promotion"
486
555
  },
556
+ "GUTSCHEIN_AUSZAHLUNG": {
557
+ "erlaubt": "allowed",
558
+ "nie": "never"
559
+ },
560
+ "GUTSCHEIN_BETRAG_MODUS": {
561
+ "frei": "free",
562
+ "fix": "fixed"
563
+ },
487
564
  "GUTSCHEIN_MUSTER": {
488
565
  "unbefristet": "unlimited",
489
566
  "1+3": "1+3",
490
567
  "frei": "custom"
491
568
  },
569
+ "GUTSCHEIN_SORTE_MUSTER": {
570
+ "unbefristet": "unlimited",
571
+ "jahre": "years"
572
+ },
492
573
  "KASSE_BETRIEB_WERTE.cardProvider": {
493
574
  "keiner": "none",
494
575
  "extern": "external",
@@ -4,4 +4,4 @@
4
4
  * Client-Version, Nachtrag §6). Ein Test haelt sie gleich mit `package.json`;
5
5
  * beim Anheben der Version beide Stellen aendern.
6
6
  */
7
- export declare const PACKAGE_VERSION = "1.16.0";
7
+ export declare const PACKAGE_VERSION = "1.17.1";
@@ -7,4 +7,4 @@ exports.PACKAGE_VERSION = void 0;
7
7
  * Client-Version, Nachtrag §6). Ein Test haelt sie gleich mit `package.json`;
8
8
  * beim Anheben der Version beide Stellen aendern.
9
9
  */
10
- exports.PACKAGE_VERSION = '1.16.0';
10
+ exports.PACKAGE_VERSION = '1.17.1';
@@ -1,4 +1,5 @@
1
1
  import { ReceiptType, KeckPaymentMethod, CreditCardProvider, VoucherAction, VoucherType, } from '../enums/index.js';
2
+ import { istWertVerkauf } from '../models/voucher.js';
2
3
  import { fromReceiptCompanyPayload, fromReceiptPayload, toReceiptItemPayload, toVoucherPayload, receiptItemIsValid, voucherIsValid, isNewFormVoucher, voucherServerFields, fromReceiptSummaryPayload, isCancellationReason, isReturnDisposition, RETURN_DISPOSITIONS, isTipRefundSource, TIP_REFUND_SOURCES, RECEIPT_EMAIL_VIAS, readRegistrationInfo, } from '../models/index.js';
3
4
  import { RECEIPT_OUTPUT_ENTRIES_MAX, RECEIPT_OUTPUT_KINDS, RECEIPT_OUTPUT_RESULTS, receiptOutputsFromWire, } from '../models/receipt-output.js';
4
5
  import { VoucherCode } from '@kreiseck/validator';
@@ -122,6 +123,13 @@ export function createReceiptParams(options) {
122
123
  if (typ.value === ReceiptType.training.value && vouchers.some(isNewFormVoucher)) {
123
124
  throw eingabefehler('Gutscheine der neuen Form gibt es nicht auf Schulungsbelegen (receiptType training).');
124
125
  }
126
+ // Gutscheine Stufe 4b: ein Wertgutschein nur ueber eine Sorte, die Sorte nur an einem solchen Verkauf.
127
+ if (vouchers.some((voucher) => istWertVerkauf(voucher) && voucher.typeId == null)) {
128
+ throw eingabefehler('voucher_type_required: Ein Mehrzweck- oder Einzweckgutschein wird nur ueber eine Gutschein-Sorte verkauft (typeId aus getKasseSettings vouchers.types).');
129
+ }
130
+ if (vouchers.some((voucher) => voucher.typeId != null && !istWertVerkauf(voucher))) {
131
+ throw eingabefehler('voucher_invalid: typeId gehoert nur an den Verkauf eines Mehrzweck- oder Einzweckgutscheins.');
132
+ }
125
133
  if (vouchers.some((voucher) => !voucherIsValid(voucher))) {
126
134
  throw eingabefehler('Ungueltiger Gutschein uebergeben.');
127
135
  }
@@ -1,16 +1,17 @@
1
1
  import { type Receipt, type ReceiptCompany, type ReportMonth } from '../models/index.js';
2
2
  import type { InternerBinaerTransport, InternerTransport } from './aufrufe.js';
3
3
  /**
4
- * Bericht-Downloads — Zwilling von `downloadDailyReport`/`downloadMonthlyReport`
5
- * in kasseneck_api/lib/kasseneck_api.dart (Zeilen 113-128).
4
+ * Bericht-Downloads — Zwilling von `getCashregisterReport`,
5
+ * `downloadDailyReport` und `downloadMonthlyReport` in
6
+ * kasseneck_api/lib/kasseneck_api.dart.
6
7
  *
7
- * **Beide liefern ein PDF, also Binaerdaten.** Das Flutter-Vorbild liest die
8
- * Antwort als Zeichenkette und nimmt davon `codeUnits`; in JavaScript waere das
9
- * schlicht falsch — `response.text()` deutet die Bytes als UTF-8 und ersetzt
10
- * jedes Byte ueber 0x7F durch U+FFFD. Ein so "heruntergeladener" Tagesbericht
11
- * liesse sich in keinem Betrachter oeffnen. Dieses Paket weicht daher bewusst
12
- * ab: es liest `arrayBuffer()` und liefert `Uint8Array` (siehe
13
- * [createBinaryTransport] in transport.ts).
8
+ * **Alle drei liefern ein PDF, also Binaerdaten.** `response.text()` waere hier
9
+ * falsch: es deutet die Bytes als UTF-8 und ersetzt jedes Byte ueber 0x7F
10
+ * durch U+FFFD, ein so "heruntergeladener" Bericht liesse sich in keinem
11
+ * Betrachter oeffnen. Gelesen wird `arrayBuffer()`, geliefert `Uint8Array`;
12
+ * eine Ablehnung mit HTTP 200 und Huelle (`period_not_closed`) wird zum Fehler
13
+ * (siehe [createBinaryTransport] in transport.ts). Der Dart-Zwilling reichte
14
+ * sie bis 11.8.0 als PDF durch und prueft seit 11.8.1 ebenso die ersten Bytes.
14
15
  *
15
16
  * **Kassen-Benutzer-Weg (`registerUserAuth`, Browser-Kasse):** Keiner der
16
17
  * beiden Download-Endpunkte setzt `allowRegisterUser`; sie funktionieren nur
@@ -2,16 +2,17 @@ import { fromReceiptCompanyPayload, fromReceiptPayload, } from '../models/index.
2
2
  import { toViennaWallClock } from '../vienna-time.js';
3
3
  import { KasseneckValidationError } from './errors.js';
4
4
  /**
5
- * Bericht-Downloads — Zwilling von `downloadDailyReport`/`downloadMonthlyReport`
6
- * in kasseneck_api/lib/kasseneck_api.dart (Zeilen 113-128).
5
+ * Bericht-Downloads — Zwilling von `getCashregisterReport`,
6
+ * `downloadDailyReport` und `downloadMonthlyReport` in
7
+ * kasseneck_api/lib/kasseneck_api.dart.
7
8
  *
8
- * **Beide liefern ein PDF, also Binaerdaten.** Das Flutter-Vorbild liest die
9
- * Antwort als Zeichenkette und nimmt davon `codeUnits`; in JavaScript waere das
10
- * schlicht falsch — `response.text()` deutet die Bytes als UTF-8 und ersetzt
11
- * jedes Byte ueber 0x7F durch U+FFFD. Ein so "heruntergeladener" Tagesbericht
12
- * liesse sich in keinem Betrachter oeffnen. Dieses Paket weicht daher bewusst
13
- * ab: es liest `arrayBuffer()` und liefert `Uint8Array` (siehe
14
- * [createBinaryTransport] in transport.ts).
9
+ * **Alle drei liefern ein PDF, also Binaerdaten.** `response.text()` waere hier
10
+ * falsch: es deutet die Bytes als UTF-8 und ersetzt jedes Byte ueber 0x7F
11
+ * durch U+FFFD, ein so "heruntergeladener" Bericht liesse sich in keinem
12
+ * Betrachter oeffnen. Gelesen wird `arrayBuffer()`, geliefert `Uint8Array`;
13
+ * eine Ablehnung mit HTTP 200 und Huelle (`period_not_closed`) wird zum Fehler
14
+ * (siehe [createBinaryTransport] in transport.ts). Der Dart-Zwilling reichte
15
+ * sie bis 11.8.0 als PDF durch und prueft seit 11.8.1 ebenso die ersten Bytes.
15
16
  *
16
17
  * **Kassen-Benutzer-Weg (`registerUserAuth`, Browser-Kasse):** Keiner der
17
18
  * beiden Download-Endpunkte setzt `allowRegisterUser`; sie funktionieren nur
@@ -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, isVoucherItem, isVoucherFloatItem, type Voucher, type VoucherArticle, type IssuedVoucher, type VoucherPayload, toVoucherPayload, fromVoucherPayload, voucherIsValid, type Receipt, type RegistrationInfo, type ReceiptPayload, type ReceiptPayloadRead, toReceiptPayload, fromReceiptPayload, receiptSubSumCents, receiptSumCents, receiptValueVoucherSign, 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, RECEIPT_OUTPUT_KINDS, type ReceiptOutputKind, RECEIPT_OUTPUT_LOG_KINDS, type ReceiptOutputLogKind, RECEIPT_OUTPUT_RESULTS, type ReceiptOutputResult, RECEIPT_OUTPUT_ENTRIES_MAX, type ReceiptOutput, type ReceiptOutputActor, RECEIPT_OUTPUT_ENTRY_ERROR_CODES, type ReceiptOutputEntryErrorCode, RECEIPT_OUTPUT_ERROR_CODES, type ReceiptOutputErrorCode, isReceiptOutputErrorCode, receiptOutputErrorCode, isReceiptOutputError, receiptOutputFieldErrors, type ReceiptOutputFieldError, type ReceiptErrorCode, type ReceiptFieldError, RECEIPT_ERROR_CODES, isReceiptErrorCode, receiptErrorCode, isReceiptError, receiptFieldErrors, remainingQuantities, TIP_REFUND_SOURCES, type TipRefundSource, isTipRefundSource, openStaffTipCents, cancellationItemsForTip, cancellationCashRefundCents, asksTipRefundSource, asksRefundTip, type ReceiptCompany, type ReceiptCompanyPayload, fromReceiptCompanyPayload, receiptCompanyTaxInfo, type Cashregister, type CashregisterOnboarding, type CashregisterPayload, type CashregisterOnboardingPayload, type CashregisterAutoLogout, type CashregisterAutoLogoutPayload, 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
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, type KasseneckPdfOrDataTransport, type PdfOrData, ALL_CALLS, type ApiCall, PUBLIC_CALLS, POS_CALLS, UNKNOWN_OUTCOME_CALLS, type PublicCall, type PosCall, createTransport, createBinaryTransport, createPdfOrDataTransport, 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, type ReceiptOutputEntry, type LogReceiptOutputsOptions, type LogReceiptOutputsResult, type RejectedReceiptOutput, logReceiptOutputs, downloadDailyReport, downloadMonthlyReport, getCashregisterReport, type CashregisterReportPeriod, getReportV2, type ReportV2, type ReportV2Metadata, type ReportV2Options, listReceipts, listAllReceipts, fromListReceiptsSummaryPayload, LIST_RECEIPTS_VIEWS, LIST_RECEIPTS_ORDERS, LIST_RECEIPTS_LIMIT_MAX, LIST_RECEIPTS_DAYS_MAX, LIST_ALL_RECEIPTS_MAX_PAGES, LIST_RECEIPTS_ERROR_CODES, type ListReceiptsErrorCode, type ListReceiptsView, type ListReceiptsOrder, type ListReceiptsOptions, type ListReceiptsWindow, type ListReceiptsGrossByRate, type ListReceiptsSummary, type ListReceiptsDaySummary, type ListReceiptsPage, type ListedReceipt, type CashboxStatus, type SignatureStatus, getCashboxStatus, getSignatureStatus, type KasseneckApi, createKasseneckApi, } from './client/index.js';
4
- export { type ReceiptDueTip, type ReceiptDueTipRecipient, type ReceiptDueOptions, type ReceiptDueBuckets, type ReceiptDueBreakdown, type ReceiptDueErrorReason, receiptDueCents, receiptDueBreakdown, ReceiptDueError, RECEIPT_DUE_ERROR_REASONS, isReceiptDueError, type VoucherDueInfo, type VoucherDueArticle, type VoucherRedeemContext, voucherRedeemMaxCents, VOUCHER_ZERO_RATE_BUCKET_FROM, } from './receipt/due.js';
4
+ export { type ReceiptDueTip, type ReceiptDueTipRecipient, type ReceiptDueOptions, type ReceiptDueBuckets, type ReceiptDueBreakdown, type ReceiptDueErrorReason, receiptDueCents, receiptDueBreakdown, ReceiptDueError, RECEIPT_DUE_ERROR_REASONS, isReceiptDueError, type VoucherDueInfo, type VoucherDueArticle, type VoucherDueType, type VoucherRedeemContext, voucherRedeemMaxCents, VOUCHER_ZERO_RATE_BUCKET_FROM, } 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, voucherPermsOf, } from './pos/index.js';
@@ -14,6 +14,12 @@ export interface Voucher {
14
14
  name?: string;
15
15
  code?: string;
16
16
  action: VoucherAction | string;
17
+ /**
18
+ * Art des Gutscheins. Beim Verkauf ueber eine Sorte die Art der Sorte
19
+ * (`PosVoucherType.kind`): der Server prueft sie gegen die Sorte und lehnt
20
+ * eine andere ab (`voucher_invalid`). Am Draht darf sie dort fehlen (die Art
21
+ * kommt dann aus der Sorte); ein so gelesener Wunsch geht ohne `type` hinaus.
22
+ */
17
23
  type: VoucherType | string;
18
24
  valueCents?: number;
19
25
  /** Neue Form: Betrag in Cent (Verkauf, Einloesung, Auszahlung). */
@@ -26,6 +32,18 @@ export interface Voucher {
26
32
  positions?: number[];
27
33
  /** Neue Form, Auszahlung: Grund, 1 bis 200 Zeichen. */
28
34
  reason?: string;
35
+ /**
36
+ * Neue Form, Wertgutschein verkaufen: die Gutschein-Sorte
37
+ * (`PosVoucherType.id` aus `getKasseSettings`). Pflicht fuer jeden Verkauf
38
+ * eines Mehrzweck- oder Einzweckgutscheins (Server: `voucher_type_required`),
39
+ * an jeder anderen Aktion oder Art verboten. Am gelesenen Eintrag die Sorte
40
+ * des Verkaufs (fehlt ohne Sorte).
41
+ */
42
+ typeId?: string;
43
+ /** Name der Sorte beim Verkauf (eingefroren). */
44
+ typeName?: string;
45
+ /** Auszahlung des verkauften Gutscheins (`allowed`/`never`, eingefroren). */
46
+ payout?: string;
29
47
  voucherType?: string;
30
48
  voucherId?: string;
31
49
  /** Letzte vier Zeichen des Codes; der Klartext steht nie am Beleg. */
@@ -53,8 +71,13 @@ export interface IssuedVoucher {
53
71
  quantity?: number;
54
72
  /** Nur bei Leistungsgutscheinen: Name des verkauften Artikels; sonst fehlt das Feld. */
55
73
  articleName?: string;
74
+ /** Verkauf ueber eine Sorte: ihre Kennung und ihr Name; sonst fehlen die Felder. */
75
+ typeId?: string;
76
+ typeName?: string;
56
77
  validity?: {
57
78
  pattern: string;
79
+ /** Sorte „N Jahre“: die Zahl N (Muster `1+3` fuer jedes N, die Daten gelten); fehlt sonst. */
80
+ redeemableYears?: number;
58
81
  redeemableUntil: string | null;
59
82
  refundableUntil: string | null;
60
83
  validUntil: string | null;
@@ -87,6 +110,9 @@ export interface VoucherPayload {
87
110
  quantity?: number;
88
111
  positions?: number[];
89
112
  reason?: string;
113
+ typeId?: string;
114
+ typeName?: string;
115
+ payout?: string;
90
116
  voucherType?: string;
91
117
  voucherId?: string;
92
118
  codeSuffix?: string;
@@ -100,10 +126,19 @@ export interface VoucherPayload {
100
126
  }
101
127
  /** Arten der neuen Gutscheinform (die Altwerte sind `value` und `promo`). */
102
128
  export declare const NEUE_GUTSCHEINARTEN: readonly string[];
103
- /** Gehoert der Gutschein zur neuen Form (Art oder Aktion `payout`)? */
104
- export declare function isNewFormVoucher(voucher: Pick<Voucher, 'type' | 'action'>): boolean;
105
- /** Felder, die nur der Server setzt; an einem Wunsch sind sie `voucher_invalid`. */
106
- export declare const GUTSCHEIN_SERVERFELDER: readonly ["voucherId", "codeSuffix", "zeroRateBucket", "voucherType"];
129
+ /** Gehoert der Gutschein zur neuen Form (Art, Aktion `payout` oder Verkauf ueber eine Sorte ohne Art)? */
130
+ export declare function isNewFormVoucher(voucher: Pick<Voucher, 'type' | 'action' | 'typeId'>): boolean;
131
+ /**
132
+ * Wert-Verkauf: ein Mehrzweck- oder Einzweckgutschein wird verkauft (mit Art
133
+ * oder nur ueber die Sorte). Paketintern: Zahlbetrag und Pruefung vor dem
134
+ * Senden entscheiden daran, ob eine Sorte noetig ist.
135
+ */
136
+ export declare function istWertVerkauf(voucher: Pick<Voucher, 'type' | 'action' | 'typeId'>): boolean;
137
+ /**
138
+ * Felder, die nur der Server setzt; an einem Wunsch sind sie `voucher_invalid`.
139
+ * Sortenname und Auszahlung friert der Server beim Verkauf ein (Stufe 4b).
140
+ */
141
+ export declare const GUTSCHEIN_SERVERFELDER: readonly ["voucherId", "codeSuffix", "zeroRateBucket", "voucherType", "typeName", "payout"];
107
142
  /** Welche Serverfelder tragt der Gutschein (leere Liste = keines)? */
108
143
  export declare function voucherServerFields(voucher: Voucher): string[];
109
144
  export declare function toVoucherPayload(voucher: Voucher): VoucherPayload;
@@ -115,3 +150,10 @@ export declare function toVoucherPayload(voucher: Voucher): VoucherPayload;
115
150
  */
116
151
  export declare function voucherIsValid(voucher: Voucher): boolean;
117
152
  export declare function fromVoucherPayload(payload: VoucherPayload): Voucher;
153
+ /**
154
+ * Die Form eines Wunschs der neuen Form. `sorteNoetig: false` laesst einen
155
+ * Wert-Verkauf ohne `typeId` zu: so rechnet der Zahlbetrag den Verkauf eines
156
+ * Aufrufers bis 1.16 mit der alten Gutschein-Einstellung weiter (der Server ab
157
+ * Stufe 4b antwortet darauf `voucher_type_required`). Paketintern.
158
+ */
159
+ export declare function wunschFormGueltig(v: Voucher, sorteNoetig: boolean): boolean;
@@ -8,23 +8,44 @@ export const NEUE_GUTSCHEINARTEN = [
8
8
  VoucherType.service,
9
9
  VoucherType.promotion,
10
10
  ];
11
- /** Gehoert der Gutschein zur neuen Form (Art oder Aktion `payout`)? */
11
+ /**
12
+ * Verkauf ueber eine Sorte ohne Art (`typeId` ohne `type`): die Art kommt aus
13
+ * der Sorte. Zwilling von `gutschein-beleg.istSortenVerkauf`.
14
+ */
15
+ function istSortenVerkaufOhneArt(voucher) {
16
+ return voucher.action === VoucherAction.sell && voucher.type == null && voucher.typeId != null;
17
+ }
18
+ /** Gehoert der Gutschein zur neuen Form (Art, Aktion `payout` oder Verkauf ueber eine Sorte ohne Art)? */
12
19
  export function isNewFormVoucher(voucher) {
13
- return NEUE_GUTSCHEINARTEN.includes(voucher.type) || voucher.action === VoucherAction.payout;
20
+ return NEUE_GUTSCHEINARTEN.includes(voucher.type) || voucher.action === VoucherAction.payout || istSortenVerkaufOhneArt(voucher);
21
+ }
22
+ /**
23
+ * Wert-Verkauf: ein Mehrzweck- oder Einzweckgutschein wird verkauft (mit Art
24
+ * oder nur ueber die Sorte). Paketintern: Zahlbetrag und Pruefung vor dem
25
+ * Senden entscheiden daran, ob eine Sorte noetig ist.
26
+ */
27
+ export function istWertVerkauf(voucher) {
28
+ return voucher.action === VoucherAction.sell
29
+ && (voucher.type === VoucherType.multi_purpose || voucher.type === VoucherType.single_purpose || istSortenVerkaufOhneArt(voucher));
14
30
  }
15
- /** Felder, die nur der Server setzt; an einem Wunsch sind sie `voucher_invalid`. */
16
- export const GUTSCHEIN_SERVERFELDER = ['voucherId', 'codeSuffix', 'zeroRateBucket', 'voucherType'];
31
+ /**
32
+ * Felder, die nur der Server setzt; an einem Wunsch sind sie `voucher_invalid`.
33
+ * Sortenname und Auszahlung friert der Server beim Verkauf ein (Stufe 4b).
34
+ */
35
+ export const GUTSCHEIN_SERVERFELDER = ['voucherId', 'codeSuffix', 'zeroRateBucket', 'voucherType', 'typeName', 'payout'];
17
36
  /** Welche Serverfelder tragt der Gutschein (leere Liste = keines)? */
18
37
  export function voucherServerFields(voucher) {
19
38
  return GUTSCHEIN_SERVERFELDER.filter((feld) => voucher[feld] != null);
20
39
  }
21
40
  const NEUE_FELDER = [
22
- 'amountCents', 'articleId', 'quantity', 'positions', 'reason', 'voucherType', 'voucherId', 'codeSuffix',
41
+ 'amountCents', 'articleId', 'quantity', 'positions', 'reason', 'typeId', 'typeName', 'payout', 'voucherType', 'voucherId', 'codeSuffix',
23
42
  'vatRateBp', 'article', 'balanceAfterCents', 'remainingQuantityAfter', 'taxedWith', 'exempt', 'zeroRateBucket',
24
43
  ];
25
44
  export function toVoucherPayload(voucher) {
26
45
  const action = requireEnumKey(VoucherAction, voucher.action, 'Gutschein-Aktion');
27
- const type = requireEnumKey(VoucherType, voucher.type, 'Gutscheinart');
46
+ // Verkauf ueber eine Sorte ohne Art: `type` bleibt weg wie im Wunsch (die Art kommt aus der Sorte).
47
+ const ohneArt = istSortenVerkaufOhneArt(voucher);
48
+ const type = ohneArt ? undefined : requireEnumKey(VoucherType, voucher.type, 'Gutscheinart');
28
49
  // Felder der neuen Form gehen roh hinaus, soweit gesetzt (auch an einem
29
50
  // gelesenen Altbeleg: dort fehlen sie, die Nutzlast bleibt byte-gleich).
30
51
  const roh = voucher;
@@ -34,7 +55,7 @@ export function toVoucherPayload(voucher) {
34
55
  neu[feld] = roh[feld];
35
56
  return {
36
57
  action,
37
- type,
58
+ ...(ohneArt ? {} : { type }),
38
59
  // Die neue Form kennt kein `valueCents`; nur ein gelesener Eintrag (die
39
60
  // Auszahlung steht beim Server als Wert mit Cent) traegt es weiter.
40
61
  ...(isNewFormVoucher(voucher) && voucher.valueCents == null ? {} : { valueCents: voucher.valueCents ?? null }),
@@ -87,11 +108,13 @@ export function fromVoucherPayload(payload) {
87
108
  : payload.value != null
88
109
  ? euroToCents(payload.value)
89
110
  : undefined;
111
+ // Ein Verkaufswunsch ueber eine Sorte darf ohne Art sein: dann bleibt `type` weg (nicht `undefined`).
112
+ const ohneArt = payload.type == null && payload.action === VoucherAction.sell && payload.typeId != null;
90
113
  return {
91
114
  name: payload.name ?? undefined,
92
115
  code: payload.code ?? undefined,
93
116
  action: readEnumKey(VoucherAction, payload.action),
94
- type: readEnumKey(VoucherType, payload.type),
117
+ ...(ohneArt ? {} : { type: readEnumKey(VoucherType, payload.type) }),
95
118
  valueCents,
96
119
  ...lesenNeu(payload),
97
120
  };
@@ -112,15 +135,31 @@ const MAX_GRUND = 200;
112
135
  const istCent = (n) => typeof n === 'number' && Number.isInteger(n) && n >= 1 && n <= MAX_BETRAG_CENTS;
113
136
  const istMenge = (n) => typeof n === 'number' && Number.isInteger(n) && n >= 1 && n <= MAX_STUECK;
114
137
  const hatText = (t) => typeof t === 'string' && t.trim().length > 0;
138
+ /**
139
+ * Form einer Sorten-Kennung am Wunsch (gutschein-core.ID_MUSTER ohne den
140
+ * Ausschluss): eine reservierte `__…__` ist der Form nach gueltig, der Server
141
+ * kennt sie nur nicht (`voucher_type_not_found`), ebenso der Zahlbetrag.
142
+ */
143
+ const SORTE_ID_FORM = /^[A-Za-z0-9_-]{1,128}$/;
115
144
  /**
116
145
  * Wunsch der neuen Form sendbar? Bildet die Regeln des Servers ab: Serverfelder
117
146
  * nie, Betrag/Menge ganz und positiv, Code bei Einloesung und Auszahlung,
118
147
  * Auszahlung nur Mehrzweck/Einzweck mit Grund (1 bis 200 Zeichen), Aktion nur
119
148
  * einloesbar, Leistung braucht Artikel und Menge (Verkauf) bzw. Positionen
120
- * (Einloesung). Felder, die zu einer anderen Aktion/Art gehoeren, sind
149
+ * (Einloesung), ein Wertgutschein wird nur ueber eine Sorte verkauft
150
+ * (`typeId`). Felder, die zu einer anderen Aktion/Art gehoeren, sind
121
151
  * ebenfalls nicht erlaubt (der Server wiese sie ab).
122
152
  */
123
153
  function newFormVoucherIsValid(v) {
154
+ return wunschFormGueltig(v, true);
155
+ }
156
+ /**
157
+ * Die Form eines Wunschs der neuen Form. `sorteNoetig: false` laesst einen
158
+ * Wert-Verkauf ohne `typeId` zu: so rechnet der Zahlbetrag den Verkauf eines
159
+ * Aufrufers bis 1.16 mit der alten Gutschein-Einstellung weiter (der Server ab
160
+ * Stufe 4b antwortet darauf `voucher_type_required`). Paketintern.
161
+ */
162
+ export function wunschFormGueltig(v, sorteNoetig) {
124
163
  if (voucherServerFields(v).length > 0)
125
164
  return false;
126
165
  const r = v;
@@ -130,6 +169,14 @@ function newFormVoucherIsValid(v) {
130
169
  }
131
170
  if (v.valueCents != null)
132
171
  return false;
172
+ // Die Sorte gehoert nur an einen Wert-Verkauf (Server: sorteId sonst voucher_invalid).
173
+ if (istWertVerkauf(v)) {
174
+ if (v.typeId == null ? sorteNoetig : (typeof v.typeId !== 'string' || !SORTE_ID_FORM.test(v.typeId)))
175
+ return false;
176
+ return v.articleId == null && v.quantity == null && v.positions == null && v.reason == null && istCent(v.amountCents);
177
+ }
178
+ if (v.typeId != null)
179
+ return false;
133
180
  const allein = v.type === VoucherType.multi_purpose || v.type === VoucherType.single_purpose;
134
181
  if (v.action === VoucherAction.payout) {
135
182
  return allein && hatText(v.code) && istCent(v.amountCents) && hatText(v.reason) && v.reason.trim().length <= MAX_GRUND
@@ -140,8 +187,6 @@ function newFormVoucherIsValid(v) {
140
187
  if (allein) {
141
188
  if (v.articleId != null || v.quantity != null || v.positions != null)
142
189
  return false;
143
- if (v.action === VoucherAction.sell)
144
- return istCent(v.amountCents);
145
190
  if (v.action === VoucherAction.redeem)
146
191
  return hatText(v.code) && istCent(v.amountCents);
147
192
  return false;
@@ -88,6 +88,14 @@ export interface PosArticle {
88
88
  * traegt (aeltere Backends) -- dann nicht aus anderen Feldern ableiten.
89
89
  */
90
90
  stockTracked?: boolean | null;
91
+ /**
92
+ * Als Leistungsgutschein verkaufbar (Gutscheine Stufe 4b, Haken im
93
+ * Artikelstamm). Die Kachel „Leistungsgutschein“ bietet nur diese Artikel
94
+ * an; der Server verkauft einen anderen nicht (`voucher_service_not_allowed`).
95
+ * Optional wie `stockLocationIds`, der Leser setzt es immer: nur ein
96
+ * ausdrueckliches `true` gilt.
97
+ */
98
+ serviceVoucher?: boolean;
91
99
  }
92
100
  /** Deckelt eine gewuenschte Menge an der Hoechstmenge des Artikels (null = keine Grenze). */
93
101
  export declare function allowedQuantity(a: Pick<PosArticle, 'maxQuantity'>, wanted: number): number;
@@ -113,6 +121,7 @@ export interface PosArticlePayload {
113
121
  ean?: string | null;
114
122
  internalCode?: string | null;
115
123
  stockTracked?: boolean | null;
124
+ serviceVoucher?: boolean | null;
116
125
  }
117
126
  export declare function fromPosArticlePayload(p: PosArticlePayload): PosArticle;
118
127
  /**
@@ -71,6 +71,7 @@ export function fromPosArticlePayload(p) {
71
71
  ean: textOderNull(p.ean),
72
72
  internalCode: textOderNull(p.internalCode),
73
73
  stockTracked: typeof p.stockTracked === 'boolean' ? p.stockTracked : null,
74
+ serviceVoucher: p.serviceVoucher === true,
74
75
  };
75
76
  }
76
77
  /**