@kreiseck/kasseneck-api 1.4.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/CHANGELOG.md +166 -0
  2. package/README.md +255 -36
  3. package/dist/cjs/client/aufrufe.d.ts +58 -4
  4. package/dist/cjs/client/aufrufe.js +196 -1
  5. package/dist/cjs/client/errors.d.ts +32 -19
  6. package/dist/cjs/client/errors.js +28 -17
  7. package/dist/cjs/client/index.d.ts +2 -2
  8. package/dist/cjs/client/index.js +2 -1
  9. package/dist/cjs/client/transport.d.ts +27 -1
  10. package/dist/cjs/client/transport.js +25 -27
  11. package/dist/cjs/index.d.ts +1 -1
  12. package/dist/cjs/index.js +3 -2
  13. package/dist/cjs/inventory/api.d.ts +19 -3
  14. package/dist/cjs/inventory/api.js +18 -2
  15. package/dist/cjs/inventory/endpunkte.d.ts +22 -2
  16. package/dist/cjs/inventory/endpunkte.js +6 -1
  17. package/dist/cjs/inventory/fehler.d.ts +11 -1
  18. package/dist/cjs/inventory/fehler.js +19 -0
  19. package/dist/cjs/inventory/index.d.ts +6 -4
  20. package/dist/cjs/inventory/index.js +32 -2
  21. package/dist/cjs/inventory/lesen.d.ts +8 -1
  22. package/dist/cjs/inventory/lesen.js +131 -1
  23. package/dist/cjs/inventory/schreiben.d.ts +86 -0
  24. package/dist/cjs/inventory/schreiben.js +320 -0
  25. package/dist/cjs/inventory/typen.d.ts +371 -11
  26. package/dist/cjs/inventory/vertrag.d.ts +76 -16
  27. package/dist/cjs/inventory/vertrag.js +138 -13
  28. package/dist/cjs/inventory/webhook.d.ts +3 -1
  29. package/dist/cjs/inventory/webhook.js +7 -1
  30. package/dist/cjs/invoice/endpunkte.d.ts +6 -0
  31. package/dist/cjs/invoice/endpunkte.js +13 -2
  32. package/dist/cjs/invoice/index.d.ts +2 -2
  33. package/dist/cjs/invoice/index.js +2 -1
  34. package/dist/cjs/invoice/typen.d.ts +46 -2
  35. package/dist/cjs/invoice/vertrag.d.ts +19 -5
  36. package/dist/cjs/invoice/vertrag.js +37 -5
  37. package/dist/cjs/pos/texte.d.ts +11 -6
  38. package/dist/cjs/pos/texte.js +11 -6
  39. package/dist/cjs/stored/vokabular.d.ts +1 -1
  40. package/dist/cjs/stored/vokabular.js +5 -3
  41. package/dist/cjs/version.d.ts +1 -1
  42. package/dist/cjs/version.js +1 -1
  43. package/dist/esm/client/aufrufe.d.ts +58 -4
  44. package/dist/esm/client/aufrufe.js +194 -0
  45. package/dist/esm/client/errors.d.ts +32 -19
  46. package/dist/esm/client/errors.js +28 -17
  47. package/dist/esm/client/index.d.ts +2 -2
  48. package/dist/esm/client/index.js +1 -1
  49. package/dist/esm/client/transport.d.ts +27 -1
  50. package/dist/esm/client/transport.js +26 -28
  51. package/dist/esm/index.d.ts +1 -1
  52. package/dist/esm/index.js +1 -1
  53. package/dist/esm/inventory/api.d.ts +19 -3
  54. package/dist/esm/inventory/api.js +18 -2
  55. package/dist/esm/inventory/endpunkte.d.ts +22 -2
  56. package/dist/esm/inventory/endpunkte.js +6 -5
  57. package/dist/esm/inventory/fehler.d.ts +11 -1
  58. package/dist/esm/inventory/fehler.js +18 -1
  59. package/dist/esm/inventory/index.d.ts +6 -4
  60. package/dist/esm/inventory/index.js +5 -3
  61. package/dist/esm/inventory/lesen.d.ts +8 -1
  62. package/dist/esm/inventory/lesen.js +127 -1
  63. package/dist/esm/inventory/schreiben.d.ts +86 -0
  64. package/dist/esm/inventory/schreiben.js +303 -0
  65. package/dist/esm/inventory/typen.d.ts +371 -11
  66. package/dist/esm/inventory/vertrag.d.ts +76 -16
  67. package/dist/esm/inventory/vertrag.js +137 -12
  68. package/dist/esm/inventory/webhook.d.ts +3 -1
  69. package/dist/esm/inventory/webhook.js +8 -2
  70. package/dist/esm/invoice/endpunkte.d.ts +6 -0
  71. package/dist/esm/invoice/endpunkte.js +13 -2
  72. package/dist/esm/invoice/index.d.ts +2 -2
  73. package/dist/esm/invoice/index.js +1 -1
  74. package/dist/esm/invoice/typen.d.ts +46 -2
  75. package/dist/esm/invoice/vertrag.d.ts +19 -5
  76. package/dist/esm/invoice/vertrag.js +36 -4
  77. package/dist/esm/pos/texte.d.ts +11 -6
  78. package/dist/esm/pos/texte.js +11 -6
  79. package/dist/esm/stored/vokabular.d.ts +1 -1
  80. package/dist/esm/stored/vokabular.js +5 -3
  81. package/dist/esm/version.d.ts +1 -1
  82. package/dist/esm/version.js +1 -1
  83. package/fixtures/hobex-hps-codes.json +1 -1
  84. package/fixtures/invoice-api-examples/credit-error-reservation.json +26 -0
  85. package/fixtures/invoice-api-examples/issue-error-reservation-article.json +25 -0
  86. package/fixtures/invoice-api-examples/issue-error-vat-id-risk.json +26 -0
  87. package/fixtures/invoice-api-examples/issue-reservation.json +24 -0
  88. package/fixtures/invoice-api-examples/issue-vat-id-risk.json +28 -0
  89. package/fixtures/invoice-api.schema.json +15 -2
  90. package/fixtures/invoice-texts.json +1 -1
  91. package/fixtures/pos-texts.json +1 -1
  92. package/fixtures/surface.json +206 -9
  93. package/fixtures/v3/antworten/belege.json +2 -2
  94. package/fixtures/v3/antworten/belegmail.json +2 -2
  95. package/fixtures/v3/antworten/kasse-belege.json +2 -2
  96. package/fixtures/v3/antworten/kasse.json +3 -3
  97. package/fixtures/v3/antworten/lager.json +2491 -130
  98. package/fixtures/v3/antworten/rechnungen.json +267 -44
  99. package/fixtures/v3/antworten/storno.json +2 -2
  100. package/fixtures/v3/stored/belege.json +2 -2
  101. package/fixtures/v3/stored/kasse.json +3 -3
  102. package/fixtures/v3/stored/rechnungen.json +174 -18
  103. package/fixtures/v3/v3-vokabular.json +593 -23
  104. package/fixtures/v3/zahlbetrag-faelle.json +2 -2
  105. package/package.json +1 -1
