kassza 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +99 -99
  2. package/dist/client-CL3fuH6A.js +1596 -0
  3. package/dist/{client-zv4enyq7.d.ts → client-CickRRFr.d.ts} +307 -217
  4. package/dist/client-CsmGIFRS.cjs +1637 -0
  5. package/dist/{client-B9kbKKBf.d.cts → client-DvWZoX_E.d.cts} +307 -217
  6. package/dist/create-once-CqdYmQD8.js +330 -0
  7. package/dist/create-once-D0pwuenl.cjs +389 -0
  8. package/dist/crypto-B8lERvR1.cjs +56 -0
  9. package/dist/crypto-DK_osBVy.js +33 -0
  10. package/dist/{dates-DtHzwNU6.d.cts → dates-9zvESP0i.d.cts} +2 -1
  11. package/dist/{dates-DtHzwNU6.d.ts → dates-9zvESP0i.d.ts} +2 -1
  12. package/dist/{dates-PPxH0n5H.cjs → dates-CPgBodkP.cjs} +44 -1
  13. package/dist/{dates-D2XebOIg.js → dates-CXyj7Azy.js} +39 -2
  14. package/dist/delegation/index.cjs +395 -0
  15. package/dist/delegation/index.d.cts +99 -0
  16. package/dist/delegation/index.d.ts +99 -0
  17. package/dist/delegation/index.js +377 -0
  18. package/dist/{errors-DapdV5DK.js → errors-DLrb0g64.js} +122 -5
  19. package/dist/{errors-B0QJhUW1.cjs → errors-DxeuTslP.cjs} +127 -4
  20. package/dist/index.cjs +21 -1410
  21. package/dist/index.d.cts +18 -3
  22. package/dist/index.d.ts +18 -3
  23. package/dist/index.js +8 -1409
  24. package/dist/ipn/index.cjs +1 -1
  25. package/dist/ipn/index.js +1 -1
  26. package/dist/{create-DZsl3Z4m.cjs → issue-BsyYdrIG.cjs} +664 -311
  27. package/dist/{create-5YkUcJSe.js → issue-C6Fcjvln.js} +589 -272
  28. package/dist/json-4y4E2xxS.cjs +61 -0
  29. package/dist/json-B70TwoX1.d.cts +4 -0
  30. package/dist/json-B70TwoX1.d.ts +4 -0
  31. package/dist/json-DjnqnaJK.js +32 -0
  32. package/dist/money/index.cjs +12 -10
  33. package/dist/money/index.js +3 -1
  34. package/dist/{money-C9j7nBNP.js → money-DAA7OwiO.js} +4 -101
  35. package/dist/{money-DkiGukAw.cjs → money-DrhGkWHW.cjs} +19 -170
  36. package/dist/payments/barion.cjs +208 -0
  37. package/dist/payments/barion.d.cts +28 -0
  38. package/dist/payments/barion.d.ts +28 -0
  39. package/dist/payments/barion.js +199 -0
  40. package/dist/payments/index.cjs +16 -0
  41. package/dist/payments/index.d.cts +31 -0
  42. package/dist/payments/index.d.ts +31 -0
  43. package/dist/payments/index.js +3 -0
  44. package/dist/payments/paypal.cjs +351 -0
  45. package/dist/payments/paypal.d.cts +59 -0
  46. package/dist/payments/paypal.d.ts +59 -0
  47. package/dist/payments/paypal.js +337 -0
  48. package/dist/payments/revolut.cjs +261 -0
  49. package/dist/payments/revolut.d.cts +48 -0
  50. package/dist/payments/revolut.d.ts +48 -0
  51. package/dist/payments/revolut.js +249 -0
  52. package/dist/payments/simplepay.cjs +313 -0
  53. package/dist/payments/simplepay.d.cts +86 -0
  54. package/dist/payments/simplepay.d.ts +86 -0
  55. package/dist/payments/simplepay.js +299 -0
  56. package/dist/payments/stripe.cjs +315 -0
  57. package/dist/payments/stripe.d.cts +49 -0
  58. package/dist/payments/stripe.d.ts +49 -0
  59. package/dist/payments/stripe.js +303 -0
  60. package/dist/reports/index.cjs +256 -0
  61. package/dist/reports/index.d.cts +70 -0
  62. package/dist/reports/index.d.ts +70 -0
  63. package/dist/reports/index.js +247 -0
  64. package/dist/rounding-BLyHjjI5.js +20 -0
  65. package/dist/rounding-TxoWy2ww.cjs +37 -0
  66. package/dist/storage/fs.cjs +1 -1
  67. package/dist/storage/fs.js +1 -1
  68. package/dist/storage/index.cjs +2 -2
  69. package/dist/storage/index.d.cts +1 -1
  70. package/dist/storage/index.d.ts +1 -1
  71. package/dist/storage/index.js +2 -2
  72. package/dist/tax-number-BYFkBp4A.cjs +141 -0
  73. package/dist/tax-number-BdqKsxNR.js +76 -0
  74. package/dist/testing/index.cjs +183 -84
  75. package/dist/testing/index.d.cts +10 -2
  76. package/dist/testing/index.d.ts +10 -2
  77. package/dist/testing/index.js +181 -82
  78. package/dist/types-COf1LAD-.d.cts +56 -0
  79. package/dist/types-COf1LAD-.d.ts +56 -0
  80. package/dist/types-DH8QoNZK.d.cts +135 -0
  81. package/dist/types-k--zHf4l.d.ts +135 -0
  82. package/dist/validators/index.cjs +14 -88
  83. package/dist/validators/index.js +1 -75
  84. package/dist/vat-g35srbNG.cjs +116 -0
  85. package/dist/vat-v_dcWCto.js +81 -0
  86. package/dist/webhook-C76bV-4R.cjs +245 -0
  87. package/dist/webhook-CfaDgcL0.d.cts +6 -0
  88. package/dist/webhook-D4lvtex1.js +174 -0
  89. package/dist/webhook-q2OzNwd7.d.ts +6 -0
  90. package/package.json +106 -2
