kassza 0.12.0 → 0.14.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 (177) hide show
  1. package/README.en.md +48 -0
  2. package/README.md +427 -32
  3. package/agents/README.md +26 -6
  4. package/agents/api.md +218 -3
  5. package/agents/pitfalls.md +27 -3
  6. package/agents/recipes.md +280 -51
  7. package/agents/skills/kassza/SKILL.md +14 -8
  8. package/agents/skills/migrate-from-szamlazz-js/SKILL.md +39 -0
  9. package/dist/batch/index.cjs +346 -0
  10. package/dist/batch/index.d.cts +91 -0
  11. package/dist/batch/index.d.ts +91 -0
  12. package/dist/batch/index.js +339 -0
  13. package/dist/cli.cjs +643 -0
  14. package/dist/cli.d.cts +1 -0
  15. package/dist/cli.d.ts +1 -0
  16. package/dist/cli.js +643 -0
  17. package/dist/client-CLFvJCVW.cjs +1452 -0
  18. package/dist/{client-CL3fuH6A.js → client-Cvf-hTz_.js} +306 -515
  19. package/dist/client-DeWWQ-RZ.d.ts +341 -0
  20. package/dist/client-SVZu25MB.d.cts +341 -0
  21. package/dist/context-CFNKzStE.d.cts +449 -0
  22. package/dist/context-kb33TgzE.d.ts +449 -0
  23. package/dist/cookie-stores/index.cjs +21 -150
  24. package/dist/cookie-stores/index.d.cts +4 -63
  25. package/dist/cookie-stores/index.d.ts +4 -63
  26. package/dist/cookie-stores/index.js +3 -144
  27. package/dist/create-CflXrPip.js +204 -0
  28. package/dist/create-CvUvLUaT.cjs +257 -0
  29. package/dist/{create-once-D0pwuenl.cjs → create-once-9yxR_Er_.cjs} +291 -33
  30. package/dist/create-once-Bh6fOWkW.d.cts +20 -0
  31. package/dist/{create-once-CqdYmQD8.js → create-once-Ca2gMk1h.js} +250 -34
  32. package/dist/create-once-VKp0tVow.d.ts +20 -0
  33. package/dist/{crypto-B8lERvR1.cjs → crypto-Dpn4FHQ6.cjs} +9 -0
  34. package/dist/{crypto-DK_osBVy.js → crypto-usDg8L2K.js} +4 -1
  35. package/dist/data-link/index.cjs +232 -0
  36. package/dist/data-link/index.d.cts +29 -0
  37. package/dist/data-link/index.d.ts +29 -0
  38. package/dist/data-link/index.js +224 -0
  39. package/dist/delegation/index.cjs +35 -34
  40. package/dist/delegation/index.d.cts +2 -1
  41. package/dist/delegation/index.d.ts +2 -1
  42. package/dist/delegation/index.js +4 -3
  43. package/dist/{errors-DLrb0g64.js → errors-DtN4g5Z9.js} +9 -1
  44. package/dist/{errors-DxeuTslP.cjs → errors-EE96_6D_.cjs} +20 -0
  45. package/dist/get-BdMTseh4.cjs +271 -0
  46. package/dist/get-Byc9T5WO.d.cts +151 -0
  47. package/dist/get-Byc9T5WO.d.ts +151 -0
  48. package/dist/get-CZEShCcj.js +260 -0
  49. package/dist/index-BhUPY_EH.d.cts +109 -0
  50. package/dist/index-BqGgQ4t3.d.ts +109 -0
  51. package/dist/{index-CYAGCdKJ.d.cts → index-C-7yWV7L.d.cts} +24 -1
  52. package/dist/{index-CYAGCdKJ.d.ts → index-C-7yWV7L.d.ts} +24 -1
  53. package/dist/index.cjs +19 -5
  54. package/dist/index.d.cts +11 -19
  55. package/dist/index.d.ts +11 -19
  56. package/dist/index.js +6 -6
  57. package/dist/ipn/index.cjs +26 -5
  58. package/dist/ipn/index.d.cts +12 -1
  59. package/dist/ipn/index.d.ts +12 -1
  60. package/dist/ipn/index.js +26 -6
  61. package/dist/issue-Bin4tKD_.cjs +988 -0
  62. package/dist/issue-DMA1Nbr1.js +905 -0
  63. package/dist/journal/index.cjs +454 -0
  64. package/dist/journal/index.d.cts +18 -0
  65. package/dist/journal/index.d.ts +18 -0
  66. package/dist/journal/index.js +445 -0
  67. package/dist/journal-DvI81Kt7.d.cts +114 -0
  68. package/dist/journal-Y9qrIB8G.d.ts +114 -0
  69. package/dist/mcp/index.cjs +10 -0
  70. package/dist/mcp/index.d.cts +71 -0
  71. package/dist/mcp/index.d.ts +71 -0
  72. package/dist/mcp/index.js +2 -0
  73. package/dist/money/index.cjs +2 -1
  74. package/dist/money/index.d.cts +2 -2
  75. package/dist/money/index.d.ts +2 -2
  76. package/dist/money/index.js +2 -2
  77. package/dist/{money-DAA7OwiO.js → money-Cw457SD6.js} +120 -12
  78. package/dist/{money-DrhGkWHW.cjs → money-K9j0wPit.cjs} +124 -10
  79. package/dist/nav/index.cjs +1046 -0
  80. package/dist/nav/index.d.cts +247 -0
  81. package/dist/nav/index.d.ts +247 -0
  82. package/dist/nav/index.js +1012 -0
  83. package/dist/nav-BNbc8U0R.cjs +203 -0
  84. package/dist/nav-BcCerwWS.js +156 -0
  85. package/dist/node/index.cjs +124 -0
  86. package/dist/node/index.d.cts +35 -0
  87. package/dist/node/index.d.ts +35 -0
  88. package/dist/node/index.js +120 -0
  89. package/dist/observe/index.cjs +311 -0
  90. package/dist/observe/index.d.cts +53 -0
  91. package/dist/observe/index.d.ts +53 -0
  92. package/dist/observe/index.js +303 -0
  93. package/dist/once-BN_3B5OF.cjs +103 -0
  94. package/dist/once-CqqZxsXG.js +74 -0
  95. package/dist/parse-Cr7yQ3_z.js +291 -0
  96. package/dist/parse-DOA2XQ3e.cjs +380 -0
  97. package/dist/payments/barion.cjs +26 -2
  98. package/dist/payments/barion.d.cts +2 -2
  99. package/dist/payments/barion.d.ts +2 -2
  100. package/dist/payments/barion.js +26 -2
  101. package/dist/payments/index.cjs +7 -2
  102. package/dist/payments/index.d.cts +4 -4
  103. package/dist/payments/index.d.ts +4 -4
  104. package/dist/payments/index.js +3 -3
  105. package/dist/payments/paypal.cjs +16 -2
  106. package/dist/payments/paypal.d.cts +2 -2
  107. package/dist/payments/paypal.d.ts +2 -2
  108. package/dist/payments/paypal.js +16 -2
  109. package/dist/payments/revolut.cjs +17 -3
  110. package/dist/payments/revolut.d.cts +2 -2
  111. package/dist/payments/revolut.d.ts +2 -2
  112. package/dist/payments/revolut.js +17 -3
  113. package/dist/payments/simplepay.cjs +37 -5
  114. package/dist/payments/simplepay.d.cts +2 -2
  115. package/dist/payments/simplepay.d.ts +2 -2
  116. package/dist/payments/simplepay.js +37 -5
  117. package/dist/payments/stripe.cjs +20 -3
  118. package/dist/payments/stripe.d.cts +2 -2
  119. package/dist/payments/stripe.d.ts +2 -2
  120. package/dist/payments/stripe.js +20 -3
  121. package/dist/push-BXj0Sf0Z.d.ts +52 -0
  122. package/dist/push-D4nNbCNV.d.cts +52 -0
  123. package/dist/reference-B5TATqb5.js +124 -0
  124. package/dist/reference-BIdYMK0t.cjs +183 -0
  125. package/dist/reports/index.cjs +11 -164
  126. package/dist/reports/index.d.cts +1 -1
  127. package/dist/reports/index.d.ts +1 -1
  128. package/dist/reports/index.js +1 -154
  129. package/dist/request-body-CH6ZGOrq.cjs +34 -0
  130. package/dist/request-body-uZHMRlQr.js +29 -0
  131. package/dist/serialize-B2eFh3D-.js +219 -0
  132. package/dist/serialize-CquIsxA-.cjs +290 -0
  133. package/dist/server-BrJUbXs7.js +1505 -0
  134. package/dist/server-Dw9j8Mnd.cjs +1558 -0
  135. package/dist/session-Ckl5eJhV.d.ts +7 -0
  136. package/dist/{session-CKOuE6Jc.cjs → session-DeM5vjvC.cjs} +69 -13
  137. package/dist/{session-rMKaJcmq.js → session-SaEEXu2N.js} +58 -14
  138. package/dist/session-YbChChx7.d.cts +7 -0
  139. package/dist/storage/fs.cjs +1 -1
  140. package/dist/storage/fs.js +1 -1
  141. package/dist/storage/index.cjs +1 -1
  142. package/dist/storage/index.js +1 -1
  143. package/dist/store-C1rHd9DB.d.cts +19 -0
  144. package/dist/store-C1rHd9DB.d.ts +19 -0
  145. package/dist/stores/index.cjs +24 -0
  146. package/dist/stores/index.d.cts +4 -0
  147. package/dist/stores/index.d.ts +4 -0
  148. package/dist/stores/index.js +3 -0
  149. package/dist/stores-BNrS0dWl.cjs +506 -0
  150. package/dist/stores-DhjGBrl_.js +441 -0
  151. package/dist/testing/index.cjs +1500 -15
  152. package/dist/testing/index.d.cts +198 -3
  153. package/dist/testing/index.d.ts +198 -3
  154. package/dist/testing/index.js +1498 -15
  155. package/dist/{types-COf1LAD-.d.ts → types-B1A8mUIE.d.cts} +14 -2
  156. package/dist/{types-COf1LAD-.d.cts → types-ByAEvGsZ.d.ts} +14 -2
  157. package/dist/{types-k--zHf4l.d.ts → types-D1zDOH_F.d.ts} +1 -1
  158. package/dist/{types-DH8QoNZK.d.cts → types-lnKkQdot.d.cts} +1 -1
  159. package/dist/warnings-B3DXnveC.d.cts +31 -0
  160. package/dist/warnings-B3DXnveC.d.ts +31 -0
  161. package/dist/warnings-DeIw5RFj.cjs +20 -0
  162. package/dist/warnings-DwTl5J-2.js +15 -0
  163. package/dist/{webhook-D4lvtex1.js → webhook-CQVShAfI.js} +47 -26
  164. package/dist/{webhook-C76bV-4R.cjs → webhook-Ckj-_hPD.cjs} +70 -25
  165. package/dist/webhook-CmdhGiH5.d.cts +11 -0
  166. package/dist/webhook-D6lEejob.d.ts +11 -0
  167. package/llms.txt +6 -5
  168. package/package.json +134 -4
  169. package/dist/client-CickRRFr.d.ts +0 -838
  170. package/dist/client-CsmGIFRS.cjs +0 -1637
  171. package/dist/client-DvWZoX_E.d.cts +0 -838
  172. package/dist/issue-BsyYdrIG.cjs +0 -1531
  173. package/dist/issue-C6Fcjvln.js +0 -1274
  174. package/dist/session-Dm_45x8K.d.cts +0 -11
  175. package/dist/session-Dm_45x8K.d.ts +0 -11
  176. package/dist/webhook-CfaDgcL0.d.cts +0 -6
  177. package/dist/webhook-q2OzNwd7.d.ts +0 -6