@@ -1,14 +1,17 @@
1
1
  /**
2
- * Der Vertrag der Lager-API (Backend Stufe 5a) als Daten: Endpunkte,
3
- * Wertkataloge, Ereignisse und Fehlercodes, englisch wie am Draht `/v3`.
2
+ * Der Vertrag der Lager-API (Backend Stufe 5a lesen, 5b schreiben und
3
+ * reservieren) als Daten: Endpunkte, Wertkataloge, Ereignisse, Fehler- und
4
+ * Hinweiscodes, englisch wie am Draht `/v3`.
4
5
  *
5
6
  * Quelle ist der Vertrags-Export des Backends (`fixtures/v3/v3-vokabular.json`):
6
7
  * `endpoints.public`, die Kataloge `STANDORT_TYP`, `BEWEGUNG_ART`,
7
- * `BEWEGUNG_QUELLE`, `LAGER_ZUSTAND`, `LAGER_URSACHE`, `ZUSTELLUNG` und
8
- * `events`. `test/inventory.test.ts` haelt jede Liste deckungsgleich mit
9
- * dieser Datei; nichts hier wird geraten.
8
+ * `BEWEGUNG_QUELLE`, `LAGER_ZUSTAND`, `LAGER_URSACHE`, `ZUSTELLUNG`,
9
+ * `LAGER_ABGANG_GRUND`, `LAGER_ENTNAHME_ART`, `LAGER_NEBENKOSTEN_ART`,
10
+ * `LAGER_VERTEILUNG`, `RESERVIERUNG_STATUS`, dazu `events`, `errorCodes.inventory`
11
+ * und `warningCodes.inventory`. `test/inventory.test.ts` haelt jede Liste
12
+ * deckungsgleich mit dieser Datei; nichts hier wird geraten.
10
13
  */