@@ -0,0 +1,1596 @@
1
+ import { a as INVOICE_TEMPLATES, c as AGENT_ACTIONS, i as resolveInvoice, n as optionalAgentDate$1, o as TAXPAYER_TYPE_CODES, r as presentText, s as emitDocumentEvent, t as createReceiptOnce } from "./create-once-CqdYmQD8.js";
2
+ import { a as parseErrorCode, i as isSzamlazzError, n as SzamlazzError, r as createAgentError } from "./errors-DLrb0g64.js";
3
+ import { t as base64ToBytes } from "./binary-D0M9U2MD.js";
4
+ import { A as parseResponseXml, B as childNumber, C as buildXmlDocument, E as createAgentResponse, F as throwIfHttpError, H as findChild, I as throwIfTextError, L as throwIfXmlFailure, M as readHeader$1, N as throwIfAnyError, O as looksLikeXml, P as throwIfHeaderError, R as unexpectedResponse, T as optionalEl, U as findChildren, V as childText, _ as createInvoiceOnce, c as RECEIPT_XSD_BASE_URL, d as requireReceiptNumber, f as validateTemplate$1, j as readDocumentHeaders, k as parseDoneText, l as optionalText$1, m as convertReceiptToInvoice, n as issueForPayment, o as createReceipt, s as parseReceiptResponse, u as receiptValidationError, w as el, z as childBoolean } from "./issue-C6Fcjvln.js";
5
+ import { i as sessionKeyFor, n as memoryCookieStore, r as mergeSetCookies, t as SESSION_TTL_SECONDS } from "./session-rMKaJcmq.js";
6
+ import { a as todayInBudapest, n as toAgentDate } from "./dates-CXyj7Azy.js";
7
+ import { r as formatVatRate } from "./vat-v_dcWCto.js";
8
+ import { i as summarizeItems } from "./money-DAA7OwiO.js";
9
+ //#region src/core/attempt-ledger.ts
10
+ const ATTEMPT_LEDGER_TTL_SECONDS = 86400;
11
+ const ATTEMPT_LEDGER_KEY_PREFIX = "szamlazz:attempts:";
12
+ const COUNTED_CATEGORIES = /* @__PURE__ */ new Set([
13
+ "auth",
14
+ "account",
15
+ "validation",
16
+ "maintenance",
17
+ "rate_limit",
18
+ "network",
19
+ "timeout",
20
+ "unexpected_response",
21
+ "unknown"
22
+ ]);
23
+ function countsAsFailedAttempt(error) {
24
+ return COUNTED_CATEGORIES.has(error.category);
25
+ }
26
+ const encoder = new TextEncoder();
27
+ async function attemptLedgerKey(request) {
28
+ const attachments = (request.attachments ?? []).map((attachment) => `${attachment.filename}:${attachment.size}`).join("|");
29
+ const digest = await crypto.subtle.digest("SHA-256", encoder.encode(`${request.action}\n${request.xml}\n${attachments}`));
30
+ const hex = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0"));
31
+ return `${ATTEMPT_LEDGER_KEY_PREFIX}${hex.join("")}`;
32
+ }
33
+ function parseCount(value) {
34
+ if (value === void 0 || value === null) return 0;
35
+ const parsed = Number.parseInt(value, 10);
36
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : 0;
37
+ }
38
+ function createAttemptLedger(store) {
39
+ return {
40
+ async failures(key) {
41
+ return parseCount(await store.get(key));
42
+ },
43
+ async recordFailure(key, previous) {
44
+ const next = previous + 1;
45
+ await store.set(key, String(next), ATTEMPT_LEDGER_TTL_SECONDS);
46
+ return next;
47
+ },
48
+ async reset(key) {
49
+ await store.delete(key);
50
+ }
51
+ };
52
+ }
53
+ function attemptLimitError(action, key, failures) {
54
+ return new SzamlazzError(`Ezt a kérést már ${failures} alkalommal sikertelenül küldtük el, ezért a kassza nem küldi el újra.`, {
55
+ category: "attempt_limit",
56
+ action,
57
+ details: { attemptKey: key },
58
+ hint: "A Számlázz.hu szabályai szerint öt sikertelen próbálkozás után emberi beavatkozás kell, különben kitiltás jöhet. Javítsd a hibát, majd a kassza.resetAttempts(error) hívással töröld a számlálót."
59
+ });
60
+ }
61
+ const DEFAULT_SAFE_ATTEMPTS = 3;
62
+ const DEFAULT_RETRY_DELAY_MS = 1e3;
63
+ function readEnv(name) {
64
+ const value = (globalThis.process?.env)?.[name]?.trim();
65
+ return value ? value : void 0;
66
+ }
67
+ function configurationError(message) {
68
+ return new SzamlazzError(message, { category: "configuration" });
69
+ }
70
+ function resolveCredentials(options) {
71
+ const agentKey = options.agentKey?.trim() || (options.username ? void 0 : readEnv("SZAMLAZZ_AGENT_KEY"));
72
+ if (agentKey) {
73
+ if (agentKey !== agentKey.toLowerCase()) throw configurationError("Az Agent kulcs nagybetűt tartalmaz. A Számlázz.hu csak kisbetűs kulcsot fogad el, másold ki újra a kulcsot.");
74
+ return [el("szamlaagentkulcs", agentKey)];
75
+ }
76
+ if (options.username && options.password) return [el("felhasznalo", options.username), el("jelszo", options.password)];
77
+ throw configurationError("Hiányzik az Agent kulcs. Add meg az agentKey opciót, vagy állítsd be a SZAMLAZZ_AGENT_KEY környezeti változót.");
78
+ }
79
+ function toBlob(attachment) {
80
+ const type = attachment.contentType ?? "application/octet-stream";
81
+ if (attachment.content instanceof Blob) return attachment.content;
82
+ return new Blob([attachment.content], { type });
83
+ }
84
+ function buildFormData(request) {
85
+ const form = new FormData();
86
+ form.append(AGENT_ACTIONS[request.action], new Blob([request.xml], { type: "text/xml; charset=UTF-8" }), "request.xml");
87
+ request.attachments?.forEach((attachment, index) => {
88
+ form.append(`attachfile${index + 1}`, toBlob(attachment), attachment.filename);
89
+ });
90
+ return form;
91
+ }
92
+ function isAbortError(error) {
93
+ return error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError");
94
+ }
95
+ function sleep(ms, signal) {
96
+ return new Promise((resolve, reject) => {
97
+ if (signal?.aborted) {
98
+ reject(signal.reason);
99
+ return;
100
+ }
101
+ const timer = setTimeout(() => {
102
+ signal?.removeEventListener("abort", onAbort);
103
+ resolve();
104
+ }, ms);
105
+ const onAbort = () => {
106
+ clearTimeout(timer);
107
+ reject(signal?.reason);
108
+ };
109
+ signal?.addEventListener("abort", onAbort, { once: true });
110
+ });
111
+ }
112
+ async function ignoreStoreFailure(operation) {
113
+ try {
114
+ return await operation();
115
+ } catch {
116
+ return;
117
+ }
118
+ }
119
+ function callHook(hook, event) {
120
+ if (!hook) return;
121
+ try {
122
+ const result = hook(event);
123
+ if (result instanceof Promise) result.catch(() => void 0);
124
+ } catch {
125
+ return;
126
+ }
127
+ }
128
+ function clampAttempts(value) {
129
+ if (value === void 0) return DEFAULT_SAFE_ATTEMPTS;
130
+ if (!Number.isInteger(value) || value < 1) throw configurationError(`A maxAttempts értéke legalább 1 egész szám legyen, kapott: ${value}`);
131
+ return Math.min(value, 5);
132
+ }
133
+ function resolveCooldown(value) {
134
+ if (value === void 0) return 0;
135
+ if (!Number.isFinite(value) || value < 0) throw configurationError(`A maintenanceCooldownMs értéke nemnegatív szám legyen, kapott: ${value}`);
136
+ return value;
137
+ }
138
+ function attachmentSize(attachment) {
139
+ const { content } = attachment;
140
+ if (typeof content === "string") return new TextEncoder().encode(content).byteLength;
141
+ if (content instanceof Blob) return content.size;
142
+ return content.byteLength;
143
+ }
144
+ function maintenanceCooldownError(action, remainingMs) {
145
+ return new SzamlazzError(`A Számlázz.hu karbantartás miatt nem érhető el, a kassza még ${Math.ceil(remainingMs / 1e3)} másodpercig nem küld kérést.`, {
146
+ category: "maintenance",
147
+ action,
148
+ hint: "A maintenanceCooldownMs beállítás miatt a kérés el sem indult. Válts tartalék folyamatra (például kézi nyugtatömbre), vagy próbáld később."
149
+ });
150
+ }
151
+ function createAgentContext(options = {}) {
152
+ const credentials = resolveCredentials(options);
153
+ const endpoint = options.endpoint ?? "https://www.szamlazz.hu/szamla/";
154
+ const fetchImpl = options.fetch ?? globalThis.fetch;
155
+ if (typeof fetchImpl !== "function") throw configurationError("Nem található fetch implementáció. Add meg a fetch opciót.");
156
+ const timeoutMs = options.timeoutMs ?? 6e4;
157
+ const safeAttempts = clampAttempts(options.maxAttempts);
158
+ const retryDelayMs = options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
159
+ const cookieStore = options.cookieStore === false ? void 0 : options.cookieStore ?? memoryCookieStore();
160
+ const sessionSecret = credentials.map((node) => String(node.content)).join("|");
161
+ let sessionKeyPromise;
162
+ const resolveSessionKey = () => {
163
+ sessionKeyPromise ??= sessionKeyFor(sessionSecret);
164
+ return sessionKeyPromise;
165
+ };
166
+ const hooks = options.hooks ?? {};
167
+ const ledger = options.attemptLedger ? createAttemptLedger(options.attemptLedger) : void 0;
168
+ const cooldownMs = resolveCooldown(options.maintenanceCooldownMs);
169
+ let blockedUntil = 0;
170
+ async function send(request) {
171
+ const cookie = cookieStore ? await ignoreStoreFailure(async () => cookieStore.get(await resolveSessionKey())) : void 0;
172
+ request.signal?.throwIfAborted();
173
+ const headers = new Headers({ Accept: "application/xml, application/pdf, text/plain, */*" });
174
+ if (cookie) headers.set("Cookie", cookie);
175
+ const timeoutSignal = AbortSignal.timeout(timeoutMs);
176
+ const signal = request.signal ? AbortSignal.any([request.signal, timeoutSignal]) : timeoutSignal;
177
+ let response;
178
+ let body;
179
+ try {
180
+ response = await fetchImpl(endpoint, {
181
+ method: "POST",
182
+ headers,
183
+ body: buildFormData(request),
184
+ signal
185
+ });
186
+ body = new Uint8Array(await response.arrayBuffer());
187
+ } catch (error) {
188
+ if (request.signal?.aborted) throw request.signal.reason;
189
+ if (timeoutSignal.aborted || isAbortError(error)) throw new SzamlazzError(`A Számlázz.hu nem válaszolt ${timeoutMs} ms alatt.`, {
190
+ category: "timeout",
191
+ action: request.action,
192
+ cause: error
193
+ });
194
+ throw new SzamlazzError("Hálózati hiba a Számlázz.hu elérésekor.", {
195
+ category: "network",
196
+ action: request.action,
197
+ cause: error
198
+ });
199
+ }
200
+ if (cookieStore) {
201
+ const merged = mergeSetCookies(cookie, response.headers);
202
+ if (merged) await ignoreStoreFailure(async () => cookieStore.set(await resolveSessionKey(), merged, SESSION_TTL_SECONDS));
203
+ }
204
+ return createAgentResponse(request.action, response.status, response.headers, body);
205
+ }
206
+ async function resetSession() {
207
+ if (cookieStore) await ignoreStoreFailure(async () => cookieStore.delete(await resolveSessionKey()));
208
+ }
209
+ async function resetAttempts(key) {
210
+ if (ledger) await ledger.reset(key);
211
+ }
212
+ async function ledgerKeyFor(request) {
213
+ if (!ledger) return void 0;
214
+ return attemptLedgerKey({
215
+ action: request.action,
216
+ xml: request.xml,
217
+ attachments: (request.attachments ?? []).map((attachment) => ({
218
+ filename: attachment.filename,
219
+ size: attachmentSize(attachment)
220
+ }))
221
+ });
222
+ }
223
+ function assertNoCooldown(action) {
224
+ const remainingMs = blockedUntil - Date.now();
225
+ if (remainingMs > 0) throw maintenanceCooldownError(action, remainingMs);
226
+ }
227
+ async function execute(request, parse) {
228
+ const maxAttempts = request.safeToRetry ? safeAttempts : 1;
229
+ const ledgerKey = await ledgerKeyFor(request);
230
+ for (let attempt = 1;; attempt++) {
231
+ assertNoCooldown(request.action);
232
+ const failures = ledger && ledgerKey !== void 0 ? await ignoreStoreFailure(() => ledger.failures(ledgerKey)) ?? 0 : 0;
233
+ if (ledgerKey !== void 0 && failures >= 5) throw attemptLimitError(request.action, ledgerKey, failures);
234
+ const startedAt = Date.now();
235
+ callHook(hooks.onRequest, {
236
+ action: request.action,
237
+ attempt
238
+ });
239
+ try {
240
+ const response = await send(request);
241
+ callHook(hooks.onResponse, {
242
+ action: request.action,
243
+ attempt,
244
+ status: response.status,
245
+ durationMs: Date.now() - startedAt
246
+ });
247
+ const result = await parse(response);
248
+ if (ledger && ledgerKey !== void 0 && failures > 0) await ignoreStoreFailure(() => ledger.reset(ledgerKey));
249
+ return result;
250
+ } catch (error) {
251
+ if (!(error instanceof SzamlazzError)) throw error;
252
+ if (ledger && ledgerKey !== void 0 && countsAsFailedAttempt(error)) await ignoreStoreFailure(() => ledger.recordFailure(ledgerKey, failures));
253
+ if (error.category === "maintenance" && cooldownMs > 0) blockedUntil = Date.now() + cooldownMs;
254
+ const willRetry = error.retryable && attempt < maxAttempts && !(error.category === "maintenance" && cooldownMs > 0);
255
+ callHook(hooks.onError, {
256
+ action: request.action,
257
+ attempt,
258
+ error,
259
+ willRetry
260
+ });
261
+ if (error.category === "auth") await resetSession();
262
+ if (!willRetry) throw error;
263
+ await sleep(retryDelayMs * 2 ** (attempt - 1), request.signal);
264
+ }
265
+ }
266
+ }
267
+ return {
268
+ credentials,
269
+ execute,
270
+ resetSession,
271
+ resetAttempts
272
+ };
273
+ }
274
+ //#endregion
275
+ //#region src/invoices/create-response.ts
276
+ function readRawResponse(response) {
277
+ throwIfAnyError(response);
278
+ const headers = readDocumentHeaders(response.headers);
279
+ const fromHeaders = {
280
+ number: headers.number,
281
+ netTotal: headers.netTotal,
282
+ grossTotal: headers.grossTotal,
283
+ outstanding: void 0,
284
+ buyerAccountUrl: headers.buyerAccountUrl,
285
+ pdf: void 0
286
+ };
287
+ if (response.isPdf) return {
288
+ ...fromHeaders,
289
+ pdf: response.body
290
+ };
291
+ if (looksLikeXml(response)) {
292
+ const root = parseResponseXml(response);
293
+ throwIfXmlFailure(root, response);
294
+ const pdfBase64 = childText(root, "pdf");
295
+ return {
296
+ number: childText(root, "szamlaszam") ?? headers.number,
297
+ netTotal: childNumber(root, "szamlanetto") ?? headers.netTotal,
298
+ grossTotal: childNumber(root, "szamlabrutto") ?? headers.grossTotal,
299
+ outstanding: childNumber(root, "kintlevoseg"),
300
+ buyerAccountUrl: childText(root, "vevoifiokurl") ?? headers.buyerAccountUrl,
301
+ pdf: pdfBase64 === void 0 ? void 0 : base64ToBytes(pdfBase64)
302
+ };
303
+ }
304
+ const done = parseDoneText(response.text());
305
+ if (done) return {
306
+ ...fromHeaders,
307
+ number: done.number ?? headers.number
308
+ };
309
+ if (headers.number !== void 0) return fromHeaders;
310
+ throw unexpectedResponse(response, "Számlaszámot vagy PDF-et vártunk.");
311
+ }
312
+ function totalsFor(raw, items) {
313
+ if (raw.netTotal !== void 0 && raw.grossTotal !== void 0) return {
314
+ netTotal: raw.netTotal,
315
+ grossTotal: raw.grossTotal
316
+ };
317
+ const computed = summarizeItems(items);
318
+ return {
319
+ netTotal: raw.netTotal ?? computed.netAmount,
320
+ grossTotal: raw.grossTotal ?? computed.grossAmount
321
+ };
322
+ }
323
+ function parseCreateInvoiceResponse(response, items = []) {
324
+ const raw = readRawResponse(response);
325
+ if (raw.number === void 0) throw unexpectedResponse(response, "A sikeres válaszból hiányzik a számlaszám.");
326
+ return {
327
+ number: raw.number,
328
+ ...totalsFor(raw, items),
329
+ outstanding: raw.outstanding,
330
+ buyerAccountUrl: raw.buyerAccountUrl,
331
+ pdf: raw.pdf,
332
+ items
333
+ };
334
+ }
335
+ function parseInvoicePreviewResponse(response, items = []) {
336
+ const raw = readRawResponse(response);
337
+ if (raw.pdf === void 0) throw unexpectedResponse(response, "Az előnézeti válaszból hiányzik a PDF.");
338
+ return {
339
+ pdf: raw.pdf,
340
+ ...totalsFor(raw, items),
341
+ items
342
+ };
343
+ }
344
+ //#endregion
345
+ //#region src/invoices/create-xml.ts
346
+ const INVOICE_XML_NAMESPACE = "http://www.szamlazz.hu/xmlszamla";
347
+ const INVOICE_XML_SCHEMA_LOCATION = "https://www.szamlazz.hu/szamla/docs/xsds/agent/xmlszamla.xsd";
348
+ const RESPONSE_VERSION_XML = 2;
349
+ function textEl(name, value) {
350
+ return optionalEl(name, presentText(value));
351
+ }
352
+ function settingsNode(credentials, invoice, preview) {
353
+ return el("beallitasok", [
354
+ ...credentials,
355
+ el("eszamla", invoice.eInvoice),
356
+ el("szamlaLetoltes", preview || invoice.downloadPdf),
357
+ el("valaszVerzio", RESPONSE_VERSION_XML),
358
+ textEl("aggregator", invoice.aggregator),
359
+ optionalEl("guardian", invoice.guardian),
360
+ optionalEl("cikkazoninvoice", invoice.articleIdentifierInvoice),
361
+ textEl("szamlaKulsoAzon", invoice.input.externalId)
362
+ ]);
363
+ }
364
+ function documentTypeNodes(invoice) {
365
+ const { input, type } = invoice;
366
+ return [
367
+ type === "advance" && el("elolegszamla", true),
368
+ type === "final" && el("vegszamla", true),
369
+ input.type === "final" && textEl("elolegSzamlaszam", input.advanceInvoiceNumber),
370
+ type === "corrective" && el("helyesbitoszamla", true),
371
+ input.type === "corrective" && textEl("helyesbitettSzamlaszam", input.correctedInvoiceNumber),
372
+ type === "proforma" && el("dijbekero", true),
373
+ type === "deliveryNote" && el("szallitolevel", true)
374
+ ];
375
+ }
376
+ function headerNode(invoice, preview) {
377
+ const { input } = invoice;
378
+ return el("fejlec", [
379
+ el("keltDatum", invoice.issueDate),
380
+ el("teljesitesDatum", invoice.fulfillmentDate),
381
+ el("fizetesiHataridoDatum", invoice.dueDate),
382
+ el("fizmod", invoice.paymentMethod),
383
+ el("penznem", invoice.currency),
384
+ el("szamlaNyelve", invoice.language),
385
+ textEl("megjegyzes", input.comment),
386
+ textEl("arfolyamBank", invoice.exchangeBank),
387
+ optionalEl("arfolyam", invoice.exchangeRate),
388
+ textEl("rendelesSzam", input.orderNumber),
389
+ textEl("dijbekeroSzamlaszam", input.proformaNumber),
390
+ ...documentTypeNodes(invoice),
391
+ textEl("logoExtra", invoice.logoExtra),
392
+ textEl("szamlaszamElotag", invoice.prefix),
393
+ optionalEl("fizetendoKorrekcio", input.paymentCorrection),
394
+ optionalEl("fizetve", input.paid),
395
+ optionalEl("arresAfa", input.marginVat),
396
+ optionalEl("eusAfa", invoice.euVat),
397
+ optionalEl("szamlaSablon", invoice.template),
398
+ preview && el("elonezetpdf", true),
399
+ optionalEl("simpleItems", invoice.simpleItems)
400
+ ]);
401
+ }
402
+ function sellerNode(seller) {
403
+ return el("elado", [
404
+ textEl("bank", seller.bank),
405
+ textEl("bankszamlaszam", seller.bankAccount),
406
+ textEl("emailReplyto", seller.emailReplyTo),
407
+ textEl("emailTargy", seller.emailSubject),
408
+ textEl("emailSzoveg", seller.emailText),
409
+ textEl("alairoNeve", seller.signatoryName)
410
+ ]);
411
+ }
412
+ function buyerLedgerNode(ledger) {
413
+ if (!ledger) return void 0;
414
+ return optionalEl("vevoFokonyv", [
415
+ optionalEl("konyvelesDatum", optionalAgentDate$1(ledger.bookingDate, "buyer.ledger.bookingDate")),
416
+ textEl("vevoAzonosito", ledger.buyerId),
417
+ textEl("vevoFokonyviSzam", ledger.ledgerAccount),
418
+ optionalEl("folyamatosTelj", ledger.continuousFulfillment),
419
+ optionalEl("elszDatumTol", optionalAgentDate$1(ledger.settlementPeriodStart, "buyer.ledger.settlementPeriodStart")),
420
+ optionalEl("elszDatumIg", optionalAgentDate$1(ledger.settlementPeriodEnd, "buyer.ledger.settlementPeriodEnd"))
421
+ ]);
422
+ }
423
+ function buyerNode(buyer, sendEmail) {
424
+ const taxpayerType = buyer.taxpayerType;
425
+ return el("vevo", [
426
+ el("nev", buyer.name),
427
+ textEl("orszag", buyer.country),
428
+ el("irsz", buyer.zip),
429
+ el("telepules", buyer.city),
430
+ el("cim", buyer.address),
431
+ textEl("email", buyer.email),
432
+ el("sendEmail", sendEmail),
433
+ optionalEl("adoalany", taxpayerType === void 0 ? void 0 : TAXPAYER_TYPE_CODES[taxpayerType]),
434
+ textEl("adoszam", buyer.taxNumber),
435
+ textEl("csoportazonosito", buyer.groupTaxNumber),
436
+ textEl("adoszamEU", buyer.euTaxNumber),
437
+ textEl("postazasiNev", buyer.postal?.name),
438
+ textEl("postazasiOrszag", buyer.postal?.country),
439
+ textEl("postazasiIrsz", buyer.postal?.zip),
440
+ textEl("postazasiTelepules", buyer.postal?.city),
441
+ textEl("postazasiCim", buyer.postal?.address),
442
+ buyerLedgerNode(buyer.ledger),
443
+ textEl("azonosito", buyer.identifier),
444
+ textEl("alairoNeve", buyer.signatoryName),
445
+ textEl("telefonszam", buyer.phone),
446
+ textEl("megjegyzes", buyer.comment)
447
+ ]);
448
+ }
449
+ function waybillNode(waybill) {
450
+ if (!waybill) return void 0;
451
+ const { transOFlex: tof, pickPackPoint: ppp, sprinter, mpl } = waybill;
452
+ return el("fuvarlevel", [
453
+ textEl("futarSzolgalat", waybill.courier),
454
+ textEl("vonalkod", waybill.barcode),
455
+ textEl("megjegyzes", waybill.comment),
456
+ tof && el("tof", [
457
+ textEl("azonosito", tof.id),
458
+ textEl("shipmentID", tof.shipmentId),
459
+ optionalEl("csomagszam", tof.packageCount),
460
+ textEl("countryCode", tof.countryCode),
461
+ textEl("zip", tof.zip),
462
+ textEl("service", tof.service)
463
+ ]),
464
+ ppp && el("ppp", [textEl("vonalkodPrefix", ppp.barcodePrefix), textEl("vonalkodPostfix", ppp.barcodePostfix)]),
465
+ sprinter && el("sprinter", [
466
+ textEl("azonosito", sprinter.id),
467
+ textEl("feladokod", sprinter.senderCode),
468
+ textEl("iranykod", sprinter.directionCode),
469
+ optionalEl("csomagszam", sprinter.packageCount),
470
+ textEl("vonalkodPostfix", sprinter.barcodePostfix),
471
+ textEl("szallitasiIdo", sprinter.deliveryTime)
472
+ ]),
473
+ mpl && el("mpl", [
474
+ el("vevokod", mpl.customerCode),
475
+ el("vonalkod", mpl.barcode),
476
+ el("tomeg", String(mpl.weight)),
477
+ textEl("kulonszolgaltatasok", mpl.services),
478
+ optionalEl("erteknyilvanitas", mpl.declaredValue)
479
+ ])
480
+ ]);
481
+ }
482
+ function itemLedgerNode(ledger, label) {
483
+ if (!ledger) return void 0;
484
+ return optionalEl("tetelFokonyv", [
485
+ textEl("gazdasagiEsem", ledger.economicEvent),
486
+ textEl("gazdasagiEsemAfa", ledger.vatEconomicEvent),
487
+ textEl("arbevetelFokonyviSzam", ledger.revenueLedgerAccount),
488
+ textEl("afaFokonyviSzam", ledger.vatLedgerAccount),
489
+ optionalEl("elszDatumTol", optionalAgentDate$1(ledger.settlementPeriodStart, `${label} settlementPeriodStart`)),
490
+ optionalEl("elszDatumIg", optionalAgentDate$1(ledger.settlementPeriodEnd, `${label} settlementPeriodEnd`))
491
+ ]);
492
+ }
493
+ function itemNode(item, index) {
494
+ const { input, amounts } = item;
495
+ return el("tetel", [
496
+ el("megnevezes", input.name),
497
+ textEl("azonosito", input.identifier),
498
+ el("mennyiseg", amounts.quantity),
499
+ el("mennyisegiEgyseg", item.unit),
500
+ el("nettoEgysegar", amounts.netUnitPrice),
501
+ el("afakulcs", formatVatRate(amounts.vat)),
502
+ optionalEl("arresAfaAlap", input.marginVatBase),
503
+ el("nettoErtek", amounts.netAmount),
504
+ el("afaErtek", amounts.vatAmount),
505
+ el("bruttoErtek", amounts.grossAmount),
506
+ textEl("megjegyzes", input.comment),
507
+ itemLedgerNode(input.ledger, `${index + 1}. tétel ledger`),
508
+ optionalEl("torloKod", input.dataDeletionCode)
509
+ ]);
510
+ }
511
+ function renderInvoiceXml(credentials, invoice, options = {}) {
512
+ const preview = options.preview === true;
513
+ return buildXmlDocument({
514
+ root: "xmlszamla",
515
+ namespace: INVOICE_XML_NAMESPACE,
516
+ schemaLocation: INVOICE_XML_SCHEMA_LOCATION,
517
+ children: [
518
+ settingsNode(credentials, invoice, preview),
519
+ headerNode(invoice, preview),
520
+ sellerNode(invoice.seller),
521
+ buyerNode(invoice.input.buyer, invoice.sendEmail),
522
+ waybillNode(invoice.input.waybill),
523
+ el("tetelek", invoice.items.map(itemNode))
524
+ ]
525
+ });
526
+ }
527
+ //#endregion
528
+ //#region src/invoices/create.ts
529
+ function buildRequest(ctx, invoice, preview, options) {
530
+ const xml = renderInvoiceXml(ctx.credentials, invoice, { preview });
531
+ const attachments = preview ? [] : invoice.attachments;
532
+ return {
533
+ action: "createInvoice",
534
+ xml,
535
+ signal: options.signal,
536
+ ...attachments.length > 0 ? { attachments } : {}
537
+ };
538
+ }
539
+ function itemsOf(invoice) {
540
+ return invoice.items.map((item) => item.amounts);
541
+ }
542
+ async function createInvoice(ctx, defaults, input, options = {}) {
543
+ const invoice = resolveInvoice(defaults, input, /* @__PURE__ */ new Date());
544
+ const items = itemsOf(invoice);
545
+ return ctx.execute(buildRequest(ctx, invoice, false, options), (response) => parseCreateInvoiceResponse(response, items));
546
+ }
547
+ async function previewInvoice(ctx, defaults, input, options = {}) {
548
+ const invoice = resolveInvoice(defaults, input, /* @__PURE__ */ new Date());
549
+ const items = itemsOf(invoice);
550
+ return ctx.execute(buildRequest(ctx, invoice, true, options), (response) => parseInvoicePreviewResponse(response, items));
551
+ }
552
+ //#endregion
553
+ //#region src/invoices/reference.ts
554
+ const AGENT_XSD_BASE_URL = "https://www.szamlazz.hu/szamla/docs/xsds/";
555
+ function validationError(message) {
556
+ return new SzamlazzError(message, { category: "validation" });
557
+ }
558
+ function requireText(value, message) {
559
+ const trimmed = typeof value === "string" ? value.trim() : "";
560
+ if (trimmed === "") throw validationError(message);
561
+ return trimmed;
562
+ }
563
+ function optionalText(value) {
564
+ const trimmed = value?.trim();
565
+ return trimmed ? trimmed : void 0;
566
+ }
567
+ function agentDate(input, field) {
568
+ try {
569
+ return toAgentDate(input);
570
+ } catch (error) {
571
+ const detail = error instanceof Error ? error.message : String(error);
572
+ throw new SzamlazzError(`Érvénytelen dátum (${field}): ${detail}`, {
573
+ category: "validation",
574
+ cause: error
575
+ });
576
+ }
577
+ }
578
+ function optionalAgentDate(input, field) {
579
+ return input === void 0 ? void 0 : agentDate(input, field);
580
+ }
581
+ const REFERENCE_KEYS = [
582
+ "invoiceNumber",
583
+ "orderNumber",
584
+ "externalId"
585
+ ];
586
+ const REFERENCE_HINT$1 = "Add meg a számlaszámot szövegként, vagy pontosan egyet ezek közül: { invoiceNumber }, { orderNumber }, { externalId }.";
587
+ function resolveInvoiceReference(reference) {
588
+ if (typeof reference === "string") return {
589
+ kind: "invoiceNumber",
590
+ value: requireText(reference, `Üres számlaszám. ${REFERENCE_HINT$1}`)
591
+ };
592
+ if (typeof reference !== "object" || reference === null) throw validationError(`Érvénytelen bizonylat-hivatkozás. ${REFERENCE_HINT$1}`);
593
+ const record = reference;
594
+ const present = REFERENCE_KEYS.filter((key) => record[key] !== void 0);
595
+ const [kind] = present;
596
+ if (kind === void 0 || present.length > 1) throw validationError(`Érvénytelen bizonylat-hivatkozás. ${REFERENCE_HINT$1}`);
597
+ return {
598
+ kind,
599
+ value: requireText(record[kind], `Üres ${kind} érték. ${REFERENCE_HINT$1}`)
600
+ };
601
+ }
602
+ function referenceValue(reference, kind) {
603
+ return reference.kind === kind ? reference.value : void 0;
604
+ }
605
+ function readNumericHeader(headers, name) {
606
+ const value = readHeader$1(headers, name);
607
+ if (value === void 0) return void 0;
608
+ const parsed = Number(value.replace(",", "."));
609
+ return Number.isFinite(parsed) ? parsed : void 0;
610
+ }
611
+ function headerSummary(response) {
612
+ const headers = readDocumentHeaders(response.headers);
613
+ return {
614
+ number: headers.number,
615
+ netTotal: headers.netTotal,
616
+ grossTotal: headers.grossTotal,
617
+ outstanding: readNumericHeader(response.headers, "szlahu_kintlevoseg"),
618
+ buyerAccountUrl: headers.buyerAccountUrl
619
+ };
620
+ }
621
+ function decodeResponsePdf(root, response) {
622
+ const encoded = childText(root, "pdf");
623
+ if (encoded === void 0) return void 0;
624
+ try {
625
+ return base64ToBytes(encoded);
626
+ } catch (error) {
627
+ throw new SzamlazzError("A válaszban kapott PDF nem érvényes base64.", {
628
+ category: "unexpected_response",
629
+ action: response.action,
630
+ httpStatus: response.status,
631
+ cause: error
632
+ });
633
+ }
634
+ }
635
+ function readInvoiceResultXml(root, response) {
636
+ const headers = headerSummary(response);
637
+ return {
638
+ number: childText(root, "szamlaszam") ?? headers.number,
639
+ netTotal: childNumber(root, "szamlanetto") ?? headers.netTotal,
640
+ grossTotal: childNumber(root, "szamlabrutto") ?? headers.grossTotal,
641
+ outstanding: childNumber(root, "kintlevoseg") ?? headers.outstanding,
642
+ buyerAccountUrl: childText(root, "vevoifiokurl") ?? headers.buyerAccountUrl,
643
+ pdf: decodeResponsePdf(root, response)
644
+ };
645
+ }
646
+ const INVOICE_RESULT_ROOT = "xmlszamlavalasz";
647
+ function parseInvoiceResult(response) {
648
+ throwIfHeaderError(response);
649
+ if (response.isPdf) return {
650
+ ...headerSummary(response),
651
+ pdf: response.body
652
+ };
653
+ throwIfTextError(response);
654
+ throwIfHttpError(response);
655
+ if (looksLikeXml(response)) {
656
+ const root = parseResponseXml(response);
657
+ throwIfXmlFailure(root, response);
658
+ if (root.name !== INVOICE_RESULT_ROOT || childText(root, "sikeres")?.toLowerCase() !== "true") throw unexpectedResponse(response, `${INVOICE_RESULT_ROOT} XML választ vártunk.`);
659
+ return readInvoiceResultXml(root, response);
660
+ }
661
+ const headers = headerSummary(response);
662
+ const done = parseDoneText(response.text());
663
+ if (done) return {
664
+ ...headers,
665
+ number: done.number ?? headers.number
666
+ };
667
+ if (headers.number !== void 0) return headers;
668
+ throw unexpectedResponse(response);
669
+ }
670
+ //#endregion
671
+ //#region src/invoices/get.ts
672
+ const INVOICE_DOCUMENT_TYPE_CODES = {
673
+ invoice: "SZ",
674
+ proforma: "D",
675
+ advance: "ES",
676
+ final: "VS",
677
+ corrective: "HS",
678
+ reversal: "SS",
679
+ deliveryNote: "SL"
680
+ };
681
+ function buildGetInvoiceXml(credentials, reference, query = {}) {
682
+ const resolved = resolveInvoiceReference(reference);
683
+ return buildXmlDocument({
684
+ root: "xmlszamlaxml",
685
+ namespace: "http://www.szamlazz.hu/xmlszamlaxml",
686
+ schemaLocation: `${AGENT_XSD_BASE_URL}agentxml/xmlszamlaxml.xsd`,
687
+ children: [
688
+ ...credentials,
689
+ optionalEl("szamlaszam", referenceValue(resolved, "invoiceNumber")),
690
+ optionalEl("rendelesSzam", referenceValue(resolved, "orderNumber")),
691
+ optionalEl("pdf", query.includePdf),
692
+ optionalEl("szamlaKulsoAzon", referenceValue(resolved, "externalId"))
693
+ ]
694
+ });
695
+ }
696
+ var InvoiceReader = class {
697
+ response;
698
+ constructor(response) {
699
+ this.response = response;
700
+ }
701
+ missing(path) {
702
+ return unexpectedResponse(this.response, `Hiányzik a(z) <${path}> elem a számla XML-ből.`);
703
+ }
704
+ element(parent, name, path) {
705
+ const child = findChild(parent, name);
706
+ if (!child) throw this.missing(path);
707
+ return child;
708
+ }
709
+ text(parent, name, path) {
710
+ const value = childText(parent, name);
711
+ if (value === void 0) throw this.missing(`${path}/${name}`);
712
+ return value;
713
+ }
714
+ number(parent, name, path) {
715
+ const value = childNumber(parent, name);
716
+ if (value === void 0) throw this.missing(`${path}/${name}`);
717
+ return value;
718
+ }
719
+ };
720
+ function readAddress(element) {
721
+ if (!element) return void 0;
722
+ return {
723
+ name: childText(element, "nev"),
724
+ country: childText(element, "orszag"),
725
+ zip: childText(element, "irsz"),
726
+ city: childText(element, "telepules"),
727
+ address: childText(element, "cim")
728
+ };
729
+ }
730
+ function readSeller(root, reader) {
731
+ const seller = reader.element(root, "szallito", "szallito");
732
+ const bank = findChild(seller, "bank");
733
+ return {
734
+ id: childNumber(seller, "id"),
735
+ name: reader.text(seller, "nev", "szallito"),
736
+ address: readAddress(findChild(seller, "cim")),
737
+ postalAddress: readAddress(findChild(seller, "postacim")),
738
+ taxNumber: childText(seller, "adoszam"),
739
+ groupTaxNumber: childText(seller, "csoportazonosito"),
740
+ euTaxNumber: childText(seller, "adoszameu"),
741
+ bank: bank && {
742
+ name: childText(bank, "nev"),
743
+ accountNumber: childText(bank, "bankszamla")
744
+ }
745
+ };
746
+ }
747
+ const DOCUMENT_TYPES_BY_CODE = new Map(Object.entries(INVOICE_DOCUMENT_TYPE_CODES).map(([type, code]) => [code, type]));
748
+ const E_INVOICE_CODES = /* @__PURE__ */ new Set([2, 3]);
749
+ function readHeader(root, reader) {
750
+ const header = reader.element(root, "alap", "alap");
751
+ const typeCode = reader.text(header, "tipus", "alap");
752
+ const appearanceCode = childNumber(header, "eszamla");
753
+ return {
754
+ id: childNumber(header, "id"),
755
+ number: reader.text(header, "szamlaszam", "alap"),
756
+ economicEventId: childNumber(header, "gazdEsemAzon"),
757
+ sourceSystem: childNumber(header, "forras"),
758
+ registrationNumber: childText(header, "iktatoszam"),
759
+ type: DOCUMENT_TYPES_BY_CODE.get(typeCode) ?? "unknown",
760
+ typeCode,
761
+ eInvoice: appearanceCode !== void 0 && E_INVOICE_CODES.has(appearanceCode),
762
+ appearanceCode,
763
+ referencedInvoiceNumber: childText(header, "hivszamlaszam"),
764
+ referencedProformaNumber: childText(header, "hivdijbekszam"),
765
+ issueDate: reader.text(header, "kelt", "alap"),
766
+ fulfillmentDate: childText(header, "telj"),
767
+ dueDate: childText(header, "fizh"),
768
+ paymentMethod: childText(header, "fizmod"),
769
+ unifiedPaymentMethod: childText(header, "fizmodunified"),
770
+ cash: childBoolean(header, "keszpenz"),
771
+ orderNumber: childText(header, "rendelesszam"),
772
+ language: childText(header, "nyelv"),
773
+ currency: childText(header, "devizanem"),
774
+ exchangeBank: childText(header, "devizabank"),
775
+ exchangeRate: childNumber(header, "devizaarf"),
776
+ comment: childText(header, "megjegyzes"),
777
+ vatType: childText(header, "afatipus"),
778
+ cashAccounting: childBoolean(header, "penzforg"),
779
+ kata: childBoolean(header, "kata"),
780
+ kataLedger: childBoolean(header, "katafokonyv"),
781
+ email: childText(header, "email"),
782
+ test: childBoolean(header, "teszt"),
783
+ reversed: childBoolean(header, "sztornozott")
784
+ };
785
+ }
786
+ function readBuyerLedger(element) {
787
+ if (!element) return void 0;
788
+ return {
789
+ ledgerAccount: childText(element, "vevo"),
790
+ buyerId: childText(element, "vevoazon"),
791
+ bookingDate: childText(element, "datum"),
792
+ continuousFulfillment: childBoolean(element, "folyamatostelj"),
793
+ settlementPeriodStart: childText(element, "elszDatTol") ?? childText(element, "elszdattol"),
794
+ settlementPeriodEnd: childText(element, "elszDatIg") ?? childText(element, "elszdatig")
795
+ };
796
+ }
797
+ function readBuyer(root, reader) {
798
+ const buyer = reader.element(root, "vevo", "vevo");
799
+ return {
800
+ id: childNumber(buyer, "id"),
801
+ name: reader.text(buyer, "nev", "vevo"),
802
+ identifier: childText(buyer, "azonosito"),
803
+ address: readAddress(findChild(buyer, "cim")),
804
+ postalAddress: readAddress(findChild(buyer, "postacim")),
805
+ email: childText(buyer, "email"),
806
+ taxNumber: childText(buyer, "adoszam"),
807
+ groupTaxNumber: childText(buyer, "csoportazonosito"),
808
+ euTaxNumber: childText(buyer, "adoszameu"),
809
+ location: childNumber(buyer, "lokacio"),
810
+ privatePerson: childBoolean(buyer, "privatePersonIndicator"),
811
+ ledger: readBuyerLedger(findChild(buyer, "fokonyv"))
812
+ };
813
+ }
814
+ function readItemLedger(element) {
815
+ if (!element) return void 0;
816
+ return {
817
+ revenueLedgerAccount: childText(element, "arbevetel"),
818
+ vatLedgerAccount: childText(element, "afa"),
819
+ economicEvent: childText(element, "gazdasagiesemeny"),
820
+ vatEconomicEvent: childText(element, "gazdasagiesemenyafa"),
821
+ settlementPeriodStart: childText(element, "elszdattol"),
822
+ settlementPeriodEnd: childText(element, "elszdatig")
823
+ };
824
+ }
825
+ function readItem(item, reader) {
826
+ const path = "tetelek/tetel";
827
+ return {
828
+ name: reader.text(item, "nev", path),
829
+ identifier: childText(item, "azonosito"),
830
+ quantity: reader.number(item, "mennyiseg", path),
831
+ unit: childText(item, "mennyisegiegyseg"),
832
+ netUnitPrice: reader.number(item, "nettoegysegar", path),
833
+ vat: reader.number(item, "afakulcs", path),
834
+ vatCode: childText(item, "afatipus"),
835
+ netAmount: reader.number(item, "netto", path),
836
+ marginVatBase: childNumber(item, "arresafaalap"),
837
+ vatAmount: reader.number(item, "afa", path),
838
+ grossAmount: reader.number(item, "brutto", path),
839
+ comment: childText(item, "megjegyzes"),
840
+ position: childNumber(item, "sztetordering"),
841
+ ledger: readItemLedger(findChild(item, "fokonyv"))
842
+ };
843
+ }
844
+ function readLabels(element) {
845
+ return findChildren(element, "cimke").flatMap((label) => {
846
+ const value = label.text.trim();
847
+ return value === "" ? [] : [value];
848
+ });
849
+ }
850
+ function readFinancialItem(item, reader) {
851
+ const path = "qutetek/qutet";
852
+ return {
853
+ name: reader.text(item, "nev", path),
854
+ vat: reader.number(item, "afakulcs", path),
855
+ vatCode: childText(item, "afatipus"),
856
+ netAmount: reader.number(item, "netto", path),
857
+ vatAmount: reader.number(item, "afa", path),
858
+ grossAmount: reader.number(item, "brutto", path),
859
+ settlementPeriodStart: childText(item, "elszdattol"),
860
+ settlementPeriodEnd: childText(item, "elszdatig"),
861
+ vatDeduction: childNumber(item, "afalevon"),
862
+ labels: readLabels(findChild(item, "cimkek"))
863
+ };
864
+ }
865
+ function readTotals(root, reader) {
866
+ const totals = reader.element(root, "osszegek", "osszegek");
867
+ const total = reader.element(totals, "totalossz", "osszegek/totalossz");
868
+ const path = "osszegek/totalossz";
869
+ return {
870
+ netAmount: reader.number(total, "netto", path),
871
+ vatAmount: reader.number(total, "afa", path),
872
+ grossAmount: reader.number(total, "brutto", path),
873
+ byVat: findChildren(totals, "afakulcsossz").map((entry) => ({
874
+ vat: reader.number(entry, "afakulcs", "osszegek/afakulcsossz"),
875
+ vatCode: childText(entry, "afatipus"),
876
+ netAmount: reader.number(entry, "netto", "osszegek/afakulcsossz"),
877
+ vatAmount: reader.number(entry, "afa", "osszegek/afakulcsossz"),
878
+ grossAmount: reader.number(entry, "brutto", "osszegek/afakulcsossz")
879
+ }))
880
+ };
881
+ }
882
+ function readPayment(payment, reader) {
883
+ const path = "kifizetesek/kifizetes";
884
+ return {
885
+ date: reader.text(payment, "datum", path),
886
+ method: reader.text(payment, "jogcim", path),
887
+ amount: reader.number(payment, "osszeg", path),
888
+ comment: childText(payment, "megjegyzes"),
889
+ bankAccountNumber: childText(payment, "bankszamlaszam"),
890
+ bankTransactionId: childNumber(payment, "banktranzid"),
891
+ exchangeRate: childNumber(payment, "devizaarf")
892
+ };
893
+ }
894
+ function parseInvoiceDetailsXml(root, response) {
895
+ const reader = new InvoiceReader(response);
896
+ return {
897
+ seller: readSeller(root, reader),
898
+ header: readHeader(root, reader),
899
+ buyer: readBuyer(root, reader),
900
+ items: findChildren(findChild(root, "tetelek"), "tetel").map((item) => readItem(item, reader)),
901
+ financialItems: findChildren(findChild(root, "qutetek"), "qutet").map((item) => readFinancialItem(item, reader)),
902
+ labels: readLabels(findChild(root, "cimkek")),
903
+ totals: readTotals(root, reader),
904
+ payments: findChildren(findChild(root, "kifizetesek"), "kifizetes").map((payment) => readPayment(payment, reader)),
905
+ pdf: decodeResponsePdf(root, response)
906
+ };
907
+ }
908
+ function parseGetInvoiceResponse(response) {
909
+ throwIfHeaderError(response);
910
+ throwIfTextError(response);
911
+ throwIfHttpError(response);
912
+ const root = parseResponseXml(response);
913
+ throwIfXmlFailure(root, response);
914
+ if (root.name !== "szamla") throw unexpectedResponse(response, "A számla XML (<szamla>) helyett más válasz érkezett.");
915
+ return parseInvoiceDetailsXml(root, response);
916
+ }
917
+ async function getInvoice(ctx, reference, query = {}, options = {}) {
918
+ const xml = buildGetInvoiceXml(ctx.credentials, reference, query);
919
+ return ctx.execute({
920
+ action: "getInvoiceXml",
921
+ xml,
922
+ signal: options.signal,
923
+ safeToRetry: true
924
+ }, parseGetInvoiceResponse);
925
+ }
926
+ function normalizeRegisterInput(input) {
927
+ const payments = "payments" in input ? input.payments : [{
928
+ amount: input.amount,
929
+ method: input.method ?? "átutalás",
930
+ date: input.date,
931
+ description: input.description
932
+ }];
933
+ if (!Array.isArray(payments) || payments.length === 0) throw validationError("Adj meg legalább egy befizetést (payments). A korábbi befizetések törléséhez a clearPayments függvényt használd.");
934
+ if (payments.length > 5) throw validationError(`Egy kérésben legfeljebb 5 befizetés rögzíthető, kapott: ${payments.length}.`);
935
+ return {
936
+ invoiceNumber: input.invoiceNumber,
937
+ taxNumber: input.taxNumber,
938
+ additive: input.additive ?? true,
939
+ payments
940
+ };
941
+ }
942
+ function normalizeClearInput(input) {
943
+ const target = typeof input === "string" ? { invoiceNumber: input } : input;
944
+ return {
945
+ invoiceNumber: target.invoiceNumber,
946
+ taxNumber: target.taxNumber,
947
+ additive: false,
948
+ payments: []
949
+ };
950
+ }
951
+ function paymentNode(payment, index) {
952
+ const position = index + 1;
953
+ if (typeof payment.amount !== "number" || !Number.isFinite(payment.amount)) throw validationError(`A(z) ${position}. befizetés összege (amount) nem véges szám.`);
954
+ return el("kifizetes", [
955
+ el("datum", payment.date === void 0 ? todayInBudapest() : agentDate(payment.date, "date")),
956
+ el("jogcim", requireText(payment.method, `Add meg a(z) ${position}. befizetés módját (method).`)),
957
+ el("osszeg", payment.amount),
958
+ optionalEl("leiras", optionalText(payment.description))
959
+ ]);
960
+ }
961
+ function buildPaymentXml(credentials, request) {
962
+ const invoiceNumber = requireText(request.invoiceNumber, "Add meg a számla számát (invoiceNumber), amelyhez a befizetés tartozik.");
963
+ return buildXmlDocument({
964
+ root: "xmlszamlakifiz",
965
+ namespace: "http://www.szamlazz.hu/xmlszamlakifiz",
966
+ schemaLocation: `${AGENT_XSD_BASE_URL}agentkifiz/xmlszamlakifiz.xsd`,
967
+ children: [el("beallitasok", [
968
+ ...credentials,
969
+ el("szamlaszam", invoiceNumber),
970
+ optionalEl("adoszam", optionalText(request.taxNumber)),
971
+ el("additiv", request.additive),
972
+ el("valaszVerzio", 2)
973
+ ]), ...request.payments.map(paymentNode)]
974
+ });
975
+ }
976
+ function parseRegisterPaymentResponse(response, invoiceNumber) {
977
+ const result = parseInvoiceResult(response);
978
+ return {
979
+ invoiceNumber: result.number ?? invoiceNumber.trim(),
980
+ netTotal: result.netTotal,
981
+ grossTotal: result.grossTotal,
982
+ outstanding: result.outstanding,
983
+ buyerAccountUrl: result.buyerAccountUrl
984
+ };
985
+ }
986
+ function sendPaymentRequest(ctx, request, options) {
987
+ const xml = buildPaymentXml(ctx.credentials, request);
988
+ return ctx.execute({
989
+ action: "registerPayment",
990
+ xml,
991
+ signal: options.signal,
992
+ safeToRetry: !request.additive
993
+ }, (response) => parseRegisterPaymentResponse(response, request.invoiceNumber));
994
+ }
995
+ async function registerPayment(ctx, input, options = {}) {
996
+ return sendPaymentRequest(ctx, normalizeRegisterInput(input), options);
997
+ }
998
+ async function clearPayments(ctx, input, options = {}) {
999
+ return sendPaymentRequest(ctx, normalizeClearInput(input), options);
1000
+ }
1001
+ //#endregion
1002
+ //#region src/invoices/pdf.ts
1003
+ function buildInvoicePdfXml(credentials, reference) {
1004
+ const resolved = resolveInvoiceReference(reference);
1005
+ return buildXmlDocument({
1006
+ root: "xmlszamlapdf",
1007
+ namespace: "http://www.szamlazz.hu/xmlszamlapdf",
1008
+ schemaLocation: `${AGENT_XSD_BASE_URL}agentpdf/xmlszamlapdf.xsd`,
1009
+ children: [
1010
+ ...credentials,
1011
+ optionalEl("szamlaszam", referenceValue(resolved, "invoiceNumber")),
1012
+ optionalEl("rendelesSzam", referenceValue(resolved, "orderNumber")),
1013
+ el("valaszVerzio", 2),
1014
+ optionalEl("szamlaKulsoAzon", referenceValue(resolved, "externalId"))
1015
+ ]
1016
+ });
1017
+ }
1018
+ function parseInvoicePdfResponse(response) {
1019
+ const { pdf, ...rest } = parseInvoiceResult(response);
1020
+ if (pdf === void 0 || pdf.length === 0) throw unexpectedResponse(response, "A válasz nem tartalmaz PDF-et.");
1021
+ return {
1022
+ ...rest,
1023
+ pdf
1024
+ };
1025
+ }
1026
+ async function getInvoicePdf(ctx, reference, options = {}) {
1027
+ const xml = buildInvoicePdfXml(ctx.credentials, reference);
1028
+ return ctx.execute({
1029
+ action: "getInvoicePdf",
1030
+ xml,
1031
+ signal: options.signal,
1032
+ safeToRetry: true
1033
+ }, parseInvoicePdfResponse);
1034
+ }
1035
+ const RESPONSE_ROOTS = /* @__PURE__ */ new Set(["xmlszamladbkdelvalasz", "xmlszamlavalasz"]);
1036
+ const REFERENCE_HINT = "Add meg a díjbekérő számát szövegként, vagy pontosan egyet ezek közül: { proformaNumber }, { orderNumber }.";
1037
+ function resolveProformaReference(reference) {
1038
+ if (typeof reference === "string") return { proformaNumber: requireText(reference, `Üres díjbekérőszám. ${REFERENCE_HINT}`) };
1039
+ if (typeof reference !== "object" || reference === null) throw validationError(`Érvénytelen díjbekérő-hivatkozás. ${REFERENCE_HINT}`);
1040
+ const record = reference;
1041
+ const hasNumber = record.proformaNumber !== void 0;
1042
+ if (hasNumber === (record.orderNumber !== void 0)) throw validationError(`Érvénytelen díjbekérő-hivatkozás. ${REFERENCE_HINT}`);
1043
+ return hasNumber ? { proformaNumber: requireText(record.proformaNumber, `Üres proformaNumber. ${REFERENCE_HINT}`) } : { orderNumber: requireText(record.orderNumber, `Üres orderNumber. ${REFERENCE_HINT}`) };
1044
+ }
1045
+ function buildDeleteProformaXml(credentials, reference) {
1046
+ const resolved = resolveProformaReference(reference);
1047
+ return buildXmlDocument({
1048
+ root: "xmlszamladbkdel",
1049
+ namespace: "http://www.szamlazz.hu/xmlszamladbkdel",
1050
+ schemaLocation: "http://www.szamlazz.hu/docs/xsds/szamladbkdel/xmlszamladbkdel.xsd",
1051
+ children: [el("beallitasok", [...credentials]), el("fejlec", [optionalEl("szamlaszam", resolved.proformaNumber), optionalEl("rendelesszam", resolved.orderNumber)])]
1052
+ });
1053
+ }
1054
+ function withProformaCategory(error) {
1055
+ if (!(error instanceof SzamlazzError) || error.code !== 335) return error;
1056
+ return new SzamlazzError(error.message, {
1057
+ category: "not_found",
1058
+ code: error.code,
1059
+ hint: "A díjbekérő nem létezik, vagy már törölték.",
1060
+ action: error.action,
1061
+ httpStatus: error.httpStatus,
1062
+ rawResponse: error.rawResponse,
1063
+ cause: error
1064
+ });
1065
+ }
1066
+ function parseDeleteProformaResponse(response) {
1067
+ try {
1068
+ throwIfHeaderError(response);
1069
+ throwIfTextError(response);
1070
+ throwIfHttpError(response);
1071
+ const root = parseResponseXml(response);
1072
+ throwIfXmlFailure(root, response);
1073
+ if (!RESPONSE_ROOTS.has(root.name) || childText(root, "sikeres")?.toLowerCase() !== "true") throw unexpectedResponse(response, "xmlszamladbkdelvalasz XML választ vártunk.");
1074
+ } catch (error) {
1075
+ throw withProformaCategory(error);
1076
+ }
1077
+ }
1078
+ async function deleteProforma(ctx, reference, options = {}) {
1079
+ const xml = buildDeleteProformaXml(ctx.credentials, reference);
1080
+ await ctx.execute({
1081
+ action: "deleteProforma",
1082
+ xml,
1083
+ signal: options.signal
1084
+ }, parseDeleteProformaResponse);
1085
+ }
1086
+ const templates = new Set(INVOICE_TEMPLATES);
1087
+ function normalizeInput$2(input) {
1088
+ return typeof input === "string" ? { invoiceNumber: input } : input;
1089
+ }
1090
+ function validateTemplate(template) {
1091
+ if (template === void 0 || templates.has(template)) return template;
1092
+ throw validationError(`Ismeretlen számlasablon: ${String(template)}. Lehetséges értékek: ${INVOICE_TEMPLATES.join(", ")}.`);
1093
+ }
1094
+ function buildReverseInvoiceXml(credentials, input) {
1095
+ const options = normalizeInput$2(input);
1096
+ const invoiceNumber = requireText(options.invoiceNumber, "Add meg a sztornózandó számla számát (invoiceNumber).");
1097
+ const email = options.email;
1098
+ const buyer = options.buyer;
1099
+ return buildXmlDocument({
1100
+ root: "xmlszamlast",
1101
+ namespace: "http://www.szamlazz.hu/xmlszamlast",
1102
+ schemaLocation: `${AGENT_XSD_BASE_URL}agentst/xmlszamlast.xsd`,
1103
+ children: [
1104
+ el("beallitasok", [
1105
+ ...credentials,
1106
+ el("eszamla", options.eInvoice ?? false),
1107
+ el("szamlaLetoltes", options.downloadPdf ?? true),
1108
+ el("valaszVerzio", 2),
1109
+ optionalEl("szamlaKulsoAzon", optionalText(options.externalId))
1110
+ ]),
1111
+ el("fejlec", [
1112
+ el("szamlaszam", invoiceNumber),
1113
+ optionalEl("keltDatum", optionalAgentDate(options.issueDate, "issueDate")),
1114
+ optionalEl("teljesitesDatum", optionalAgentDate(options.fulfillmentDate, "fulfillmentDate")),
1115
+ optionalEl("megjegyzes", optionalText(options.comment)),
1116
+ el("tipus", "SS"),
1117
+ optionalEl("szamlaSablon", validateTemplate(options.template))
1118
+ ]),
1119
+ optionalEl("elado", [
1120
+ optionalEl("emailReplyto", optionalText(email?.replyTo)),
1121
+ optionalEl("emailTargy", optionalText(email?.subject)),
1122
+ optionalEl("emailSzoveg", optionalText(email?.text))
1123
+ ]),
1124
+ optionalEl("vevo", [
1125
+ optionalEl("email", optionalText(buyer?.email)),
1126
+ optionalEl("adoszam", optionalText(buyer?.taxNumber)),
1127
+ optionalEl("adoszamEU", optionalText(buyer?.euTaxNumber))
1128
+ ])
1129
+ ]
1130
+ });
1131
+ }
1132
+ function parseReverseInvoiceResponse(response, originalInvoiceNumber) {
1133
+ const result = parseInvoiceResult(response);
1134
+ if (result.number === void 0) throw unexpectedResponse(response, "A válaszban nincs sztornó számlaszám.");
1135
+ if (originalInvoiceNumber !== void 0 && result.number === originalInvoiceNumber.trim()) throw new SzamlazzError(`A(z) ${result.number} bizonylat nem lett sztornózva: a Számlázz.hu az eredeti bizonylatot adta vissza.`, {
1136
+ category: "validation",
1137
+ action: response.action,
1138
+ httpStatus: response.status,
1139
+ hint: "Díjbekérő és szállítólevél nem sztornózható. Díjbekérőt a deleteProforma függvénnyel törölhetsz."
1140
+ });
1141
+ return {
1142
+ ...result,
1143
+ number: result.number
1144
+ };
1145
+ }
1146
+ async function reverseInvoice(ctx, input, options = {}) {
1147
+ const invoiceNumber = normalizeInput$2(input).invoiceNumber;
1148
+ const xml = buildReverseInvoiceXml(ctx.credentials, input);
1149
+ return ctx.execute({
1150
+ action: "reverseInvoice",
1151
+ xml,
1152
+ signal: options.signal
1153
+ }, (response) => parseReverseInvoiceResponse(response, invoiceNumber));
1154
+ }
1155
+ //#endregion
1156
+ //#region src/receipts/get.ts
1157
+ const GET_RECEIPT_NAMESPACE = "http://www.szamlazz.hu/xmlnyugtaget";
1158
+ function normalizeInput$1(input) {
1159
+ return typeof input === "string" ? { receiptNumber: input } : input;
1160
+ }
1161
+ function resolveIdentifier(input) {
1162
+ const receiptNumber = optionalText$1(input.receiptNumber);
1163
+ const orderNumber = optionalText$1(input.orderNumber);
1164
+ if (receiptNumber === void 0 && orderNumber === void 0) throw receiptValidationError("A nyugta lekérdezéséhez add meg a nyugtaszámot (receiptNumber) vagy a rendelésszámot (orderNumber).");
1165
+ if (receiptNumber !== void 0 && orderNumber !== void 0) throw receiptValidationError("A nyugta lekérdezéséhez a nyugtaszám (receiptNumber) és a rendelésszám (orderNumber) közül csak az egyiket add meg.");
1166
+ return {
1167
+ receiptNumber,
1168
+ orderNumber
1169
+ };
1170
+ }
1171
+ function buildGetReceiptXml(credentials, input) {
1172
+ const normalized = normalizeInput$1(input);
1173
+ const { receiptNumber, orderNumber } = resolveIdentifier(normalized);
1174
+ return buildXmlDocument({
1175
+ root: "xmlnyugtaget",
1176
+ namespace: GET_RECEIPT_NAMESPACE,
1177
+ schemaLocation: `${RECEIPT_XSD_BASE_URL}nyugtaget/xmlnyugtaget.xsd`,
1178
+ children: [el("beallitasok", [...credentials, el("pdfLetoltes", normalized.downloadPdf ?? true)]), el("fejlec", [
1179
+ optionalEl("nyugtaszam", receiptNumber),
1180
+ optionalEl("rendelesSzam", orderNumber),
1181
+ optionalEl("hivasAzonosito", optionalText$1(normalized.callId)),
1182
+ optionalEl("pdfSablon", validateTemplate$1(normalized.template))
1183
+ ])]
1184
+ });
1185
+ }
1186
+ function getReceipt(ctx, input, options = {}) {
1187
+ const xml = buildGetReceiptXml(ctx.credentials, input);
1188
+ return ctx.execute({
1189
+ action: "getReceipt",
1190
+ xml,
1191
+ signal: options.signal,
1192
+ safeToRetry: true
1193
+ }, parseReceiptResponse);
1194
+ }
1195
+ //#endregion
1196
+ //#region src/receipts/reverse.ts
1197
+ const REVERSE_RECEIPT_NAMESPACE = "http://www.szamlazz.hu/xmlnyugtast";
1198
+ function normalizeInput(input) {
1199
+ return typeof input === "string" ? { receiptNumber: input } : input;
1200
+ }
1201
+ function buildReverseReceiptXml(credentials, input) {
1202
+ const normalized = normalizeInput(input);
1203
+ return buildXmlDocument({
1204
+ root: "xmlnyugtast",
1205
+ namespace: REVERSE_RECEIPT_NAMESPACE,
1206
+ schemaLocation: `${RECEIPT_XSD_BASE_URL}nyugtast/xmlnyugtast.xsd`,
1207
+ children: [el("beallitasok", [...credentials, el("pdfLetoltes", normalized.downloadPdf ?? true)]), el("fejlec", [
1208
+ el("nyugtaszam", requireReceiptNumber(normalized.receiptNumber)),
1209
+ optionalEl("pdfSablon", validateTemplate$1(normalized.template)),
1210
+ optionalEl("hivasAzonosito", optionalText$1(normalized.callId))
1211
+ ])]
1212
+ });
1213
+ }
1214
+ function reverseReceipt(ctx, input, options = {}) {
1215
+ const normalized = normalizeInput(input);
1216
+ const xml = buildReverseReceiptXml(ctx.credentials, normalized);
1217
+ return ctx.execute({
1218
+ action: "reverseReceipt",
1219
+ xml,
1220
+ signal: options.signal,
1221
+ safeToRetry: optionalText$1(normalized.callId) !== void 0
1222
+ }, parseReceiptResponse);
1223
+ }
1224
+ //#endregion
1225
+ //#region src/receipts/send.ts
1226
+ const SEND_RECEIPT_NAMESPACE = "http://www.szamlazz.hu/xmlnyugtasend";
1227
+ const EMAIL_PATTERN = /^[^\s@,;<>]+@[^\s@,;<>]+\.[^\s@,;<>]+$/;
1228
+ function isValidEmail(value) {
1229
+ return EMAIL_PATTERN.test(value);
1230
+ }
1231
+ function assertEmail(value, field) {
1232
+ if (!isValidEmail(value)) throw receiptValidationError(`Érvénytelen e-mail cím a(z) ${field} mezőben: ${value}`);
1233
+ return value;
1234
+ }
1235
+ function normalizeEmails(emails) {
1236
+ const list = (typeof emails === "string" ? [emails] : [...emails]).flatMap((entry) => entry.split(/[,;]/)).map((entry) => entry.trim()).filter((entry) => entry !== "");
1237
+ if (list.length === 0) throw receiptValidationError("Adj meg legalább egy címzett e-mail címet (emails).");
1238
+ return list.map((email) => assertEmail(email, "emails"));
1239
+ }
1240
+ function buildSendReceiptXml(credentials, input) {
1241
+ const receiptNumber = requireReceiptNumber(input.receiptNumber);
1242
+ const emails = normalizeEmails(input.emails);
1243
+ const replyTo = optionalText$1(input.replyTo);
1244
+ if (replyTo !== void 0) assertEmail(replyTo, "replyTo");
1245
+ return buildXmlDocument({
1246
+ root: "xmlnyugtasend",
1247
+ namespace: SEND_RECEIPT_NAMESPACE,
1248
+ schemaLocation: `${RECEIPT_XSD_BASE_URL}nyugtasend/xmlnyugtasend.xsd`,
1249
+ children: [
1250
+ el("beallitasok", credentials),
1251
+ el("fejlec", [el("nyugtaszam", receiptNumber)]),
1252
+ el("emailKuldes", [
1253
+ el("email", emails.join(",")),
1254
+ optionalEl("emailReplyto", replyTo),
1255
+ el("emailTargy", optionalText$1(input.subject) ?? `Nyugta ${receiptNumber}`),
1256
+ optionalEl("emailSzoveg", input.text?.trim() ? input.text : void 0)
1257
+ ])
1258
+ ]
1259
+ });
1260
+ }
1261
+ function parseSendReceiptResponse(response) {
1262
+ throwIfHeaderError(response);
1263
+ throwIfTextError(response);
1264
+ if (!looksLikeXml(response)) {
1265
+ throwIfHttpError(response);
1266
+ if (parseDoneText(response.text())) return;
1267
+ throw unexpectedResponse(response, "XML választ vártunk a nyugta kiküldésére.");
1268
+ }
1269
+ const root = parseResponseXml(response);
1270
+ throwIfXmlFailure(root, response);
1271
+ if (childBoolean(root, "sikeres") !== true) {
1272
+ throwIfHttpError(response);
1273
+ throw unexpectedResponse(response, "A válasz nem jelez sikeres kiküldést.");
1274
+ }
1275
+ }
1276
+ function sendReceipt(ctx, input, options = {}) {
1277
+ const xml = buildSendReceiptXml(ctx.credentials, input);
1278
+ return ctx.execute({
1279
+ action: "sendReceipt",
1280
+ xml,
1281
+ signal: options.signal
1282
+ }, parseSendReceiptResponse);
1283
+ }
1284
+ //#endregion
1285
+ //#region src/taxpayer/address.ts
1286
+ const ROMAN_NUMERAL = /^[IVX]{1,5}\.?$/;
1287
+ function isShouting(value) {
1288
+ return value === value.toUpperCase() && value !== value.toLowerCase();
1289
+ }
1290
+ function capitalizeWord(word) {
1291
+ if (ROMAN_NUMERAL.test(word)) return word;
1292
+ return word.split("-").map((part) => part.toLowerCase().replace(/\p{L}/u, (letter) => letter.toUpperCase())).join("-");
1293
+ }
1294
+ function toReadableName(value) {
1295
+ if (value === void 0 || !isShouting(value)) return value;
1296
+ return value.split(" ").map(capitalizeWord).join(" ");
1297
+ }
1298
+ function toLowerIfShouting(value) {
1299
+ return value !== void 0 && isShouting(value) ? value.toLowerCase() : value;
1300
+ }
1301
+ function withOrdinalDot(value) {
1302
+ if (value === void 0) return void 0;
1303
+ return /^\d+$/.test(value) ? `${value}.` : value;
1304
+ }
1305
+ function joinParts(parts) {
1306
+ return parts.filter((part) => part !== void 0 && part !== "").join(" ");
1307
+ }
1308
+ function formatAddress(address) {
1309
+ return [
1310
+ joinParts([address.postalCode, address.city]),
1311
+ joinParts([
1312
+ address.street,
1313
+ address.publicPlaceCategory,
1314
+ withOrdinalDot(address.number),
1315
+ address.building === void 0 ? void 0 : `${address.building} ép.`,
1316
+ address.staircase === void 0 ? void 0 : `${withOrdinalDot(address.staircase)} lh.`,
1317
+ address.floor === void 0 ? void 0 : `${withOrdinalDot(address.floor)} em.`,
1318
+ address.door === void 0 ? void 0 : `${withOrdinalDot(address.door)} ajtó`
1319
+ ]),
1320
+ address.lotNumber === void 0 ? void 0 : `hrsz. ${address.lotNumber}`,
1321
+ address.countryCode === "" || address.countryCode === "HU" ? void 0 : address.countryCode
1322
+ ].filter((part) => part !== void 0 && part !== "").join(", ");
1323
+ }
1324
+ function readDetailedAddress(element) {
1325
+ return {
1326
+ countryCode: childText(element, "countryCode"),
1327
+ region: childText(element, "region"),
1328
+ postalCode: childText(element, "postalCode"),
1329
+ city: childText(element, "city"),
1330
+ streetName: childText(element, "streetName"),
1331
+ publicPlaceCategory: childText(element, "publicPlaceCategory"),
1332
+ number: childText(element, "number"),
1333
+ building: childText(element, "building"),
1334
+ staircase: childText(element, "staircase"),
1335
+ floor: childText(element, "floor"),
1336
+ door: childText(element, "door"),
1337
+ lotNumber: childText(element, "lotNumber")
1338
+ };
1339
+ }
1340
+ function parseTaxpayerAddress(item) {
1341
+ const raw = readDetailedAddress(findChild(item, "taxpayerAddress"));
1342
+ const address = {
1343
+ type: childText(item, "taxpayerAddressType")?.toUpperCase() ?? "",
1344
+ countryCode: raw.countryCode?.toUpperCase() ?? "",
1345
+ region: toReadableName(raw.region),
1346
+ postalCode: raw.postalCode ?? "",
1347
+ city: toReadableName(raw.city) ?? "",
1348
+ street: toReadableName(raw.streetName),
1349
+ publicPlaceCategory: toLowerIfShouting(raw.publicPlaceCategory),
1350
+ number: raw.number,
1351
+ building: raw.building,
1352
+ staircase: raw.staircase,
1353
+ floor: raw.floor,
1354
+ door: raw.door,
1355
+ lotNumber: raw.lotNumber
1356
+ };
1357
+ return {
1358
+ ...address,
1359
+ formatted: formatAddress(address),
1360
+ raw
1361
+ };
1362
+ }
1363
+ //#endregion
1364
+ //#region src/taxpayer/query-taxpayer.ts
1365
+ const TAXPAYER_NAMESPACE = "http://www.szamlazz.hu/xmltaxpayer";
1366
+ const TAXPAYER_SCHEMA_LOCATION = "http://www.szamlazz.hu/docs/xsds/agent/xmltaxpayer.xsd";
1367
+ function toTaxpayerId(taxNumber) {
1368
+ const digits = typeof taxNumber === "string" ? taxNumber.replace(/[\s-]+/g, "").replace(/^HU/i, "") : "";
1369
+ if (!/^(?:\d{8}|\d{11})$/.test(digits)) throw new SzamlazzError(`Érvénytelen adószám: "${String(taxNumber)}". Add meg a 8 jegyű törzsszámot vagy a 11 jegyű adószámot (pl. 12345678-2-42).`, {
1370
+ category: "validation",
1371
+ action: "queryTaxpayer"
1372
+ });
1373
+ return digits.slice(0, 8);
1374
+ }
1375
+ function buildQueryTaxpayerXml(credentials, taxNumber) {
1376
+ return buildXmlDocument({
1377
+ root: "xmltaxpayer",
1378
+ namespace: TAXPAYER_NAMESPACE,
1379
+ schemaLocation: TAXPAYER_SCHEMA_LOCATION,
1380
+ children: [el("beallitasok", credentials), el("torzsszam", toTaxpayerId(taxNumber))]
1381
+ });
1382
+ }
1383
+ function throwIfNavError(root, response) {
1384
+ const result = findChild(root, "result");
1385
+ if (childText(result, "funcCode")?.toUpperCase() !== "ERROR") return;
1386
+ const errorCode = childText(result, "errorCode");
1387
+ const code = parseErrorCode(errorCode);
1388
+ const message = childText(result, "message");
1389
+ const textCode = code === void 0 ? errorCode : void 0;
1390
+ throw createAgentError({
1391
+ code,
1392
+ message: textCode === void 0 ? message : [textCode, message].filter(Boolean).join(": "),
1393
+ action: response.action,
1394
+ httpStatus: response.status,
1395
+ rawResponse: response.text().slice(0, 2e3)
1396
+ });
1397
+ }
1398
+ function readTaxNumber(data) {
1399
+ const detail = findChild(data, "taxNumberDetail");
1400
+ const taxpayerId = childText(detail, "taxpayerId");
1401
+ if (taxpayerId === void 0) return void 0;
1402
+ const vatCode = childText(detail, "vatCode");
1403
+ const countyCode = childText(detail, "countyCode");
1404
+ return {
1405
+ taxpayerId,
1406
+ vatCode,
1407
+ countyCode,
1408
+ formatted: vatCode !== void 0 && countyCode !== void 0 ? `${taxpayerId}-${vatCode}-${countyCode}` : void 0
1409
+ };
1410
+ }
1411
+ function readAddresses(data) {
1412
+ return findChildren(findChild(data, "taxpayerAddressList"), "taxpayerAddressItem").map(parseTaxpayerAddress);
1413
+ }
1414
+ function readRequestId(root) {
1415
+ const requestId = childText(findChild(root, "header"), "requestId");
1416
+ return requestId === "-" ? void 0 : requestId;
1417
+ }
1418
+ function parseQueryTaxpayerResponse(response) {
1419
+ throwIfAnyError(response);
1420
+ const root = parseResponseXml(response);
1421
+ throwIfXmlFailure(root, response);
1422
+ if (root.name !== "QueryTaxpayerResponse") throw unexpectedResponse(response, "QueryTaxpayerResponse XML választ vártunk.");
1423
+ throwIfNavError(root, response);
1424
+ const requestId = readRequestId(root);
1425
+ const infoDate = childText(root, "infoDate");
1426
+ const data = findChild(root, "taxpayerData");
1427
+ const validity = childBoolean(root, "taxpayerValidity");
1428
+ if (validity === false || data === void 0) return {
1429
+ valid: validity === true,
1430
+ addresses: [],
1431
+ infoDate,
1432
+ requestId
1433
+ };
1434
+ const addresses = readAddresses(data);
1435
+ return {
1436
+ valid: true,
1437
+ name: childText(data, "taxpayerName"),
1438
+ shortName: childText(data, "taxpayerShortName"),
1439
+ taxNumber: readTaxNumber(data),
1440
+ address: addresses.find((address) => address.type === "HQ") ?? addresses[0],
1441
+ addresses,
1442
+ incorporation: childText(data, "incorporation"),
1443
+ vatGroupMembership: childText(data, "vatGroupMembership"),
1444
+ infoDate,
1445
+ requestId
1446
+ };
1447
+ }
1448
+ async function queryTaxpayer(ctx, taxNumber, options = {}) {
1449
+ const xml = buildQueryTaxpayerXml(ctx.credentials, taxNumber);
1450
+ return ctx.execute({
1451
+ action: "queryTaxpayer",
1452
+ xml,
1453
+ signal: options.signal,
1454
+ safeToRetry: true
1455
+ }, parseQueryTaxpayerResponse);
1456
+ }
1457
+ //#endregion
1458
+ //#region src/client.ts
1459
+ const CREDENTIAL_PROBE_INVOICE_NUMBER = "KASSZA-CREDENTIAL-PROBE-0";
1460
+ async function nullIfNotFound(promise) {
1461
+ try {
1462
+ return await promise;
1463
+ } catch (error) {
1464
+ if (isSzamlazzError(error) && (error.isNotFound || error.code === 7)) return null;
1465
+ throw error;
1466
+ }
1467
+ }
1468
+ function attemptKeyOf(target) {
1469
+ if (typeof target === "string") return target;
1470
+ const key = target.details?.attemptKey;
1471
+ if (key === void 0) throw new TypeError("A resetAttempts egy attempt_limit hibát vagy annak details.attemptKey kulcsát várja.");
1472
+ return key;
1473
+ }
1474
+ function invoiceNumberOf(input) {
1475
+ return typeof input === "string" ? input : input.invoiceNumber;
1476
+ }
1477
+ function receiptNumberOf(input) {
1478
+ return typeof input === "string" ? input : input.receiptNumber;
1479
+ }
1480
+ function createInvoicesApi(ctx, defaults, onDocument) {
1481
+ const api = {
1482
+ async create(input, options) {
1483
+ const document = await createInvoice(ctx, defaults, input, options);
1484
+ await emitDocumentEvent(onDocument, {
1485
+ kind: "invoice",
1486
+ action: "created",
1487
+ number: document.number,
1488
+ document,
1489
+ input
1490
+ });
1491
+ return document;
1492
+ },
1493
+ createOnce: (input, options) => createInvoiceOnce(api, input, options),
1494
+ preview: (input, options) => previewInvoice(ctx, defaults, input, options),
1495
+ async reverse(input, options) {
1496
+ const document = await reverseInvoice(ctx, input, options);
1497
+ await emitDocumentEvent(onDocument, {
1498
+ kind: "invoice",
1499
+ action: "reversed",
1500
+ number: document.number,
1501
+ reversedNumber: invoiceNumberOf(input),
1502
+ document
1503
+ });
1504
+ return document;
1505
+ },
1506
+ async registerPayment(input, options) {
1507
+ const document = await registerPayment(ctx, input, options);
1508
+ await emitDocumentEvent(onDocument, {
1509
+ kind: "invoice",
1510
+ action: "payment",
1511
+ number: document.invoiceNumber,
1512
+ document
1513
+ });
1514
+ return document;
1515
+ },
1516
+ async clearPayments(input, options) {
1517
+ const document = await clearPayments(ctx, input, options);
1518
+ await emitDocumentEvent(onDocument, {
1519
+ kind: "invoice",
1520
+ action: "payment",
1521
+ number: document.invoiceNumber,
1522
+ document
1523
+ });
1524
+ return document;
1525
+ },
1526
+ getPdf: (reference, options) => getInvoicePdf(ctx, reference, options),
1527
+ get: (reference, query, options) => getInvoice(ctx, reference, query, options),
1528
+ find: (reference, query, options) => nullIfNotFound(getInvoice(ctx, reference, query, options)),
1529
+ deleteProforma: (reference, options) => deleteProforma(ctx, reference, options)
1530
+ };
1531
+ return api;
1532
+ }
1533
+ function createReceiptsApi(ctx, defaults, invoices, onDocument) {
1534
+ const api = {
1535
+ async create(input, options) {
1536
+ const document = await createReceipt(ctx, defaults, input, options);
1537
+ await emitDocumentEvent(onDocument, {
1538
+ kind: "receipt",
1539
+ action: "created",
1540
+ number: document.number,
1541
+ document
1542
+ });
1543
+ return document;
1544
+ },
1545
+ createOnce: (input, options) => createReceiptOnce(api, input, options),
1546
+ async reverse(input, options) {
1547
+ const document = await reverseReceipt(ctx, input, options);
1548
+ await emitDocumentEvent(onDocument, {
1549
+ kind: "receipt",
1550
+ action: "reversed",
1551
+ number: document.number,
1552
+ reversedNumber: receiptNumberOf(input),
1553
+ document
1554
+ });
1555
+ return document;
1556
+ },
1557
+ get: (input, options) => getReceipt(ctx, input, options),
1558
+ find: (input, options) => nullIfNotFound(getReceipt(ctx, input, options)),
1559
+ send: (input, options) => sendReceipt(ctx, input, options),
1560
+ convertToInvoice: (input, options) => convertReceiptToInvoice({
1561
+ receipts: api,
1562
+ invoices
1563
+ }, input, options)
1564
+ };
1565
+ return api;
1566
+ }
1567
+ function createKassza(options = {}) {
1568
+ const ctx = createAgentContext(options);
1569
+ const onDocument = options.hooks?.onDocument;
1570
+ const invoices = createInvoicesApi(ctx, options.defaults?.invoice ?? {}, onDocument);
1571
+ const receipts = createReceiptsApi(ctx, options.defaults?.receipt ?? {}, invoices, onDocument);
1572
+ return {
1573
+ invoices,
1574
+ receipts,
1575
+ taxpayer: { query: (taxNumber, requestOptions) => queryTaxpayer(ctx, taxNumber, requestOptions) },
1576
+ async verifyCredentials(requestOptions) {
1577
+ try {
1578
+ await getInvoicePdf(ctx, CREDENTIAL_PROBE_INVOICE_NUMBER, requestOptions);
1579
+ return true;
1580
+ } catch (error) {
1581
+ if (!isSzamlazzError(error)) throw error;
1582
+ if (error.category === "auth") return false;
1583
+ if (error.isNotFound || error.code === 7) return true;
1584
+ throw error;
1585
+ }
1586
+ },
1587
+ resetSession: () => ctx.resetSession(),
1588
+ resetAttempts: (target) => ctx.resetAttempts(attemptKeyOf(target)),
1589
+ issueForPayment: (payment, issueOptions) => issueForPayment({
1590
+ invoices,
1591
+ receipts
1592
+ }, payment, issueOptions)
1593
+ };
1594
+ }
1595
+ //#endregion
1596
+ export { ATTEMPT_LEDGER_KEY_PREFIX as a, createAgentContext as i, queryTaxpayer as n, ATTEMPT_LEDGER_TTL_SECONDS as o, getInvoicePdf as r, attemptLedgerKey as s, createKassza as t };