@@ -1,8 +1,1480 @@
1
- import { i as resolveInvoice, s as emitDocumentEvent, t as createReceiptOnce } from "../create-once-CqdYmQD8.js";
2
- import { n as SzamlazzError } from "../errors-DLrb0g64.js";
3
- import { _ as createInvoiceOnce, a as calculateReceiptItems, i as buildCreateReceiptXml, m as convertReceiptToInvoice, n as issueForPayment } from "../issue-C6Fcjvln.js";
4
- import { n as toAgentDate } from "../dates-CXyj7Azy.js";
5
- import { i as summarizeItems } from "../money-DAA7OwiO.js";
1
+ import { c as resolveInvoice, h as AGENT_ACTIONS, p as emitDocumentEvent, r as registerPaymentOnce, t as createReceiptOnce } from "../create-once-Ca2gMk1h.js";
2
+ import { r as SzamlazzError, t as AGENT_ERROR_CODES } from "../errors-DtN4g5Z9.js";
3
+ import { i as encodeUtf8, n as bytesToBase64 } from "../binary-D0M9U2MD.js";
4
+ import { a as optionalEl, c as childNumber, d as findChildren, f as parseXml, i as formatXmlNumber, l as childText, n as buildXmlDocument, r as el, s as childBoolean, u as findChild } from "../serialize-B2eFh3D-.js";
5
+ import { l as createInvoiceOnce, n as issueForPayment, o as convertReceiptToInvoice } from "../issue-DMA1Nbr1.js";
6
+ import { n as toAgentDate, r as toBudapestDate } from "../dates-CXyj7Azy.js";
7
+ import { n as decimalPlaces, r as roundMoney } from "../rounding-BLyHjjI5.js";
8
+ import { i as isHuf, t as NUMERIC_VAT_RATES } from "../vat-v_dcWCto.js";
9
+ import { a as summarizeItems } from "../money-Cw457SD6.js";
10
+ import { n as calculateReceiptItems, t as buildCreateReceiptXml } from "../create-CflXrPip.js";
11
+ //#region src/testing/fake-agent-http.ts
12
+ const XML_CONTENT_TYPE = "application/xml; charset=UTF-8";
13
+ const TEXT_CONTENT_TYPE = "text/plain; charset=UTF-8";
14
+ const PDF_CONTENT_TYPE = "application/pdf";
15
+ const ERROR_ROOTS = {
16
+ invoice: "xmlszamlavalasz",
17
+ receipt: "xmlnyugtavalasz",
18
+ "receipt-send": "xmlnyugtasendvalasz",
19
+ proforma: "xmlszamladbkdelvalasz"
20
+ };
21
+ function encodeHeaderValue(value) {
22
+ return encodeURIComponent(value).replace(/%20/g, "+");
23
+ }
24
+ function xmlResponse(xml, headers = {}) {
25
+ return {
26
+ status: 200,
27
+ headers: {
28
+ "content-type": XML_CONTENT_TYPE,
29
+ ...headers
30
+ },
31
+ body: xml
32
+ };
33
+ }
34
+ function textResponse(text, headers = {}, status = 200) {
35
+ return {
36
+ status,
37
+ headers: {
38
+ "content-type": TEXT_CONTENT_TYPE,
39
+ ...headers
40
+ },
41
+ body: text
42
+ };
43
+ }
44
+ function pdfResponse(pdf, headers = {}) {
45
+ return {
46
+ status: 200,
47
+ headers: {
48
+ "content-type": PDF_CONTENT_TYPE,
49
+ ...headers
50
+ },
51
+ body: pdf
52
+ };
53
+ }
54
+ function serverErrorResponse() {
55
+ return {
56
+ status: 500,
57
+ headers: { "content-type": "text/html; charset=UTF-8" },
58
+ body: "<!DOCTYPE html><html><body><h1>500 Internal Server Error</h1></body></html>"
59
+ };
60
+ }
61
+ function namespaceOf(root) {
62
+ return `http://www.szamlazz.hu/${root}`;
63
+ }
64
+ function xmlDocument(root, children) {
65
+ return buildXmlDocument({
66
+ root,
67
+ namespace: namespaceOf(root),
68
+ children
69
+ });
70
+ }
71
+ function errorHeaders(failure) {
72
+ return {
73
+ szlahu_error: encodeHeaderValue(failure.message),
74
+ ...failure.code === void 0 ? {} : { szlahu_error_code: String(failure.code) }
75
+ };
76
+ }
77
+ function errorText(failure) {
78
+ return `[ERR] ${failure.code === void 0 ? "" : `[${failure.code}] `}${failure.message}\n----------\nkassza hamis Agent\n`;
79
+ }
80
+ function errorResponse(style, failure) {
81
+ if (style === "text") return textResponse(errorText(failure), errorHeaders(failure));
82
+ return xmlResponse(xmlDocument(ERROR_ROOTS[style], [
83
+ el("sikeres", false),
84
+ optionalEl("hibakod", failure.code),
85
+ el("hibauzenet", failure.message)
86
+ ]), style === "invoice" ? errorHeaders(failure) : {});
87
+ }
88
+ function invoiceResultHeaders(fields) {
89
+ const headers = {};
90
+ if (fields.number !== void 0) headers.szlahu_szamlaszam = encodeHeaderValue(fields.number);
91
+ if (fields.netTotal !== void 0) headers.szlahu_nettovegosszeg = formatXmlNumber(fields.netTotal);
92
+ if (fields.grossTotal !== void 0) headers.szlahu_bruttovegosszeg = formatXmlNumber(fields.grossTotal);
93
+ if (fields.outstanding !== void 0) headers.szlahu_kintlevoseg = formatXmlNumber(fields.outstanding);
94
+ if (fields.paymentMethod !== void 0) headers.szlahu_fizetesmod = encodeHeaderValue(fields.paymentMethod);
95
+ return headers;
96
+ }
97
+ function invoiceResultResponse(fields, version) {
98
+ const headers = invoiceResultHeaders(fields);
99
+ if (version === 2) return xmlResponse(xmlDocument("xmlszamlavalasz", [
100
+ el("sikeres", true),
101
+ optionalEl("szamlaszam", fields.number),
102
+ optionalEl("szamlanetto", fields.netTotal),
103
+ optionalEl("szamlabrutto", fields.grossTotal),
104
+ optionalEl("kintlevoseg", fields.outstanding),
105
+ optionalEl("pdf", fields.pdf && bytesToBase64(fields.pdf))
106
+ ]), headers);
107
+ if (fields.pdf) return pdfResponse(fields.pdf, headers);
108
+ return textResponse(`xmlagentresponse=DONE${fields.number === void 0 ? "" : `;${fields.number}`}\n`, headers);
109
+ }
110
+ function toFetchResponse(response) {
111
+ const body = typeof response.body === "string" ? response.body : new Blob([response.body]);
112
+ return new Response(body, {
113
+ status: response.status,
114
+ headers: response.headers
115
+ });
116
+ }
117
+ //#endregion
118
+ //#region src/testing/fake-agent-state.ts
119
+ var FakeAgentFailure = class extends Error {
120
+ name = "FakeAgentFailure";
121
+ code;
122
+ constructor(code, message) {
123
+ super(message);
124
+ this.code = code;
125
+ }
126
+ };
127
+ function agentFailure(code, message) {
128
+ return new FakeAgentFailure(code, message ?? AGENT_ERROR_CODES[code]?.message ?? `Hiba (${code}).`);
129
+ }
130
+ function nextCounter(state, key) {
131
+ const next = (state.counters.get(key) ?? 0) + 1;
132
+ state.counters.set(key, next);
133
+ return next;
134
+ }
135
+ function today(state) {
136
+ return toBudapestDate(state.now());
137
+ }
138
+ function nextDocumentNumber(state, series) {
139
+ const year = today(state).slice(0, 4);
140
+ return `${series}-${year}-${nextCounter(state, `${series}|${year}`)}`;
141
+ }
142
+ function nextDocumentId(state) {
143
+ return nextCounter(state, "#id");
144
+ }
145
+ function fakePdf(label) {
146
+ return encodeUtf8(`%PDF-1.4\n%kassza hamis Agent: ${label}\n%%EOF\n`);
147
+ }
148
+ function taxpayerKey(value) {
149
+ return value.replace(/\D/g, "").slice(0, 8);
150
+ }
151
+ //#endregion
152
+ //#region src/testing/fake-agent-items.ts
153
+ const SERVER_VAT_CODES = /* @__PURE__ */ new Set([
154
+ "TAM",
155
+ "AAM",
156
+ "EU",
157
+ "EUK",
158
+ "MAA",
159
+ "F.AFA",
160
+ "K.AFA",
161
+ "ÁKK",
162
+ "TAHK",
163
+ "TEHK",
164
+ "EUT",
165
+ "EUKT",
166
+ "HO",
167
+ "EUE",
168
+ "EUFADE",
169
+ "EUFAD37",
170
+ "ATK",
171
+ "NAM",
172
+ "EAM",
173
+ "KBAUK",
174
+ "KBAET"
175
+ ]);
176
+ const NUMERIC_RATES = new Set(NUMERIC_VAT_RATES);
177
+ const AMOUNT_FIELDS = {
178
+ invoice: {
179
+ net: "nettoErtek",
180
+ vat: "afaErtek",
181
+ gross: "bruttoErtek"
182
+ },
183
+ receipt: {
184
+ net: "netto",
185
+ vat: "afa",
186
+ gross: "brutto"
187
+ }
188
+ };
189
+ const HUF_TOLERANCE = 2;
190
+ const FOREIGN_TOLERANCE = .02;
191
+ const SUM_EPSILON = 1e-6;
192
+ const RECEIPT_DECIMALS = 2;
193
+ const TOTAL_DECIMALS = 6;
194
+ function xmlFailure(detail) {
195
+ return new FakeAgentFailure(57, `XML beolvasási hiba: ${detail}`);
196
+ }
197
+ function requiredText$2(element, name, position) {
198
+ const value = childText(element, name);
199
+ if (value === void 0) throw xmlFailure(`hiányzik a(z) ${position}. tétel <${name}> eleme.`);
200
+ return value;
201
+ }
202
+ function requiredNumber(element, name, position) {
203
+ const value = childNumber(element, name);
204
+ if (value === void 0) throw xmlFailure(`a(z) ${position}. tétel <${name}> eleme hiányzik vagy nem szám.`);
205
+ return value;
206
+ }
207
+ function parseVat(raw, itemName) {
208
+ const numeric = Number(raw.replace(",", "."));
209
+ if (Number.isFinite(numeric) && NUMERIC_RATES.has(numeric)) return { rate: numeric };
210
+ if (SERVER_VAT_CODES.has(raw)) return {
211
+ rate: 0,
212
+ code: raw
213
+ };
214
+ throw new FakeAgentFailure(395, `Érvénytelen áfakulcs: ${raw}. Termék: ${itemName}`);
215
+ }
216
+ function ledgerOf(element) {
217
+ const revenue = childText(element, "arbevetel");
218
+ const vat = childText(element, "afa");
219
+ return revenue === void 0 && vat === void 0 ? void 0 : {
220
+ revenue,
221
+ vat
222
+ };
223
+ }
224
+ function parseItem(element, kind, position) {
225
+ const fields = AMOUNT_FIELDS[kind];
226
+ const name = requiredText$2(element, "megnevezes", position);
227
+ const vat = parseVat(requiredText$2(element, "afakulcs", position), name);
228
+ return {
229
+ name,
230
+ identifier: childText(element, "azonosito"),
231
+ quantity: requiredNumber(element, "mennyiseg", position),
232
+ unit: requiredText$2(element, "mennyisegiEgyseg", position),
233
+ netUnitPrice: requiredNumber(element, "nettoEgysegar", position),
234
+ vatRate: vat.rate,
235
+ vatCode: vat.code,
236
+ netAmount: requiredNumber(element, fields.net, position),
237
+ vatAmount: requiredNumber(element, fields.vat, position),
238
+ grossAmount: requiredNumber(element, fields.gross, position),
239
+ comment: childText(element, "megjegyzes"),
240
+ ledger: kind === "receipt" ? ledgerOf(findChild(element, "fokonyv")) : void 0
241
+ };
242
+ }
243
+ function parseItems(root, kind) {
244
+ const elements = findChildren(findChild(root, "tetelek"), "tetel");
245
+ if (elements.length === 0) throw xmlFailure("legalább egy tételt (<tetel>) meg kell adni.");
246
+ return elements.map((element, index) => parseItem(element, kind, index + 1));
247
+ }
248
+ function amountFailure(code, item) {
249
+ return new FakeAgentFailure(code, `${{
250
+ 259: "A tétel nettó értéke nem megfelelő; nettó érték = nettó egységár x mennyiség.",
251
+ 260: "A tétel áfa értéke nem megfelelő; áfa érték = tétel nettó értéke x áfakulcs mértéke / 100.",
252
+ 261: "A tétel bruttó értéke nem megfelelő; bruttó érték = tétel nettó értéke + tétel áfa értéke.",
253
+ 363: "A tétel bruttó értékének egész számnak kell lennie.",
254
+ 364: "A tétel nettó értéke maximum 2 tizedes jegyet tartalmazhat.",
255
+ 365: "A tétel áfa értéke maximum 2 tizedes jegyet tartalmazhat."
256
+ }[code] ?? "Hibás tételösszeg."} Termék: ${item.name}`);
257
+ }
258
+ function netMismatch(item, tolerance) {
259
+ return Math.abs(item.netUnitPrice * item.quantity - item.netAmount) > tolerance;
260
+ }
261
+ function vatMismatch(item, tolerance) {
262
+ return Math.abs(item.netAmount * item.vatRate / 100 - item.vatAmount) > tolerance;
263
+ }
264
+ function grossMismatch(item) {
265
+ return Math.abs(item.netAmount + item.vatAmount - item.grossAmount) > SUM_EPSILON;
266
+ }
267
+ function assertInvoiceItems(items, currency, hasMarginVat) {
268
+ const tolerance = isHuf(currency) ? HUF_TOLERANCE : FOREIGN_TOLERANCE;
269
+ items.forEach((item, index) => {
270
+ if (netMismatch(item, tolerance)) throw amountFailure(259, item);
271
+ if (!hasMarginVat(index) && vatMismatch(item, tolerance)) throw amountFailure(260, item);
272
+ if (grossMismatch(item)) throw amountFailure(261, item);
273
+ });
274
+ }
275
+ function assertReceiptItems(items, currency) {
276
+ if (!isHuf(currency)) return;
277
+ for (const item of items) {
278
+ if (grossMismatch(item)) throw amountFailure(261, item);
279
+ if (!Number.isInteger(item.grossAmount)) throw amountFailure(363, item);
280
+ if (decimalPlaces(item.netAmount) > RECEIPT_DECIMALS) throw amountFailure(364, item);
281
+ if (decimalPlaces(item.vatAmount) > RECEIPT_DECIMALS) throw amountFailure(365, item);
282
+ if (netMismatch(item, HUF_TOLERANCE)) throw amountFailure(259, item);
283
+ if (vatMismatch(item, HUF_TOLERANCE)) throw amountFailure(260, item);
284
+ }
285
+ }
286
+ function sum(values) {
287
+ return roundMoney(values.reduce((total, value) => total + value, 0), TOTAL_DECIMALS);
288
+ }
289
+ function totalsOf(items) {
290
+ return {
291
+ net: sum(items.map((item) => item.netAmount)),
292
+ vat: sum(items.map((item) => item.vatAmount)),
293
+ gross: sum(items.map((item) => item.grossAmount))
294
+ };
295
+ }
296
+ function vatGroupsOf(items) {
297
+ const groups = /* @__PURE__ */ new Map();
298
+ for (const item of items) {
299
+ const key = `${item.vatCode ?? ""}|${item.vatRate}`;
300
+ groups.set(key, [...groups.get(key) ?? [], item]);
301
+ }
302
+ return [...groups.values()].flatMap((group) => {
303
+ const [first] = group;
304
+ if (!first) return [];
305
+ const totals = totalsOf(group);
306
+ return [{
307
+ vatRate: first.vatRate,
308
+ vatCode: first.vatCode,
309
+ net: totals.net,
310
+ vat: totals.vat,
311
+ gross: totals.gross
312
+ }];
313
+ });
314
+ }
315
+ function negateItem(item) {
316
+ return {
317
+ ...item,
318
+ quantity: -item.quantity,
319
+ netAmount: -item.netAmount,
320
+ vatAmount: -item.vatAmount,
321
+ grossAmount: -item.grossAmount
322
+ };
323
+ }
324
+ function negateTotals(totals) {
325
+ return {
326
+ net: -totals.net,
327
+ vat: -totals.vat,
328
+ gross: -totals.gross
329
+ };
330
+ }
331
+ function outstandingOf(gross, paid) {
332
+ return gross > 0 ? Math.max(0, sum([gross, -paid])) : 0;
333
+ }
334
+ //#endregion
335
+ //#region src/testing/fake-agent-account.ts
336
+ const NAV_API_NAMESPACE = "http://schemas.nav.gov.hu/OSA/3.0/api";
337
+ const TAXPAYER_ID_PATTERN = /^\d{8}$/;
338
+ const CONNECT_PRINCIPAL_MESSAGES = {
339
+ created: "DONE",
340
+ ownerInviteResent: "Már létező fiók, nincs fiókgazdája. Fiókgazdai meghívó (megbízott számlakibocsátás) email újraküldve.",
341
+ joinRequestSent: "Már létező fiók fiókgazdával. Csatlakozási kérelmet küldtünk a fiókgazdának.",
342
+ joinRequestResent: "Már létező fiók fiókgazdával. A csatlakozási kérelem emailt újraküldtük a fiókgazdának."
343
+ };
344
+ function authenticateDelegate(state, username, password) {
345
+ const delegate = state.delegates.get(username);
346
+ if (!delegate) return false;
347
+ if (delegate.password !== password || !delegate.approved) throw agentFailure(3);
348
+ if (state.principals.get(delegate.taxpayerId)?.state !== "owned") throw agentFailure(250);
349
+ return true;
350
+ }
351
+ function authenticate(state, credentials) {
352
+ const { agentKey, username, password } = credentials;
353
+ if (agentKey !== void 0) {
354
+ if (!state.config.strictAuth || state.config.agentKeys.has(agentKey)) return;
355
+ throw agentFailure(3);
356
+ }
357
+ if (username === void 0 || password === void 0) throw agentFailure(3);
358
+ if (authenticateDelegate(state, username, password)) return;
359
+ if (!state.config.strictAuth || state.users.get(username) === password) return;
360
+ throw agentFailure(3);
361
+ }
362
+ function acceptDelegation(state, taxNumber) {
363
+ const key = taxpayerKey(taxNumber);
364
+ const principal = state.principals.get(key);
365
+ if (!principal) throw new TypeError(`Nincs ilyen megbízói fiók a hamis Agentben: ${taxNumber}`);
366
+ state.principals.set(key, {
367
+ ...principal,
368
+ state: "owned"
369
+ });
370
+ for (const [email, delegate] of state.delegates) if (delegate.taxpayerId === key) state.delegates.set(email, {
371
+ ...delegate,
372
+ approved: true
373
+ });
374
+ }
375
+ function addressNode(taxpayer) {
376
+ const { address } = taxpayer;
377
+ if (!address) return void 0;
378
+ return el("taxpayerAddressList", [el("taxpayerAddressItem", [el("taxpayerAddressType", "HQ"), el("taxpayerAddress", [
379
+ el("countryCode", "HU"),
380
+ el("postalCode", address.postalCode),
381
+ el("city", address.city),
382
+ optionalEl("streetName", address.streetName),
383
+ optionalEl("publicPlaceCategory", address.publicPlaceCategory),
384
+ optionalEl("number", address.number)
385
+ ])])]);
386
+ }
387
+ function taxpayerDataNode(taxpayerId, taxpayer) {
388
+ return el("taxpayerData", [
389
+ el("taxpayerName", taxpayer.name),
390
+ optionalEl("taxpayerShortName", taxpayer.shortName),
391
+ el("taxNumberDetail", [
392
+ el("taxpayerId", taxpayerId),
393
+ optionalEl("vatCode", taxpayer.vatCode),
394
+ optionalEl("countyCode", taxpayer.countyCode)
395
+ ]),
396
+ optionalEl("incorporation", taxpayer.incorporation),
397
+ addressNode(taxpayer)
398
+ ]);
399
+ }
400
+ function handleQueryTaxpayer(state, request) {
401
+ const taxpayerId = childText(request.root, "torzsszam");
402
+ if (taxpayerId === void 0 || !TAXPAYER_ID_PATTERN.test(taxpayerId)) throw xmlFailure("a <torzsszam> elemben 8 jegyű adószám-törzsszám kell.");
403
+ const taxpayer = state.config.taxpayers[taxpayerId];
404
+ const valid = taxpayer !== void 0 && taxpayer.valid !== false;
405
+ const timestamp = state.now().toISOString();
406
+ return xmlResponse(buildXmlDocument({
407
+ root: "QueryTaxpayerResponse",
408
+ namespace: NAV_API_NAMESPACE,
409
+ children: [
410
+ el("header", [
411
+ el("requestId", `KASSZAFAKE${nextCounter(state, "#nav")}`),
412
+ el("timestamp", timestamp),
413
+ el("requestVersion", "3.0"),
414
+ el("headerVersion", "1.0")
415
+ ]),
416
+ el("result", [el("funcCode", "OK")]),
417
+ el("infoDate", timestamp),
418
+ el("taxpayerValidity", valid),
419
+ valid && taxpayer && taxpayerDataNode(taxpayerId, taxpayer)
420
+ ]
421
+ }));
422
+ }
423
+ function connectResponse(message) {
424
+ const encoded = encodeHeaderValue(message);
425
+ return textResponse(`xmlagentresponse=${encoded}\n`, { XML_AGENT_RESPONSE: encoded });
426
+ }
427
+ function handleConnectPrincipal(state, request) {
428
+ const company = findChild(request.root, "cegMb");
429
+ const user = findChild(request.root, "usrMb");
430
+ const taxNumber = childText(company, "cegtaxnumber");
431
+ if (taxNumber === void 0) throw xmlFailure("hiányzik a(z) <cegMb/cegtaxnumber> elem.");
432
+ const key = taxpayerKey(taxNumber);
433
+ const principal = state.principals.get(key);
434
+ const email = childText(user, "usremail");
435
+ const password = childText(user, "usrpassword");
436
+ if (email === void 0 || password === void 0) throw xmlFailure("hiányzik a(z) <usrMb/usremail> vagy <usrMb/usrpassword> elem.");
437
+ if (!principal) {
438
+ state.principals.set(key, {
439
+ state: "unowned",
440
+ joinRequests: 0
441
+ });
442
+ state.delegates.set(email, {
443
+ taxpayerId: key,
444
+ password,
445
+ approved: true
446
+ });
447
+ return connectResponse(CONNECT_PRINCIPAL_MESSAGES.created);
448
+ }
449
+ if (principal.state === "unowned") return connectResponse(CONNECT_PRINCIPAL_MESSAGES.ownerInviteResent);
450
+ if (!state.delegates.has(email)) state.delegates.set(email, {
451
+ taxpayerId: key,
452
+ password,
453
+ approved: false
454
+ });
455
+ state.principals.set(key, {
456
+ ...principal,
457
+ joinRequests: principal.joinRequests + 1
458
+ });
459
+ return connectResponse(principal.joinRequests === 0 ? CONNECT_PRINCIPAL_MESSAGES.joinRequestSent : CONNECT_PRINCIPAL_MESSAGES.joinRequestResent);
460
+ }
461
+ //#endregion
462
+ //#region src/testing/fake-agent-invoice-xml.ts
463
+ const UNIFIED_PAYMENT_METHODS = [
464
+ "átutalás",
465
+ "készpénz",
466
+ "bankkártya",
467
+ "csekk",
468
+ "utánvét",
469
+ "ajándékutalvány",
470
+ "barion",
471
+ "barter",
472
+ "csoportos beszedés",
473
+ "OTP Simple",
474
+ "kompenzáció",
475
+ "kupon",
476
+ "PayPal",
477
+ "PayU",
478
+ "SZÉP kártya",
479
+ "utalvány",
480
+ "MasterCard Mobile",
481
+ "Borgun",
482
+ "EP kártya",
483
+ "térítésmentes",
484
+ "egyéb"
485
+ ];
486
+ const OTHER_PAYMENT_METHOD = "egyéb";
487
+ const CASH_PAYMENT_METHOD = "készpénz";
488
+ const SELLER_ID = 1;
489
+ const DOMESTIC_LOCATION = 1;
490
+ const PAPER_APPEARANCE = 0;
491
+ const E_INVOICE_APPEARANCE = 2;
492
+ function unifiedPaymentMethod(method) {
493
+ const normalized = method.trim().toLowerCase();
494
+ return UNIFIED_PAYMENT_METHODS.find((candidate) => candidate.toLowerCase() === normalized) ?? OTHER_PAYMENT_METHOD;
495
+ }
496
+ function sellerNode(invoice) {
497
+ const { seller } = invoice;
498
+ return el("szallito", [
499
+ el("id", SELLER_ID),
500
+ el("nev", seller.name),
501
+ el("cim", [
502
+ optionalEl("orszag", seller.country),
503
+ el("irsz", seller.zip),
504
+ el("telepules", seller.city),
505
+ el("cim", seller.address)
506
+ ]),
507
+ el("adoszam", seller.taxNumber),
508
+ optionalEl("bank", [optionalEl("nev", seller.bankName), optionalEl("bankszamla", seller.bankAccount)])
509
+ ]);
510
+ }
511
+ function headerNode(invoice, testAccount) {
512
+ const unified = unifiedPaymentMethod(invoice.paymentMethod);
513
+ return el("alap", [
514
+ el("id", invoice.id),
515
+ el("szamlaszam", invoice.number),
516
+ el("gazdEsemAzon", invoice.id),
517
+ el("tipus", invoice.typeCode),
518
+ el("eszamla", invoice.eInvoice ? E_INVOICE_APPEARANCE : PAPER_APPEARANCE),
519
+ optionalEl("hivszamlaszam", invoice.referencedInvoiceNumber),
520
+ optionalEl("hivdijbekszam", invoice.referencedProformaNumber),
521
+ el("kelt", invoice.issueDate),
522
+ el("telj", invoice.fulfillmentDate),
523
+ el("fizh", invoice.dueDate),
524
+ el("fizmod", invoice.paymentMethod),
525
+ el("fizmodunified", unified),
526
+ el("keszpenz", unified === CASH_PAYMENT_METHOD),
527
+ optionalEl("rendelesszam", invoice.orderNumber),
528
+ el("nyelv", invoice.language),
529
+ el("devizanem", invoice.currency),
530
+ optionalEl("devizabank", invoice.exchangeBank),
531
+ optionalEl("devizaarf", invoice.exchangeRate),
532
+ optionalEl("megjegyzes", invoice.comment),
533
+ el("penzforg", false),
534
+ el("kata", false),
535
+ el("katafokonyv", false),
536
+ optionalEl("email", invoice.buyer.email),
537
+ el("teszt", testAccount),
538
+ el("sztornozott", invoice.reversed)
539
+ ]);
540
+ }
541
+ function buyerNode(invoice) {
542
+ const { buyer } = invoice;
543
+ return el("vevo", [
544
+ el("nev", buyer.name),
545
+ optionalEl("azonosito", buyer.identifier),
546
+ el("cim", [
547
+ optionalEl("orszag", buyer.country),
548
+ el("irsz", buyer.zip),
549
+ el("telepules", buyer.city),
550
+ el("cim", buyer.address)
551
+ ]),
552
+ optionalEl("email", buyer.email),
553
+ el("adoszam", buyer.taxNumber ?? ""),
554
+ optionalEl("csoportazonosito", buyer.groupTaxNumber),
555
+ optionalEl("adoszameu", buyer.euTaxNumber),
556
+ el("lokacio", DOMESTIC_LOCATION),
557
+ el("privatePersonIndicator", buyer.taxNumber === void 0 && buyer.euTaxNumber === void 0)
558
+ ]);
559
+ }
560
+ function itemNode$1(item, index) {
561
+ return el("tetel", [
562
+ el("nev", item.name),
563
+ optionalEl("azonosito", item.identifier),
564
+ el("mennyiseg", item.quantity),
565
+ el("mennyisegiegyseg", item.unit),
566
+ el("nettoegysegar", item.netUnitPrice),
567
+ optionalEl("afatipus", item.vatCode),
568
+ el("afakulcs", item.vatRate),
569
+ el("netto", item.netAmount),
570
+ el("afa", item.vatAmount),
571
+ el("brutto", item.grossAmount),
572
+ optionalEl("megjegyzes", item.comment),
573
+ el("sztetordering", index + 1)
574
+ ]);
575
+ }
576
+ function vatGroupNode(group) {
577
+ return el("afakulcsossz", [
578
+ optionalEl("afatipus", group.vatCode),
579
+ el("afakulcs", group.vatRate),
580
+ el("netto", group.net),
581
+ el("afa", group.vat),
582
+ el("brutto", group.gross)
583
+ ]);
584
+ }
585
+ function totalNode(totals) {
586
+ return el("totalossz", [
587
+ el("netto", totals.net),
588
+ el("afa", totals.vat),
589
+ el("brutto", totals.gross)
590
+ ]);
591
+ }
592
+ function paymentNode$1(payment) {
593
+ return el("kifizetes", [
594
+ el("datum", payment.date),
595
+ el("jogcim", payment.method),
596
+ el("osszeg", payment.amount),
597
+ optionalEl("megjegyzes", payment.comment)
598
+ ]);
599
+ }
600
+ function renderInvoiceXml(invoice, testAccount, includePdf) {
601
+ return buildXmlDocument({
602
+ root: "szamla",
603
+ namespace: "http://www.szamlazz.hu/szamla",
604
+ children: [
605
+ sellerNode(invoice),
606
+ headerNode(invoice, testAccount),
607
+ buyerNode(invoice),
608
+ el("tetelek", invoice.items.map(itemNode$1)),
609
+ el("osszegek", [...vatGroupsOf(invoice.items).map(vatGroupNode), totalNode(invoice.totals)]),
610
+ invoice.payments.length > 0 && el("kifizetesek", invoice.payments.map(paymentNode$1)),
611
+ includePdf && el("pdf", bytesToBase64(fakePdf(invoice.number)))
612
+ ]
613
+ });
614
+ }
615
+ //#endregion
616
+ //#region src/testing/fake-agent-request.ts
617
+ const REQUEST_ROOTS = {
618
+ createInvoice: "xmlszamla",
619
+ reverseInvoice: "xmlszamlast",
620
+ registerPayment: "xmlszamlakifiz",
621
+ getInvoicePdf: "xmlszamlapdf",
622
+ getInvoiceXml: "xmlszamlaxml",
623
+ deleteProforma: "xmlszamladbkdel",
624
+ createReceipt: "xmlnyugtacreate",
625
+ reverseReceipt: "xmlnyugtast",
626
+ getReceipt: "xmlnyugtaget",
627
+ sendReceipt: "xmlnyugtasend",
628
+ queryTaxpayer: "xmltaxpayer",
629
+ connectPrincipal: "XmlCegMb"
630
+ };
631
+ const MAX_ATTACHMENTS = 5;
632
+ const ACTION_FIELDS = Object.entries(AGENT_ACTIONS);
633
+ async function readForm(input, init) {
634
+ if (init?.body instanceof FormData) return init.body;
635
+ try {
636
+ return await (input instanceof Request && init === void 0 ? input : new Request(input, init)).formData();
637
+ } catch {
638
+ return;
639
+ }
640
+ }
641
+ async function entryText(value) {
642
+ return typeof value === "string" ? value : value.text();
643
+ }
644
+ function attachmentsOf(form) {
645
+ const attachments = [];
646
+ for (let index = 1; index <= MAX_ATTACHMENTS; index++) {
647
+ const value = form.get(`attachfile${index}`);
648
+ if (value instanceof Blob) attachments.push({
649
+ filename: value instanceof File ? value.name : "",
650
+ size: value.size
651
+ });
652
+ }
653
+ return attachments;
654
+ }
655
+ async function readFakeAgentForm(input, init) {
656
+ const form = await readForm(input, init);
657
+ if (!form) return {
658
+ action: void 0,
659
+ xml: void 0,
660
+ attachments: []
661
+ };
662
+ for (const [action, field] of ACTION_FIELDS) {
663
+ const value = form.get(field);
664
+ if (value !== null) return {
665
+ action,
666
+ xml: await entryText(value),
667
+ attachments: attachmentsOf(form)
668
+ };
669
+ }
670
+ return {
671
+ action: void 0,
672
+ xml: void 0,
673
+ attachments: attachmentsOf(form)
674
+ };
675
+ }
676
+ function parseFakeAgentRequest(action, xml, attachments) {
677
+ let root;
678
+ try {
679
+ root = parseXml(xml);
680
+ } catch (error) {
681
+ throw new FakeAgentFailure(57, `XML beolvasási hiba.${error instanceof Error ? ` ${error.message}` : ""}`);
682
+ }
683
+ const expected = REQUEST_ROOTS[action];
684
+ if (root.name !== expected) throw new FakeAgentFailure(57, `XML beolvasási hiba. A(z) ${action} művelethez <${expected}> gyökérelem kell, érkezett: <${root.name}>.`);
685
+ return {
686
+ action,
687
+ xml,
688
+ root,
689
+ attachments
690
+ };
691
+ }
692
+ function credentialsOf(root) {
693
+ for (const holder of [
694
+ findChild(root, "login"),
695
+ findChild(root, "beallitasok"),
696
+ root
697
+ ]) {
698
+ const agentKey = childText(holder, "szamlaagentkulcs");
699
+ const username = childText(holder, "felhasznalo") ?? childText(holder, "loginname");
700
+ const password = childText(holder, "jelszo") ?? childText(holder, "password");
701
+ if (agentKey !== void 0 || username !== void 0 || password !== void 0) return {
702
+ agentKey,
703
+ username,
704
+ password
705
+ };
706
+ }
707
+ return {};
708
+ }
709
+ function responseVersion(root) {
710
+ return childNumber(findChild(root, "beallitasok"), "valaszVerzio") ?? childNumber(root, "valaszVerzio") ?? 1;
711
+ }
712
+ function errorStyleFor(action, root) {
713
+ switch (action) {
714
+ case "createInvoice":
715
+ case "reverseInvoice":
716
+ case "registerPayment":
717
+ case "getInvoicePdf": return root !== void 0 && responseVersion(root) === 2 ? "invoice" : "text";
718
+ case "getInvoiceXml": return "invoice";
719
+ case "deleteProforma": return "proforma";
720
+ case "createReceipt":
721
+ case "reverseReceipt":
722
+ case "getReceipt": return "receipt";
723
+ case "sendReceipt": return "receipt-send";
724
+ case "queryTaxpayer":
725
+ case "connectPrincipal": return "text";
726
+ }
727
+ }
728
+ //#endregion
729
+ //#region src/testing/fake-agent-invoices.ts
730
+ const LANGUAGES = /* @__PURE__ */ new Set([
731
+ "hu",
732
+ "en",
733
+ "de",
734
+ "it",
735
+ "ro",
736
+ "sk",
737
+ "hr",
738
+ "fr",
739
+ "es",
740
+ "cz",
741
+ "pl",
742
+ "bg",
743
+ "nl",
744
+ "ru",
745
+ "si"
746
+ ]);
747
+ const DUPLICATE_WINDOW_MS = 1728e5;
748
+ const MAX_PAYMENTS = 5;
749
+ const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
750
+ function requiredText$1(parent, name, path) {
751
+ const value = childText(parent, name);
752
+ if (value === void 0) throw xmlFailure(`hiányzik a(z) <${path}/${name}> elem.`);
753
+ return value;
754
+ }
755
+ function checkedDate(value, name, path) {
756
+ if (!DATE_PATTERN.test(value)) throw xmlFailure(`a(z) <${path}/${name}> nem ÉÉÉÉ-HH-NN formátumú dátum: ${value}.`);
757
+ return value;
758
+ }
759
+ function requiredDate(parent, name, path) {
760
+ return checkedDate(requiredText$1(parent, name, path), name, path);
761
+ }
762
+ function optionalDate(parent, name, path) {
763
+ const value = childText(parent, name);
764
+ return value === void 0 ? void 0 : checkedDate(value, name, path);
765
+ }
766
+ function typeCodeOf(header) {
767
+ if (childBoolean(header, "dijbekero") === true) return "D";
768
+ if (childBoolean(header, "elolegszamla") === true) return "ES";
769
+ if (childBoolean(header, "vegszamla") === true) return "VS";
770
+ if (childBoolean(header, "helyesbitoszamla") === true) return "HS";
771
+ if (childBoolean(header, "szallitolevel") === true) return "SL";
772
+ return "SZ";
773
+ }
774
+ function seriesOf(typeCode, prefix, eInvoice) {
775
+ if (typeCode === "D") return `D-${prefix}`;
776
+ if (typeCode === "SL") return `SZL-${prefix}`;
777
+ return eInvoice ? `E-${prefix}` : prefix;
778
+ }
779
+ function buyerOf(root) {
780
+ const buyer = findChild(root, "vevo");
781
+ return {
782
+ name: requiredText$1(buyer, "nev", "vevo"),
783
+ identifier: childText(buyer, "azonosito"),
784
+ country: childText(buyer, "orszag"),
785
+ zip: requiredText$1(buyer, "irsz", "vevo"),
786
+ city: requiredText$1(buyer, "telepules", "vevo"),
787
+ address: requiredText$1(buyer, "cim", "vevo"),
788
+ email: childText(buyer, "email"),
789
+ taxNumber: childText(buyer, "adoszam"),
790
+ groupTaxNumber: childText(buyer, "csoportazonosito"),
791
+ euTaxNumber: childText(buyer, "adoszamEU")
792
+ };
793
+ }
794
+ function sellerOf(state, root) {
795
+ const seller = findChild(root, "elado");
796
+ const defaults = state.config.seller;
797
+ return {
798
+ ...defaults,
799
+ bankName: childText(seller, "bank") ?? defaults.bankName,
800
+ bankAccount: childText(seller, "bankszamlaszam") ?? defaults.bankAccount
801
+ };
802
+ }
803
+ function resolvePrefix$1(state, header) {
804
+ const prefix = childText(header, "szamlaszamElotag") ?? state.config.defaultInvoicePrefix;
805
+ const allowed = state.config.invoicePrefixes;
806
+ if (allowed !== void 0 && !allowed.has(prefix)) throw agentFailure(202);
807
+ return prefix;
808
+ }
809
+ function marginVatOf(root, header) {
810
+ const wholeInvoice = childBoolean(header, "arresAfa") === true;
811
+ const items = findChildren(findChild(root, "tetelek"), "tetel");
812
+ return (index) => wholeInvoice || childText(items[index], "arresAfaAlap") !== void 0;
813
+ }
814
+ function readInvoiceRequest(state, root) {
815
+ const settings = findChild(root, "beallitasok");
816
+ const header = findChild(root, "fejlec");
817
+ if (!header) throw xmlFailure("hiányzik a <fejlec> blokk.");
818
+ const currency = requiredText$1(header, "penznem", "fejlec");
819
+ const language = requiredText$1(header, "szamlaNyelve", "fejlec");
820
+ if (!LANGUAGES.has(language)) throw xmlFailure(`ismeretlen számlanyelv: ${language}.`);
821
+ const issueDate = requiredDate(header, "keltDatum", "fejlec");
822
+ const fulfillmentDate = requiredDate(header, "teljesitesDatum", "fejlec");
823
+ const dueDate = requiredDate(header, "fizetesiHataridoDatum", "fejlec");
824
+ const paymentMethod = requiredText$1(header, "fizmod", "fejlec");
825
+ const buyer = buyerOf(root);
826
+ const items = parseItems(root, "invoice");
827
+ const prefix = resolvePrefix$1(state, header);
828
+ assertInvoiceItems(items, currency, marginVatOf(root, header));
829
+ const typeCode = typeCodeOf(header);
830
+ const eInvoice = childBoolean(settings, "eszamla") === true;
831
+ const totals = totalsOf(items);
832
+ const foreign = !isHuf(currency);
833
+ return {
834
+ preview: childBoolean(header, "elonezetpdf") === true,
835
+ downloadPdf: childBoolean(settings, "szamlaLetoltes") === true,
836
+ fields: {
837
+ prefix,
838
+ series: seriesOf(typeCode, prefix, eInvoice),
839
+ typeCode,
840
+ eInvoice,
841
+ issueDate,
842
+ fulfillmentDate,
843
+ dueDate,
844
+ paymentMethod,
845
+ language,
846
+ currency,
847
+ exchangeBank: foreign ? childText(header, "arfolyamBank") : void 0,
848
+ exchangeRate: foreign ? childNumber(header, "arfolyam") : void 0,
849
+ comment: childText(header, "megjegyzes"),
850
+ orderNumber: childText(header, "rendelesSzam"),
851
+ externalId: childText(settings, "szamlaKulsoAzon"),
852
+ referencedInvoiceNumber: childText(header, "helyesbitettSzamlaszam") ?? childText(header, "elolegSzamlaszam"),
853
+ referencedProformaNumber: childText(header, "dijbekeroSzamlaszam"),
854
+ seller: sellerOf(state, root),
855
+ buyer,
856
+ items,
857
+ totals,
858
+ payments: childBoolean(header, "fizetve") === true ? [{
859
+ date: issueDate,
860
+ method: paymentMethod,
861
+ amount: totals.gross
862
+ }] : [],
863
+ reversed: false,
864
+ deleted: false
865
+ }
866
+ };
867
+ }
868
+ function activeInvoice(state, number) {
869
+ const invoice = state.invoices.get(number);
870
+ return invoice && !invoice.deleted ? invoice : void 0;
871
+ }
872
+ function paidAmount(invoice) {
873
+ return invoice.payments.reduce((sum, payment) => sum + payment.amount, 0);
874
+ }
875
+ function resultFields(invoice, pdf) {
876
+ return {
877
+ number: invoice.number,
878
+ netTotal: invoice.totals.net,
879
+ grossTotal: invoice.totals.gross,
880
+ outstanding: invoice.typeCode === "SS" ? void 0 : outstandingOf(invoice.totals.gross, paidAmount(invoice)),
881
+ paymentMethod: invoice.paymentMethod,
882
+ pdf: pdf ? fakePdf(invoice.number) : void 0
883
+ };
884
+ }
885
+ function invoiceResult(invoice, version, downloadPdf) {
886
+ return invoiceResultResponse(resultFields(invoice, downloadPdf), version);
887
+ }
888
+ function isSameInvoice(existing, fields) {
889
+ return existing.buyer.name === fields.buyer.name && existing.totals.gross === fields.totals.gross && existing.issueDate === fields.issueDate && existing.dueDate === fields.dueDate && existing.fulfillmentDate === fields.fulfillmentDate;
890
+ }
891
+ function findOrderDuplicate(state, fields) {
892
+ const { orderNumber, typeCode } = fields;
893
+ if (!state.config.uniqueInvoiceOrderNumbers || orderNumber === void 0 || typeCode === "HS") return;
894
+ return [...state.invoices.values()].findLast((invoice) => invoice.typeCode === typeCode && invoice.orderNumber === orderNumber && !invoice.reversed && !invoice.deleted);
895
+ }
896
+ function handleCreateInvoice(state, request) {
897
+ const version = responseVersion(request.root);
898
+ const { fields, preview, downloadPdf } = readInvoiceRequest(state, request.root);
899
+ if (preview) return invoiceResultResponse({
900
+ netTotal: fields.totals.net,
901
+ grossTotal: fields.totals.gross,
902
+ pdf: fakePdf("előnézet")
903
+ }, version);
904
+ const duplicate = findOrderDuplicate(state, fields);
905
+ if (duplicate) {
906
+ if (!(state.now().getTime() - duplicate.createdAt <= DUPLICATE_WINDOW_MS) || !isSameInvoice(duplicate, fields)) throw agentFailure(152, `Már létező rendelésszám: ${fields.orderNumber}. Az ismétlődés engedélyezhető a Beállítások oldalon.`);
907
+ return invoiceResult(duplicate, version, downloadPdf);
908
+ }
909
+ const invoice = {
910
+ ...fields,
911
+ id: nextDocumentId(state),
912
+ number: nextDocumentNumber(state, fields.series),
913
+ createdAt: state.now().getTime()
914
+ };
915
+ state.invoices.set(invoice.number, invoice);
916
+ return invoiceResult(invoice, version, downloadPdf);
917
+ }
918
+ function reversalOf(state, original, root) {
919
+ const settings = findChild(root, "beallitasok");
920
+ const header = findChild(root, "fejlec");
921
+ const buyer = findChild(root, "vevo");
922
+ const issueDate = optionalDate(header, "keltDatum", "fejlec") ?? today(state);
923
+ return {
924
+ ...original,
925
+ id: nextDocumentId(state),
926
+ number: nextDocumentNumber(state, original.series),
927
+ typeCode: "SS",
928
+ createdAt: state.now().getTime(),
929
+ eInvoice: original.eInvoice || childBoolean(settings, "eszamla") === true,
930
+ issueDate,
931
+ fulfillmentDate: optionalDate(header, "teljesitesDatum", "fejlec") ?? original.fulfillmentDate,
932
+ dueDate: issueDate,
933
+ comment: childText(header, "megjegyzes"),
934
+ externalId: childText(settings, "szamlaKulsoAzon"),
935
+ referencedInvoiceNumber: original.number,
936
+ referencedProformaNumber: void 0,
937
+ buyer: {
938
+ ...original.buyer,
939
+ email: childText(buyer, "email") ?? original.buyer.email,
940
+ taxNumber: childText(buyer, "adoszam") ?? original.buyer.taxNumber
941
+ },
942
+ items: original.items.map(negateItem),
943
+ totals: negateTotals(original.totals),
944
+ payments: [],
945
+ reversed: false,
946
+ deleted: false
947
+ };
948
+ }
949
+ function handleReverseInvoice(state, request) {
950
+ const { root } = request;
951
+ const version = responseVersion(root);
952
+ const downloadPdf = childBoolean(findChild(root, "beallitasok"), "szamlaLetoltes") === true;
953
+ const number = requiredText$1(findChild(root, "fejlec"), "szamlaszam", "fejlec");
954
+ const original = activeInvoice(state, number);
955
+ if (!original) throw agentFailure(7, `Hiányzó adat: sztornózandó számla (ismeretlen számlaszám: ${number}).`);
956
+ if (original.typeCode === "D" || original.typeCode === "SL") return invoiceResult(original, version, downloadPdf);
957
+ if (original.typeCode === "SS") throw new FakeAgentFailure(void 0, `A(z) ${number} sztornó számla, nem sztornózható.`);
958
+ if (original.reversed) throw new FakeAgentFailure(void 0, `A(z) ${number} számlát már sztornózták.`);
959
+ const reversal = reversalOf(state, original, root);
960
+ state.invoices.set(original.number, {
961
+ ...original,
962
+ reversed: true
963
+ });
964
+ state.invoices.set(reversal.number, reversal);
965
+ return invoiceResult(reversal, version, downloadPdf);
966
+ }
967
+ function paymentOf$1(element, index) {
968
+ const path = `kifizetes[${index + 1}]`;
969
+ const amount = childNumber(element, "osszeg");
970
+ if (amount === void 0) throw xmlFailure(`a(z) <${path}/osszeg> hiányzik vagy nem szám.`);
971
+ return {
972
+ date: requiredDate(element, "datum", path),
973
+ method: requiredText$1(element, "jogcim", path),
974
+ amount,
975
+ comment: childText(element, "leiras")
976
+ };
977
+ }
978
+ function handleRegisterPayment(state, request) {
979
+ const { root } = request;
980
+ const settings = findChild(root, "beallitasok");
981
+ const number = requiredText$1(settings, "szamlaszam", "beallitasok");
982
+ const additive = childBoolean(settings, "additiv");
983
+ if (additive === void 0) throw xmlFailure("hiányzik a(z) <beallitasok/additiv> elem.");
984
+ const elements = findChildren(root, "kifizetes");
985
+ if (elements.length > MAX_PAYMENTS) throw xmlFailure(`egy kérésben legfeljebb ${MAX_PAYMENTS} <kifizetes> elem lehet.`);
986
+ const entries = elements.map(paymentOf$1);
987
+ const invoice = activeInvoice(state, number);
988
+ if (!invoice) throw agentFailure(7, `Hiányzó adat: ismeretlen számlaszám (${number}).`);
989
+ const updated = {
990
+ ...invoice,
991
+ payments: additive ? [...invoice.payments, ...entries] : entries
992
+ };
993
+ state.invoices.set(number, updated);
994
+ const fields = {
995
+ ...resultFields(updated, false),
996
+ paymentMethod: void 0
997
+ };
998
+ if (responseVersion(root) === 2) return invoiceResultResponse(fields, 2);
999
+ return textResponse("xmlagentresponse=DONE\n", invoiceResultHeaders(fields));
1000
+ }
1001
+ function lookupInvoice(state, root) {
1002
+ const number = childText(root, "szamlaszam");
1003
+ if (number !== void 0) return activeInvoice(state, number);
1004
+ const orderNumber = childText(root, "rendelesSzam");
1005
+ const externalId = childText(root, "szamlaKulsoAzon");
1006
+ if (orderNumber === void 0 && externalId === void 0) throw xmlFailure("add meg a számlaszámot, a rendelésszámot vagy a külső azonosítót.");
1007
+ return [...state.invoices.values()].findLast((invoice) => !invoice.deleted && (orderNumber !== void 0 ? invoice.orderNumber === orderNumber : invoice.externalId === externalId));
1008
+ }
1009
+ function handleGetInvoicePdf(state, request) {
1010
+ const invoice = lookupInvoice(state, request.root);
1011
+ if (!invoice) throw agentFailure(7, "Hiányzó adat: számla pdf (ismeretlen számlaszám, rendelésszám vagy külső azonosító).");
1012
+ return invoiceResult(invoice, responseVersion(request.root), true);
1013
+ }
1014
+ function handleGetInvoiceXml(state, request) {
1015
+ const invoice = lookupInvoice(state, request.root);
1016
+ if (!invoice) throw agentFailure(7, "Hiányzó adat: számla xml (ismeretlen számlaszám, rendelésszám vagy külső azonosító).");
1017
+ const includePdf = childBoolean(request.root, "pdf") === true;
1018
+ return xmlResponse(renderInvoiceXml(invoice, state.config.testAccount, includePdf));
1019
+ }
1020
+ function handleDeleteProforma(state, request) {
1021
+ const header = findChild(request.root, "fejlec");
1022
+ const number = childText(header, "szamlaszam");
1023
+ const orderNumber = childText(header, "rendelesszam");
1024
+ if (number === void 0 && orderNumber === void 0) throw xmlFailure("add meg a díjbekérő számát vagy a rendelésszámot.");
1025
+ const targets = [...state.invoices.values()].filter((invoice) => invoice.typeCode === "D" && !invoice.deleted && (number !== void 0 ? invoice.number === number : invoice.orderNumber === orderNumber));
1026
+ if (targets.length === 0) throw agentFailure(335);
1027
+ for (const target of targets) state.invoices.set(target.number, {
1028
+ ...target,
1029
+ deleted: true
1030
+ });
1031
+ return xmlResponse(xmlDocument("xmlszamladbkdelvalasz", [el("sikeres", true)]));
1032
+ }
1033
+ //#endregion
1034
+ //#region src/testing/fake-agent-receipts.ts
1035
+ const PREFIX_PATTERN = /^[A-Z0-9]+$/;
1036
+ const MONEY_DECIMALS = 2;
1037
+ function requiredText(parent, name, path) {
1038
+ const value = childText(parent, name);
1039
+ if (value === void 0) throw xmlFailure(`hiányzik a(z) <${path}/${name}> elem.`);
1040
+ return value;
1041
+ }
1042
+ function assertUnusedCallId(state, callId) {
1043
+ if (callId === void 0) return;
1044
+ if ([...state.receipts.values()].some((receipt) => receipt.callId === callId)) throw agentFailure(338, `A hívásazonosító már létezik: ${callId}.`);
1045
+ }
1046
+ function isInvoicePrefix(state, prefix) {
1047
+ if (state.config.invoicePrefixes?.has(prefix)) return true;
1048
+ return [...state.invoices.values()].some((invoice) => invoice.prefix === prefix);
1049
+ }
1050
+ function resolvePrefix(state, header) {
1051
+ const prefix = requiredText(header, "elotag", "fejlec");
1052
+ if (!PREFIX_PATTERN.test(prefix)) throw agentFailure(337);
1053
+ if (isInvoicePrefix(state, prefix)) throw agentFailure(336);
1054
+ const enabled = state.config.receiptPrefixes;
1055
+ if (enabled !== void 0 && !enabled.has(prefix)) throw agentFailure(524);
1056
+ return prefix;
1057
+ }
1058
+ function paymentOf(element, index) {
1059
+ const path = `kifizetesek/kifizetes[${index + 1}]`;
1060
+ const amount = childNumber(element, "osszeg");
1061
+ if (amount === void 0) throw xmlFailure(`a(z) <${path}/osszeg> hiányzik vagy nem szám.`);
1062
+ return {
1063
+ method: requiredText(element, "fizetoeszkoz", path),
1064
+ amount,
1065
+ description: childText(element, "leiras")
1066
+ };
1067
+ }
1068
+ function assertPaymentsMatch(payments, gross) {
1069
+ if (payments.length === 0) return;
1070
+ const paid = roundMoney(payments.reduce((sum, payment) => sum + payment.amount, 0), MONEY_DECIMALS);
1071
+ if (paid !== roundMoney(gross, MONEY_DECIMALS)) throw agentFailure(340, `A kifizetett összeg (${paid}) eltér a bruttó végösszegtől (${gross}).`);
1072
+ }
1073
+ function assertUniqueOrderNumber(state, orderNumber) {
1074
+ if (!state.config.uniqueReceiptOrderNumbers || orderNumber === void 0) return;
1075
+ if ([...state.receipts.values()].some((receipt) => receipt.type === "NY" && receipt.orderNumber === orderNumber && !receipt.reversed)) throw agentFailure(152, `Már létező rendelésszám: ${orderNumber}. Az ismétlődés engedélyezhető a Beállítások oldalon.`);
1076
+ }
1077
+ function exchangeOf(header, currency) {
1078
+ if (isHuf(currency)) return {
1079
+ exchangeBank: void 0,
1080
+ exchangeRate: void 0
1081
+ };
1082
+ const exchangeRate = childNumber(header, "devizaarf");
1083
+ const exchangeBank = childText(header, "devizabank");
1084
+ if (exchangeRate === void 0 || exchangeRate <= 0 || exchangeBank === void 0) throw xmlFailure(`devizás (${currency}) nyugtánál az árfolyam (devizaarf) és a bank (devizabank) megadása kötelező.`);
1085
+ return {
1086
+ exchangeBank,
1087
+ exchangeRate
1088
+ };
1089
+ }
1090
+ function itemNode(item) {
1091
+ return el("tetel", [
1092
+ el("megnevezes", item.name),
1093
+ optionalEl("azonosito", item.identifier),
1094
+ el("nettoEgysegar", item.netUnitPrice),
1095
+ el("mennyiseg", item.quantity),
1096
+ el("mennyisegiEgyseg", item.unit),
1097
+ el("netto", item.netAmount),
1098
+ optionalEl("afatipus", item.vatCode),
1099
+ el("afakulcs", item.vatRate),
1100
+ el("afa", item.vatAmount),
1101
+ el("brutto", item.grossAmount),
1102
+ item.ledger && optionalEl("fokonyv", [optionalEl("arbevetel", item.ledger.revenue), optionalEl("afa", item.ledger.vat)])
1103
+ ]);
1104
+ }
1105
+ function paymentNode(payment) {
1106
+ return el("kifizetes", [
1107
+ el("fizetoeszkoz", payment.method),
1108
+ el("osszeg", payment.amount),
1109
+ optionalEl("leiras", payment.description)
1110
+ ]);
1111
+ }
1112
+ function receiptNode(receipt, testAccount) {
1113
+ return el("nyugta", [
1114
+ el("alap", [
1115
+ el("id", receipt.id),
1116
+ optionalEl("hivasAzonosito", receipt.callId),
1117
+ el("nyugtaszam", receipt.number),
1118
+ el("tipus", receipt.type),
1119
+ el("stornozott", receipt.reversed),
1120
+ optionalEl("stornozottNyugtaszam", receipt.reversedNumber),
1121
+ el("kelt", receipt.issueDate),
1122
+ el("fizmod", receipt.paymentMethod),
1123
+ el("penznem", receipt.currency),
1124
+ optionalEl("devizabank", receipt.exchangeBank),
1125
+ optionalEl("devizaarf", receipt.exchangeRate),
1126
+ optionalEl("megjegyzes", receipt.comment),
1127
+ optionalEl("fokonyvVevo", receipt.customerLedgerId),
1128
+ el("teszt", testAccount),
1129
+ optionalEl("rendelesSzam", receipt.orderNumber)
1130
+ ]),
1131
+ el("tetelek", receipt.items.map(itemNode)),
1132
+ receipt.payments.length > 0 && el("kifizetesek", receipt.payments.map(paymentNode)),
1133
+ el("osszegek", [...vatGroupsOf(receipt.items).map(vatGroupNode), totalNode(receipt.totals)])
1134
+ ]);
1135
+ }
1136
+ function receiptResponse(state, receipt, includePdf) {
1137
+ return xmlResponse(xmlDocument("xmlnyugtavalasz", [
1138
+ el("sikeres", true),
1139
+ includePdf && el("nyugtaPdf", bytesToBase64(fakePdf(receipt.number))),
1140
+ receiptNode(receipt, state.config.testAccount)
1141
+ ]));
1142
+ }
1143
+ function downloadPdfOf(root) {
1144
+ return childBoolean(findChild(root, "beallitasok"), "pdfLetoltes") === true;
1145
+ }
1146
+ function handleCreateReceipt(state, request) {
1147
+ const { root } = request;
1148
+ const header = findChild(root, "fejlec");
1149
+ if (!header) throw xmlFailure("hiányzik a <fejlec> blokk.");
1150
+ const callId = childText(header, "hivasAzonosito");
1151
+ assertUnusedCallId(state, callId);
1152
+ const prefix = resolvePrefix(state, header);
1153
+ const paymentMethod = requiredText(header, "fizmod", "fejlec");
1154
+ const currency = childText(header, "penznem") ?? "HUF";
1155
+ const exchange = exchangeOf(header, currency);
1156
+ const items = parseItems(root, "receipt");
1157
+ assertReceiptItems(items, currency);
1158
+ const totals = totalsOf(items);
1159
+ const payments = findChildren(findChild(root, "kifizetesek"), "kifizetes").map(paymentOf);
1160
+ assertPaymentsMatch(payments, totals.gross);
1161
+ const orderNumber = childText(header, "rendelesSzam");
1162
+ assertUniqueOrderNumber(state, orderNumber);
1163
+ const receipt = {
1164
+ id: nextDocumentId(state),
1165
+ number: nextDocumentNumber(state, prefix),
1166
+ prefix,
1167
+ callId,
1168
+ type: "NY",
1169
+ reversed: false,
1170
+ issueDate: today(state),
1171
+ paymentMethod,
1172
+ currency,
1173
+ ...exchange,
1174
+ comment: childText(header, "megjegyzes"),
1175
+ customerLedgerId: childText(header, "fokonyvVevo"),
1176
+ orderNumber,
1177
+ items,
1178
+ payments,
1179
+ totals,
1180
+ sentTo: []
1181
+ };
1182
+ state.receipts.set(receipt.number, receipt);
1183
+ return receiptResponse(state, receipt, downloadPdfOf(root));
1184
+ }
1185
+ function handleReverseReceipt(state, request) {
1186
+ const { root } = request;
1187
+ const header = findChild(root, "fejlec");
1188
+ const number = requiredText(header, "nyugtaszam", "fejlec");
1189
+ const callId = childText(header, "hivasAzonosito");
1190
+ assertUnusedCallId(state, callId);
1191
+ const original = state.receipts.get(number);
1192
+ if (!original) throw agentFailure(339, "Hiányzó adat: sztornózandó nyugta (nincs ilyen nyugtaszám)");
1193
+ if (original.type === "SN") throw new FakeAgentFailure(void 0, "Hiányzó adat: sztornózandó nyugta (ez a nyugta egy sztornónyugta)");
1194
+ if (original.reversed) throw new FakeAgentFailure(void 0, `Hiányzó adat: sztornózandó nyugta (ezt a nyugtát már sztornózták: ${number})`);
1195
+ const reversal = {
1196
+ ...original,
1197
+ id: nextDocumentId(state),
1198
+ number: nextDocumentNumber(state, original.prefix),
1199
+ callId,
1200
+ type: "SN",
1201
+ reversed: false,
1202
+ reversedNumber: original.number,
1203
+ issueDate: today(state),
1204
+ items: original.items.map(negateItem),
1205
+ payments: original.payments.map((payment) => ({
1206
+ ...payment,
1207
+ amount: -payment.amount
1208
+ })),
1209
+ totals: negateTotals(original.totals),
1210
+ sentTo: []
1211
+ };
1212
+ state.receipts.set(original.number, {
1213
+ ...original,
1214
+ reversed: true
1215
+ });
1216
+ state.receipts.set(reversal.number, reversal);
1217
+ return receiptResponse(state, reversal, downloadPdfOf(root));
1218
+ }
1219
+ function handleGetReceipt(state, request) {
1220
+ const { root } = request;
1221
+ const header = findChild(root, "fejlec");
1222
+ const number = childText(header, "nyugtaszam");
1223
+ const orderNumber = childText(header, "rendelesSzam");
1224
+ if (number === void 0 && orderNumber === void 0) throw xmlFailure("add meg a nyugtaszámot (nyugtaszam) vagy a rendelésszámot (rendelesSzam).");
1225
+ const receipt = number !== void 0 ? state.receipts.get(number) : [...state.receipts.values()].findLast((candidate) => candidate.orderNumber === orderNumber);
1226
+ if (!receipt) throw agentFailure(339);
1227
+ return receiptResponse(state, receipt, downloadPdfOf(root));
1228
+ }
1229
+ function handleSendReceipt(state, request) {
1230
+ const { root } = request;
1231
+ const number = requiredText(findChild(root, "fejlec"), "nyugtaszam", "fejlec");
1232
+ const email = findChild(root, "emailKuldes");
1233
+ const recipients = childText(email, "email");
1234
+ if (recipients === void 0) throw agentFailure(7, "Hiányzó adat: email elem.");
1235
+ if (childText(email, "emailTargy") === void 0) throw agentFailure(7, "Hiányzó adat: emailtargy elem.");
1236
+ const receipt = state.receipts.get(number);
1237
+ if (!receipt) throw agentFailure(339);
1238
+ const addresses = recipients.split(/[,;]/).map((address) => address.trim()).filter((address) => address !== "");
1239
+ state.receipts.set(number, {
1240
+ ...receipt,
1241
+ sentTo: [...receipt.sentTo, addresses]
1242
+ });
1243
+ return xmlResponse(xmlDocument("xmlnyugtasendvalasz", [el("sikeres", true)]));
1244
+ }
1245
+ //#endregion
1246
+ //#region src/testing/fake-agent.ts
1247
+ const HANDLERS = {
1248
+ createInvoice: handleCreateInvoice,
1249
+ reverseInvoice: handleReverseInvoice,
1250
+ registerPayment: handleRegisterPayment,
1251
+ getInvoicePdf: handleGetInvoicePdf,
1252
+ getInvoiceXml: handleGetInvoiceXml,
1253
+ deleteProforma: handleDeleteProforma,
1254
+ createReceipt: handleCreateReceipt,
1255
+ reverseReceipt: handleReverseReceipt,
1256
+ getReceipt: handleGetReceipt,
1257
+ sendReceipt: handleSendReceipt,
1258
+ queryTaxpayer: handleQueryTaxpayer,
1259
+ connectPrincipal: handleConnectPrincipal
1260
+ };
1261
+ const NAMED_FAULTS = {
1262
+ ghostSuccess: {
1263
+ stage: "after",
1264
+ effect: "timeout"
1265
+ },
1266
+ timeout: {
1267
+ stage: "before",
1268
+ effect: "timeout"
1269
+ },
1270
+ networkError: {
1271
+ stage: "before",
1272
+ effect: "network"
1273
+ },
1274
+ serverError: {
1275
+ stage: "before",
1276
+ effect: "server-error"
1277
+ },
1278
+ maintenance: {
1279
+ stage: "before",
1280
+ effect: "code",
1281
+ code: 1
1282
+ },
1283
+ partialSuccess: {
1284
+ stage: "after",
1285
+ effect: "code",
1286
+ code: 56
1287
+ },
1288
+ testAccountLimit: {
1289
+ stage: "before",
1290
+ effect: "code",
1291
+ code: 167
1292
+ },
1293
+ duplicateCallId: {
1294
+ stage: "before",
1295
+ effect: "code",
1296
+ code: 338
1297
+ },
1298
+ duplicateOrderNumber: {
1299
+ stage: "before",
1300
+ effect: "code",
1301
+ code: 152
1302
+ }
1303
+ };
1304
+ const DEFAULT_SELLER = {
1305
+ name: "Kassza Teszt Kft.",
1306
+ taxNumber: "12345676-2-42",
1307
+ zip: "1111",
1308
+ city: "Budapest",
1309
+ address: "Teszt utca 1."
1310
+ };
1311
+ const DEFAULT_INVOICE_PREFIX = "KASSZA";
1312
+ const KNOWN_ACTIONS = new Set(Object.keys(AGENT_ACTIONS));
1313
+ function behaviorOf(fault) {
1314
+ if (typeof fault === "string") {
1315
+ const behavior = NAMED_FAULTS[fault];
1316
+ if (!behavior) throw new TypeError(`Ismeretlen hamis Agent hiba: ${String(fault)}`);
1317
+ return behavior;
1318
+ }
1319
+ if (!Number.isInteger(fault.code) || fault.code < 1) throw new TypeError(`A hibakód pozitív egész szám legyen, kapott: ${String(fault.code)}`);
1320
+ return {
1321
+ stage: fault.afterSuccess === true ? "after" : "before",
1322
+ effect: "code",
1323
+ code: fault.code,
1324
+ message: fault.message
1325
+ };
1326
+ }
1327
+ function pendingFault(fault, options) {
1328
+ const times = options.times ?? 1;
1329
+ if (!Number.isInteger(times) || times < 1) throw new TypeError(`A times értéke legalább 1 egész szám legyen, kapott: ${String(times)}`);
1330
+ if (options.action !== void 0 && !KNOWN_ACTIONS.has(options.action)) throw new TypeError(`Ismeretlen Agent művelet: ${String(options.action)}`);
1331
+ return {
1332
+ behavior: behaviorOf(fault),
1333
+ action: options.action,
1334
+ remaining: times
1335
+ };
1336
+ }
1337
+ function duplicateFlags(value) {
1338
+ if (typeof value === "boolean") return {
1339
+ invoices: value,
1340
+ receipts: value
1341
+ };
1342
+ return {
1343
+ invoices: value?.invoices === true,
1344
+ receipts: value?.receipts === true
1345
+ };
1346
+ }
1347
+ function normalizedTaxpayers(taxpayers) {
1348
+ return Object.fromEntries(Object.entries(taxpayers ?? {}).map(([taxNumber, taxpayer]) => [taxpayerKey(taxNumber), taxpayer]));
1349
+ }
1350
+ function seededPrincipals(options) {
1351
+ return new Map(Object.entries(options.principals ?? {}).map(([taxNumber, state]) => [taxpayerKey(taxNumber), {
1352
+ state,
1353
+ joinRequests: 0
1354
+ }]));
1355
+ }
1356
+ function createState(options) {
1357
+ const duplicates = duplicateFlags(options.rejectDuplicateOrderNumbers);
1358
+ return {
1359
+ now: options.now ?? (() => /* @__PURE__ */ new Date()),
1360
+ config: {
1361
+ seller: {
1362
+ ...DEFAULT_SELLER,
1363
+ ...options.seller
1364
+ },
1365
+ testAccount: options.testAccount ?? true,
1366
+ defaultInvoicePrefix: options.defaultInvoicePrefix ?? options.invoicePrefixes?.[0] ?? DEFAULT_INVOICE_PREFIX,
1367
+ invoicePrefixes: options.invoicePrefixes && new Set(options.invoicePrefixes),
1368
+ receiptPrefixes: options.receiptPrefixes && new Set(options.receiptPrefixes),
1369
+ uniqueInvoiceOrderNumbers: duplicates.invoices,
1370
+ uniqueReceiptOrderNumbers: duplicates.receipts,
1371
+ strictAuth: options.agentKeys !== void 0 || options.users !== void 0,
1372
+ agentKeys: new Set(options.agentKeys ?? []),
1373
+ taxpayers: normalizedTaxpayers(options.taxpayers)
1374
+ },
1375
+ invoices: /* @__PURE__ */ new Map(),
1376
+ receipts: /* @__PURE__ */ new Map(),
1377
+ counters: /* @__PURE__ */ new Map(),
1378
+ principals: seededPrincipals(options),
1379
+ delegates: /* @__PURE__ */ new Map(),
1380
+ users: new Map(Object.entries(options.users ?? {}))
1381
+ };
1382
+ }
1383
+ function timeoutError() {
1384
+ return new DOMException("A hamis Agent nem küldött választ (időtúllépés).", "TimeoutError");
1385
+ }
1386
+ function orderNumberOf(root) {
1387
+ return childText(findChild(root, "fejlec"), "rendelesSzam");
1388
+ }
1389
+ function faultFailure(behavior, root) {
1390
+ const code = behavior.code ?? 1;
1391
+ if (behavior.message !== void 0) return new FakeAgentFailure(code, behavior.message);
1392
+ if (code === 152) return agentFailure(152, `Már létező rendelésszám: ${orderNumberOf(root) ?? "XXX"}. Az ismétlődés engedélyezhető a Beállítások oldalon.`);
1393
+ return agentFailure(code);
1394
+ }
1395
+ function respondBefore(behavior, request) {
1396
+ if (behavior.effect === "timeout") throw timeoutError();
1397
+ if (behavior.effect === "network") throw new TypeError("fetch failed");
1398
+ if (behavior.effect === "server-error") return serverErrorResponse();
1399
+ return errorResponse(errorStyleFor(request.action, request.root), faultFailure(behavior, request.root));
1400
+ }
1401
+ function createFakeAgentFetch(options = {}) {
1402
+ let state = createState(options);
1403
+ const requests = [];
1404
+ const faults = [];
1405
+ const scheduleInitialFaults = () => {
1406
+ for (const scheduled of options.faults ?? []) faults.push(pendingFault(scheduled.fault, scheduled));
1407
+ };
1408
+ scheduleInitialFaults();
1409
+ const takeFault = (action) => {
1410
+ const index = faults.findIndex((fault) => fault.action === void 0 || fault.action === action);
1411
+ const fault = faults[index];
1412
+ if (!fault) return void 0;
1413
+ fault.remaining -= 1;
1414
+ if (fault.remaining === 0) faults.splice(index, 1);
1415
+ return fault.behavior;
1416
+ };
1417
+ const perform = (request) => {
1418
+ try {
1419
+ authenticate(state, credentialsOf(request.root));
1420
+ return {
1421
+ response: HANDLERS[request.action](state, request),
1422
+ ok: true
1423
+ };
1424
+ } catch (error) {
1425
+ if (!(error instanceof FakeAgentFailure)) throw error;
1426
+ return {
1427
+ response: errorResponse(errorStyleFor(request.action, request.root), error),
1428
+ ok: false
1429
+ };
1430
+ }
1431
+ };
1432
+ const handle = (action, xml, attachments) => {
1433
+ let request;
1434
+ try {
1435
+ request = parseFakeAgentRequest(action, xml, attachments);
1436
+ } catch (error) {
1437
+ if (!(error instanceof FakeAgentFailure)) throw error;
1438
+ return errorResponse(errorStyleFor(action, void 0), error);
1439
+ }
1440
+ const fault = takeFault(action);
1441
+ if (fault?.stage === "before") return respondBefore(fault, request);
1442
+ const { response, ok } = perform(request);
1443
+ if (fault?.effect === "timeout") throw timeoutError();
1444
+ if (fault && ok) return errorResponse(errorStyleFor(action, request.root), faultFailure(fault, request.root));
1445
+ return response;
1446
+ };
1447
+ const fakeFetch = async (input, init) => {
1448
+ init?.signal?.throwIfAborted();
1449
+ const record = await readFakeAgentForm(input, init);
1450
+ requests.push(record);
1451
+ if (record.action === void 0 || record.xml === void 0) return toFetchResponse(errorResponse("text", agentFailure(53)));
1452
+ return toFetchResponse(handle(record.action, record.xml, record.attachments));
1453
+ };
1454
+ return {
1455
+ fetch: fakeFetch,
1456
+ requests,
1457
+ get invoices() {
1458
+ return state.invoices;
1459
+ },
1460
+ get receipts() {
1461
+ return state.receipts;
1462
+ },
1463
+ fail(fault, faultOptions = {}) {
1464
+ faults.push(pendingFault(fault, faultOptions));
1465
+ },
1466
+ acceptDelegation(taxNumber) {
1467
+ acceptDelegation(state, taxNumber);
1468
+ },
1469
+ reset() {
1470
+ state = createState(options);
1471
+ requests.length = 0;
1472
+ faults.length = 0;
1473
+ scheduleInitialFaults();
1474
+ }
1475
+ };
1476
+ }
1477
+ //#endregion
6
1478
  //#region src/testing/index.ts