11
- /** Die 14 Endpunkte, in der Reihenfolge von `endpoints.public`. */
14
+ /** Die 27 Endpunkte (14 aus 5a, 13 aus 5b), in der Reihenfolge von `endpoints.public`. */
12
15
  export const INVENTORY_ENDPOINTS = [
13
16
  'getArticle',
14
17
  'listArticles',
@@ -24,6 +27,19 @@ export const INVENTORY_ENDPOINTS = [
24
27
  'sendWebhookTest',
25
28
  'rotateWebhookSecret',
26
29
  'listWebhookDeliveries',
30
+ 'createArticle',
31
+ 'updateArticle',
32
+ 'deactivateArticle',
33
+ 'receiveGoods',
34
+ 'transferStock',
35
+ 'recordStockLoss',
36
+ 'changeStockCondition',
37
+ 'reverseStockMovement',
38
+ 'createReservation',
39
+ 'extendReservation',
40
+ 'releaseReservation',
41
+ 'getReservation',
42
+ 'listReservations',
27
43
  ];
28
44
  /** Art eines Standorts (Katalog `STANDORT_TYP`). */
29
45
  export const LOCATION_TYPES = ['warehouse', 'store', 'vehicle', 'other'];
@@ -31,6 +47,8 @@ export const LOCATION_TYPES = ['warehouse', 'store', 'vehicle', 'other'];
31
47
  * Art einer Lagerbewegung (Katalog `BEWEGUNG_ART`); zugleich der Filter `type`.
32
48
  * `goods_receipt` ist der Wareneingang, `takeover` der uebernommene Anfangsbestand
33
49
  * (auch per Import). `receipt` gibt es hier nicht: das ist der Kassenbeleg (Quelle).
50
+ * `reservation` (seit 1.5.0) aendert nur `reserved`: `quantityDelta` ist 0, die
51
+ * Menge steht in `reservedDelta`.
34
52
  */
35
53
  export const STOCK_MOVEMENT_TYPES = [
36
54
  'sale',
@@ -47,6 +65,7 @@ export const STOCK_MOVEMENT_TYPES = [
47
65
  'reversal',
48
66
  'revaluation',
49
67
  'method_change',
68
+ 'reservation',
50
69
  ];
51
70
  /**
52
71
  * Woher eine Bewegung kommt (Katalog `BEWEGUNG_QUELLE`); zugleich der Filter
@@ -89,8 +108,11 @@ export const STOCK_CHANGE_CAUSES = [
89
108
  /** Stand einer Zustellung (Katalog `ZUSTELLUNG`, derselbe wie bei Partner-Webhooks). */
90
109
  export const WEBHOOK_DELIVERY_STATUSES = ['delivered', 'pending', 'failed', 'dropped'];
91
110
  /**
92
- * Die Ereignisse, die ein Konto-Webhook abonnieren kann (Stufe 5a). Spaetere
93
- * Stufen ergaenzen `reservation.*` und `variant_group.*`.
111
+ * Die Ereignisse, die ein Konto-Webhook abonnieren kann, in der Reihenfolge von
112
+ * `listWebhooks().events`. `reservation.*` (seit 1.5.0) tragen die Reservierung
113
+ * wie `getReservation`, mit dem Status danach: `reservation.released` und
114
+ * `reservation.redeemed` kommen bei jeder wirksamen Freigabe bzw. Einloesung,
115
+ * auch einer teilweisen (dann bleibt der Status `active`).
94
116
  */
95
117
  export const INVENTORY_WEBHOOK_EVENTS = [
96
118
  'stock.changed',
@@ -98,6 +120,9 @@ export const INVENTORY_WEBHOOK_EVENTS = [
98
120
  'article.created',
99
121
  'article.updated',
100
122
  'article.deactivated',
123
+ 'reservation.expired',
124
+ 'reservation.released',
125
+ 'reservation.redeemed',
101
126
  ];
102
127
  /**
103
128
  * Die Felder der Huelle jeder Zustellung, in der Reihenfolge am Draht. Statt
@@ -110,10 +135,21 @@ export const INVENTORY_WEBHOOK_LIMIT = 5;
110
135
  /** Groesstes `limit` einer Liste; ohne Angabe liefert der Server 50. */
111
136
  export const INVENTORY_LIST_LIMIT_MAX = 200;
112
137
  /**
113
- * Die Codes, die die Lager-Endpunkte selbst senden. `validation` traegt
114
- * `errors: [{ field, message }]`, `rate_limited` traegt `retryAfterSec`
115
- * (dazu die Kopfzeile `Retry-After`) – auch bei `sendWebhookTest` nach 20
116
- * Probesendungen je Wiener Kalendertag (dann bis Mitternacht in Wien).
138
+ * Die Codes, die die Lager-Endpunkte selbst senden (`errorCodes.inventory`;
139
+ * `register_user_not_allowed` steht bei [INVENTORY_REQUEST_ERROR_CODES]).
140
+ * `validation` traegt `errors: [{ field, message }]`, `rate_limited` traegt
141
+ * `retryAfterSec` (dazu die Kopfzeile `Retry-After`) – auch bei
142
+ * `sendWebhookTest` nach 20 Probesendungen je Wiener Kalendertag (dann bis
143
+ * Mitternacht in Wien).
144
+ *
145
+ * Seit 1.5.0 hinten angehaengt, in der Reihenfolge des Vertrags: die Codes
146
+ * der schreibenden Endpunkte. `idempotency_key_required` (Schluessel fehlt),
147
+ * `idempotency_conflict` (derselbe Schluessel mit anderem Inhalt),
148
+ * `exceeds_stock` (Abgang, Umbuchung und Zustandswechsel ueberziehen nie),
149
+ * `insufficient_available` (Reservierung; `data.details[]`, siehe
150
+ * [inventoryShortfalls]), `code_taken` und `external_id_taken` (mit `field` und
151
+ * `articleId` des Artikels, dem der Code gehoert), `stock_kind_locked`,
152
+ * `reservation_not_found`, `reservation_not_active` …
117
153
  */
118
154
  export const INVENTORY_ERROR_CODES = [
119
155
  'validation',
@@ -128,6 +164,55 @@ export const INVENTORY_ERROR_CODES = [
128
164
  'module_inactive',
129
165
  'rate_limited',
130
166
  'server_error',
167
+ 'idempotency_key_required',
168
+ 'idempotency_conflict',
169
+ 'location_not_found',
170
+ 'location_inactive',
171
+ 'invalid_location',
172
+ 'invalid_locations',
173
+ 'invalid_transfer',
174
+ 'operation_not_found',
175
+ 'already_reversed',
176
+ 'reversal_not_possible',
177
+ 'reversal_not_supported',
178
+ 'exceeds_stock',
179
+ 'no_positions',
180
+ 'too_many_positions',
181
+ 'invalid_step',
182
+ 'invalid_quantity',
183
+ 'invalid_amount',
184
+ 'invalid_price',
185
+ 'negative_value',
186
+ 'invalid_reason',
187
+ 'note_required',
188
+ 'withdrawal_type_required',
189
+ 'invalid_method',
190
+ 'invalid_stock_kind',
191
+ 'invalid_minimum',
192
+ 'invalid_dimensions',
193
+ 'weight_missing',
194
+ 'invalid_landed_cost',
195
+ 'invalid_distribution',
196
+ 'landed_costs_mismatch',
197
+ 'return_totals_mismatch',
198
+ 'lot_not_found',
199
+ 'invalid_serial',
200
+ 'serial_required',
201
+ 'serial_not_allowed',
202
+ 'serial_already_exists',
203
+ 'serial_not_in_stock',
204
+ 'code_taken',
205
+ 'external_id_taken',
206
+ 'group_not_found',
207
+ 'revenue_group_not_found',
208
+ 'stock_kind_locked',
209
+ 'article_inactive',
210
+ 'invalid_position',
211
+ 'invalid_condition',
212
+ 'reason_required',
213
+ 'insufficient_available',
214
+ 'reservation_not_found',
215
+ 'reservation_not_active',
131
216
  ];
132
217
  /**
133
218
  * Codes, die Anmeldung und Rand auf jedem Lager-Aufruf erzeugen koennen,
@@ -161,3 +246,43 @@ export const INVENTORY_REQUEST_ERROR_CODES = [
161
246
  'user_verification_failed',
162
247
  'route_missing',
163
248
  ];
249
+ // ---- Schreiben und Reservierung (Backend Stufe 5b, seit 1.5.0) -----------------
250
+ /**
251
+ * Hinweise einer Buchung (`warnings[].code`, `warningCodes.inventory`). Sie sind
252
+ * keine Fehler: die Buchung hat gewirkt. `insufficient_stock` gibt es nur beim
253
+ * Verkauf (Abgang, Umbuchung und Zustandswechsel weisen mit `exceeds_stock` ab),
254
+ * `below_minimum` misst am verfuegbaren Bestand (`onHand − reserved`) gegen den
255
+ * Mindestbestand des Standorts, `reservation_exceeded` meldet eine Rechnung, die
256
+ * mehr verkauft als reserviert war.
257
+ */
258
+ export const INVENTORY_WARNING_CODES = [
259
+ 'insufficient_stock',
260
+ 'below_minimum',
261
+ 'return_exceeds_sale',
262
+ 'reservation_exceeded',
263
+ ];
264
+ /**
265
+ * Bestandsart eines Artikels (`stockKind`): `quantity` = Menge, `serial` =
266
+ * Einzelstueck mit Seriennummer. Kein Katalog des Vokabulars, der Server
267
+ * uebersetzt das Feld selbst; nach der ersten Bewegung fest (`stock_kind_locked`).
268
+ */
269
+ export const STOCK_KINDS = ['quantity', 'serial'];
270
+ /** Grund eines Abgangs (`recordStockLoss.reason`, Katalog `LAGER_ABGANG_GRUND`). `other` braucht `note`. */
271
+ export const STOCK_LOSS_REASONS = ['breakage', 'shrinkage', 'theft', 'expired', 'withdrawal', 'disposal', 'other'];
272
+ /** Art einer Entnahme (`withdrawalType`, Katalog `LAGER_ENTNAHME_ART`); Pflicht bei `reason: 'withdrawal'`, sonst nicht erlaubt. */
273
+ export const WITHDRAWAL_TYPES = ['private', 'staff', 'gift', 'sample'];
274
+ /** Art von Nebenkosten eines Wareneingangs (`landedCosts[].type`, Katalog `LAGER_NEBENKOSTEN_ART`). */
275
+ export const LANDED_COST_TYPES = ['freight', 'customs', 'insurance', 'other', 'discount', 'cash_discount'];
276
+ /** Verteilung der Nebenkosten (`allocation`, Katalog `LAGER_VERTEILUNG`); Vorgabe des Servers `value`. */
277
+ export const LANDED_COST_ALLOCATIONS = ['value', 'quantity', 'weight', 'manual'];
278
+ /**
279
+ * Stand einer Reservierung (Katalog `RESERVIERUNG_STATUS`). Nur `active` haelt
280
+ * Ware zurueck; die drei anderen sind endgueltig: `redeemed` (ueber eine
281
+ * Rechnung eingeloest), `released` (freigegeben), `expired` (abgelaufen).
282
+ */
283
+ export const RESERVATION_STATUSES = ['active', 'redeemed', 'released', 'expired'];
284
+ /** Laengster `idempotencyKey` (Zeichen); laenger weist der Server ab, er schneidet nie ab. */
285
+ export const INVENTORY_IDEMPOTENCY_KEY_MAX = 120;
286
+ /** Kuerzeste und laengste Haltedauer einer Reservierung in Minuten (`expiresInMinutes`, 30 Tage). */
287
+ export const RESERVATION_MINUTES_MIN = 5;
288
+ export const RESERVATION_MINUTES_MAX = 43_200;
@@ -39,8 +39,10 @@ export declare function verifyInventoryWebhookSignature(secret: string | readonl
39
39
  * Liest eine Zustellung als typisiertes Ereignis. Vorher die Signatur pruefen
40
40
  * ([verifyInventoryWebhookSignature]).
41
41
  *
42
- * - Ein Ereignis, das diese Paketversion nicht kennt (etwa `reservation.*`
42
+ * - Ein Ereignis, das diese Paketversion nicht kennt (etwa `variant_group.*`
43
43
  * einer spaeteren Stufe), ergibt `null`: mit 2xx antworten und uebergehen.
44
+ * - `reservation.expired|released|redeemed` tragen die Reservierung wie
45
+ * `getReservation`, mit dem Status nach dem Vorgang (seit 1.5.0).
44
46
  * - Ein Rumpf, der keine Huelle ist, oder eine Bruchzahl in einer Menge wirft
45
47
  * `KasseneckValidationError` (`scope: 'response'`).
46
48
  *
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import { KasseneckValidationError } from '../client/errors.js';
17
17
  import { verifyWebhookSignature as pruefeSignatur } from '../partner/webhook-signatur.js';
18
- import { artikel, bestandGeaendert, objekt, unterMindestbestand } from './lesen.js';
18
+ import { artikel, bestandGeaendert, objekt, reservierung, unterMindestbestand } from './lesen.js';
19
19
  import { INVENTORY_WEBHOOK_EVENTS } from './vertrag.js';
20
20
  export { WEBHOOK_SIGNATURE_HEADER, WEBHOOK_EVENT_HEADER, WEBHOOK_DELIVERY_HEADER, WEBHOOK_TOLERANCE_SEC, } from '../partner/webhook-signatur.js';
21
21
  /**
@@ -56,8 +56,10 @@ function kaputt(grund) {
56
56
  * Liest eine Zustellung als typisiertes Ereignis. Vorher die Signatur pruefen
57
57
  * ([verifyInventoryWebhookSignature]).
58
58
  *
59
- * - Ein Ereignis, das diese Paketversion nicht kennt (etwa `reservation.*`
59
+ * - Ein Ereignis, das diese Paketversion nicht kennt (etwa `variant_group.*`
60
60
  * einer spaeteren Stufe), ergibt `null`: mit 2xx antworten und uebergehen.
61
+ * - `reservation.expired|released|redeemed` tragen die Reservierung wie
62
+ * `getReservation`, mit dem Status nach dem Vorgang (seit 1.5.0).
61
63
  * - Ein Rumpf, der keine Huelle ist, oder eine Bruchzahl in einer Menge wirft
62
64
  * `KasseneckValidationError` (`scope: 'response'`).
63
65
  *
@@ -95,6 +97,10 @@ export function parseInventoryWebhookEvent(rawBody) {
95
97
  return { ...huelle, type: huelle.type, data: bestandGeaendert(ort, data) };
96
98
  case 'stock.below_minimum':
97
99
  return { ...huelle, type: huelle.type, data: unterMindestbestand(ort, data) };
100
+ case 'reservation.expired':
101
+ case 'reservation.released':
102
+ case 'reservation.redeemed':
103
+ return { ...huelle, type: huelle.type, data: reservierung(ort, data) };
98
104
  default:
99
105
  return { ...huelle, type: huelle.type, data: artikel(ort, data) };
100
106
  }
@@ -12,6 +12,12 @@
12
12
  * **Nicht automatisch wiederholen.** Wer nach einem Zeitlimit erneut
13
13
  * ausstellt, tut das mit **demselben** `idempotencyKey`: dann kommt die schon
14
14
  * ausgestellte Rechnung zurueck (`replayed: true`) statt einer zweiten.
15
+ * Jeder Aufruf mit Wirkung (ausstellen, stornieren, gutschreiben, Zahlung
16
+ * nachtragen, Kunde anlegen oder aendern) meldet nach Zeitlimit, Netzfehler,
17
+ * HTTP 5xx oder unlesbarer Antwort `outcome: 'unknown'`: er kann gewirkt
18
+ * haben. Mit Schluessel denselben Schluessel erneut senden, ohne Schluessel
19
+ * (`updateCustomer`, `createCustomer` ohne) erst nachlesen. Lesen und der
20
+ * Probelauf (`previewInvoice`) bleiben `'rejected'`.
15
21
  *
16
22
  * Nach dem Senden wird nichts hart gecastet: fehlt ein zugesagtes Feld, wirft
17
23
  * der Aufruf `KasseneckValidationError` mit `scope:'response'`.
@@ -12,6 +12,12 @@
12
12
  * **Nicht automatisch wiederholen.** Wer nach einem Zeitlimit erneut
13
13
  * ausstellt, tut das mit **demselben** `idempotencyKey`: dann kommt die schon
14
14
  * ausgestellte Rechnung zurueck (`replayed: true`) statt einer zweiten.
15
+ * Jeder Aufruf mit Wirkung (ausstellen, stornieren, gutschreiben, Zahlung
16
+ * nachtragen, Kunde anlegen oder aendern) meldet nach Zeitlimit, Netzfehler,
17
+ * HTTP 5xx oder unlesbarer Antwort `outcome: 'unknown'`: er kann gewirkt
18
+ * haben. Mit Schluessel denselben Schluessel erneut senden, ohne Schluessel
19
+ * (`updateCustomer`, `createCustomer` ohne) erst nachlesen. Lesen und der
20
+ * Probelauf (`previewInvoice`) bleiben `'rejected'`.
15
21
  *
16
22
  * Nach dem Senden wird nichts hart gecastet: fehlt ein zugesagtes Feld, wirft
17
23
  * der Aufruf `KasseneckValidationError` mit `scope:'response'`.
@@ -93,7 +99,10 @@ export async function searchCustomers(transport, search) {
93
99
  }
94
100
  // ---- Rechnungen -------------------------------------------------------------
95
101
  export async function issueInvoice(transport, request) {
96
- const daten = await transport('issueInvoice', nutzlast(request));
102
+ const params = nutzlast(request);
103
+ // Ohne Typen kann `dryRun: true` hier ankommen: dann ist es ein Probelauf
104
+ // ohne Wirkung (sonst: `previewInvoice`).
105
+ const daten = await transport('issueInvoice', params, undefined, undefined, { hasEffect: params['dryRun'] !== true });
97
106
  const ergebnis = {
98
107
  invoice: pflichtObjekt('issueInvoice', daten, 'invoice'),
99
108
  replayed: objekt(daten)['replayed'] === true,
@@ -114,7 +123,9 @@ export async function issueInvoice(transport, request) {
114
123
  * Probelauf und Ausstellen kann sich der Kunde oder das Konto aendern.
115
124
  */
116
125
  export async function previewInvoice(transport, request) {
117
- const daten = await transport('issueInvoice', { ...nutzlast(request), dryRun: true });
126
+ // Ein Probelauf schreibt nichts: nach einem Zeitlimit bleibt er `rejected`,
127
+ // obwohl `issueInvoice` sonst Wirkung hat.
128
+ const daten = await transport('issueInvoice', { ...nutzlast(request), dryRun: true }, undefined, undefined, { hasEffect: false });
118
129
  const ergebnis = { preview: pflichtObjekt('issueInvoice', daten, 'preview') };
119
130
  const notice = hinweise(daten);
120
131
  if (notice)
@@ -14,8 +14,8 @@ export { createInvoiceApi, type InvoiceApi, type InvoiceApiOptions } from './api
14
14
  export { invoiceKeyAuth, type InvoiceKeyAuthOptions } from './auth.js';
15
15
  export { isInvoiceError, isInvoiceErrorCode, invoiceErrorCode, invoiceFieldErrors, type InvoiceApiErrorCode, type InvoiceFieldError, } from './fehler.js';
16
16
  export { cancelInvoice, createCreditNote, createCustomer, getCustomer, getInvoice, getInvoicePdf, getInvoiceSetupStatus, getInvoiceXml, issueInvoice, listBrands, listInvoices, previewInvoice, recordInvoicePayment, searchCustomers, updateCustomer, } from './endpunkte.js';
17
- export type { Brand, CancelInvoiceRequest, CancelResult, CreditNoteItemInput, CreditNoteRequest, CreditNoteResult, Customer, CustomerInput, CustomerPage, CustomerSearch, EInvoiceStatus, Invoice, InvoiceDetail, InvoiceDetailPayment, InvoiceItem, InvoiceItemInput, InvoiceListQuery, InvoicePage, InvoiceRecipient, InvoiceSetupGap, InvoiceSetupStatus, InvoiceTotals, InvoiceXml, InvoiceNotice, InvoicePayment, InvoicePreview, InvoiceRateTotals, IssueInvoiceRequest, IssueResult, PaymentInput, PreviewResult, RecordPaymentRequest, RecordPaymentResult, } from './typen.js';
17
+ export type { Brand, CancelInvoiceRequest, CancelResult, CreditNoteItemInput, CreditNoteRequest, CreditNoteResult, Customer, CustomerInput, CustomerPage, CustomerSearch, EInvoiceStatus, Invoice, InvoiceDetail, InvoiceDetailPayment, InvoiceItem, InvoiceItemInput, IssueInvoiceItemInput, InvoiceListQuery, InvoicePage, InvoiceRecipient, InvoiceSetupGap, InvoiceSetupStatus, InvoiceTotals, InvoiceXml, InvoiceNotice, InvoicePayment, InvoicePreview, InvoiceRateTotals, InvoiceVatIdProof, InvoiceVatIdRisk, IssueInvoiceRequest, IssueResult, PaymentInput, PreviewResult, RecordPaymentRequest, RecordPaymentResult, } from './typen.js';
18
18
  export { INVOICE_TEXTS, invoiceText, type InvoiceTextKey } from './texte.js';
19
19
  export { computeInvoiceTotals, ZERO_RATED_TAX_SCHEMES, type TotalsItem } from './summen.js';
20
20
  export { proratedPriceMicros, MAX_AMOUNT_CENTS, itemFromEuro, formatUnitPrice, CalcError, calculateInvoice, roundDiv, vatRateMapKey, formatVatRate, type CalcResult, type CalcErrorCode, type CalcOptions, type CalcItem, type RateTotal, type ItemConversion, type ConversionReason, type LineAmount, } from './calc.js';
21
- export { INVOICE_CONTRACT_VERSION, INVOICE_ENDPOINTS, INVOICE_ERROR_CODES, INVOICE_REQUEST_ERROR_CODES, CREDIT_NOTE_REASONS, TAX_SCHEMES, PRICE_MODES, VAT_RATES, CUSTOMER_TYPES, INVOICE_LIST_STATUS, DOC_TYPES, EINVOICE_FORMATS, EINVOICE_MISSING_CODES, WRITE_OFF_REASON_CODES, INVOICE_LANGUAGES, INVOICE_PAYMENT_METHODS, ITEM_KINDS, REVERSE_CHARGE_REASONS, INVOICE_NOTICE_CODES, INVOICE_UNITS, INVOICE_UNIT_CODES, INVOICE_SETUP_REQUIREMENTS, CUSTOMER_FIELDS, ITEM_FIELDS, CREDIT_NOTE_ITEM_FIELDS, RETURN_DISPOSITIONS, ITEM_PRICE_EXACTLY_ONE, INVOICE_REQUESTS, INVOICE_EXACTLY_ONE, INVOICE_AT_LEAST_ONE, type InvoiceEndpoint, type InvoiceErrorCode, type InvoiceRequestErrorCode, type CreditNoteReason, type ReturnDisposition, type TaxScheme, type PriceMode, type VatRatePercent, type CustomerType, type InvoiceListStatus, type DocType, type EInvoiceFormat, type EInvoiceMissingCode, type WriteOffReasonCode, type InvoiceLanguage, type InvoicePaymentMethod, type ItemKind, type ReverseChargeReason, type InvoiceNoticeCode, type InvoiceUnit, type InvoiceSetupRequirement, type FieldFormat, type Field, } from './vertrag.js';
21
+ export { INVOICE_CONTRACT_VERSION, INVOICE_ENDPOINTS, INVOICE_ERROR_CODES, INVOICE_REQUEST_ERROR_CODES, CREDIT_NOTE_REASONS, TAX_SCHEMES, PRICE_MODES, VAT_RATES, CUSTOMER_TYPES, INVOICE_LIST_STATUS, DOC_TYPES, EINVOICE_FORMATS, EINVOICE_MISSING_CODES, WRITE_OFF_REASON_CODES, INVOICE_LANGUAGES, INVOICE_PAYMENT_METHODS, ITEM_KINDS, REVERSE_CHARGE_REASONS, INVOICE_NOTICE_CODES, INVOICE_UNITS, INVOICE_UNIT_CODES, INVOICE_SETUP_REQUIREMENTS, CUSTOMER_FIELDS, ITEM_FIELDS, INVOICE_ITEM_FIELDS, CREDIT_NOTE_ITEM_FIELDS, RETURN_DISPOSITIONS, ITEM_PRICE_EXACTLY_ONE, INVOICE_REQUESTS, INVOICE_EXACTLY_ONE, INVOICE_AT_LEAST_ONE, type InvoiceEndpoint, type InvoiceErrorCode, type InvoiceRequestErrorCode, type CreditNoteReason, type ReturnDisposition, type TaxScheme, type PriceMode, type VatRatePercent, type CustomerType, type InvoiceListStatus, type DocType, type EInvoiceFormat, type EInvoiceMissingCode, type WriteOffReasonCode, type InvoiceLanguage, type InvoicePaymentMethod, type ItemKind, type ReverseChargeReason, type InvoiceNoticeCode, type InvoiceUnit, type InvoiceSetupRequirement, type FieldFormat, type Field, } from './vertrag.js';
@@ -17,4 +17,4 @@ export { cancelInvoice, createCreditNote, createCustomer, getCustomer, getInvoic
17
17
  export { INVOICE_TEXTS, invoiceText } from './texte.js';
18
18
  export { computeInvoiceTotals, ZERO_RATED_TAX_SCHEMES } from './summen.js';
19
19
  export { proratedPriceMicros, MAX_AMOUNT_CENTS, itemFromEuro, formatUnitPrice, CalcError, calculateInvoice, roundDiv, vatRateMapKey, formatVatRate, } from './calc.js';
20
- export { INVOICE_CONTRACT_VERSION, INVOICE_ENDPOINTS, INVOICE_ERROR_CODES, INVOICE_REQUEST_ERROR_CODES, CREDIT_NOTE_REASONS, TAX_SCHEMES, PRICE_MODES, VAT_RATES, CUSTOMER_TYPES, INVOICE_LIST_STATUS, DOC_TYPES, EINVOICE_FORMATS, EINVOICE_MISSING_CODES, WRITE_OFF_REASON_CODES, INVOICE_LANGUAGES, INVOICE_PAYMENT_METHODS, ITEM_KINDS, REVERSE_CHARGE_REASONS, INVOICE_NOTICE_CODES, INVOICE_UNITS, INVOICE_UNIT_CODES, INVOICE_SETUP_REQUIREMENTS, CUSTOMER_FIELDS, ITEM_FIELDS, CREDIT_NOTE_ITEM_FIELDS, RETURN_DISPOSITIONS, ITEM_PRICE_EXACTLY_ONE, INVOICE_REQUESTS, INVOICE_EXACTLY_ONE, INVOICE_AT_LEAST_ONE, } from './vertrag.js';
20
+ export { INVOICE_CONTRACT_VERSION, INVOICE_ENDPOINTS, INVOICE_ERROR_CODES, INVOICE_REQUEST_ERROR_CODES, CREDIT_NOTE_REASONS, TAX_SCHEMES, PRICE_MODES, VAT_RATES, CUSTOMER_TYPES, INVOICE_LIST_STATUS, DOC_TYPES, EINVOICE_FORMATS, EINVOICE_MISSING_CODES, WRITE_OFF_REASON_CODES, INVOICE_LANGUAGES, INVOICE_PAYMENT_METHODS, ITEM_KINDS, REVERSE_CHARGE_REASONS, INVOICE_NOTICE_CODES, INVOICE_UNITS, INVOICE_UNIT_CODES, INVOICE_SETUP_REQUIREMENTS, CUSTOMER_FIELDS, ITEM_FIELDS, INVOICE_ITEM_FIELDS, CREDIT_NOTE_ITEM_FIELDS, RETURN_DISPOSITIONS, ITEM_PRICE_EXACTLY_ONE, INVOICE_REQUESTS, INVOICE_EXACTLY_ONE, INVOICE_AT_LEAST_ONE, } from './vertrag.js';
@@ -89,7 +89,20 @@ export interface InvoiceItemInput {
89
89
  /** Artikel aus dem Artikelstamm; bestandsgefuehrt bucht das Ausstellen ihn vom Lager ab. */
90
90
  articleId?: string;
91
91
  }
92
- /** Eine Gutschriftsposition: wie eine Rechnungsposition, dazu die Rueckgabe-Wahl. */
92
+ /**
93
+ * Eine Position beim Ausstellen (`issueInvoice`): dazu optional die
94
+ * Reservierung aus der Lager-API, die diese Position einloest.
95
+ */
96
+ export interface IssueInvoiceItemInput extends InvoiceItemInput {
97
+ /**
98
+ * Kennung aus `createReservation` (`./inventory`); braucht `articleId`.
99
+ * Geprueft beim Ausstellen (`reservation_not_found`, `reservation_mismatch`,
100
+ * `reservation_not_active`; abgelaufen = Hinweis `reservation_expired`),
101
+ * eingeloest beim Buchen der Rechnung am Lagerstandort der Rechnung.
102
+ */
103
+ reservationId?: string;
104
+ }
105
+ /** Eine Gutschriftsposition: wie eine Rechnungsposition (ohne Reservierung), dazu die Rueckgabe-Wahl. */
93
106
  export interface CreditNoteItemInput extends InvoiceItemInput {
94
107
  /** Wohin die Ware dieser Position geht; fehlt = Vorgabe des Aufrufs bzw. `restock`. */
95
108
  returnDisposition?: ReturnDisposition;
@@ -115,7 +128,7 @@ export interface IssueInvoiceRequest {
115
128
  paymentReference?: string;
116
129
  girocode?: boolean;
117
130
  tracking?: boolean;
118
- items: InvoiceItemInput[];
131
+ items: IssueInvoiceItemInput[];
119
132
  /** Eigene Merkmale (hoechstens 20), nie gedruckt. */
120
133
  metadata?: Record<string, string>;
121
134
  /** Sprache dieser Rechnung; sonst die des Kunden, sonst `de`. Eine Rechnung, eine Nummer, eine Sprache. */
@@ -130,6 +143,15 @@ export interface IssueInvoiceRequest {
130
143
  * Zahlungsinformationen und keinen Giro-QR.
131
144
  */
132
145
  payment?: PaymentInput;
146
+ /**
147
+ * Nur fuer Rechnungen ohne Steuer, die die UID des Kunden verlangen (ig.
148
+ * Lieferung, Reverse Charge): hat die UID-Pruefung noch kein Ergebnis
149
+ * (`vat_id_check_pending`), stellt `true` trotzdem aus. Der Aussteller traegt
150
+ * dann das Risiko, die Rechnung traegt `vatIdRisk`. Eine ungueltige UID
151
+ * (`vat_id_invalid`) sperrt auch damit. Gehoert nicht zur Anfrage im Sinn der
152
+ * Idempotenz: dieselbe Anfrage mit und ohne das Feld ist dieselbe Rechnung.
153
+ */
154
+ acceptVatIdRisk?: boolean;
133
155
  }
134
156
  /** Eine Zahlung, wie das Fremdsystem sie meldet. */
135
157
  export interface PaymentInput {
@@ -168,6 +190,8 @@ export interface InvoicePayment {
168
190
  export interface InvoiceNotice {
169
191
  code: InvoiceNoticeCode;
170
192
  message: string;
193
+ /** Bei `reservation_expired`: die abgelaufene Reservierung. */
194
+ reservationId?: string;
171
195
  }
172
196
  export interface RecordPaymentResult {
173
197
  invoice: Invoice;
@@ -238,6 +262,26 @@ export interface Invoice {
238
262
  paidCents: number;
239
263
  /** Was noch offen ist; `0` heisst bezahlt. */
240
264
  openCents: number;
265
+ /** Beim Festschreiben eingefrorener UID-Nachweis des Kunden; sonst `null`. */
266
+ vatIdProof: InvoiceVatIdProof | null;
267
+ /** Ohne Ergebnis der UID-Pruefung mit `acceptVatIdRisk` ausgestellt; sonst `null`. */
268
+ vatIdRisk: InvoiceVatIdRisk | null;
269
+ }
270
+ /** UID-Nachweis an einer Rechnung: gueltige Pruefung der Kunden-UID, hoechstens 30 Tage vor dem Festschreiben. */
271
+ export interface InvoiceVatIdProof {
272
+ /** Wiener Tag der Pruefung (`YYYY-MM-DD`). */
273
+ checkedOn: string;
274
+ /** Wer geprueft hat: FinanzOnline (Stufe 2 mit Name und Anschrift) oder VIES. */
275
+ source: 'finanzonline' | 'vies';
276
+ /** Stufe der Pruefung: 1 = nur UID, 2 = UID mit Name und Anschrift. */
277
+ level: 1 | 2;
278
+ /** Pruefcode fuer die oeffentliche Pruefseite (auf dem PDF als QR); `null`, wenn keiner vergeben wurde. */
279
+ code: string | null;
280
+ }
281
+ /** Ausgestellt ohne Ergebnis der UID-Pruefung, das Risiko traegt der Aussteller. */
282
+ export interface InvoiceVatIdRisk {
283
+ /** Wiener Tag der Bestaetigung (`YYYY-MM-DD`). */
284
+ acceptedOn: string;
241
285
  }
242
286
  /** Eine Marke des Kontos (Logo, Farbe, Absender) — `id` geht als `brandId` in `issueInvoice`. */
243
287
  export interface Brand {
@@ -27,7 +27,7 @@ export type InvoiceEndpoint = (typeof INVOICE_ENDPOINTS)[number];
27
27
  * Stabile Fehlercodes. Das Fremdsystem verzweigt am Code, der Text darf sich
28
28
  * aendern. `validation` traegt zusaetzlich `errors: [{ field, message }]`.
29
29
  */
30
- export declare const INVOICE_ERROR_CODES: readonly ["validation", "idempotency_conflict", "module_inactive", "customer_not_found", "customer_exists", "short_code_taken", "short_code_immutable", "recipient_required", "invoice_requirements_missing", "invoice_not_found", "invoice_ambiguous", "not_cancellable", "partial_credit_exists", "credit_exceeds_invoice", "einvoice_incomplete", "invoice_api_not_enabled", "invoice_setup_incomplete", "language_not_allowed", "brand_not_found", "not_payable", "payment_exceeds_invoice", "tax_scheme_mismatch", "vat_rate_not_in_country", "reverse_charge_reason_required", "reverse_charge_threshold", "mixed_supply_not_allowed", "oss_not_enabled", "einvoice_unavailable", "amount_too_large"];
30
+ export declare const INVOICE_ERROR_CODES: readonly ["validation", "idempotency_conflict", "module_inactive", "customer_not_found", "customer_exists", "short_code_taken", "short_code_immutable", "recipient_required", "invoice_requirements_missing", "invoice_not_found", "invoice_ambiguous", "not_cancellable", "partial_credit_exists", "credit_exceeds_invoice", "einvoice_incomplete", "invoice_api_not_enabled", "invoice_setup_incomplete", "language_not_allowed", "brand_not_found", "not_payable", "payment_exceeds_invoice", "tax_scheme_mismatch", "vat_rate_not_in_country", "reverse_charge_reason_required", "reverse_charge_threshold", "mixed_supply_not_allowed", "oss_not_enabled", "einvoice_unavailable", "amount_too_large", "vat_id_invalid", "vat_id_check_pending", "reservation_not_found", "reservation_mismatch", "reservation_not_active"];
31
31
  export type InvoiceErrorCode = (typeof INVOICE_ERROR_CODES)[number];
32
32
  /**
33
33
  * Codes, die Anmeldung und Rand auf jedem Rechnungsaufruf erzeugen koennen,
@@ -170,7 +170,7 @@ export type InvoicePaymentMethod = (typeof INVOICE_PAYMENT_METHODS)[number];
170
170
  * Hinweise, die eine erfolgreiche Antwort zusaetzlich tragen kann (`data.notice`).
171
171
  * Sie sind keine Fehler: der Aufruf hat gewirkt, es gibt nur etwas zu wissen.
172
172
  */
173
- export declare const INVOICE_NOTICE_CODES: readonly ["cash_receipt_required", "recapitulative_statement_due", "place_of_supply_check"];
173
+ export declare const INVOICE_NOTICE_CODES: readonly ["cash_receipt_required", "recapitulative_statement_due", "place_of_supply_check", "reservation_expired"];
174
174
  export type InvoiceNoticeCode = (typeof INVOICE_NOTICE_CODES)[number];
175
175
  /**
176
176
  * Einheiten einer Position. Die API nimmt nur diese Schluessel an; gedruckt
@@ -270,12 +270,26 @@ export declare const CUSTOMER_FIELDS: Readonly<Record<string, Field>>;
270
270
  * die bisher gerundet eingereicht werden mussten.
271
271
  */
272
272
  export declare const ITEM_FIELDS: Readonly<Record<string, Field>>;
273
+ /**
274
+ * Eine Rechnungsposition beim Ausstellen: die gemeinsamen Positionsfelder plus
275
+ * `reservationId` (seit 1.5.0). Die Reservierung aus der Lager-API
276
+ * (`createReservation`) wird beim Ausstellen geprueft und beim Buchen der
277
+ * Rechnung eingeloest; die Position braucht dazu `articleId`. Unbekannt =
278
+ * `reservation_not_found`, schon eingeloest oder freigegeben =
279
+ * `reservation_not_active`, kein offener Rest dieses Artikels am Lagerstandort
280
+ * der Rechnung (`stockLocationId`, sonst der Standard-Standort) =
281
+ * `reservation_mismatch`; abgelaufen ist kein Fehler, sondern der Hinweis
282
+ * `reservation_expired`. Weniger verkauft als reserviert gibt den Rest frei.
283
+ * Gutschriften kennen das Feld nicht (`validation`).
284
+ */
285
+ export declare const INVOICE_ITEM_FIELDS: Readonly<Record<string, Field>>;
273
286
  /** Genau einer der beiden Preise je Position (§ 9.1). */
274
287
  export declare const ITEM_PRICE_EXACTLY_ONE: readonly (readonly string[])[];
275
288
  /**
276
- * Eine Gutschriftsposition: die Rechnungsposition plus `returnDisposition`
277
- * (wohin die zurueckgenommene Ware geht). An einer Rechnungsposition weist der
278
- * Server das Feld als unbekannt ab.
289
+ * Eine Gutschriftsposition: die gemeinsamen Positionsfelder plus
290
+ * `returnDisposition` (wohin die zurueckgenommene Ware geht), ohne
291
+ * `reservationId`. An einer Rechnungsposition weist der Server
292
+ * `returnDisposition` als unbekannt ab.
279
293
  */
280
294
  export declare const CREDIT_NOTE_ITEM_FIELDS: Readonly<Record<string, Field>>;
281
295
  /**
@@ -70,6 +70,13 @@ export const INVOICE_ERROR_CODES = [
70
70
  'oss_not_enabled',
71
71
  'einvoice_unavailable', // zu dieser Rechnung entsteht keine E-Rechnung, Grund in `reason`
72
72
  'amount_too_large', // Betrag ueber der Grenze des Ganzzahlkerns; erst ab dessen Umstieg gesendet
73
+ // Seit 1.5.0 (0.x: 0.33.0): UID-Pruefung beim Ausstellen ohne Steuer.
74
+ 'vat_id_invalid', // UID des Kunden laut FinanzOnline/VIES ungueltig, sperrt auch mit acceptVatIdRisk
75
+ 'vat_id_check_pending', // noch kein Ergebnis der UID-Pruefung; `retryAfter` in Sekunden, oder acceptVatIdRisk
76
+ // Seit 1.5.0: Position mit `reservationId` (nur `issueInvoice`), geprueft beim Ausstellen.
77
+ 'reservation_not_found', // unbekannt oder einem anderen Konto
78
+ 'reservation_mismatch', // keine offene Position mit gleichem Artikel am Lagerstandort der Rechnung
79
+ 'reservation_not_active', // schon eingeloest oder freigegeben
73
80
  ];
74
81
  /**
75
82
  * Codes, die Anmeldung und Rand auf jedem Rechnungsaufruf erzeugen koennen,
@@ -227,6 +234,10 @@ export const INVOICE_NOTICE_CODES = [
227
234
  /** Leistung an eine Privatperson im Drittland: der Leistungsort haengt von der
228
235
  * Art der Leistung ab — wir nehmen den oesterreichischen Fall an. */
229
236
  'place_of_supply_check',
237
+ /** Die Reservierung einer Position war beim Ausstellen schon abgelaufen: die
238
+ * Rechnung entsteht trotzdem, verkauft wird ohne Reservierung (seit 1.5.0).
239
+ * Der Hinweis nennt `reservationId`, je Reservierung einmal. */
240
+ 'reservation_expired',
230
241
  ];
231
242
  /**
232
243
  * Einheiten einer Position. Die API nimmt nur diese Schluessel an; gedruckt
@@ -429,6 +440,19 @@ export const ITEM_FIELDS = Object.freeze({
429
440
  */
430
441
  articleId: id,
431
442
  });
443
+ /**
444
+ * Eine Rechnungsposition beim Ausstellen: die gemeinsamen Positionsfelder plus
445
+ * `reservationId` (seit 1.5.0). Die Reservierung aus der Lager-API
446
+ * (`createReservation`) wird beim Ausstellen geprueft und beim Buchen der
447
+ * Rechnung eingeloest; die Position braucht dazu `articleId`. Unbekannt =
448
+ * `reservation_not_found`, schon eingeloest oder freigegeben =
449
+ * `reservation_not_active`, kein offener Rest dieses Artikels am Lagerstandort
450
+ * der Rechnung (`stockLocationId`, sonst der Standard-Standort) =
451
+ * `reservation_mismatch`; abgelaufen ist kein Fehler, sondern der Hinweis
452
+ * `reservation_expired`. Weniger verkauft als reserviert gibt den Rest frei.
453
+ * Gutschriften kennen das Feld nicht (`validation`).
454
+ */
455
+ export const INVOICE_ITEM_FIELDS = Object.freeze({ ...ITEM_FIELDS, reservationId: id });
432
456
  /** Genau einer der beiden Preise je Position (§ 9.1). */
433
457
  export const ITEM_PRICE_EXACTLY_ONE = Object.freeze([
434
458
  Object.freeze(['unitPriceCents']),
@@ -440,15 +464,16 @@ const positionen = {
440
464
  min: 1,
441
465
  max: 500,
442
466
  item: {
443
- type: 'object', required: true, fields: ITEM_FIELDS, exactlyOne: ITEM_PRICE_EXACTLY_ONE,
467
+ type: 'object', required: true, fields: INVOICE_ITEM_FIELDS, exactlyOne: ITEM_PRICE_EXACTLY_ONE,
444
468
  },
445
469
  };
446
470
  /** Rueckgabe-Wahl einer Gutschrift: Vorgabe des Aufrufs oder je Position. */
447
471
  const returnDisposition = { type: 'enum', required: false, values: RETURN_DISPOSITIONS };
448
472
  /**
449
- * Eine Gutschriftsposition: die Rechnungsposition plus `returnDisposition`
450
- * (wohin die zurueckgenommene Ware geht). An einer Rechnungsposition weist der
451
- * Server das Feld als unbekannt ab.
473
+ * Eine Gutschriftsposition: die gemeinsamen Positionsfelder plus
474
+ * `returnDisposition` (wohin die zurueckgenommene Ware geht), ohne
475
+ * `reservationId`. An einer Rechnungsposition weist der Server
476
+ * `returnDisposition` als unbekannt ab.
452
477
  */
453
478
  export const CREDIT_NOTE_ITEM_FIELDS = Object.freeze({ ...ITEM_FIELDS, returnDisposition });
454
479
  const gutschriftPositionen = {
@@ -545,6 +570,13 @@ export const INVOICE_REQUESTS = Object.freeze({
545
570
  * Idempotenz-Eintrag. Die Antwort traegt `preview` statt `invoice`.
546
571
  */
547
572
  dryRun: { type: 'boolean', required: false },
573
+ /**
574
+ * Rechnung ohne Steuer, deren UID-Pruefung (FinanzOnline, sonst VIES) noch
575
+ * kein Ergebnis hat: `true` stellt trotzdem aus. Der Aussteller traegt das
576
+ * Risiko, die Rechnung steht dann mit `vatIdRisk`. Eine ungueltige UID
577
+ * (`vat_id_invalid`) sperrt auch damit.
578
+ */
579
+ acceptVatIdRisk: { type: 'boolean', required: false },
548
580
  },
549
581
  cancelInvoice: {
550
582
  idempotencyKey: idempotencyKey(true),
@@ -661,12 +661,17 @@ export interface ErrorRuleDetail {
661
661
  export declare function findErrorRule(kind: ErrorKind, detail?: ErrorRuleDetail): ErrorRule;
662
662
  /**
663
663
  * Kassen-Aufrufe mit Wirkung, die sich nach einem Netzfehler nicht gefahrlos
664
- * wiederholen lassen: die sechs, deren Ausgang das Paket selbst als unklar
665
- * fuehrt (Beleg, auch Null- und Startbeleg ueber `createReceipt`, Storno,
666
- * FinanzOnline, die drei Geldwege), dazu der Druckjob (zweiter Bon) und die
667
- * Belegmail (zweite Mail). Ob die Anfrage vor dem Abriss schon draussen war,
668
- * sieht das Paket nicht (fetch wirft in beiden Faellen gleich); darum gilt
669
- * hier immer der vorsichtige Satz.
664
+ * wiederholen lassen: Beleg (auch Null- und Startbeleg ueber
665
+ * `createReceipt`), Storno, FinanzOnline, die drei Geldwege, der Druckjob
666
+ * (zweiter Bon) und die Belegmail (zweite Mail). Ob die Anfrage vor dem
667
+ * Abriss schon draussen war, sieht das Paket nicht (fetch wirft in beiden
668
+ * Faellen gleich); darum gilt hier immer der vorsichtige Satz, auch fuer
669
+ * einen Fehler, der vor dem Senden entstand.
670
+ *
671
+ * Seit 1.5.1 fuehrt der Transport jeden Aufruf mit Wirkung als unklar
672
+ * (`UNKNOWN_OUTCOME_CALLS`, eine Obermenge dieser Liste), und
673
+ * [messageOutcome] folgt zuerst ihm. Die Liste bleibt als Vertrag der
674
+ * Kassentexte (`callsWithEffect` in `fixtures/pos-texts.json`) unveraendert.
670
675
  */
671
676
  export declare const CALLS_WITH_EFFECT: readonly ["createReceipt", "cancelReceipt", "financeWebService", "hobexPayApi", "hobexRefundApi", "stripeCaptureIntent", "createPrintJob", "sendReceiptEmail"];
672
677
  /**
@@ -368,12 +368,17 @@ export function findErrorRule(kind, detail = {}) {
368
368
  }
369
369
  /**
370
370
  * Kassen-Aufrufe mit Wirkung, die sich nach einem Netzfehler nicht gefahrlos
371
- * wiederholen lassen: die sechs, deren Ausgang das Paket selbst als unklar
372
- * fuehrt (Beleg, auch Null- und Startbeleg ueber `createReceipt`, Storno,
373
- * FinanzOnline, die drei Geldwege), dazu der Druckjob (zweiter Bon) und die
374
- * Belegmail (zweite Mail). Ob die Anfrage vor dem Abriss schon draussen war,
375
- * sieht das Paket nicht (fetch wirft in beiden Faellen gleich); darum gilt
376
- * hier immer der vorsichtige Satz.
371
+ * wiederholen lassen: Beleg (auch Null- und Startbeleg ueber
372
+ * `createReceipt`), Storno, FinanzOnline, die drei Geldwege, der Druckjob
373
+ * (zweiter Bon) und die Belegmail (zweite Mail). Ob die Anfrage vor dem
374
+ * Abriss schon draussen war, sieht das Paket nicht (fetch wirft in beiden
375
+ * Faellen gleich); darum gilt hier immer der vorsichtige Satz, auch fuer
376
+ * einen Fehler, der vor dem Senden entstand.
377
+ *
378
+ * Seit 1.5.1 fuehrt der Transport jeden Aufruf mit Wirkung als unklar
379
+ * (`UNKNOWN_OUTCOME_CALLS`, eine Obermenge dieser Liste), und
380
+ * [messageOutcome] folgt zuerst ihm. Die Liste bleibt als Vertrag der
381
+ * Kassentexte (`callsWithEffect` in `fixtures/pos-texts.json`) unveraendert.
377
382
  */
378
383
  export const CALLS_WITH_EFFECT = Object.freeze([
379
384
  'createReceipt',
@@ -1,5 +1,5 @@
1
1
  /** Fingerabdruck des Vertrags-Exports, aus dem diese Datei stammt (`_quelle.sha256`). */
2
- export declare const VOKABULAR_QUELLE = "79931a40ccaea45777da4713bba475c2f74e1fe7d6264f294cecd321964f9ded";
2
+ export declare const VOKABULAR_QUELLE = "d351a778c02888291e325068f96156ad1346859f6ff97bae27f91089e9619e8c";
3
3
  /** Schema-Notation des Vertrags: Blatt 'aussen': 'innen', Objekt { __: 'innen', ... }, Liste [ { __: 'innen', ... } ]. */
4
4
  export type SchemaEintrag = string | SchemaObjekt | readonly [SchemaObjekt];
5
5
  export interface SchemaObjekt {
@@ -1,7 +1,7 @@
1
1
  // Erzeugt von scripts/stored-vokabular.mjs aus fixtures/v3/v3-vokabular.json.
2
2
  // Nicht von Hand aendern: test/stored.test.ts vergleicht mit dem Vertrag.
3
3
  /** Fingerabdruck des Vertrags-Exports, aus dem diese Datei stammt (`_quelle.sha256`). */
4
- export const VOKABULAR_QUELLE = "79931a40ccaea45777da4713bba475c2f74e1fe7d6264f294cecd321964f9ded";
4
+ export const VOKABULAR_QUELLE = "d351a778c02888291e325068f96156ad1346859f6ff97bae27f91089e9619e8c";
5
5
  /** Schema je Endpunkt (aussen -> innen) und Wertverweise auf die Kataloge. */
6
6
  export const SCHEMAS = {
7
7
  "getReceipt": {
@@ -220,7 +220,8 @@ export const SCHEMAS = {
220
220
  "visible": "sichtbar",
221
221
  "sort": "sort"
222
222
  },
223
- "stockLocationIds": "standorte"
223
+ "stockLocationIds": "standorte",
224
+ "minStockByLocation": "mindestJeStandort"
224
225
  }
225
226
  ]
226
227
  },
@@ -258,7 +259,8 @@ export const ARTIKEL_FELDER = [
258
259
  "active",
259
260
  "groupId",
260
261
  "tile",
261
- "stockLocationIds"
262
+ "stockLocationIds",
263
+ "minStockByLocation"
262
264
  ];
263
265
  /** Wertkataloge innen (deutsch) -> aussen (englisch). */
264
266
  export const KATALOGE = {