@kreiseck/kasseneck-api 1.11.0 → 1.12.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 (187) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +2 -1
  3. package/dist/cjs/client/aufrufe.d.ts +4 -4
  4. package/dist/cjs/client/aufrufe.js +15 -0
  5. package/dist/cjs/client/receipts.d.ts +5 -0
  6. package/dist/cjs/client/receipts.js +65 -6
  7. package/dist/cjs/enums/voucher-action.d.ts +2 -0
  8. package/dist/cjs/enums/voucher-action.js +2 -0
  9. package/dist/cjs/enums/voucher-type.d.ts +10 -0
  10. package/dist/cjs/enums/voucher-type.js +10 -0
  11. package/dist/cjs/index.d.ts +3 -3
  12. package/dist/cjs/index.js +9 -3
  13. package/dist/cjs/models/index.d.ts +3 -3
  14. package/dist/cjs/models/index.js +7 -2
  15. package/dist/cjs/models/receipt-errors.d.ts +1 -1
  16. package/dist/cjs/models/receipt-errors.js +2 -0
  17. package/dist/cjs/models/receipt-item.d.ts +11 -3
  18. package/dist/cjs/models/receipt-item.js +22 -1
  19. package/dist/cjs/models/receipt.d.ts +31 -1
  20. package/dist/cjs/models/receipt.js +45 -5
  21. package/dist/cjs/models/voucher.d.ts +57 -4
  22. package/dist/cjs/models/voucher.js +111 -3
  23. package/dist/cjs/partner/fehler.d.ts +1 -1
  24. package/dist/cjs/partner/fehler.js +2 -0
  25. package/dist/cjs/partner/index.d.ts +1 -1
  26. package/dist/cjs/partner/typen.d.ts +7 -1
  27. package/dist/cjs/partner/typen.js +3 -0
  28. package/dist/cjs/pos/client.d.ts +2 -1
  29. package/dist/cjs/pos/client.js +3 -1
  30. package/dist/cjs/pos/gutschein.d.ts +90 -0
  31. package/dist/cjs/pos/gutschein.js +164 -0
  32. package/dist/cjs/pos/index.d.ts +3 -2
  33. package/dist/cjs/pos/index.js +13 -2
  34. package/dist/cjs/pos/settings.d.ts +3 -0
  35. package/dist/cjs/pos/settings.js +12 -10
  36. package/dist/cjs/pos/texte.d.ts +156 -0
  37. package/dist/cjs/pos/texte.js +72 -1
  38. package/dist/cjs/react/index.js +8 -2
  39. package/dist/cjs/receipt/due.d.ts +83 -2
  40. package/dist/cjs/receipt/due.js +202 -36
  41. package/dist/cjs/receipt/grid.js +13 -1
  42. package/dist/cjs/receipt/gutschein-plan.d.ts +104 -0
  43. package/dist/cjs/receipt/gutschein-plan.js +360 -0
  44. package/dist/cjs/receipt/index.d.ts +1 -1
  45. package/dist/cjs/receipt/index.js +3 -0
  46. package/dist/cjs/receipt/layout.js +186 -10
  47. package/dist/cjs/register/pairing.d.ts +21 -1
  48. package/dist/cjs/register/pairing.js +17 -0
  49. package/dist/cjs/stored/bon-layout.d.ts +8 -0
  50. package/dist/cjs/stored/bon-layout.js +23 -0
  51. package/dist/cjs/stored/draht.d.ts +3 -1
  52. package/dist/cjs/stored/draht.js +53 -6
  53. package/dist/cjs/stored/einstellungen.js +2 -1
  54. package/dist/cjs/stored/gutscheine.d.ts +3 -0
  55. package/dist/cjs/stored/gutscheine.js +60 -0
  56. package/dist/cjs/stored/index.js +2 -17
  57. package/dist/cjs/stored/vokabular.d.ts +6 -4
  58. package/dist/cjs/stored/vokabular.js +48 -2
  59. package/dist/cjs/version.d.ts +1 -1
  60. package/dist/cjs/version.js +1 -1
  61. package/dist/esm/client/aufrufe.d.ts +4 -4
  62. package/dist/esm/client/aufrufe.js +15 -0
  63. package/dist/esm/client/receipts.d.ts +5 -0
  64. package/dist/esm/client/receipts.js +66 -8
  65. package/dist/esm/enums/voucher-action.d.ts +2 -0
  66. package/dist/esm/enums/voucher-action.js +2 -0
  67. package/dist/esm/enums/voucher-type.d.ts +10 -0
  68. package/dist/esm/enums/voucher-type.js +10 -0
  69. package/dist/esm/index.d.ts +3 -3
  70. package/dist/esm/index.js +3 -3
  71. package/dist/esm/models/index.d.ts +3 -3
  72. package/dist/esm/models/index.js +3 -3
  73. package/dist/esm/models/receipt-errors.d.ts +1 -1
  74. package/dist/esm/models/receipt-errors.js +2 -0
  75. package/dist/esm/models/receipt-item.d.ts +11 -3
  76. package/dist/esm/models/receipt-item.js +20 -1
  77. package/dist/esm/models/receipt.d.ts +31 -1
  78. package/dist/esm/models/receipt.js +44 -5
  79. package/dist/esm/models/voucher.d.ts +57 -4
  80. package/dist/esm/models/voucher.js +108 -3
  81. package/dist/esm/partner/fehler.d.ts +1 -1
  82. package/dist/esm/partner/fehler.js +2 -0
  83. package/dist/esm/partner/index.d.ts +1 -1
  84. package/dist/esm/partner/typen.d.ts +7 -1
  85. package/dist/esm/partner/typen.js +3 -0
  86. package/dist/esm/pos/client.d.ts +2 -1
  87. package/dist/esm/pos/client.js +3 -1
  88. package/dist/esm/pos/gutschein.d.ts +90 -0
  89. package/dist/esm/pos/gutschein.js +158 -0
  90. package/dist/esm/pos/index.d.ts +3 -2
  91. package/dist/esm/pos/index.js +4 -2
  92. package/dist/esm/pos/settings.d.ts +3 -0
  93. package/dist/esm/pos/settings.js +2 -0
  94. package/dist/esm/pos/texte.d.ts +156 -0
  95. package/dist/esm/pos/texte.js +70 -0
  96. package/dist/esm/react/index.js +8 -2
  97. package/dist/esm/receipt/due.d.ts +83 -2
  98. package/dist/esm/receipt/due.js +198 -34
  99. package/dist/esm/receipt/grid.js +13 -1
  100. package/dist/esm/receipt/gutschein-plan.d.ts +104 -0
  101. package/dist/esm/receipt/gutschein-plan.js +352 -0
  102. package/dist/esm/receipt/index.d.ts +1 -1
  103. package/dist/esm/receipt/index.js +1 -1
  104. package/dist/esm/receipt/layout.js +187 -11
  105. package/dist/esm/register/pairing.d.ts +21 -1
  106. package/dist/esm/register/pairing.js +16 -0
  107. package/dist/esm/stored/bon-layout.d.ts +8 -0
  108. package/dist/esm/stored/bon-layout.js +20 -0
  109. package/dist/esm/stored/draht.d.ts +3 -1
  110. package/dist/esm/stored/draht.js +52 -6
  111. package/dist/esm/stored/einstellungen.js +3 -2
  112. package/dist/esm/stored/gutscheine.d.ts +3 -0
  113. package/dist/esm/stored/gutscheine.js +56 -0
  114. package/dist/esm/stored/index.js +2 -17
  115. package/dist/esm/stored/vokabular.d.ts +6 -4
  116. package/dist/esm/stored/vokabular.js +48 -2
  117. package/dist/esm/version.d.ts +1 -1
  118. package/dist/esm/version.js +1 -1
  119. package/fixtures/expected/voucher-cancellation.grid32.txt +30 -0
  120. package/fixtures/expected/voucher-cancellation.grid48.txt +29 -0
  121. package/fixtures/expected/voucher-cancellation.lines.json +252 -0
  122. package/fixtures/expected/voucher-cancellation.sheet32.json +206 -0
  123. package/fixtures/expected/voucher-cancellation.sheet48.json +200 -0
  124. package/fixtures/expected/voucher-multi-purpose-redeem.grid32.txt +25 -0
  125. package/fixtures/expected/voucher-multi-purpose-redeem.grid48.txt +25 -0
  126. package/fixtures/expected/voucher-multi-purpose-redeem.lines.json +259 -0
  127. package/fixtures/expected/voucher-multi-purpose-redeem.sheet32.json +176 -0
  128. package/fixtures/expected/voucher-multi-purpose-redeem.sheet48.json +176 -0
  129. package/fixtures/expected/voucher-multi-purpose-sale.grid32.txt +24 -0
  130. package/fixtures/expected/voucher-multi-purpose-sale.grid48.txt +23 -0
  131. package/fixtures/expected/voucher-multi-purpose-sale.lines.json +216 -0
  132. package/fixtures/expected/voucher-multi-purpose-sale.sheet32.json +170 -0
  133. package/fixtures/expected/voucher-multi-purpose-sale.sheet48.json +164 -0
  134. package/fixtures/expected/voucher-payout.grid32.txt +23 -0
  135. package/fixtures/expected/voucher-payout.grid48.txt +22 -0
  136. package/fixtures/expected/voucher-payout.lines.json +216 -0
  137. package/fixtures/expected/voucher-payout.sheet32.json +164 -0
  138. package/fixtures/expected/voucher-payout.sheet48.json +158 -0
  139. package/fixtures/expected/voucher-service-redeem.grid32.txt +26 -0
  140. package/fixtures/expected/voucher-service-redeem.grid48.txt +25 -0
  141. package/fixtures/expected/voucher-service-redeem.lines.json +261 -0
  142. package/fixtures/expected/voucher-service-redeem.sheet32.json +182 -0
  143. package/fixtures/expected/voucher-service-redeem.sheet48.json +176 -0
  144. package/fixtures/expected/voucher-single-purpose-redeem-exempt.grid32.txt +30 -0
  145. package/fixtures/expected/voucher-single-purpose-redeem-exempt.grid48.txt +29 -0
  146. package/fixtures/expected/voucher-single-purpose-redeem-exempt.lines.json +331 -0
  147. package/fixtures/expected/voucher-single-purpose-redeem-exempt.sheet32.json +206 -0
  148. package/fixtures/expected/voucher-single-purpose-redeem-exempt.sheet48.json +200 -0
  149. package/fixtures/expected/voucher-single-purpose-redeem.grid32.txt +25 -0
  150. package/fixtures/expected/voucher-single-purpose-redeem.grid48.txt +24 -0
  151. package/fixtures/expected/voucher-single-purpose-redeem.lines.json +246 -0
  152. package/fixtures/expected/voucher-single-purpose-redeem.sheet32.json +176 -0
  153. package/fixtures/expected/voucher-single-purpose-redeem.sheet48.json +170 -0
  154. package/fixtures/expected/voucher-single-purpose-sale.grid32.txt +26 -0
  155. package/fixtures/expected/voucher-single-purpose-sale.grid48.txt +24 -0
  156. package/fixtures/expected/voucher-single-purpose-sale.lines.json +225 -0
  157. package/fixtures/expected/voucher-single-purpose-sale.sheet32.json +182 -0
  158. package/fixtures/expected/voucher-single-purpose-sale.sheet48.json +170 -0
  159. package/fixtures/hobex-hps-codes.json +1 -1
  160. package/fixtures/invoice-api.schema.json +1 -1
  161. package/fixtures/invoice-texts.json +1 -1
  162. package/fixtures/manifest.json +64 -0
  163. package/fixtures/pos-texts.json +170 -1
  164. package/fixtures/receipt-due-generated.json +1 -1
  165. package/fixtures/receipt-due-voucher-generated.json +494 -0
  166. package/fixtures/receipts/voucher-cancellation.json +76 -0
  167. package/fixtures/receipts/voucher-multi-purpose-redeem.json +62 -0
  168. package/fixtures/receipts/voucher-multi-purpose-sale.json +63 -0
  169. package/fixtures/receipts/voucher-payout.json +65 -0
  170. package/fixtures/receipts/voucher-service-redeem.json +82 -0
  171. package/fixtures/receipts/voucher-single-purpose-redeem-exempt.json +86 -0
  172. package/fixtures/receipts/voucher-single-purpose-redeem.json +71 -0
  173. package/fixtures/receipts/voucher-single-purpose-sale.json +88 -0
  174. package/fixtures/surface.json +35 -5
  175. package/fixtures/v3/antworten/belege.json +3405 -3
  176. package/fixtures/v3/antworten/belegmail.json +5 -2
  177. package/fixtures/v3/antworten/kasse-belege.json +3423 -3
  178. package/fixtures/v3/antworten/kasse.json +621 -14
  179. package/fixtures/v3/antworten/lager.json +1 -1
  180. package/fixtures/v3/antworten/rechnungen.json +5 -2
  181. package/fixtures/v3/antworten/storno.json +214 -3
  182. package/fixtures/v3/stored/belege.json +5 -2
  183. package/fixtures/v3/stored/kasse.json +225 -4
  184. package/fixtures/v3/stored/rechnungen.json +5 -2
  185. package/fixtures/v3/v3-vokabular.json +1375 -23
  186. package/fixtures/v3/zahlbetrag-faelle.json +293 -3
  187. package/package.json +4 -1