7
1479
  const MOCK_PDF = new TextEncoder().encode("%PDF-1.4\n1 0 obj << /Type /Catalog >> endobj\ntrailer << /Root 1 0 R >>\n%%EOF\n");
8
1480
  function notFound(code, message) {
@@ -37,11 +1509,18 @@ function normalizePayments(input, today) {
37
1509
  description: input.description
38
1510
  }];
39
1511
  }
1512
+ let mockScopes = 0;
40
1513
  function createMockKassza(options = {}) {
41
1514
  const now = options.now ?? (() => /* @__PURE__ */ new Date());
42
1515
  const calls = [];
43
1516
  const failures = /* @__PURE__ */ new Map();
44
- const onDocument = options.hooks?.onDocument;
1517
+ const hooks = options.hooks;
1518
+ const emit = (event) => emitDocumentEvent(hooks?.onDocument, event, {
1519
+ mode: hooks?.onDocumentError,
1520
+ onWarning: hooks?.onWarning
1521
+ });
1522
+ mockScopes += 1;
1523
+ const guard = { scope: `mock:${mockScopes}` };
45
1524
  const invoices = /* @__PURE__ */ new Map();
46
1525
  const receipts = /* @__PURE__ */ new Map();
47
1526
  const sequences = /* @__PURE__ */ new Map();
@@ -254,7 +1733,7 @@ function createMockKassza(options = {}) {
254
1733
  const invoicesApi = {
255
1734
  async create(input) {
256
1735
  const document = await run("invoices.create", [input], () => createInvoiceRecord(input));
257
- await emitDocumentEvent(onDocument, {
1736
+ await emit({
258
1737
  kind: "invoice",
259
1738
  action: "created",
260
1739
  number: document.number,
@@ -266,7 +1745,7 @@ function createMockKassza(options = {}) {
266
1745
  createOnce: (input, requestOptions) => run("invoices.createOnce", [input], () => createInvoiceOnce(invoicesApi, input, {
267
1746
  recoveryDelayMs: 0,
268
1747
  ...requestOptions
269
- })),
1748
+ }, guard)),
270
1749
  preview: (input) => run("invoices.preview", [input], () => {
271
1750
  const items = resolveInvoice(options.defaults?.invoice ?? {}, input, now()).items.map((item) => item.amounts);
272
1751
  const totals = summarizeItems(items);
@@ -319,7 +1798,7 @@ function createMockKassza(options = {}) {
319
1798
  ...downloadPdf ? { pdf: MOCK_PDF } : {}
320
1799
  };
321
1800
  });
322
- await emitDocumentEvent(onDocument, {
1801
+ await emit({
323
1802
  kind: "invoice",
324
1803
  action: "reversed",
325
1804
  number: document.number,
@@ -347,7 +1826,7 @@ function createMockKassza(options = {}) {
347
1826
  outstanding: Math.max(0, found.details.totals.grossAmount - paid)
348
1827
  };
349
1828
  });
350
- await emitDocumentEvent(onDocument, {
1829
+ await emit({
351
1830
  kind: "invoice",
352
1831
  action: "payment",
353
1832
  number: document.invoiceNumber,
@@ -355,6 +1834,10 @@ function createMockKassza(options = {}) {
355
1834
  });
356
1835
  return document;
357
1836
  },
1837
+ registerPaymentOnce: (input, requestOptions) => run("invoices.registerPaymentOnce", [input], () => registerPaymentOnce(invoicesApi, input, {
1838
+ recoveryDelayMs: 0,
1839
+ ...requestOptions
1840
+ }, guard)),
358
1841
  async clearPayments(input) {
359
1842
  const document = await run("invoices.clearPayments", [input], () => {
360
1843
  const found = findInvoice(typeof input === "string" ? input : input.invoiceNumber);
@@ -366,7 +1849,7 @@ function createMockKassza(options = {}) {
366
1849
  outstanding: found.details.totals.grossAmount
367
1850
  };
368
1851
  });
369
- await emitDocumentEvent(onDocument, {
1852
+ await emit({
370
1853
  kind: "invoice",
371
1854
  action: "payment",
372
1855
  number: document.invoiceNumber,
@@ -395,7 +1878,7 @@ function createMockKassza(options = {}) {
395
1878
  const receiptsApi = {
396
1879
  async create(input) {
397
1880
  const document = await run("receipts.create", [input], () => createReceiptRecord(input, input.callId));
398
- await emitDocumentEvent(onDocument, {
1881
+ await emit({
399
1882
  kind: "receipt",
400
1883
  action: "created",
401
1884
  number: document.number,
@@ -406,7 +1889,7 @@ function createMockKassza(options = {}) {
406
1889
  createOnce: (input, requestOptions) => run("receipts.createOnce", [input], () => createReceiptOnce(receiptsApi, input, {
407
1890
  recoveryDelayMs: 0,
408
1891
  ...requestOptions
409
- })),
1892
+ }, guard)),
410
1893
  async reverse(input) {
411
1894
  const receiptNumber = typeof input === "string" ? input : input.receiptNumber;
412
1895
  const callId = typeof input === "string" ? void 0 : input.callId;
@@ -439,7 +1922,7 @@ function createMockKassza(options = {}) {
439
1922
  pdf: MOCK_PDF
440
1923
  };
441
1924
  });
442
- await emitDocumentEvent(onDocument, {
1925
+ await emit({
443
1926
  kind: "receipt",
444
1927
  action: "reversed",
445
1928
  number: document.number,
@@ -503,4 +1986,4 @@ function createMockKassza(options = {}) {
503
1986
  };
504
1987
  }
505
1988
  //#endregion
506
- export { MOCK_PDF, createMockKassza };
1989
+ export { CONNECT_PRINCIPAL_MESSAGES, MOCK_PDF, createFakeAgentFetch, createMockKassza };