kassza 0.13.0 → 0.15.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.
- package/README.en.md +48 -0
- package/README.md +152 -22
- package/agents/README.md +6 -1
- package/agents/api.md +64 -12
- package/agents/pitfalls.md +12 -1
- package/agents/recipes.md +67 -8
- package/agents/skills/kassza/SKILL.md +3 -0
- package/agents/skills/migrate-from-szamlazz-js/SKILL.md +39 -0
- package/dist/batch/index.cjs +346 -0
- package/dist/batch/index.d.cts +91 -0
- package/dist/batch/index.d.ts +91 -0
- package/dist/batch/index.js +339 -0
- package/dist/cli.cjs +105 -14
- package/dist/cli.js +104 -13
- package/dist/{client-C-PdfL_P.cjs → client-CLFvJCVW.cjs} +358 -181
- package/dist/{client-CfaS1-Jx.js → client-Cvf-hTz_.js} +311 -152
- package/dist/{client-6MkeuFqD.d.ts → client-DeWWQ-RZ.d.ts} +99 -26
- package/dist/{client-B5FryKxJ.d.cts → client-SVZu25MB.d.cts} +99 -26
- package/dist/{context-DXNbTPwz.d.cts → context-CFNKzStE.d.cts} +82 -58
- package/dist/{context-BxQlIlug.d.ts → context-kb33TgzE.d.ts} +82 -58
- package/dist/cookie-stores/index.cjs +21 -150
- package/dist/cookie-stores/index.d.cts +4 -63
- package/dist/cookie-stores/index.d.ts +4 -63
- package/dist/cookie-stores/index.js +3 -144
- package/dist/create-CflXrPip.js +204 -0
- package/dist/create-CvUvLUaT.cjs +257 -0
- package/dist/{create-once-DgMtKKcG.cjs → create-once-9yxR_Er_.cjs} +285 -33
- package/dist/create-once-Bh6fOWkW.d.cts +20 -0
- package/dist/{create-once-Cz621l8r.js → create-once-Ca2gMk1h.js} +250 -34
- package/dist/create-once-VKp0tVow.d.ts +20 -0
- package/dist/data-link/index.cjs +4 -4
- package/dist/data-link/index.d.cts +2 -52
- package/dist/data-link/index.d.ts +2 -52
- package/dist/data-link/index.js +4 -4
- package/dist/delegation/index.cjs +4 -4
- package/dist/delegation/index.d.cts +2 -2
- package/dist/delegation/index.d.ts +2 -2
- package/dist/delegation/index.js +4 -4
- package/dist/{errors-DLrb0g64.js → errors-DtN4g5Z9.js} +9 -1
- package/dist/{errors-DxeuTslP.cjs → errors-EE96_6D_.cjs} +20 -0
- package/dist/{get-Csm2n0rZ.cjs → get-BdMTseh4.cjs} +9 -183
- package/dist/{get-DT3JEgQ6.js → get-CZEShCcj.js} +4 -124
- package/dist/index-BhUPY_EH.d.cts +109 -0
- package/dist/index-BqGgQ4t3.d.ts +109 -0
- package/dist/{index-CYAGCdKJ.d.cts → index-C-7yWV7L.d.cts} +24 -1
- package/dist/{index-CYAGCdKJ.d.ts → index-C-7yWV7L.d.ts} +24 -1
- package/dist/index.cjs +19 -5
- package/dist/index.d.cts +10 -20
- package/dist/index.d.ts +10 -20
- package/dist/index.js +6 -6
- package/dist/ipn/index.cjs +26 -5
- package/dist/ipn/index.d.cts +12 -1
- package/dist/ipn/index.d.ts +12 -1
- package/dist/ipn/index.js +26 -6
- package/dist/{issue-AGRohSm7.cjs → issue-Bin4tKD_.cjs} +416 -342
- package/dist/{issue-DtSLpVdJ.js → issue-DMA1Nbr1.js} +394 -266
- package/dist/journal/index.cjs +454 -0
- package/dist/journal/index.d.cts +18 -0
- package/dist/journal/index.d.ts +18 -0
- package/dist/journal/index.js +445 -0
- package/dist/journal-DvI81Kt7.d.cts +114 -0
- package/dist/journal-Y9qrIB8G.d.ts +114 -0
- package/dist/mcp/index.cjs +1 -1
- package/dist/mcp/index.d.cts +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/money/index.cjs +2 -1
- package/dist/money/index.d.cts +2 -2
- package/dist/money/index.d.ts +2 -2
- package/dist/money/index.js +2 -2
- package/dist/{money-t7uy1n91.js → money-Cw457SD6.js} +95 -3
- package/dist/{money-BxytJW6f.cjs → money-K9j0wPit.cjs} +99 -1
- package/dist/nav/index.cjs +2 -2
- package/dist/nav/index.d.cts +1 -1
- package/dist/nav/index.d.ts +1 -1
- package/dist/nav/index.js +2 -2
- package/dist/{nav-BEwcX7-N.cjs → nav-BNbc8U0R.cjs} +1 -1
- package/dist/{nav-CK1WgYo7.js → nav-BcCerwWS.js} +1 -1
- package/dist/node/index.cjs +124 -0
- package/dist/node/index.d.cts +35 -0
- package/dist/node/index.d.ts +35 -0
- package/dist/node/index.js +120 -0
- package/dist/observe/index.cjs +311 -0
- package/dist/observe/index.d.cts +53 -0
- package/dist/observe/index.d.ts +53 -0
- package/dist/observe/index.js +303 -0
- package/dist/once-BN_3B5OF.cjs +103 -0
- package/dist/once-CqqZxsXG.js +74 -0
- package/dist/{parse-C608ehqM.js → parse-Cr7yQ3_z.js} +2 -2
- package/dist/{parse-BJj-aqKy.cjs → parse-DOA2XQ3e.cjs} +2 -2
- package/dist/payments/barion.cjs +26 -2
- package/dist/payments/barion.d.cts +2 -2
- package/dist/payments/barion.d.ts +2 -2
- package/dist/payments/barion.js +26 -2
- package/dist/payments/index.cjs +7 -2
- package/dist/payments/index.d.cts +4 -4
- package/dist/payments/index.d.ts +4 -4
- package/dist/payments/index.js +3 -3
- package/dist/payments/paypal.cjs +16 -2
- package/dist/payments/paypal.d.cts +2 -2
- package/dist/payments/paypal.d.ts +2 -2
- package/dist/payments/paypal.js +16 -2
- package/dist/payments/revolut.cjs +16 -2
- package/dist/payments/revolut.d.cts +2 -2
- package/dist/payments/revolut.d.ts +2 -2
- package/dist/payments/revolut.js +16 -2
- package/dist/payments/simplepay.cjs +36 -4
- package/dist/payments/simplepay.d.cts +2 -2
- package/dist/payments/simplepay.d.ts +2 -2
- package/dist/payments/simplepay.js +36 -4
- package/dist/payments/stripe.cjs +19 -2
- package/dist/payments/stripe.d.cts +2 -2
- package/dist/payments/stripe.d.ts +2 -2
- package/dist/payments/stripe.js +19 -2
- package/dist/push-BXj0Sf0Z.d.ts +52 -0
- package/dist/push-D4nNbCNV.d.cts +52 -0
- package/dist/reference-B5TATqb5.js +124 -0
- package/dist/reference-BIdYMK0t.cjs +183 -0
- package/dist/reports/index.cjs +1 -1
- package/dist/reports/index.d.cts +1 -1
- package/dist/reports/index.d.ts +1 -1
- package/dist/reports/index.js +1 -1
- package/dist/{serialize-DSE_o9RK.js → serialize-B2eFh3D-.js} +5 -1
- package/dist/{serialize-BXOww1Uq.cjs → serialize-CquIsxA-.cjs} +5 -1
- package/dist/{server-Cd8HB661.js → server-CqqECkMp.js} +8 -7
- package/dist/{server-C6PoNkdD.cjs → server-DENsDDW9.cjs} +17 -16
- package/dist/session-Ckl5eJhV.d.ts +7 -0
- package/dist/{session-CKOuE6Jc.cjs → session-DeM5vjvC.cjs} +69 -13
- package/dist/{session-rMKaJcmq.js → session-SaEEXu2N.js} +58 -14
- package/dist/session-YbChChx7.d.cts +7 -0
- package/dist/storage/fs.cjs +1 -1
- package/dist/storage/fs.js +1 -1
- package/dist/storage/index.cjs +1 -1
- package/dist/storage/index.js +1 -1
- package/dist/store-C1rHd9DB.d.cts +19 -0
- package/dist/store-C1rHd9DB.d.ts +19 -0
- package/dist/stores/index.cjs +24 -0
- package/dist/stores/index.d.cts +4 -0
- package/dist/stores/index.d.ts +4 -0
- package/dist/stores/index.js +3 -0
- package/dist/stores-BNrS0dWl.cjs +506 -0
- package/dist/stores-DhjGBrl_.js +441 -0
- package/dist/testing/index.cjs +28 -16
- package/dist/testing/index.d.cts +6 -3
- package/dist/testing/index.d.ts +6 -3
- package/dist/testing/index.js +26 -14
- package/dist/{types-BVeR7KyU.d.ts → types-B1A8mUIE.d.cts} +13 -1
- package/dist/{types-BVeR7KyU.d.cts → types-ByAEvGsZ.d.ts} +13 -1
- package/dist/{types-k--zHf4l.d.ts → types-D1zDOH_F.d.ts} +1 -1
- package/dist/{types-DH8QoNZK.d.cts → types-lnKkQdot.d.cts} +1 -1
- package/dist/warnings-B3DXnveC.d.cts +31 -0
- package/dist/warnings-B3DXnveC.d.ts +31 -0
- package/dist/warnings-DeIw5RFj.cjs +20 -0
- package/dist/warnings-DwTl5J-2.js +15 -0
- package/dist/{webhook-CrEGohbg.js → webhook-CQVShAfI.js} +44 -1
- package/dist/{webhook-81giRMdQ.cjs → webhook-Ckj-_hPD.cjs} +67 -0
- package/dist/webhook-CmdhGiH5.d.cts +11 -0
- package/dist/webhook-D6lEejob.d.ts +11 -0
- package/llms.txt +4 -3
- package/package.json +92 -4
- package/dist/session-Dm_45x8K.d.cts +0 -11
- package/dist/session-Dm_45x8K.d.ts +0 -11
- package/dist/webhook-CpCMHhn2.d.ts +0 -6
- package/dist/webhook-CpMJuP6c.d.cts +0 -6
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { a as registerPayment, c as resolveInvoice, d as TAXPAYER_TYPE_CODES, h as AGENT_ACTIONS, i as clearPayments, o as optionalAgentDate, p as emitDocumentEvent, r as registerPaymentOnce, s as presentText, t as createReceiptOnce, u as INVOICE_TEMPLATES } from "./create-once-Ca2gMk1h.js";
|
|
2
|
+
import { i as createAgentError, o as isSzamlazzError, r as SzamlazzError, s as parseErrorCode } from "./errors-DtN4g5Z9.js";
|
|
3
3
|
import { t as base64ToBytes } from "./binary-D0M9U2MD.js";
|
|
4
|
-
import { a as optionalEl, c as childNumber, d as findChildren, l as childText, n as buildXmlDocument, r as el, s as childBoolean, u as findChild } from "./serialize-
|
|
5
|
-
import { a as looksLikeXml, c as readDocumentHeaders, d as throwIfHeaderError, f as throwIfHttpError, h as unexpectedResponse, m as throwIfXmlFailure, n as parseReceiptResponse, o as parseDoneText, p as throwIfTextError, r as createAgentResponse, s as parseResponseXml, u as throwIfAnyError } from "./parse-
|
|
6
|
-
import { i as sessionKeyFor, n as memoryCookieStore, r as mergeSetCookies, t as SESSION_TTL_SECONDS } from "./session-
|
|
7
|
-
import {
|
|
4
|
+
import { a as optionalEl, c as childNumber, d as findChildren, l as childText, n as buildXmlDocument, r as el, s as childBoolean, u as findChild } from "./serialize-B2eFh3D-.js";
|
|
5
|
+
import { a as looksLikeXml, c as readDocumentHeaders, d as throwIfHeaderError, f as throwIfHttpError, h as unexpectedResponse, m as throwIfXmlFailure, n as parseReceiptResponse, o as parseDoneText, p as throwIfTextError, r as createAgentResponse, s as parseResponseXml, u as throwIfAnyError } from "./parse-Cr7yQ3_z.js";
|
|
6
|
+
import { i as sessionKeyFor, n as memoryCookieStore, r as mergeSetCookies, t as SESSION_TTL_SECONDS } from "./session-SaEEXu2N.js";
|
|
7
|
+
import { t as emitWarning } from "./warnings-DwTl5J-2.js";
|
|
8
|
+
import { l as createInvoiceOnce, m as guardOnce, n as issueForPayment, o as convertReceiptToInvoice } from "./issue-DMA1Nbr1.js";
|
|
8
9
|
import { r as formatVatRate } from "./vat-v_dcWCto.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
10
|
+
import { a as summarizeItems } from "./money-Cw457SD6.js";
|
|
11
|
+
import { a as optionalText, c as requireText, i as optionalAgentDate$1, l as resolveInvoiceReference, o as parseInvoiceResult, s as referenceValue, t as AGENT_XSD_BASE_URL, u as validationError } from "./reference-B5TATqb5.js";
|
|
12
|
+
import { t as getInvoice } from "./get-CZEShCcj.js";
|
|
13
|
+
import { a as optionalText$1, c as validateTemplate$1, i as RECEIPT_XSD_BASE_URL, o as receiptValidationError, r as createReceipt, s as requireReceiptNumber } from "./create-CflXrPip.js";
|
|
12
14
|
//#region src/core/attempt-ledger.ts
|
|
13
15
|
const ATTEMPT_LEDGER_TTL_SECONDS = 86400;
|
|
14
16
|
const ATTEMPT_LEDGER_KEY_PREFIX = "szamlazz:attempts:";
|
|
@@ -38,17 +40,63 @@ function parseCount(value) {
|
|
|
38
40
|
const parsed = Number.parseInt(value, 10);
|
|
39
41
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : 0;
|
|
40
42
|
}
|
|
43
|
+
function createLocalCounter() {
|
|
44
|
+
const counts = /* @__PURE__ */ new Map();
|
|
45
|
+
const get = (key) => {
|
|
46
|
+
const entry = counts.get(key);
|
|
47
|
+
if (!entry) return 0;
|
|
48
|
+
if (entry.expiresAt <= Date.now()) {
|
|
49
|
+
counts.delete(key);
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
return entry.count;
|
|
53
|
+
};
|
|
54
|
+
return {
|
|
55
|
+
get,
|
|
56
|
+
bump(key) {
|
|
57
|
+
const count = get(key) + 1;
|
|
58
|
+
counts.delete(key);
|
|
59
|
+
counts.set(key, {
|
|
60
|
+
count,
|
|
61
|
+
expiresAt: Date.now() + ATTEMPT_LEDGER_TTL_SECONDS * 1e3
|
|
62
|
+
});
|
|
63
|
+
if (counts.size > 1e3) {
|
|
64
|
+
const oldest = counts.keys().next().value;
|
|
65
|
+
if (oldest !== void 0) counts.delete(oldest);
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
clear(key) {
|
|
69
|
+
counts.delete(key);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
41
73
|
function createAttemptLedger(store) {
|
|
74
|
+
const local = createLocalCounter();
|
|
75
|
+
const unpersisted = createLocalCounter();
|
|
42
76
|
return {
|
|
43
77
|
async failures(key) {
|
|
44
|
-
return parseCount(await store.get(key));
|
|
78
|
+
return parseCount(await store.get(key)) + unpersisted.get(key);
|
|
45
79
|
},
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
80
|
+
fallbackFailures(key) {
|
|
81
|
+
return local.get(key);
|
|
82
|
+
},
|
|
83
|
+
async recordFailure(key) {
|
|
84
|
+
local.bump(key);
|
|
85
|
+
try {
|
|
86
|
+
if (store.increment) {
|
|
87
|
+
await store.increment(key, ATTEMPT_LEDGER_TTL_SECONDS);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const current = parseCount(await store.get(key));
|
|
91
|
+
await store.set(key, String(current + 1), ATTEMPT_LEDGER_TTL_SECONDS);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
unpersisted.bump(key);
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
50
96
|
},
|
|
51
97
|
async reset(key) {
|
|
98
|
+
local.clear(key);
|
|
99
|
+
unpersisted.clear(key);
|
|
52
100
|
await store.delete(key);
|
|
53
101
|
}
|
|
54
102
|
};
|
|
@@ -63,6 +111,7 @@ function attemptLimitError(action, key, failures) {
|
|
|
63
111
|
}
|
|
64
112
|
const DEFAULT_SAFE_ATTEMPTS = 3;
|
|
65
113
|
const DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
114
|
+
const RETRY_JITTER = .2;
|
|
66
115
|
function readEnv(name) {
|
|
67
116
|
const value = (globalThis.process?.env)?.[name]?.trim();
|
|
68
117
|
return value ? value : void 0;
|
|
@@ -112,22 +161,49 @@ function sleep(ms, signal) {
|
|
|
112
161
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
113
162
|
});
|
|
114
163
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
164
|
+
function hookWarning(name, action, error) {
|
|
165
|
+
return {
|
|
166
|
+
kind: "hook",
|
|
167
|
+
message: `A(z) ${name} hook hibát dobott, a kassza figyelmen kívül hagyta.`,
|
|
168
|
+
error,
|
|
169
|
+
action,
|
|
170
|
+
operation: name
|
|
171
|
+
};
|
|
121
172
|
}
|
|
122
|
-
function callHook(
|
|
173
|
+
function callHook(hooks, name, event) {
|
|
174
|
+
const hook = hooks[name];
|
|
123
175
|
if (!hook) return;
|
|
124
176
|
try {
|
|
125
177
|
const result = hook(event);
|
|
126
|
-
if (result instanceof Promise) result.catch(() =>
|
|
127
|
-
} catch {
|
|
128
|
-
|
|
178
|
+
if (result instanceof Promise) result.catch((error) => emitWarning(hooks.onWarning, hookWarning(name, event.action, error)));
|
|
179
|
+
} catch (error) {
|
|
180
|
+
emitWarning(hooks.onWarning, hookWarning(name, event.action, error));
|
|
129
181
|
}
|
|
130
182
|
}
|
|
183
|
+
function parseRetryAfter(value, now) {
|
|
184
|
+
if (value === null) return void 0;
|
|
185
|
+
const trimmed = value.trim();
|
|
186
|
+
if (/^\d+$/.test(trimmed)) return Number(trimmed) * 1e3;
|
|
187
|
+
const date = Date.parse(trimmed);
|
|
188
|
+
if (Number.isNaN(date)) return void 0;
|
|
189
|
+
return Math.max(0, date - now);
|
|
190
|
+
}
|
|
191
|
+
function retryDelay(baseMs, attempt, random = Math.random()) {
|
|
192
|
+
const backoff = baseMs * 2 ** (attempt - 1);
|
|
193
|
+
return Math.round(backoff * (.8 + 2 * RETRY_JITTER * random));
|
|
194
|
+
}
|
|
195
|
+
function resolveLedgerMode(value) {
|
|
196
|
+
if (value === void 0 || value === "fail-open" || value === "fail-closed") return value ?? "fail-open";
|
|
197
|
+
throw configurationError(`Az attemptLedgerMode értéke 'fail-open' vagy 'fail-closed' lehet, kapott: ${String(value)}`);
|
|
198
|
+
}
|
|
199
|
+
function storeUnavailableError(action, error) {
|
|
200
|
+
return new SzamlazzError("A próbálkozás-napló tárolója nem érhető el, ezért a kassza nem küldte el a kérést.", {
|
|
201
|
+
category: "store_unavailable",
|
|
202
|
+
action,
|
|
203
|
+
cause: error,
|
|
204
|
+
hint: "Az attemptLedgerMode: 'fail-closed' beállítás miatt a kassza nem küld kérést, amíg a napló (például a Redis) nem elérhető. Állítsd helyre a tárolót, vagy válts 'fail-open' módra."
|
|
205
|
+
});
|
|
206
|
+
}
|
|
131
207
|
function clampAttempts(value) {
|
|
132
208
|
if (value === void 0) return DEFAULT_SAFE_ATTEMPTS;
|
|
133
209
|
if (!Number.isInteger(value) || value < 1) throw configurationError(`A maxAttempts értéke legalább 1 egész szám legyen, kapott: ${value}`);
|
|
@@ -167,11 +243,27 @@ function createAgentContext(options = {}) {
|
|
|
167
243
|
return sessionKeyPromise;
|
|
168
244
|
};
|
|
169
245
|
const hooks = options.hooks ?? {};
|
|
246
|
+
const warn = (warning) => emitWarning(hooks.onWarning, warning);
|
|
170
247
|
const ledger = options.attemptLedger ? createAttemptLedger(options.attemptLedger) : void 0;
|
|
248
|
+
const ledgerMode = resolveLedgerMode(options.attemptLedgerMode);
|
|
249
|
+
async function ignoreStoreFailure(operation, action, run) {
|
|
250
|
+
try {
|
|
251
|
+
return await run();
|
|
252
|
+
} catch (error) {
|
|
253
|
+
warn({
|
|
254
|
+
kind: "session",
|
|
255
|
+
message: `A session cookie tároló "${operation}" művelete sikertelen, a kérés session nélkül folytatódik.`,
|
|
256
|
+
error,
|
|
257
|
+
action,
|
|
258
|
+
operation
|
|
259
|
+
});
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
171
263
|
const cooldownMs = resolveCooldown(options.maintenanceCooldownMs);
|
|
172
264
|
let blockedUntil = 0;
|
|
173
265
|
async function send(request) {
|
|
174
|
-
const cookie = cookieStore ? await ignoreStoreFailure(async () => cookieStore.get(await resolveSessionKey())) : void 0;
|
|
266
|
+
const cookie = cookieStore ? await ignoreStoreFailure("get", request.action, async () => cookieStore.get(await resolveSessionKey())) : void 0;
|
|
175
267
|
request.signal?.throwIfAborted();
|
|
176
268
|
const headers = new Headers({ Accept: "application/xml, application/pdf, text/plain, */*" });
|
|
177
269
|
if (cookie) headers.set("Cookie", cookie);
|
|
@@ -202,12 +294,15 @@ function createAgentContext(options = {}) {
|
|
|
202
294
|
}
|
|
203
295
|
if (cookieStore) {
|
|
204
296
|
const merged = mergeSetCookies(cookie, response.headers);
|
|
205
|
-
if (merged) await ignoreStoreFailure(async () => cookieStore.set(await resolveSessionKey(), merged, SESSION_TTL_SECONDS));
|
|
297
|
+
if (merged) await ignoreStoreFailure("set", request.action, async () => cookieStore.set(await resolveSessionKey(), merged, SESSION_TTL_SECONDS));
|
|
206
298
|
}
|
|
207
|
-
return
|
|
299
|
+
return {
|
|
300
|
+
response: createAgentResponse(request.action, response.status, response.headers, body),
|
|
301
|
+
sessionReused: Boolean(cookie)
|
|
302
|
+
};
|
|
208
303
|
}
|
|
209
304
|
async function resetSession() {
|
|
210
|
-
if (cookieStore) await ignoreStoreFailure(async () => cookieStore.delete(await resolveSessionKey()));
|
|
305
|
+
if (cookieStore) await ignoreStoreFailure("delete", void 0, async () => cookieStore.delete(await resolveSessionKey()));
|
|
211
306
|
}
|
|
212
307
|
async function resetAttempts(key) {
|
|
213
308
|
if (ledger) await ledger.reset(key);
|
|
@@ -223,6 +318,41 @@ function createAgentContext(options = {}) {
|
|
|
223
318
|
}))
|
|
224
319
|
});
|
|
225
320
|
}
|
|
321
|
+
function ledgerWarning(operation, action, error) {
|
|
322
|
+
warn({
|
|
323
|
+
kind: "ledger",
|
|
324
|
+
message: `A próbálkozás-napló tárolójának "${operation}" művelete sikertelen. A kassza a folyamaton belüli számlálót használja, a folyamatok közötti védelem most nem él.`,
|
|
325
|
+
error,
|
|
326
|
+
action,
|
|
327
|
+
operation
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
async function readFailures(action, key) {
|
|
331
|
+
if (!ledger || key === void 0) return 0;
|
|
332
|
+
try {
|
|
333
|
+
return await ledger.failures(key);
|
|
334
|
+
} catch (error) {
|
|
335
|
+
if (ledgerMode === "fail-closed") throw storeUnavailableError(action, error);
|
|
336
|
+
ledgerWarning("get", action, error);
|
|
337
|
+
return ledger.fallbackFailures(key);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
async function recordFailure(action, key) {
|
|
341
|
+
if (!ledger || key === void 0) return;
|
|
342
|
+
try {
|
|
343
|
+
await ledger.recordFailure(key);
|
|
344
|
+
} catch (error) {
|
|
345
|
+
ledgerWarning("increment", action, error);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
async function clearFailures(action, key) {
|
|
349
|
+
if (!ledger || key === void 0) return;
|
|
350
|
+
try {
|
|
351
|
+
await ledger.reset(key);
|
|
352
|
+
} catch (error) {
|
|
353
|
+
ledgerWarning("delete", action, error);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
226
356
|
function assertNoCooldown(action) {
|
|
227
357
|
const remainingMs = blockedUntil - Date.now();
|
|
228
358
|
if (remainingMs > 0) throw maintenanceCooldownError(action, remainingMs);
|
|
@@ -230,45 +360,72 @@ function createAgentContext(options = {}) {
|
|
|
230
360
|
async function execute(request, parse) {
|
|
231
361
|
const maxAttempts = request.safeToRetry ? safeAttempts : 1;
|
|
232
362
|
const ledgerKey = await ledgerKeyFor(request);
|
|
363
|
+
const requestId = crypto.randomUUID();
|
|
233
364
|
for (let attempt = 1;; attempt++) {
|
|
234
365
|
assertNoCooldown(request.action);
|
|
235
|
-
const failures =
|
|
366
|
+
const failures = await readFailures(request.action, ledgerKey);
|
|
236
367
|
if (ledgerKey !== void 0 && failures >= 5) throw attemptLimitError(request.action, ledgerKey, failures);
|
|
237
368
|
const startedAt = Date.now();
|
|
238
|
-
|
|
369
|
+
let retryAfterMs;
|
|
370
|
+
const base = {
|
|
239
371
|
action: request.action,
|
|
240
|
-
attempt
|
|
241
|
-
|
|
372
|
+
attempt,
|
|
373
|
+
requestId
|
|
374
|
+
};
|
|
375
|
+
callHook(hooks, "onRequest", base);
|
|
242
376
|
try {
|
|
243
|
-
const response = await send(request);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
377
|
+
const { response, sessionReused } = await send(request);
|
|
378
|
+
retryAfterMs = parseRetryAfter(response.headers.get("retry-after"), Date.now());
|
|
379
|
+
callHook(hooks, "onResponse", {
|
|
380
|
+
...base,
|
|
247
381
|
status: response.status,
|
|
248
|
-
durationMs: Date.now() - startedAt
|
|
382
|
+
durationMs: Date.now() - startedAt,
|
|
383
|
+
responseBytes: response.body.byteLength,
|
|
384
|
+
sessionReused
|
|
249
385
|
});
|
|
250
386
|
const result = await parse(response);
|
|
251
|
-
if (
|
|
387
|
+
if (failures > 0) await clearFailures(request.action, ledgerKey);
|
|
388
|
+
callHook(hooks, "onComplete", {
|
|
389
|
+
...base,
|
|
390
|
+
outcome: "success",
|
|
391
|
+
durationMs: Date.now() - startedAt,
|
|
392
|
+
willRetry: false
|
|
393
|
+
});
|
|
252
394
|
return result;
|
|
253
395
|
} catch (error) {
|
|
254
|
-
if (!(error instanceof SzamlazzError))
|
|
255
|
-
|
|
396
|
+
if (!(error instanceof SzamlazzError)) {
|
|
397
|
+
callHook(hooks, "onComplete", {
|
|
398
|
+
...base,
|
|
399
|
+
outcome: "error",
|
|
400
|
+
durationMs: Date.now() - startedAt,
|
|
401
|
+
willRetry: false
|
|
402
|
+
});
|
|
403
|
+
throw error;
|
|
404
|
+
}
|
|
405
|
+
if (countsAsFailedAttempt(error)) await recordFailure(request.action, ledgerKey);
|
|
256
406
|
if (error.category === "maintenance" && cooldownMs > 0) blockedUntil = Date.now() + cooldownMs;
|
|
257
|
-
const willRetry = error.retryable && attempt < maxAttempts && !(error.category === "maintenance" && cooldownMs > 0);
|
|
258
|
-
callHook(hooks
|
|
259
|
-
|
|
260
|
-
|
|
407
|
+
const willRetry = error.retryable && attempt < maxAttempts && !(error.category === "maintenance" && cooldownMs > 0) && (retryAfterMs === void 0 || retryAfterMs <= 6e4);
|
|
408
|
+
callHook(hooks, "onError", {
|
|
409
|
+
...base,
|
|
410
|
+
error,
|
|
411
|
+
willRetry
|
|
412
|
+
});
|
|
413
|
+
callHook(hooks, "onComplete", {
|
|
414
|
+
...base,
|
|
415
|
+
outcome: "error",
|
|
416
|
+
durationMs: Date.now() - startedAt,
|
|
261
417
|
error,
|
|
262
418
|
willRetry
|
|
263
419
|
});
|
|
264
420
|
if (error.category === "auth") await resetSession();
|
|
265
421
|
if (!willRetry) throw error;
|
|
266
|
-
await sleep(retryDelayMs
|
|
422
|
+
await sleep(Math.max(retryDelay(retryDelayMs, attempt), retryAfterMs ?? 0), request.signal);
|
|
267
423
|
}
|
|
268
424
|
}
|
|
269
425
|
}
|
|
270
426
|
return {
|
|
271
427
|
credentials,
|
|
428
|
+
warn,
|
|
272
429
|
execute,
|
|
273
430
|
resetSession,
|
|
274
431
|
resetAttempts
|
|
@@ -555,81 +712,6 @@ async function previewInvoice(ctx, defaults, input, options = {}) {
|
|
|
555
712
|
const items = itemsOf(invoice);
|
|
556
713
|
return ctx.execute(buildRequest(ctx, invoice, true, options), (response) => parseInvoicePreviewResponse(response, items));
|
|
557
714
|
}
|
|
558
|
-
function normalizeRegisterInput(input) {
|
|
559
|
-
const payments = "payments" in input ? input.payments : [{
|
|
560
|
-
amount: input.amount,
|
|
561
|
-
method: input.method ?? "átutalás",
|
|
562
|
-
date: input.date,
|
|
563
|
-
description: input.description
|
|
564
|
-
}];
|
|
565
|
-
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.");
|
|
566
|
-
if (payments.length > 5) throw validationError(`Egy kérésben legfeljebb 5 befizetés rögzíthető, kapott: ${payments.length}.`);
|
|
567
|
-
return {
|
|
568
|
-
invoiceNumber: input.invoiceNumber,
|
|
569
|
-
taxNumber: input.taxNumber,
|
|
570
|
-
additive: input.additive ?? true,
|
|
571
|
-
payments
|
|
572
|
-
};
|
|
573
|
-
}
|
|
574
|
-
function normalizeClearInput(input) {
|
|
575
|
-
const target = typeof input === "string" ? { invoiceNumber: input } : input;
|
|
576
|
-
return {
|
|
577
|
-
invoiceNumber: target.invoiceNumber,
|
|
578
|
-
taxNumber: target.taxNumber,
|
|
579
|
-
additive: false,
|
|
580
|
-
payments: []
|
|
581
|
-
};
|
|
582
|
-
}
|
|
583
|
-
function paymentNode(payment, index) {
|
|
584
|
-
const position = index + 1;
|
|
585
|
-
if (typeof payment.amount !== "number" || !Number.isFinite(payment.amount)) throw validationError(`A(z) ${position}. befizetés összege (amount) nem véges szám.`);
|
|
586
|
-
return el("kifizetes", [
|
|
587
|
-
el("datum", payment.date === void 0 ? todayInBudapest() : agentDate(payment.date, "date")),
|
|
588
|
-
el("jogcim", requireText(payment.method, `Add meg a(z) ${position}. befizetés módját (method).`)),
|
|
589
|
-
el("osszeg", payment.amount),
|
|
590
|
-
optionalEl("leiras", optionalText$1(payment.description))
|
|
591
|
-
]);
|
|
592
|
-
}
|
|
593
|
-
function buildPaymentXml(credentials, request) {
|
|
594
|
-
const invoiceNumber = requireText(request.invoiceNumber, "Add meg a számla számát (invoiceNumber), amelyhez a befizetés tartozik.");
|
|
595
|
-
return buildXmlDocument({
|
|
596
|
-
root: "xmlszamlakifiz",
|
|
597
|
-
namespace: "http://www.szamlazz.hu/xmlszamlakifiz",
|
|
598
|
-
schemaLocation: `${AGENT_XSD_BASE_URL}agentkifiz/xmlszamlakifiz.xsd`,
|
|
599
|
-
children: [el("beallitasok", [
|
|
600
|
-
...credentials,
|
|
601
|
-
el("szamlaszam", invoiceNumber),
|
|
602
|
-
optionalEl("adoszam", optionalText$1(request.taxNumber)),
|
|
603
|
-
el("additiv", request.additive),
|
|
604
|
-
el("valaszVerzio", 2)
|
|
605
|
-
]), ...request.payments.map(paymentNode)]
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
function parseRegisterPaymentResponse(response, invoiceNumber) {
|
|
609
|
-
const result = parseInvoiceResult(response);
|
|
610
|
-
return {
|
|
611
|
-
invoiceNumber: result.number ?? invoiceNumber.trim(),
|
|
612
|
-
netTotal: result.netTotal,
|
|
613
|
-
grossTotal: result.grossTotal,
|
|
614
|
-
outstanding: result.outstanding,
|
|
615
|
-
buyerAccountUrl: result.buyerAccountUrl
|
|
616
|
-
};
|
|
617
|
-
}
|
|
618
|
-
function sendPaymentRequest(ctx, request, options) {
|
|
619
|
-
const xml = buildPaymentXml(ctx.credentials, request);
|
|
620
|
-
return ctx.execute({
|
|
621
|
-
action: "registerPayment",
|
|
622
|
-
xml,
|
|
623
|
-
signal: options.signal,
|
|
624
|
-
safeToRetry: !request.additive
|
|
625
|
-
}, (response) => parseRegisterPaymentResponse(response, request.invoiceNumber));
|
|
626
|
-
}
|
|
627
|
-
async function registerPayment(ctx, input, options = {}) {
|
|
628
|
-
return sendPaymentRequest(ctx, normalizeRegisterInput(input), options);
|
|
629
|
-
}
|
|
630
|
-
async function clearPayments(ctx, input, options = {}) {
|
|
631
|
-
return sendPaymentRequest(ctx, normalizeClearInput(input), options);
|
|
632
|
-
}
|
|
633
715
|
//#endregion
|
|
634
716
|
//#region src/invoices/pdf.ts
|
|
635
717
|
function buildInvoicePdfXml(credentials, reference) {
|
|
@@ -738,25 +820,25 @@ function buildReverseInvoiceXml(credentials, input) {
|
|
|
738
820
|
el("eszamla", options.eInvoice ?? false),
|
|
739
821
|
el("szamlaLetoltes", options.downloadPdf ?? true),
|
|
740
822
|
el("valaszVerzio", 2),
|
|
741
|
-
optionalEl("szamlaKulsoAzon", optionalText
|
|
823
|
+
optionalEl("szamlaKulsoAzon", optionalText(options.externalId))
|
|
742
824
|
]),
|
|
743
825
|
el("fejlec", [
|
|
744
826
|
el("szamlaszam", invoiceNumber),
|
|
745
827
|
optionalEl("keltDatum", optionalAgentDate$1(options.issueDate, "issueDate")),
|
|
746
828
|
optionalEl("teljesitesDatum", optionalAgentDate$1(options.fulfillmentDate, "fulfillmentDate")),
|
|
747
|
-
optionalEl("megjegyzes", optionalText
|
|
829
|
+
optionalEl("megjegyzes", optionalText(options.comment)),
|
|
748
830
|
el("tipus", "SS"),
|
|
749
831
|
optionalEl("szamlaSablon", validateTemplate(options.template))
|
|
750
832
|
]),
|
|
751
833
|
optionalEl("elado", [
|
|
752
|
-
optionalEl("emailReplyto", optionalText
|
|
753
|
-
optionalEl("emailTargy", optionalText
|
|
754
|
-
optionalEl("emailSzoveg", optionalText
|
|
834
|
+
optionalEl("emailReplyto", optionalText(email?.replyTo)),
|
|
835
|
+
optionalEl("emailTargy", optionalText(email?.subject)),
|
|
836
|
+
optionalEl("emailSzoveg", optionalText(email?.text))
|
|
755
837
|
]),
|
|
756
838
|
optionalEl("vevo", [
|
|
757
|
-
optionalEl("email", optionalText
|
|
758
|
-
optionalEl("adoszam", optionalText
|
|
759
|
-
optionalEl("adoszamEU", optionalText
|
|
839
|
+
optionalEl("email", optionalText(buyer?.email)),
|
|
840
|
+
optionalEl("adoszam", optionalText(buyer?.taxNumber)),
|
|
841
|
+
optionalEl("adoszamEU", optionalText(buyer?.euTaxNumber))
|
|
760
842
|
])
|
|
761
843
|
]
|
|
762
844
|
});
|
|
@@ -791,8 +873,8 @@ function normalizeInput$1(input) {
|
|
|
791
873
|
return typeof input === "string" ? { receiptNumber: input } : input;
|
|
792
874
|
}
|
|
793
875
|
function resolveIdentifier(input) {
|
|
794
|
-
const receiptNumber = optionalText(input.receiptNumber);
|
|
795
|
-
const orderNumber = optionalText(input.orderNumber);
|
|
876
|
+
const receiptNumber = optionalText$1(input.receiptNumber);
|
|
877
|
+
const orderNumber = optionalText$1(input.orderNumber);
|
|
796
878
|
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).");
|
|
797
879
|
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.");
|
|
798
880
|
return {
|
|
@@ -810,7 +892,7 @@ function buildGetReceiptXml(credentials, input) {
|
|
|
810
892
|
children: [el("beallitasok", [...credentials, el("pdfLetoltes", normalized.downloadPdf ?? true)]), el("fejlec", [
|
|
811
893
|
optionalEl("nyugtaszam", receiptNumber),
|
|
812
894
|
optionalEl("rendelesSzam", orderNumber),
|
|
813
|
-
optionalEl("hivasAzonosito", optionalText(normalized.callId)),
|
|
895
|
+
optionalEl("hivasAzonosito", optionalText$1(normalized.callId)),
|
|
814
896
|
optionalEl("pdfSablon", validateTemplate$1(normalized.template))
|
|
815
897
|
])]
|
|
816
898
|
});
|
|
@@ -839,7 +921,7 @@ function buildReverseReceiptXml(credentials, input) {
|
|
|
839
921
|
children: [el("beallitasok", [...credentials, el("pdfLetoltes", normalized.downloadPdf ?? true)]), el("fejlec", [
|
|
840
922
|
el("nyugtaszam", requireReceiptNumber(normalized.receiptNumber)),
|
|
841
923
|
optionalEl("pdfSablon", validateTemplate$1(normalized.template)),
|
|
842
|
-
optionalEl("hivasAzonosito", optionalText(normalized.callId))
|
|
924
|
+
optionalEl("hivasAzonosito", optionalText$1(normalized.callId))
|
|
843
925
|
])]
|
|
844
926
|
});
|
|
845
927
|
}
|
|
@@ -850,7 +932,7 @@ function reverseReceipt(ctx, input, options = {}) {
|
|
|
850
932
|
action: "reverseReceipt",
|
|
851
933
|
xml,
|
|
852
934
|
signal: options.signal,
|
|
853
|
-
safeToRetry: optionalText(normalized.callId) !== void 0
|
|
935
|
+
safeToRetry: optionalText$1(normalized.callId) !== void 0
|
|
854
936
|
}, parseReceiptResponse);
|
|
855
937
|
}
|
|
856
938
|
//#endregion
|
|
@@ -872,7 +954,7 @@ function normalizeEmails(emails) {
|
|
|
872
954
|
function buildSendReceiptXml(credentials, input) {
|
|
873
955
|
const receiptNumber = requireReceiptNumber(input.receiptNumber);
|
|
874
956
|
const emails = normalizeEmails(input.emails);
|
|
875
|
-
const replyTo = optionalText(input.replyTo);
|
|
957
|
+
const replyTo = optionalText$1(input.replyTo);
|
|
876
958
|
if (replyTo !== void 0) assertEmail(replyTo, "replyTo");
|
|
877
959
|
return buildXmlDocument({
|
|
878
960
|
root: "xmlnyugtasend",
|
|
@@ -884,7 +966,7 @@ function buildSendReceiptXml(credentials, input) {
|
|
|
884
966
|
el("emailKuldes", [
|
|
885
967
|
el("email", emails.join(",")),
|
|
886
968
|
optionalEl("emailReplyto", replyTo),
|
|
887
|
-
el("emailTargy", optionalText(input.subject) ?? `Nyugta ${receiptNumber}`),
|
|
969
|
+
el("emailTargy", optionalText$1(input.subject) ?? `Nyugta ${receiptNumber}`),
|
|
888
970
|
optionalEl("emailSzoveg", input.text?.trim() ? input.text : void 0)
|
|
889
971
|
])
|
|
890
972
|
]
|
|
@@ -1087,6 +1169,54 @@ async function queryTaxpayer(ctx, taxNumber, options = {}) {
|
|
|
1087
1169
|
}, parseQueryTaxpayerResponse);
|
|
1088
1170
|
}
|
|
1089
1171
|
//#endregion
|
|
1172
|
+
//#region src/taxpayer/cache.ts
|
|
1173
|
+
const TAXPAYER_CACHE_KEY_PREFIX = "szamlazz:taxpayer:";
|
|
1174
|
+
const DEFAULT_TAXPAYER_TTL_SECONDS = 86400;
|
|
1175
|
+
const DEFAULT_TAXPAYER_INVALID_TTL_SECONDS = 600;
|
|
1176
|
+
function positiveSeconds(value, fallback, field) {
|
|
1177
|
+
if (value === void 0) return fallback;
|
|
1178
|
+
if (!Number.isFinite(value) || value < 1) throw new SzamlazzError(`A(z) ${field} legalább 1 másodperc legyen, kapott: ${String(value)}`, { category: "configuration" });
|
|
1179
|
+
return Math.ceil(value);
|
|
1180
|
+
}
|
|
1181
|
+
function parseCached(value) {
|
|
1182
|
+
if (typeof value !== "string" || value === "") return void 0;
|
|
1183
|
+
try {
|
|
1184
|
+
const parsed = JSON.parse(value);
|
|
1185
|
+
if (typeof parsed !== "object" || parsed === null) return void 0;
|
|
1186
|
+
const info = parsed;
|
|
1187
|
+
return typeof info.valid === "boolean" && Array.isArray(info.addresses) ? info : void 0;
|
|
1188
|
+
} catch {
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
function cachedTaxpayerQuery(query, options, warn) {
|
|
1193
|
+
const ttl = positiveSeconds(options.ttlSeconds, DEFAULT_TAXPAYER_TTL_SECONDS, "ttlSeconds");
|
|
1194
|
+
const invalidTtl = positiveSeconds(options.invalidTtlSeconds, 600, "invalidTtlSeconds");
|
|
1195
|
+
const report = (operation, error) => warn?.({
|
|
1196
|
+
kind: "cache",
|
|
1197
|
+
message: `Az adószám-gyorsítótár "${operation}" művelete sikertelen, a kassza a Számlázz.hu-tól kérdez.`,
|
|
1198
|
+
error,
|
|
1199
|
+
action: "queryTaxpayer",
|
|
1200
|
+
operation
|
|
1201
|
+
});
|
|
1202
|
+
return async (taxNumber, requestOptions) => {
|
|
1203
|
+
const key = `${TAXPAYER_CACHE_KEY_PREFIX}${toTaxpayerId(taxNumber)}`;
|
|
1204
|
+
try {
|
|
1205
|
+
const cached = parseCached(await options.store.get(key));
|
|
1206
|
+
if (cached) return cached;
|
|
1207
|
+
} catch (error) {
|
|
1208
|
+
report("get", error);
|
|
1209
|
+
}
|
|
1210
|
+
const info = await query(taxNumber, requestOptions);
|
|
1211
|
+
try {
|
|
1212
|
+
await options.store.set(key, JSON.stringify(info), info.valid ? ttl : invalidTtl);
|
|
1213
|
+
} catch (error) {
|
|
1214
|
+
report("set", error);
|
|
1215
|
+
}
|
|
1216
|
+
return info;
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
//#endregion
|
|
1090
1220
|
//#region src/client.ts
|
|
1091
1221
|
const CREDENTIAL_PROBE_INVOICE_NUMBER = "KASSZA-CREDENTIAL-PROBE-0";
|
|
1092
1222
|
async function nullIfNotFound(promise) {
|
|
@@ -1109,11 +1239,14 @@ function invoiceNumberOf(input) {
|
|
|
1109
1239
|
function receiptNumberOf(input) {
|
|
1110
1240
|
return typeof input === "string" ? input : input.receiptNumber;
|
|
1111
1241
|
}
|
|
1112
|
-
function
|
|
1242
|
+
function createDocumentEmitter(hook, options) {
|
|
1243
|
+
return { emit: (event) => emitDocumentEvent(hook, event, options) };
|
|
1244
|
+
}
|
|
1245
|
+
function createInvoicesApi(ctx, defaults, events, guard) {
|
|
1113
1246
|
const api = {
|
|
1114
1247
|
async create(input, options) {
|
|
1115
1248
|
const document = await createInvoice(ctx, defaults, input, options);
|
|
1116
|
-
await
|
|
1249
|
+
await events.emit({
|
|
1117
1250
|
kind: "invoice",
|
|
1118
1251
|
action: "created",
|
|
1119
1252
|
number: document.number,
|
|
@@ -1122,11 +1255,11 @@ function createInvoicesApi(ctx, defaults, onDocument) {
|
|
|
1122
1255
|
});
|
|
1123
1256
|
return document;
|
|
1124
1257
|
},
|
|
1125
|
-
createOnce: (input, options) => createInvoiceOnce(api, input, options),
|
|
1258
|
+
createOnce: (input, options) => createInvoiceOnce(api, input, options, guard),
|
|
1126
1259
|
preview: (input, options) => previewInvoice(ctx, defaults, input, options),
|
|
1127
1260
|
async reverse(input, options) {
|
|
1128
1261
|
const document = await reverseInvoice(ctx, input, options);
|
|
1129
|
-
await
|
|
1262
|
+
await events.emit({
|
|
1130
1263
|
kind: "invoice",
|
|
1131
1264
|
action: "reversed",
|
|
1132
1265
|
number: document.number,
|
|
@@ -1137,7 +1270,7 @@ function createInvoicesApi(ctx, defaults, onDocument) {
|
|
|
1137
1270
|
},
|
|
1138
1271
|
async registerPayment(input, options) {
|
|
1139
1272
|
const document = await registerPayment(ctx, input, options);
|
|
1140
|
-
await
|
|
1273
|
+
await events.emit({
|
|
1141
1274
|
kind: "invoice",
|
|
1142
1275
|
action: "payment",
|
|
1143
1276
|
number: document.invoiceNumber,
|
|
@@ -1145,9 +1278,10 @@ function createInvoicesApi(ctx, defaults, onDocument) {
|
|
|
1145
1278
|
});
|
|
1146
1279
|
return document;
|
|
1147
1280
|
},
|
|
1281
|
+
registerPaymentOnce: (input, options) => registerPaymentOnce(api, input, options, guard),
|
|
1148
1282
|
async clearPayments(input, options) {
|
|
1149
1283
|
const document = await clearPayments(ctx, input, options);
|
|
1150
|
-
await
|
|
1284
|
+
await events.emit({
|
|
1151
1285
|
kind: "invoice",
|
|
1152
1286
|
action: "payment",
|
|
1153
1287
|
number: document.invoiceNumber,
|
|
@@ -1162,11 +1296,20 @@ function createInvoicesApi(ctx, defaults, onDocument) {
|
|
|
1162
1296
|
};
|
|
1163
1297
|
return api;
|
|
1164
1298
|
}
|
|
1165
|
-
function
|
|
1299
|
+
function convertedJoin(result) {
|
|
1300
|
+
return {
|
|
1301
|
+
receipt: result.receipt,
|
|
1302
|
+
invoice: {
|
|
1303
|
+
...result.invoice,
|
|
1304
|
+
created: false
|
|
1305
|
+
}
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
function createReceiptsApi(ctx, defaults, invoices, events, guard) {
|
|
1166
1309
|
const api = {
|
|
1167
1310
|
async create(input, options) {
|
|
1168
1311
|
const document = await createReceipt(ctx, defaults, input, options);
|
|
1169
|
-
await
|
|
1312
|
+
await events.emit({
|
|
1170
1313
|
kind: "receipt",
|
|
1171
1314
|
action: "created",
|
|
1172
1315
|
number: document.number,
|
|
@@ -1174,10 +1317,10 @@ function createReceiptsApi(ctx, defaults, invoices, onDocument) {
|
|
|
1174
1317
|
});
|
|
1175
1318
|
return document;
|
|
1176
1319
|
},
|
|
1177
|
-
createOnce: (input, options) => createReceiptOnce(api, input, options),
|
|
1320
|
+
createOnce: (input, options) => createReceiptOnce(api, input, options, guard),
|
|
1178
1321
|
async reverse(input, options) {
|
|
1179
1322
|
const document = await reverseReceipt(ctx, input, options);
|
|
1180
|
-
await
|
|
1323
|
+
await events.emit({
|
|
1181
1324
|
kind: "receipt",
|
|
1182
1325
|
action: "reversed",
|
|
1183
1326
|
number: document.number,
|
|
@@ -1189,22 +1332,38 @@ function createReceiptsApi(ctx, defaults, invoices, onDocument) {
|
|
|
1189
1332
|
get: (input, options) => getReceipt(ctx, input, options),
|
|
1190
1333
|
find: (input, options) => nullIfNotFound(getReceipt(ctx, input, options)),
|
|
1191
1334
|
send: (input, options) => sendReceipt(ctx, input, options),
|
|
1192
|
-
convertToInvoice: (input, options) =>
|
|
1335
|
+
convertToInvoice: (input, options = {}) => guardOnce(guard, `convert:${input.receiptNumber?.trim() ?? ""}`, {
|
|
1336
|
+
...options,
|
|
1337
|
+
lock: false
|
|
1338
|
+
}, () => convertReceiptToInvoice({
|
|
1193
1339
|
receipts: api,
|
|
1194
1340
|
invoices
|
|
1195
|
-
}, input, options)
|
|
1341
|
+
}, input, options), convertedJoin)
|
|
1196
1342
|
};
|
|
1197
1343
|
return api;
|
|
1198
1344
|
}
|
|
1345
|
+
function onceScopeOf(ctx) {
|
|
1346
|
+
return ctx.credentials.map((node) => `${node.name}=${String(node.content)}`).join("\n");
|
|
1347
|
+
}
|
|
1199
1348
|
function createKassza(options = {}) {
|
|
1200
1349
|
const ctx = createAgentContext(options);
|
|
1201
|
-
const
|
|
1202
|
-
|
|
1203
|
-
|
|
1350
|
+
const events = createDocumentEmitter(options.hooks?.onDocument, {
|
|
1351
|
+
mode: options.hooks?.onDocumentError,
|
|
1352
|
+
onWarning: options.hooks?.onWarning
|
|
1353
|
+
});
|
|
1354
|
+
const guard = {
|
|
1355
|
+
scope: onceScopeOf(ctx),
|
|
1356
|
+
lock: options.createOnceLock,
|
|
1357
|
+
warn: ctx.warn
|
|
1358
|
+
};
|
|
1359
|
+
const directQuery = (taxNumber, requestOptions) => queryTaxpayer(ctx, taxNumber, requestOptions);
|
|
1360
|
+
const taxpayerQuery = options.taxpayerCache ? cachedTaxpayerQuery(directQuery, options.taxpayerCache, ctx.warn) : directQuery;
|
|
1361
|
+
const invoices = createInvoicesApi(ctx, options.defaults?.invoice ?? {}, events, guard);
|
|
1362
|
+
const receipts = createReceiptsApi(ctx, options.defaults?.receipt ?? {}, invoices, events, guard);
|
|
1204
1363
|
return {
|
|
1205
1364
|
invoices,
|
|
1206
1365
|
receipts,
|
|
1207
|
-
taxpayer: { query:
|
|
1366
|
+
taxpayer: { query: taxpayerQuery },
|
|
1208
1367
|
async verifyCredentials(requestOptions) {
|
|
1209
1368
|
try {
|
|
1210
1369
|
await getInvoicePdf(ctx, CREDENTIAL_PROBE_INVOICE_NUMBER, requestOptions);
|
|
@@ -1225,4 +1384,4 @@ function createKassza(options = {}) {
|
|
|
1225
1384
|
};
|
|
1226
1385
|
}
|
|
1227
1386
|
//#endregion
|
|
1228
|
-
export {
|
|
1387
|
+
export { queryTaxpayer as a, createAgentContext as c, attemptLedgerKey as d, TAXPAYER_CACHE_KEY_PREFIX as i, ATTEMPT_LEDGER_KEY_PREFIX as l, DEFAULT_TAXPAYER_INVALID_TTL_SECONDS as n, getInvoicePdf as o, DEFAULT_TAXPAYER_TTL_SECONDS as r, buildCreateInvoiceXml as s, createKassza as t, ATTEMPT_LEDGER_TTL_SECONDS as u };
|