@@ -36,7 +36,7 @@ export interface ReceiptItem {
36
36
  * negative Entgeltminderungen je Steuersatz; die Kennzeichnung steuert nur
37
37
  * die Bon-Darstellung (Summenzeile mit Aufteilung), nie die Beträge.
38
38
  */
39
- kind?: 'tip' | 'discount';
39
+ kind?: 'tip' | 'discount' | 'voucher' | 'voucher_float';
40
40
  /** Empfaenger der Trinkgeld-Position; `null` = nicht zugeordnet. */
41
41
  recipient?: TipRecipient | null;
42
42
  /** Zahlart der Trinkgeld-Position (kann von der des Belegs abweichen). */
@@ -73,6 +73,14 @@ export interface TipRecipient {
73
73
  export declare function isTipItem(item: ReceiptItem | ReceiptItemPayloadRead): boolean;
74
74
  /** Rabatt-Position? Die eine Erkennungsstelle — niemand prueft `kind` selbst. */
75
75
  export declare function isDiscountItem(item: ReceiptItem | ReceiptItemPayloadRead): boolean;
76
+ /**
77
+ * Gutschein-Position (Server, neue Gutscheinform)? `voucher` ist eine
78
+ * Einloesung oder ein Verkauf mit Umsatzsteuer-Wirkung, siehe
79
+ * [isVoucherFloatItem] fuer den durchlaufenden Posten.
80
+ */
81
+ export declare function isVoucherItem(item: ReceiptItem | ReceiptItemPayloadRead): boolean;
82
+ /** Gutschein-Position als durchlaufender Posten (Mehrzweck: Verkauf, Auszahlung)? */
83
+ export declare function isVoucherFloatItem(item: ReceiptItem | ReceiptItemPayloadRead): boolean;
76
84
  /**
77
85
  * Nutzlast-Form, die dieses Paket **schreibt** (v2):
78
86
  * `{ name, quantity, unitPriceCents, vatRate }`.
@@ -82,8 +90,8 @@ export interface ReceiptItemPayload {
82
90
  quantity: number;
83
91
  unitPriceCents: number;
84
92
  vatRate: number;
85
- /** Trinkgeld-/Rabatt-Kennzeichnung, siehe [ReceiptItem.kind]. */
86
- kind?: 'tip' | 'discount';
93
+ /** Trinkgeld-/Rabatt-/Gutschein-Kennzeichnung, siehe [ReceiptItem.kind]. */
94
+ kind?: 'tip' | 'discount' | 'voucher' | 'voucher_float';
87
95
  recipient?: TipRecipient | null;
88
96
  paymentMethod?: string;
89
97
  receivedImmediately?: boolean;
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isTipItem = isTipItem;
4
4
  exports.isDiscountItem = isDiscountItem;
5
+ exports.isVoucherItem = isVoucherItem;
6
+ exports.isVoucherFloatItem = isVoucherFloatItem;
5
7
  exports.toReceiptItemPayload = toReceiptItemPayload;
6
8
  exports.fromReceiptItemPayload = fromReceiptItemPayload;
7
9
  exports.receiptItemTotalCents = receiptItemTotalCents;
@@ -18,6 +20,18 @@ function isTipItem(item) {
18
20
  function isDiscountItem(item) {
19
21
  return item != null && item.kind === 'discount';
20
22
  }
23
+ /**
24
+ * Gutschein-Position (Server, neue Gutscheinform)? `voucher` ist eine
25
+ * Einloesung oder ein Verkauf mit Umsatzsteuer-Wirkung, siehe
26
+ * [isVoucherFloatItem] fuer den durchlaufenden Posten.
27
+ */
28
+ function isVoucherItem(item) {
29
+ return item != null && item.kind === 'voucher';
30
+ }
31
+ /** Gutschein-Position als durchlaufender Posten (Mehrzweck: Verkauf, Auszahlung)? */
32
+ function isVoucherFloatItem(item) {
33
+ return item != null && item.kind === 'voucher_float';
34
+ }
21
35
  function toReceiptItemPayload(item) {
22
36
  // Schreibpfad bleibt streng: ein unaufgeloester (unbekannter) Steuersatz
23
37
  // darf nicht unbesehen wieder hinausgehen.
@@ -46,6 +60,11 @@ function toReceiptItemPayload(item) {
46
60
  // am Bon wieder als gewoehnliche Warenzeile mit "1 x" an.
47
61
  if (item.kind === 'discount')
48
62
  nutzlast.kind = 'discount';
63
+ // Gutschein-Positionen (vom Server) reisen mit: der Cache der Kasse schreibt
64
+ // gelesene Belege wieder, und ein Wunsch an den Server traegt sie nie
65
+ // (createReceipt weist sie als voucher_invalid ab).
66
+ if (item.kind === 'voucher' || item.kind === 'voucher_float')
67
+ nutzlast.kind = item.kind;
49
68
  // Artikel-Verweis reist mit (Erloesgruppen im Bericht); leere Werte nicht.
50
69
  if (item.articleId != null && item.articleId !== '')
51
70
  nutzlast.articleId = item.articleId;
@@ -90,7 +109,9 @@ function fromReceiptItemPayload(payload) {
90
109
  }
91
110
  : payload.kind === 'discount'
92
111
  ? { kind: 'discount' }
93
- : {}),
112
+ : payload.kind === 'voucher' || payload.kind === 'voucher_float'
113
+ ? { kind: payload.kind }
114
+ : {}),
94
115
  // Artikel-Verweis erhalten (Storno-Spiegelung schreibt ihn wieder mit).
95
116
  ...(typeof payload.articleId === 'string' && payload.articleId !== '' ? { articleId: payload.articleId } : {}),
96
117
  // Lager: Bezug und Rueckgabe-Wahl einer Storno-Zeile (nur gelesen; ein
@@ -143,11 +143,41 @@ export declare function readRegistrationInfo(roh: {
143
143
  cardRegisteredAt?: unknown;
144
144
  cashregisterRegisteredAt?: unknown;
145
145
  }): RegistrationInfo;
146
+ /**
147
+ * Vorzeichen der Wertgutscheine am Beleg: am Storno-Beleg -1, sonst 1.
148
+ *
149
+ * Das Backend spiegelt Wertgutscheine beim Vollstorno mit UNVERAENDERTER
150
+ * `action` und positivem Wert (storno-core.stornoVouchers); der Fluss dreht
151
+ * sich am Storno um (zahlungen-core.wertgutscheinFlussCents, hier
152
+ * `receiptDueCents`): ein verkaufter Gutschein wird zurueckgezahlt, ein
153
+ * eingeloester mindert die Rueckzahlung.
154
+ */
155
+ export declare function receiptValueVoucherSign(receipt: Receipt): 1 | -1;
146
156
  /**
147
157
  * Zwischensumme in **Cent** — Positionen plus verkaufte Wertgutscheine minus
148
158
  * eingeloeste Promotionsgutscheine. Wertgutschein-Einloesungen wirken erst auf
149
159
  * [receiptSumCents], nicht hier (siehe Dart-Vorbild `subSumCents`/`sumCents`).
160
+ * Am Storno-Beleg zaehlen Wertgutscheine mit umgekehrtem Vorzeichen
161
+ * ([receiptValueVoucherSign]), und ein gespiegelter Promotionsgutschein
162
+ * mindert nichts: den Rabatt nimmt der Server dort ueber Ausgleichspositionen
163
+ * (`kind: 'discount'`) zurueck, und belegToepfe verteilt einen Promo-Eintrag
164
+ * nur auf eine positive Topfsumme, die ein Storno nie hat.
165
+ *
166
+ * Gutscheine der neuen Form (Spec 2026-10-14): ihr Betrag steht als Position
167
+ * (`kind: 'voucher'` bei Einzweck/Leistung, `'voucher_float'` im 0-%-Topf) und
168
+ * zaehlt hier schon mit den Positionen. Ein Eintrag mit `zeroRateBucket`
169
+ * (Server: `imNullTopf`, Mehrzweck-Verkauf ab dem Stichtag, Auszahlung) zaehlt
170
+ * darum nicht noch einmal -- sonst stuende der Betrag doppelt am Bon
171
+ * (Vorfall 16.10.2026: Verkauf ueber 30 € mit „Gesamt 60,00“). Eintraege der
172
+ * Arten `single_purpose`/`service` tragen keinen Fluss (wie
173
+ * gutschein-beleg.zahlbetrag, das nur `value`/`promo` an den Fluss gibt).
150
174
  */
151
175
  export declare function receiptSubSumCents(receipt: Receipt): number;
152
- /** Gesamtsumme in **Cent** — Zwischensumme minus eingeloeste Wertgutscheine. */
176
+ /**
177
+ * Gesamtsumme in **Cent** — Zwischensumme minus eingeloeste Wertgutscheine
178
+ * (am Storno-Beleg plus, siehe [receiptValueVoucherSign]). Zwilling von
179
+ * zahlungen-core.wertgutscheinFlussCents: eine Auszahlung (`payout`) eines
180
+ * Wertgutscheins ohne `zeroRateBucket` mindert wie eine Einloesung; mit
181
+ * `zeroRateBucket` steht sie als Position und zaehlt nur dort.
182
+ */
153
183
  export declare function receiptSumCents(receipt: Receipt): number;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.toReceiptPayload = toReceiptPayload;
4
4
  exports.fromReceiptPayload = fromReceiptPayload;
5
5
  exports.readRegistrationInfo = readRegistrationInfo;
6
+ exports.receiptValueVoucherSign = receiptValueVoucherSign;
6
7
  exports.receiptSubSumCents = receiptSubSumCents;
7
8
  exports.receiptSumCents = receiptSumCents;
8
9
  const index_js_1 = require("../enums/index.js");
@@ -134,29 +135,68 @@ function gueltigeRueckzahlungen(rueckzahlungen) {
134
135
  }
135
136
  return raus;
136
137
  }
138
+ /**
139
+ * Vorzeichen der Wertgutscheine am Beleg: am Storno-Beleg -1, sonst 1.
140
+ *
141
+ * Das Backend spiegelt Wertgutscheine beim Vollstorno mit UNVERAENDERTER
142
+ * `action` und positivem Wert (storno-core.stornoVouchers); der Fluss dreht
143
+ * sich am Storno um (zahlungen-core.wertgutscheinFlussCents, hier
144
+ * `receiptDueCents`): ein verkaufter Gutschein wird zurueckgezahlt, ein
145
+ * eingeloester mindert die Rueckzahlung.
146
+ */
147
+ function receiptValueVoucherSign(receipt) {
148
+ const typ = typeof receipt.receiptType === 'object' ? receipt.receiptType.value : receipt.receiptType;
149
+ return typ === index_js_1.ReceiptType.cancellation.value ? -1 : 1;
150
+ }
137
151
  /**
138
152
  * Zwischensumme in **Cent** — Positionen plus verkaufte Wertgutscheine minus
139
153
  * eingeloeste Promotionsgutscheine. Wertgutschein-Einloesungen wirken erst auf
140
154
  * [receiptSumCents], nicht hier (siehe Dart-Vorbild `subSumCents`/`sumCents`).
155
+ * Am Storno-Beleg zaehlen Wertgutscheine mit umgekehrtem Vorzeichen
156
+ * ([receiptValueVoucherSign]), und ein gespiegelter Promotionsgutschein
157
+ * mindert nichts: den Rabatt nimmt der Server dort ueber Ausgleichspositionen
158
+ * (`kind: 'discount'`) zurueck, und belegToepfe verteilt einen Promo-Eintrag
159
+ * nur auf eine positive Topfsumme, die ein Storno nie hat.
160
+ *
161
+ * Gutscheine der neuen Form (Spec 2026-10-14): ihr Betrag steht als Position
162
+ * (`kind: 'voucher'` bei Einzweck/Leistung, `'voucher_float'` im 0-%-Topf) und
163
+ * zaehlt hier schon mit den Positionen. Ein Eintrag mit `zeroRateBucket`
164
+ * (Server: `imNullTopf`, Mehrzweck-Verkauf ab dem Stichtag, Auszahlung) zaehlt
165
+ * darum nicht noch einmal -- sonst stuende der Betrag doppelt am Bon
166
+ * (Vorfall 16.10.2026: Verkauf ueber 30 € mit „Gesamt 60,00“). Eintraege der
167
+ * Arten `single_purpose`/`service` tragen keinen Fluss (wie
168
+ * gutschein-beleg.zahlbetrag, das nur `value`/`promo` an den Fluss gibt).
141
169
  */
142
170
  function receiptSubSumCents(receipt) {
171
+ const vz = receiptValueVoucherSign(receipt);
143
172
  let cents = receipt.items.reduce((acc, item) => acc + (0, receipt_item_js_1.receiptItemTotalCents)(item), 0);
144
173
  for (const voucher of receipt.vouchers) {
145
- if (voucher.action === index_js_1.VoucherAction.redeem && voucher.type === index_js_1.VoucherType.promo) {
174
+ if (voucher.zeroRateBucket === true)
175
+ continue;
176
+ if (vz === 1 && voucher.action === index_js_1.VoucherAction.redeem && voucher.type === index_js_1.VoucherType.promo) {
146
177
  cents -= voucher.valueCents ?? 0;
147
178
  }
148
179
  if (voucher.action === index_js_1.VoucherAction.sell && voucher.type === index_js_1.VoucherType.value) {
149
- cents += voucher.valueCents ?? 0;
180
+ cents += vz * (voucher.valueCents ?? 0);
150
181
  }
151
182
  }
152
183
  return cents;
153
184
  }
154
- /** Gesamtsumme in **Cent** — Zwischensumme minus eingeloeste Wertgutscheine. */
185
+ /**
186
+ * Gesamtsumme in **Cent** — Zwischensumme minus eingeloeste Wertgutscheine
187
+ * (am Storno-Beleg plus, siehe [receiptValueVoucherSign]). Zwilling von
188
+ * zahlungen-core.wertgutscheinFlussCents: eine Auszahlung (`payout`) eines
189
+ * Wertgutscheins ohne `zeroRateBucket` mindert wie eine Einloesung; mit
190
+ * `zeroRateBucket` steht sie als Position und zaehlt nur dort.
191
+ */
155
192
  function receiptSumCents(receipt) {
193
+ const vz = receiptValueVoucherSign(receipt);
156
194
  let cents = receiptSubSumCents(receipt);
157
195
  for (const voucher of receipt.vouchers) {
158
- if (voucher.action === index_js_1.VoucherAction.redeem && voucher.type === index_js_1.VoucherType.value) {
159
- cents -= voucher.valueCents ?? 0;
196
+ if (voucher.zeroRateBucket === true || voucher.type !== index_js_1.VoucherType.value)
197
+ continue;
198
+ if (voucher.action === index_js_1.VoucherAction.redeem || voucher.action === index_js_1.VoucherAction.payout) {
199
+ cents -= vz * (voucher.valueCents ?? 0);
160
200
  }
161
201
  }
162
202
  return cents;
@@ -16,11 +16,41 @@ export interface Voucher {
16
16
  action: VoucherAction | string;
17
17
  type: VoucherType | string;
18
18
  valueCents?: number;
19
+ /** Neue Form: Betrag in Cent (Verkauf, Einloesung, Auszahlung). */
20
+ amountCents?: number;
21
+ /** Neue Form, Leistungsgutschein: verkaufter Artikel. */
22
+ articleId?: string;
23
+ /** Neue Form, Leistungsgutschein: Menge (Verkauf) bzw. eingeloeste Menge. */
24
+ quantity?: number;
25
+ /** Neue Form, Leistungsgutschein einloesen: Indizes der Belegpositionen. */
26
+ positions?: number[];
27
+ /** Neue Form, Auszahlung: Grund, 1 bis 200 Zeichen. */
28
+ reason?: string;
29
+ voucherType?: string;
30
+ voucherId?: string;
31
+ /** Letzte vier Zeichen des Codes; der Klartext steht nie am Beleg. */
32
+ codeSuffix?: string;
33
+ vatRateBp?: number;
34
+ article?: VoucherArticle;
35
+ balanceAfterCents?: number;
36
+ remainingQuantityAfter?: number;
37
+ taxedWith?: string;
38
+ exempt?: boolean;
39
+ zeroRateBucket?: boolean;
40
+ }
41
+ /** Artikel eines Leistungsgutscheins, wie der Server ihn am Beleg festhaelt. */
42
+ export interface VoucherArticle {
43
+ id: string;
44
+ name: string;
45
+ vatRateBp: number;
46
+ priceCents: number;
19
47
  }
20
48
  /**
21
- * Nutzlast eines Gutscheins. Geschrieben wird nur `valueCents` (ganze Cent);
22
- * `value` (Euro) kommt nur beim Lesen vor: der Server legt es in seinen
23
- * Antworten daneben, gelesen wird es nur, wenn `valueCents` fehlt.
49
+ * Nutzlast eines Gutscheins. Altform: nur `valueCents` (ganze Cent); `value`
50
+ * (Euro) kommt nur beim Lesen vor: der Server legt es in seinen Antworten
51
+ * daneben, gelesen wird es nur, wenn `valueCents` fehlt. Neue Form: roh mit
52
+ * `amountCents` und den weiteren Feldern; gesetzte Feldern gehen hinaus,
53
+ * fehlende fehlen (kein `valueCents: null` an der neuen Form).
24
54
  * `name` und `code` gehen nur hinaus, wenn sie gesetzt sind.
25
55
  */
26
56
  export interface VoucherPayload {
@@ -29,8 +59,31 @@ export interface VoucherPayload {
29
59
  action: string;
30
60
  type: string;
31
61
  value?: number | null;
32
- valueCents: number | null;
62
+ valueCents?: number | null;
63
+ amountCents?: number;
64
+ articleId?: string;
65
+ quantity?: number;
66
+ positions?: number[];
67
+ reason?: string;
68
+ voucherType?: string;
69
+ voucherId?: string;
70
+ codeSuffix?: string;
71
+ vatRateBp?: number;
72
+ article?: VoucherArticle;
73
+ balanceAfterCents?: number;
74
+ remainingQuantityAfter?: number;
75
+ taxedWith?: string;
76
+ exempt?: boolean;
77
+ zeroRateBucket?: boolean;
33
78
  }
79
+ /** Arten der neuen Gutscheinform (die Altwerte sind `value` und `promo`). */
80
+ export declare const NEUE_GUTSCHEINARTEN: readonly string[];
81
+ /** Gehoert der Gutschein zur neuen Form (Art oder Aktion `payout`)? */
82
+ export declare function isNewFormVoucher(voucher: Pick<Voucher, 'type' | 'action'>): boolean;
83
+ /** Felder, die nur der Server setzt; an einem Wunsch sind sie `voucher_invalid`. */
84
+ export declare const GUTSCHEIN_SERVERFELDER: readonly ["voucherId", "codeSuffix", "zeroRateBucket", "voucherType"];
85
+ /** Welche Serverfelder tragt der Gutschein (leere Liste = keines)? */
86
+ export declare function voucherServerFields(voucher: Voucher): string[];
34
87
  export declare function toVoucherPayload(voucher: Voucher): VoucherPayload;
35
88
  /**
36
89
  * Ist der Gutschein an das Backend sendbar? Zwilling von `KeckVoucher.isValid`
@@ -1,18 +1,54 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GUTSCHEIN_SERVERFELDER = exports.NEUE_GUTSCHEINARTEN = void 0;
4
+ exports.isNewFormVoucher = isNewFormVoucher;
5
+ exports.voucherServerFields = voucherServerFields;
3
6
  exports.toVoucherPayload = toVoucherPayload;
4
7
  exports.voucherIsValid = voucherIsValid;
5
8
  exports.fromVoucherPayload = fromVoucherPayload;
6
9
  const index_js_1 = require("../enums/index.js");
7
10
  const money_js_1 = require("../money.js");
8
11
  const enum_payload_js_1 = require("./enum-payload.js");
12
+ /** Arten der neuen Gutscheinform (die Altwerte sind `value` und `promo`). */
13
+ exports.NEUE_GUTSCHEINARTEN = [
14
+ index_js_1.VoucherType.multi_purpose,
15
+ index_js_1.VoucherType.single_purpose,
16
+ index_js_1.VoucherType.service,
17
+ index_js_1.VoucherType.promotion,
18
+ ];
19
+ /** Gehoert der Gutschein zur neuen Form (Art oder Aktion `payout`)? */
20
+ function isNewFormVoucher(voucher) {
21
+ return exports.NEUE_GUTSCHEINARTEN.includes(voucher.type) || voucher.action === index_js_1.VoucherAction.payout;
22
+ }
23
+ /** Felder, die nur der Server setzt; an einem Wunsch sind sie `voucher_invalid`. */
24
+ exports.GUTSCHEIN_SERVERFELDER = ['voucherId', 'codeSuffix', 'zeroRateBucket', 'voucherType'];
25
+ /** Welche Serverfelder tragt der Gutschein (leere Liste = keines)? */
26
+ function voucherServerFields(voucher) {
27
+ return exports.GUTSCHEIN_SERVERFELDER.filter((feld) => voucher[feld] != null);
28
+ }
29
+ const NEUE_FELDER = [
30
+ 'amountCents', 'articleId', 'quantity', 'positions', 'reason', 'voucherType', 'voucherId', 'codeSuffix',
31
+ 'vatRateBp', 'article', 'balanceAfterCents', 'remainingQuantityAfter', 'taxedWith', 'exempt', 'zeroRateBucket',
32
+ ];
9
33
  function toVoucherPayload(voucher) {
34
+ const action = (0, enum_payload_js_1.requireEnumKey)(index_js_1.VoucherAction, voucher.action, 'Gutschein-Aktion');
35
+ const type = (0, enum_payload_js_1.requireEnumKey)(index_js_1.VoucherType, voucher.type, 'Gutscheinart');
36
+ // Felder der neuen Form gehen roh hinaus, soweit gesetzt (auch an einem
37
+ // gelesenen Altbeleg: dort fehlen sie, die Nutzlast bleibt byte-gleich).
38
+ const roh = voucher;
39
+ const neu = {};
40
+ for (const feld of NEUE_FELDER)
41
+ if (roh[feld] != null)
42
+ neu[feld] = roh[feld];
10
43
  return {
11
- action: (0, enum_payload_js_1.requireEnumKey)(index_js_1.VoucherAction, voucher.action, 'Gutschein-Aktion'),
12
- type: (0, enum_payload_js_1.requireEnumKey)(index_js_1.VoucherType, voucher.type, 'Gutscheinart'),
13
- valueCents: voucher.valueCents ?? null,
44
+ action,
45
+ type,
46
+ // Die neue Form kennt kein `valueCents`; nur ein gelesener Eintrag (die
47
+ // Auszahlung steht beim Server als Wert mit Cent) traegt es weiter.
48
+ ...(isNewFormVoucher(voucher) && voucher.valueCents == null ? {} : { valueCents: voucher.valueCents ?? null }),
14
49
  ...(voucher.code != null ? { code: voucher.code } : {}),
15
50
  ...(voucher.name != null ? { name: voucher.name } : {}),
51
+ ...neu,
16
52
  };
17
53
  }
18
54
  /**
@@ -22,6 +58,8 @@ function toVoucherPayload(voucher) {
22
58
  * gesetzter Wert muss positiv sein.
23
59
  */
24
60
  function voucherIsValid(voucher) {
61
+ if (isNewFormVoucher(voucher))
62
+ return newFormVoucherIsValid(voucher);
25
63
  if (voucher.type === index_js_1.VoucherType.value && voucher.valueCents == null) {
26
64
  return false;
27
65
  }
@@ -63,5 +101,75 @@ function fromVoucherPayload(payload) {
63
101
  action: (0, enum_payload_js_1.readEnumKey)(index_js_1.VoucherAction, payload.action),
64
102
  type: (0, enum_payload_js_1.readEnumKey)(index_js_1.VoucherType, payload.type),
65
103
  valueCents,
104
+ ...lesenNeu(payload),
66
105
  };
67
106
  }
107
+ /** Felder der neuen Form beim Lesen: nur was dasteht (Altbelege bleiben schlank). */
108
+ function lesenNeu(payload) {
109
+ const roh = payload;
110
+ const neu = {};
111
+ for (const feld of NEUE_FELDER)
112
+ if (roh[feld] != null)
113
+ neu[feld] = roh[feld];
114
+ return neu;
115
+ }
116
+ /** Grenzen wie der Server (gutschein-beleg): Betrag 1 bis 1.000.000 Cent, Menge 1 bis 100. */
117
+ const MAX_BETRAG_CENTS = 1_000_000;
118
+ const MAX_STUECK = 100;
119
+ const MAX_GRUND = 200;
120
+ const istCent = (n) => typeof n === 'number' && Number.isInteger(n) && n >= 1 && n <= MAX_BETRAG_CENTS;
121
+ const istMenge = (n) => typeof n === 'number' && Number.isInteger(n) && n >= 1 && n <= MAX_STUECK;
122
+ const hatText = (t) => typeof t === 'string' && t.trim().length > 0;
123
+ /**
124
+ * Wunsch der neuen Form sendbar? Bildet die Regeln des Servers ab: Serverfelder
125
+ * nie, Betrag/Menge ganz und positiv, Code bei Einloesung und Auszahlung,
126
+ * Auszahlung nur Mehrzweck/Einzweck mit Grund (1 bis 200 Zeichen), Aktion nur
127
+ * einloesbar, Leistung braucht Artikel und Menge (Verkauf) bzw. Positionen
128
+ * (Einloesung). Felder, die zu einer anderen Aktion/Art gehoeren, sind
129
+ * ebenfalls nicht erlaubt (der Server wiese sie ab).
130
+ */
131
+ function newFormVoucherIsValid(v) {
132
+ if (voucherServerFields(v).length > 0)
133
+ return false;
134
+ const r = v;
135
+ for (const feld of ['vatRateBp', 'article', 'balanceAfterCents', 'remainingQuantityAfter', 'taxedWith', 'exempt']) {
136
+ if (r[feld] != null)
137
+ return false;
138
+ }
139
+ if (v.valueCents != null)
140
+ return false;
141
+ const allein = v.type === index_js_1.VoucherType.multi_purpose || v.type === index_js_1.VoucherType.single_purpose;
142
+ if (v.action === index_js_1.VoucherAction.payout) {
143
+ return allein && hatText(v.code) && istCent(v.amountCents) && hatText(v.reason) && v.reason.trim().length <= MAX_GRUND
144
+ && v.articleId == null && v.quantity == null && v.positions == null;
145
+ }
146
+ if (v.reason != null)
147
+ return false;
148
+ if (allein) {
149
+ if (v.articleId != null || v.quantity != null || v.positions != null)
150
+ return false;
151
+ if (v.action === index_js_1.VoucherAction.sell)
152
+ return istCent(v.amountCents);
153
+ if (v.action === index_js_1.VoucherAction.redeem)
154
+ return hatText(v.code) && istCent(v.amountCents);
155
+ return false;
156
+ }
157
+ if (v.type === index_js_1.VoucherType.service) {
158
+ if (v.amountCents != null)
159
+ return false;
160
+ if (v.action === index_js_1.VoucherAction.sell) {
161
+ return hatText(v.articleId) && istMenge(v.quantity) && v.positions == null;
162
+ }
163
+ if (v.action === index_js_1.VoucherAction.redeem) {
164
+ return hatText(v.code) && Array.isArray(v.positions) && v.positions.length > 0
165
+ && v.positions.every((i) => Number.isInteger(i) && i >= 0) && new Set(v.positions).size === v.positions.length && v.articleId == null && v.quantity == null;
166
+ }
167
+ return false;
168
+ }
169
+ if (v.type === index_js_1.VoucherType.promotion) {
170
+ return v.action === index_js_1.VoucherAction.redeem && hatText(v.code)
171
+ && v.amountCents == null && v.articleId == null && v.quantity == null && v.positions == null;
172
+ }
173
+ // Altart mit neuer Aktion (payout + value/promo): nicht sendbar.
174
+ return false;
175
+ }
@@ -61,7 +61,7 @@ import { KasseneckApiError } from '../client/errors.js';
61
61
  *
62
62
  * Reihenfolge und Bestand wie im Abzug des Backends.
63
63
  */
64
- export declare const PARTNER_ERROR_CODES: readonly ["validation", "rate_limited", "app_not_found", "app_not_accepted", "live_not_allowed", "customer_exists", "customer_conflict", "customer_limit", "access_not_allowed", "email_taken", "no_email", "tax_number_missing", "fon_missing", "signature_pending", "signature_missing", "signature_unknown", "signature_ambiguous", "signature_not_ready", "signature_limit", "signature_failed", "module_inactive", "cashregister_limit", "cashregister_not_found", "contracts_pending", "kind_not_allowed", "mode_not_allowed", "power_of_attorney_missing", "not_found", "no_version", "unknown_version", "text_changed", "already_accepted", "activation_failed", "webhook_limit", "webhook_inactive", "event_not_subscribed"];
64
+ export declare const PARTNER_ERROR_CODES: readonly ["validation", "rate_limited", "app_not_found", "app_not_accepted", "live_not_allowed", "customer_exists", "customer_conflict", "customer_limit", "access_not_allowed", "email_taken", "no_email", "tax_number_missing", "fon_missing", "signature_pending", "signature_missing", "signature_unknown", "signature_ambiguous", "signature_not_ready", "signature_limit", "signature_failed", "module_inactive", "cashregister_limit", "cashregister_not_found", "contracts_pending", "kind_not_allowed", "mode_not_allowed", "power_of_attorney_missing", "not_found", "no_version", "unknown_version", "text_changed", "already_accepted", "activation_failed", "activation_in_progress", "webhook_limit", "webhook_inactive", "event_not_subscribed"];
65
65
  /**
66
66
  * Die Codes, die nur im **Partner-Portal** entstehen — beim Pflegen der App,
67
67
  * der Schluessel, der Mitglieder und der Signaturkarten.
@@ -111,6 +111,7 @@ exports.PARTNER_ERROR_CODES = [
111
111
  'text_changed',
112
112
  'already_accepted',
113
113
  'activation_failed',
114
+ 'activation_in_progress',
114
115
  // Webhooks
115
116
  'webhook_limit',
116
117
  'webhook_inactive',
@@ -218,6 +219,7 @@ const RAT = {
218
219
  text_changed: 'Der gezeigte Vertragstext hat sich seit dem Laden geaendert (data.textHash traegt die aktuell geltende Pruefsumme). Neu laden und danach erneut bestaetigen lassen.',
219
220
  already_accepted: 'Diese Fassung ist bereits bestaetigt (data.contractId). Nichts weiter zu tun.',
220
221
  activation_failed: 'Die Inbetriebnahme blieb an data.step haengen (ggf. data.rc). activateCashregister erneut aufrufen — jeder Schritt ist idempotent, der Lauf setzt an der Bruchstelle an.',
222
+ activation_in_progress: 'Die Inbetriebnahme dieser Kasse laeuft bereits. Kurz warten und den Stand abfragen, nicht erneut anstossen.',
221
223
  webhook_limit: 'Hoechstens 10 Webhook-Endpunkte je Partner. Einen ungenutzten loeschen.',
222
224
  webhook_inactive: 'Der Webhook steht auf active:false. Zuerst aktivieren, dann erneut proben.',
223
225
  event_not_subscribed: 'Der Endpunkt abonniert dieses Ereignis nicht — auch eine Probe bekommt nur, was in seiner events-Liste steht. events erweitern und erneut versuchen.',
@@ -28,6 +28,6 @@ export { getPartnerInfo, createPartnerCustomer, listPartnerCustomers, checkPartn
28
28
  export { createPartnerWebhook, listPartnerWebhooks, rotatePartnerWebhookSecret, updatePartnerWebhook, deletePartnerWebhook, sendPartnerWebhookTest, listPartnerWebhookDeliveries, parseWebhookEvent, isPartnerWebhookEvent, PARTNER_WEBHOOK_EVENTS, WEBHOOK_ENVELOPE_FIELDS, WEBHOOK_DELIVERY_STATUSES, type PartnerWebhookEvent, type PartnerWebhookEventType, type PartnerWebhook, type CreateWebhookOptions, type CreateWebhookResult, type DeleteWebhookResult, type WebhookApiVersion, type WebhookDeliveryStatus, type WebhookTestDelivery, type ContractAcceptedEventData, type SignatureFailedEventData, type CashregisterFailedEventData, type WebhookPatch, type WebhookList, type WebhookDelivery, type WebhookTestResult, type WebhookEventResult, } from './webhooks.js';
29
29
  export { verifyWebhookSignature, parseSignatureHeader, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_EVENT_HEADER, WEBHOOK_DELIVERY_HEADER, WEBHOOK_TOLERANCE_SEC, WEBHOOK_RETRY_PLAN_SEC, WEBHOOK_MAX_ATTEMPTS, WEBHOOK_TIMEOUT_MS, WEBHOOK_LIMIT, type VerifyWebhookOptions, type WebhookVerifyResult, type WebhookVerifyReason, } from './webhook-signatur.js';
30
30
  export { PARTNER_ENVS, LEGAL_FORMS, AUSTRIAN_STATES, CONTACT_ROLES, AVV_MODES, FEE_INTERVALS, CONTRACT_KINDS, CONTRACT_SOURCES, SIGNATURE_HISTORY_REASONS, SIGNATURE_ERROR_CODES, } from './typen.js';
31
- export type { PartnerEnv, PartnerScope, PartnerApp, PartnerInfo, LegalForm, AustrianState, ContactRole, AvvMode, FeeInterval, PartnerFee, SignatureHistoryReason, SignatureErrorCode, RequestSignatureOptions, CustomerSignature, ContractKind, ContractSource, ReportCustomerContractOptions, ReportCustomerContractResult, BusinessAddress, BusinessTaxDetails, BusinessContact, BusinessTaxAdvisor, Business, CreateCustomerOptions, CreateCustomerResult, PartnerCustomerStatus, PartnerCustomerSummary, AvvStatus, ContractStatus, PartnerCustomerFonStatus, ListCustomersOptions, PartnerCustomerList, PartnerCustomer, FonLinkResult, SignatureRequestStatus, SignatureHistoryEntry, SignatureRequest, RequestSignatureResult, CustomerSignatureStatus, CashregisterActivationStep, CustomerCashregisterStatus, CustomerCashregister, CreateCashregisterOptions, CreateCashregisterResult, ActivateCashregisterResult, CustomerCashregisterList, CustomerCashregisterCredential, CustomerCredentials, } from './typen.js';
31
+ export type { PartnerEnv, PartnerScope, PartnerApp, PartnerInfo, LegalForm, AustrianState, ContactRole, AvvMode, FeeInterval, PartnerFee, SignatureHistoryReason, SignatureFulfillment, SignatureErrorCode, RequestSignatureOptions, CustomerSignature, ContractKind, ContractSource, ReportCustomerContractOptions, ReportCustomerContractResult, BusinessAddress, BusinessTaxDetails, BusinessContact, BusinessTaxAdvisor, Business, CreateCustomerOptions, CreateCustomerResult, PartnerCustomerStatus, PartnerCustomerSummary, AvvStatus, ContractStatus, PartnerCustomerFonStatus, ListCustomersOptions, PartnerCustomerList, PartnerCustomer, FonLinkResult, SignatureRequestStatus, SignatureHistoryEntry, SignatureRequest, RequestSignatureResult, CustomerSignatureStatus, CashregisterActivationStep, CustomerCashregisterStatus, CustomerCashregister, CreateCashregisterOptions, CreateCashregisterResult, ActivateCashregisterResult, CustomerCashregisterList, CustomerCashregisterCredential, CustomerCredentials, } from './typen.js';
32
32
  /** `credentials:read` — nicht im Standardsatz, siehe typen.ts. */
33
33
  export { SCOPE_CREDENTIALS } from './typen.js';
@@ -382,7 +382,7 @@ export type SignatureRequestStatus = 'requested' | 'assigned' | 'registered' | '
382
382
  * Gruende in der Historie eines Signaturantrags. `card_entered` und
383
383
  * `finanzonline` hiessen unter `/v1` `karte_eingetragen` und `fon`.
384
384
  */
385
- export declare const SIGNATURE_HISTORY_REASONS: readonly ["api", "portal", "card_entered", "finanzonline", "automation_off", "test_environment", "no_stock"];
385
+ export declare const SIGNATURE_HISTORY_REASONS: readonly ["api", "portal", "card_entered", "finanzonline", "automation_off", "test_environment", "no_stock", "card_pool_activated", "activation_run", "finanzonline_completed"];
386
386
  /** Offen fuer spaeter ergaenzte Gruende, siehe [SIGNATURE_HISTORY_REASONS]. */
387
387
  export type SignatureHistoryReason = typeof SIGNATURE_HISTORY_REASONS[number] | (string & {});
388
388
  /**
@@ -400,6 +400,8 @@ export interface SignatureHistoryEntry {
400
400
  at: number;
401
401
  reason: SignatureHistoryReason | null;
402
402
  }
403
+ /** Erfuellungsweg eines Signaturantrags; offen fuer spaeter ergaenzte Werte. */
404
+ export type SignatureFulfillment = 'automatic' | 'manual' | (string & {});
403
405
  export interface SignatureRequest {
404
406
  requestId: string;
405
407
  status: SignatureRequestStatus;
@@ -408,6 +410,8 @@ export interface SignatureRequest {
408
410
  kind: string;
409
411
  vdaId: string | null;
410
412
  signatureId: string | null;
413
+ /** Wie der Antrag erfuellt wird: aus dem Kartenvorrat oder von Hand. */
414
+ fulfillment?: SignatureFulfillment;
411
415
  error: {
412
416
  code: SignatureErrorCode | null;
413
417
  message: string | null;
@@ -442,6 +446,8 @@ export interface CustomerSignature {
442
446
  status: SignatureRequestStatus | 'decommissioned';
443
447
  statusText: string;
444
448
  inProgress: boolean;
449
+ /** Wie der Antrag erfuellt wird: aus dem Kartenvorrat oder von Hand. */
450
+ fulfillment?: SignatureFulfillment;
445
451
  ready: boolean;
446
452
  kind: string;
447
453
  vdaId: string | null;
@@ -100,6 +100,9 @@ exports.SIGNATURE_HISTORY_REASONS = [
100
100
  'automation_off',
101
101
  'test_environment',
102
102
  'no_stock',
103
+ 'card_pool_activated',
104
+ 'activation_run',
105
+ 'finanzonline_completed',
103
106
  ];
104
107
  /**
105
108
  * `error.code` eines Signaturantrags oder einer Signatur (`SignatureRequest`,
@@ -4,10 +4,11 @@ import { type PosSettings, type PosBusinessSettings, type PosDeviceSettings } fr
4
4
  export declare function getPosSettings(transport: InternerTransport, options?: {
5
5
  deviceId?: string;
6
6
  }): Promise<PosSettings>;
7
- /** `{business, device}` einer Antwort, gemischt mit den Standardwerten. */
7
+ /** `{business, device, vouchers}` einer Antwort, gemischt mit den Standardwerten. */
8
8
  export declare function posSettingsFromWire(data: {
9
9
  business?: unknown;
10
10
  device?: unknown;
11
+ vouchers?: unknown;
11
12
  } | null | undefined): PosSettings;
12
13
  /** Betriebsweite Einstellungen schreiben (Recht `layout`); liefert den gemischten Stand. */
13
14
  export declare function setMyPosSettings(transport: InternerTransport, business: Partial<PosBusinessSettings>): Promise<PosBusinessSettings>;
@@ -6,6 +6,7 @@ exports.setMyPosSettings = setMyPosSettings;
6
6
  exports.setMyRegisterDeviceSettings = setMyRegisterDeviceSettings;
7
7
  exports.setMyPosLogo = setMyPosLogo;
8
8
  const errors_js_1 = require("../client/errors.js");
9
+ const gutschein_js_1 = require("./gutschein.js");
9
10
  const settings_js_1 = require("./settings.js");
10
11
  /*
11
12
  * Die Einstellungs-Aufrufe am Draht `/api/v3`: Parameter und Antwort heissen
@@ -34,9 +35,10 @@ async function getPosSettings(transport, options = {}) {
34
35
  const daten = await transport('getKasseSettings', params);
35
36
  return posSettingsFromWire(daten);
36
37
  }
37
- /** `{business, device}` einer Antwort, gemischt mit den Standardwerten. */
38
+ /** `{business, device, vouchers}` einer Antwort, gemischt mit den Standardwerten. */
38
39
  function posSettingsFromWire(data) {
39
40
  return {
41
+ vouchers: (0, gutschein_js_1.posVoucherSettingsFromWire)(data?.vouchers),
40
42
  business: (0, settings_js_1.mergePosSettings)(settings_js_1.POS_BUSINESS_DEFAULTS, objekt(data?.business)),
41
43
  device: (0, settings_js_1.mergePosSettings)(settings_js_1.POS_DEVICE_DEFAULTS, objekt(data?.device)),
42
44
  };
@@ -0,0 +1,90 @@
1
+ import type { InternerTransport } from '../client/aufrufe.js';
2
+ /**
3
+ * Gutschein pruefen und Etikett nachdrucken an der Kasse (Backend
4
+ * gutschein-endpoints). Beide Aufrufe gibt es nur ueber den Kassenweg
5
+ * `/api/v3`.
6
+ *
7
+ * Der Klartext-Code lebt nur im Speicher des Aufrufs: er wird weder
8
+ * protokolliert noch in einer Fehlermeldung genannt. Die Kasse bekommt nach
9
+ * dem Pruefen nur die letzten vier Zeichen (`codeSuffix`) zurueck.
10
+ */
11
+ export type VoucherKind = 'multi_purpose' | 'single_purpose' | 'service' | 'promotion';
12
+ export type VoucherStatus = 'active' | 'used_up' | 'expired' | 'paid_out' | 'cancelled' | 'blocked';
13
+ export declare const VOUCHER_KINDS: readonly VoucherKind[];
14
+ export declare const VOUCHER_STATUSES: readonly VoucherStatus[];
15
+ /** Gueltigkeit eines Gutscheins; Daten als `YYYY-MM-DD` (Wiener Tag). Was der Server nicht nennt, fehlt. */
16
+ export interface VoucherValidity {
17
+ pattern: 'unlimited' | '1+3' | 'custom';
18
+ redeemableUntil?: string;
19
+ refundableUntil?: string;
20
+ validUntil?: string;
21
+ }
22
+ /** Der Artikel eines Dienstleistungsgutscheins. */
23
+ export interface VoucherArticle {
24
+ id: string;
25
+ name: string;
26
+ vatRateBp: number;
27
+ priceCents: number;
28
+ }
29
+ /**
30
+ * Stand eines Gutscheins nach dem Code-Eingeben. Felder, die zur Art nicht
31
+ * passen oder die der Server nicht sendet, fehlen im Modell (nie `null`).
32
+ */
33
+ export interface VoucherCheck {
34
+ type: VoucherKind;
35
+ status: VoucherStatus;
36
+ /** Die letzten vier Zeichen des Codes, fuer Anzeige und Beleg. */
37
+ codeSuffix: string;
38
+ balanceCents?: number;
39
+ faceValueCents?: number;
40
+ quantity?: number;
41
+ remainingQuantity?: number;
42
+ vatRateBp?: number;
43
+ article?: VoucherArticle;
44
+ discountCents?: number;
45
+ discountPercentBp?: number;
46
+ validity?: VoucherValidity;
47
+ /**
48
+ * Befreit verkauft (Kleinunternehmer beim Verkauf, Satz 0): eine Einloesung
49
+ * verteilt sich anteilig auf alle Saetze des Korbs, auch in einem
50
+ * inzwischen steuerpflichtigen Konto. Fehlt bei aelteren Servern.
51
+ */
52
+ exempt?: boolean;
53
+ }
54
+ /** Gutschein-Einstellungen der Kasse (Block `vouchers` aus `getKasseSettings`). */
55
+ export interface PosVoucherSettings {
56
+ sale: boolean;
57
+ valueVoucherType: 'multi_purpose' | 'single_purpose' | null;
58
+ vatRateBp: number | null;
59
+ }
60
+ /** Ohne Block `vouchers` (alter Server, Konto ohne Schalter): Verkaufen ist aus. */
61
+ export declare const VOUCHER_SETTINGS_DEFAULTS: Readonly<PosVoucherSettings>;
62
+ /**
63
+ * Block `vouchers` einer Einstellungs-Antwort, geschlossen im Zweifel: ist
64
+ * irgendein Feld unstimmig, gilt der ganze Block als nicht gelesen und
65
+ * Verkaufen bleibt aus (kein Wurf, sonst ginge das Laden aller Einstellungen
66
+ * verloren). Stimmig heisst: `sale` ein Wahrheitswert, die Art
67
+ * `multi_purpose`/`single_purpose`/`null`, der Satz eine ganze Zahl >= 0 oder
68
+ * `null`; Mehrzweck traegt keinen Satz, Einzweck braucht einen, und ein
69
+ * eingeschalteter Verkauf braucht eine Art. Ein ausgeschalteter Verkauf darf
70
+ * eine Art behalten.
71
+ */
72
+ export declare function posVoucherSettingsFromWire(block: unknown): PosVoucherSettings;
73
+ /**
74
+ * Gutschein am Code pruefen (Gutschein-Recht `voucherRedeem`). Der Code wird
75
+ * tolerant eingelesen (Gross/klein, Bindestriche, `O`/`0`, `I`/`L`/`1`) und
76
+ * vor dem Senden auf sein Pruefzeichen geprueft: ein Tippfehler geht nie ueber
77
+ * das Netz, sondern endet mit `KasseneckValidationError`. Fachliche Fehler
78
+ * kommen als `KasseneckApiError` mit dem Code des Servers
79
+ * (`voucher_not_found`, `too_many_voucher_checks`, `not_permitted` …).
80
+ */
81
+ export declare function checkVoucher(transport: InternerTransport, code: string): Promise<VoucherCheck>;
82
+ /**
83
+ * Etikett eines Gutscheins noch einmal drucken (Gutschein-Recht
84
+ * `voucherManage`). Antwort ist der Klartext-Code zum Drucken; er gehoert
85
+ * nur in den Speicher bis zum Druck. Aufrufer duerfen ihn nicht protokollieren,
86
+ * speichern oder in Meldungen nennen; Lesefehler dieser Antwort nennen ihn nie.
87
+ */
88
+ export declare function reprintVoucherLabel(transport: InternerTransport, id: string): Promise<{
89
+ code: string;
90
+ }>;