kassza 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-BrJUbXs7.js} +8 -7
- package/dist/{server-C6PoNkdD.cjs → server-Dw9j8Mnd.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
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import { o as isSzamlazzError, r as SzamlazzError } from "../errors-DtN4g5Z9.js";
|
|
2
|
+
import { n as toAgentDate, t as addBudapestDays } from "../dates-CXyj7Azy.js";
|
|
3
|
+
import { n as calculateReceiptItems } from "../create-CflXrPip.js";
|
|
4
|
+
//#region src/batch/recurring.ts
|
|
5
|
+
const INTERVALS = /* @__PURE__ */ new Set([
|
|
6
|
+
"week",
|
|
7
|
+
"month",
|
|
8
|
+
"quarter",
|
|
9
|
+
"year"
|
|
10
|
+
]);
|
|
11
|
+
const MONTHS = {
|
|
12
|
+
month: 1,
|
|
13
|
+
quarter: 3,
|
|
14
|
+
year: 12
|
|
15
|
+
};
|
|
16
|
+
function invalid$1(message) {
|
|
17
|
+
return new SzamlazzError(message, { category: "validation" });
|
|
18
|
+
}
|
|
19
|
+
function parts(day) {
|
|
20
|
+
const [year, month, date] = day.split("-").map(Number);
|
|
21
|
+
return [
|
|
22
|
+
year,
|
|
23
|
+
month,
|
|
24
|
+
date
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
function format(year, month, day) {
|
|
28
|
+
return `${String(year).padStart(4, "0")}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
|
29
|
+
}
|
|
30
|
+
function daysInMonth(year, month) {
|
|
31
|
+
return new Date(Date.UTC(year, month, 0)).getUTCDate();
|
|
32
|
+
}
|
|
33
|
+
function addDays(day, days) {
|
|
34
|
+
const [year, month, date] = parts(day);
|
|
35
|
+
return new Date(Date.UTC(year, month - 1, date + days)).toISOString().slice(0, 10);
|
|
36
|
+
}
|
|
37
|
+
function shift(anchor, interval, count) {
|
|
38
|
+
if (interval === "week") return addDays(anchor, count * 7);
|
|
39
|
+
const [year, month, day] = parts(anchor);
|
|
40
|
+
const total = year * 12 + (month - 1) + count * MONTHS[interval];
|
|
41
|
+
const targetYear = Math.floor(total / 12);
|
|
42
|
+
const targetMonth = total % 12 + 1;
|
|
43
|
+
return format(targetYear, targetMonth, Math.min(day, daysInMonth(targetYear, targetMonth)));
|
|
44
|
+
}
|
|
45
|
+
function resolve(options) {
|
|
46
|
+
if (!INTERVALS.has(options.interval)) throw invalid$1(`Ismeretlen számlázási időszak: ${String(options.interval)}`);
|
|
47
|
+
let anchor;
|
|
48
|
+
try {
|
|
49
|
+
anchor = toAgentDate(options.anchor);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
throw invalid$1(error instanceof Error ? error.message : String(error));
|
|
52
|
+
}
|
|
53
|
+
const due = options.paymentDueInDays;
|
|
54
|
+
if (due !== void 0 && (!Number.isInteger(due) || due < 0)) throw invalid$1(`A paymentDueInDays nemnegatív egész legyen, kapott: ${due}`);
|
|
55
|
+
return {
|
|
56
|
+
anchor,
|
|
57
|
+
interval: options.interval
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function billingPeriod(options, index) {
|
|
61
|
+
if (!Number.isInteger(index) || index < 0) throw invalid$1(`Az időszak sorszáma nemnegatív egész legyen, kapott: ${index}`);
|
|
62
|
+
const { anchor, interval } = resolve(options);
|
|
63
|
+
const start = shift(anchor, interval, index);
|
|
64
|
+
const end = addDays(shift(anchor, interval, index + 1), -1);
|
|
65
|
+
const due = options.paymentDueInDays;
|
|
66
|
+
return {
|
|
67
|
+
index,
|
|
68
|
+
interval,
|
|
69
|
+
start,
|
|
70
|
+
end,
|
|
71
|
+
...due === void 0 ? {} : { dueDate: addDays(start, due) },
|
|
72
|
+
key: `${interval}:${start}`
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function billingPeriodAt(options, date) {
|
|
76
|
+
const { anchor, interval } = resolve(options);
|
|
77
|
+
let day;
|
|
78
|
+
try {
|
|
79
|
+
day = toAgentDate(date);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
throw invalid$1(error instanceof Error ? error.message : String(error));
|
|
82
|
+
}
|
|
83
|
+
if (day < anchor) throw invalid$1(`A(z) ${day} dátum korábbi, mint az első időszak kezdete (${anchor}).`);
|
|
84
|
+
const [anchorYear, anchorMonth] = parts(anchor);
|
|
85
|
+
const [year, month] = parts(day);
|
|
86
|
+
let index = interval === "week" ? Math.floor((Date.parse(`${day}T00:00:00Z`) - Date.parse(`${anchor}T00:00:00Z`)) / 6048e5) : Math.floor(((year - anchorYear) * 12 + (month - anchorMonth)) / MONTHS[interval]);
|
|
87
|
+
while (index > 0 && shift(anchor, interval, index) > day) index -= 1;
|
|
88
|
+
while (shift(anchor, interval, index + 1) <= day) index += 1;
|
|
89
|
+
return billingPeriod(options, index);
|
|
90
|
+
}
|
|
91
|
+
function billingPeriodsBetween(options, from, to) {
|
|
92
|
+
const first = billingPeriodAt(options, from);
|
|
93
|
+
const last = billingPeriodAt(options, to);
|
|
94
|
+
const periods = [];
|
|
95
|
+
for (let index = first.index; index <= last.index; index++) periods.push(billingPeriod(options, index));
|
|
96
|
+
return periods;
|
|
97
|
+
}
|
|
98
|
+
function todayPeriod(options, now = /* @__PURE__ */ new Date()) {
|
|
99
|
+
return billingPeriodAt(options, addBudapestDays(now, 0));
|
|
100
|
+
}
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/batch/run.ts
|
|
103
|
+
const MAX_BATCH_CONCURRENCY = 4;
|
|
104
|
+
const DEFAULT_BATCH_RATE_PER_MINUTE = 30;
|
|
105
|
+
const STOPPING_CATEGORIES = /* @__PURE__ */ new Set([
|
|
106
|
+
"rate_limit",
|
|
107
|
+
"auth",
|
|
108
|
+
"account",
|
|
109
|
+
"configuration",
|
|
110
|
+
"maintenance",
|
|
111
|
+
"attempt_limit",
|
|
112
|
+
"store_unavailable"
|
|
113
|
+
]);
|
|
114
|
+
function invalid(message) {
|
|
115
|
+
return new SzamlazzError(message, { category: "validation" });
|
|
116
|
+
}
|
|
117
|
+
function resolveConcurrency(value) {
|
|
118
|
+
if (value === void 0) return 1;
|
|
119
|
+
if (!Number.isInteger(value) || value < 1 || value > 4) throw new SzamlazzError(`A concurrency 1 és 4 közötti egész legyen, kapott: ${value}. A Számlázz.hu a párhuzamos kérések kerülését kéri.`, { category: "configuration" });
|
|
120
|
+
return value;
|
|
121
|
+
}
|
|
122
|
+
function resolveRate(value) {
|
|
123
|
+
if (value === void 0) return 30;
|
|
124
|
+
if (!Number.isFinite(value) || value <= 0) throw new SzamlazzError(`A ratePerMinute pozitív szám legyen, kapott: ${value}`, { category: "configuration" });
|
|
125
|
+
return value;
|
|
126
|
+
}
|
|
127
|
+
function assertKeys(items) {
|
|
128
|
+
const seen = /* @__PURE__ */ new Set();
|
|
129
|
+
for (const item of items) {
|
|
130
|
+
const key = item.key?.trim();
|
|
131
|
+
if (!key) throw invalid("Minden tételhez adj meg kulcsot (key), ez lesz a rendelésszám.");
|
|
132
|
+
if (seen.has(key)) throw invalid(`A(z) ${key} kulcs kétszer szerepel a listában.`);
|
|
133
|
+
seen.add(key);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function withOrderNumber(input, key) {
|
|
137
|
+
const own = input.orderNumber?.trim();
|
|
138
|
+
if (own && own !== key) throw invalid(`A(z) ${key} tétel rendelésszáma (${own}) eltér a kulcstól. A batch a kulcsot használja rendelésszámként, hogy az újrafuttatás ne állítson ki duplát.`);
|
|
139
|
+
return {
|
|
140
|
+
...input,
|
|
141
|
+
orderNumber: key
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function wait(ms, signal) {
|
|
145
|
+
if (ms <= 0) return Promise.resolve();
|
|
146
|
+
return new Promise((resolve, reject) => {
|
|
147
|
+
if (signal?.aborted) {
|
|
148
|
+
reject(signal.reason);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const timer = setTimeout(() => {
|
|
152
|
+
signal?.removeEventListener("abort", onAbort);
|
|
153
|
+
resolve();
|
|
154
|
+
}, ms);
|
|
155
|
+
const onAbort = () => {
|
|
156
|
+
clearTimeout(timer);
|
|
157
|
+
reject(signal?.reason);
|
|
158
|
+
};
|
|
159
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
function invoiceGross(result) {
|
|
163
|
+
return result.invoice?.grossTotal ?? result.details?.totals.grossAmount;
|
|
164
|
+
}
|
|
165
|
+
async function previewDocument(api, document, key, signal) {
|
|
166
|
+
if (document.kind === "invoice") return {
|
|
167
|
+
key,
|
|
168
|
+
status: "previewed",
|
|
169
|
+
kind: "invoice",
|
|
170
|
+
grossTotal: (await api.invoices.preview(withOrderNumber(document.input, key), { signal })).grossTotal
|
|
171
|
+
};
|
|
172
|
+
const input = withOrderNumber(document.input, key);
|
|
173
|
+
if (input.items.length === 0) throw invalid(`A(z) ${key} nyugtán nincs tétel.`);
|
|
174
|
+
const gross = calculateReceiptItems(input.items, input.currency ?? "HUF").reduce((sum, item) => sum + item.amounts.grossAmount, 0);
|
|
175
|
+
return {
|
|
176
|
+
key,
|
|
177
|
+
status: "previewed",
|
|
178
|
+
kind: "receipt",
|
|
179
|
+
grossTotal: Math.round(gross * 100) / 100
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
async function issueDocument(api, document, key, options) {
|
|
183
|
+
const onceOptions = {
|
|
184
|
+
signal: options.signal,
|
|
185
|
+
recoveryDelayMs: options.recoveryDelayMs
|
|
186
|
+
};
|
|
187
|
+
if (document.kind === "invoice") {
|
|
188
|
+
const input = withOrderNumber(document.input, key);
|
|
189
|
+
const run = () => api.invoices.createOnce(input, onceOptions);
|
|
190
|
+
const result = options.journal ? await options.journal.trackInvoice(key, run) : await run();
|
|
191
|
+
return {
|
|
192
|
+
key,
|
|
193
|
+
status: result.created ? "created" : "existing",
|
|
194
|
+
kind: "invoice",
|
|
195
|
+
number: result.number,
|
|
196
|
+
grossTotal: invoiceGross(result)
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
const input = withOrderNumber(document.input, key);
|
|
200
|
+
const run = () => api.receipts.createOnce(input, onceOptions);
|
|
201
|
+
const result = options.journal ? await options.journal.trackReceipt(key, run) : await run();
|
|
202
|
+
return {
|
|
203
|
+
key,
|
|
204
|
+
status: result.created ? "created" : "existing",
|
|
205
|
+
kind: "receipt",
|
|
206
|
+
number: result.receipt.number,
|
|
207
|
+
grossTotal: result.receipt.totals.grossAmount
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function stopReason(error) {
|
|
211
|
+
if (!isSzamlazzError(error) || !STOPPING_CATEGORIES.has(error.category)) return void 0;
|
|
212
|
+
return `A(z) ${error.category} hiba miatt a batch leállt, a hátralévő tételek nem futottak le: ${error.message}`;
|
|
213
|
+
}
|
|
214
|
+
async function runBatch(api, options) {
|
|
215
|
+
const concurrency = resolveConcurrency(options.concurrency);
|
|
216
|
+
const intervalMs = 6e4 / resolveRate(options.ratePerMinute);
|
|
217
|
+
assertKeys(options.items);
|
|
218
|
+
const dryRun = options.dryRun === true;
|
|
219
|
+
const results = new Array(options.items.length);
|
|
220
|
+
const counts = {
|
|
221
|
+
created: 0,
|
|
222
|
+
existing: 0,
|
|
223
|
+
previewed: 0,
|
|
224
|
+
failed: 0,
|
|
225
|
+
skipped: 0
|
|
226
|
+
};
|
|
227
|
+
let done = 0;
|
|
228
|
+
let cursor = 0;
|
|
229
|
+
let nextStart = Date.now();
|
|
230
|
+
const control = { stopped: void 0 };
|
|
231
|
+
const currentStop = () => control.stopped;
|
|
232
|
+
const record = (index, result) => {
|
|
233
|
+
results[index] = result;
|
|
234
|
+
counts[result.status] += 1;
|
|
235
|
+
done += 1;
|
|
236
|
+
try {
|
|
237
|
+
options.onProgress?.({
|
|
238
|
+
total: options.items.length,
|
|
239
|
+
done,
|
|
240
|
+
...counts,
|
|
241
|
+
key: result.key,
|
|
242
|
+
status: result.status
|
|
243
|
+
});
|
|
244
|
+
} catch {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
const processItem = async (index, item) => {
|
|
249
|
+
const key = item.key.trim();
|
|
250
|
+
try {
|
|
251
|
+
const document = await item.document();
|
|
252
|
+
const result = dryRun ? await previewDocument(api, document, key, options.signal) : await issueDocument(api, document, key, options);
|
|
253
|
+
record(index, result);
|
|
254
|
+
} catch (error) {
|
|
255
|
+
if (options.signal?.aborted && error === options.signal.reason) {
|
|
256
|
+
control.stopped ??= {
|
|
257
|
+
reason: "A batch futását megszakították.",
|
|
258
|
+
error
|
|
259
|
+
};
|
|
260
|
+
record(index, {
|
|
261
|
+
key,
|
|
262
|
+
status: "skipped",
|
|
263
|
+
reason: "Megszakítva."
|
|
264
|
+
});
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
const reason = stopReason(error);
|
|
268
|
+
if (reason) control.stopped ??= {
|
|
269
|
+
reason,
|
|
270
|
+
error
|
|
271
|
+
};
|
|
272
|
+
record(index, {
|
|
273
|
+
key,
|
|
274
|
+
status: "failed",
|
|
275
|
+
error
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
const worker = async () => {
|
|
280
|
+
for (;;) {
|
|
281
|
+
if (control.stopped || options.signal?.aborted) return;
|
|
282
|
+
const index = cursor;
|
|
283
|
+
cursor += 1;
|
|
284
|
+
const item = options.items[index];
|
|
285
|
+
if (!item) return;
|
|
286
|
+
const delay = nextStart - Date.now();
|
|
287
|
+
nextStart = Math.max(nextStart, Date.now()) + intervalMs;
|
|
288
|
+
try {
|
|
289
|
+
await wait(delay, options.signal);
|
|
290
|
+
} catch (error) {
|
|
291
|
+
control.stopped ??= {
|
|
292
|
+
reason: "A batch futását megszakították.",
|
|
293
|
+
error
|
|
294
|
+
};
|
|
295
|
+
record(index, {
|
|
296
|
+
key: item.key.trim(),
|
|
297
|
+
status: "skipped",
|
|
298
|
+
reason: "Megszakítva."
|
|
299
|
+
});
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const stop = currentStop();
|
|
303
|
+
if (stop) {
|
|
304
|
+
record(index, {
|
|
305
|
+
key: item.key.trim(),
|
|
306
|
+
status: "skipped",
|
|
307
|
+
reason: stop.reason
|
|
308
|
+
});
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
await processItem(index, item);
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, options.items.length) }, worker));
|
|
315
|
+
if (options.signal?.aborted) control.stopped ??= { reason: "A batch futását megszakították." };
|
|
316
|
+
options.items.forEach((item, index) => {
|
|
317
|
+
if (results[index]) return;
|
|
318
|
+
record(index, {
|
|
319
|
+
key: item.key.trim(),
|
|
320
|
+
status: "skipped",
|
|
321
|
+
reason: control.stopped?.reason ?? "Nem futott le."
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
const by = (status) => results.filter((result) => result.status === status);
|
|
325
|
+
const grossTotal = results.filter((result) => result.status !== "failed" && result.status !== "skipped").reduce((sum, result) => sum + (result.grossTotal ?? 0), 0);
|
|
326
|
+
return {
|
|
327
|
+
dryRun,
|
|
328
|
+
items: results,
|
|
329
|
+
created: by("created"),
|
|
330
|
+
existing: by("existing"),
|
|
331
|
+
previewed: by("previewed"),
|
|
332
|
+
failed: by("failed"),
|
|
333
|
+
skipped: by("skipped"),
|
|
334
|
+
stopped: control.stopped,
|
|
335
|
+
grossTotal: Math.round(grossTotal * 100) / 100
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
//#endregion
|
|
339
|
+
export { DEFAULT_BATCH_RATE_PER_MINUTE, MAX_BATCH_CONCURRENCY, billingPeriod, billingPeriodAt, billingPeriodsBetween, runBatch, todayPeriod };
|
package/dist/cli.cjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_errors = require("./errors-
|
|
3
|
-
const require_client = require("./client-
|
|
4
|
-
const require_serialize = require("./serialize-
|
|
5
|
-
const
|
|
6
|
-
const require_nav = require("./nav-
|
|
7
|
-
const require_server = require("./server-
|
|
2
|
+
const require_errors = require("./errors-EE96_6D_.cjs");
|
|
3
|
+
const require_client = require("./client-CLFvJCVW.cjs");
|
|
4
|
+
const require_serialize = require("./serialize-CquIsxA-.cjs");
|
|
5
|
+
const require_create = require("./create-CvUvLUaT.cjs");
|
|
6
|
+
const require_nav = require("./nav-BNbc8U0R.cjs");
|
|
7
|
+
const require_server = require("./server-Dw9j8Mnd.cjs");
|
|
8
8
|
let node_fs_promises = require("node:fs/promises");
|
|
9
9
|
let node_readline = require("node:readline");
|
|
10
10
|
//#region src/cli/args.ts
|
|
@@ -147,7 +147,7 @@ async function xmlPreviewCommand(io, args) {
|
|
|
147
147
|
const defaultsPath = flagValue(args, "defaults");
|
|
148
148
|
const source = previewSource(await readJson(io, path), defaultsPath === void 0 ? void 0 : await readDefaults(io, defaultsPath));
|
|
149
149
|
assertDocumentShape(source.input, type);
|
|
150
|
-
const xml = type === "invoice" ? require_client.buildCreateInvoiceXml(MASKED_CREDENTIALS, source.defaults.invoice ?? {}, source.input, io.now?.() ?? /* @__PURE__ */ new Date()) :
|
|
150
|
+
const xml = type === "invoice" ? require_client.buildCreateInvoiceXml(MASKED_CREDENTIALS, source.defaults.invoice ?? {}, source.input, io.now?.() ?? /* @__PURE__ */ new Date()) : require_create.buildCreateReceiptXml(MASKED_CREDENTIALS, source.defaults.receipt ?? {}, source.input);
|
|
151
151
|
io.stdout(xml);
|
|
152
152
|
return 0;
|
|
153
153
|
}
|
|
@@ -222,6 +222,8 @@ async function navSummaryCommand(io, args) {
|
|
|
222
222
|
}
|
|
223
223
|
//#endregion
|
|
224
224
|
//#region src/cli/doctor.ts
|
|
225
|
+
const NPM_LATEST_URL = "https://registry.npmjs.org/kassza/latest";
|
|
226
|
+
const USED_BY_URL = "https://github.com/futozs/kassza/issues/new?template=used-by.yml";
|
|
225
227
|
const MINIMUM_NODE_MAJOR = 22;
|
|
226
228
|
const CLOCK_OK_SECONDS = 2;
|
|
227
229
|
const CLOCK_WARN_SECONDS = 30;
|
|
@@ -317,6 +319,57 @@ async function accountCheck(kassza, options) {
|
|
|
317
319
|
}
|
|
318
320
|
return check("account", "skip", "Fiók típusa: add meg egy meglévő bizonylat számát (--invoice vagy --receipt), abból kiderül, hogy teszt- vagy éles fiók.");
|
|
319
321
|
}
|
|
322
|
+
const PROBE_BUYER = {
|
|
323
|
+
name: "Kassza doctor próba",
|
|
324
|
+
zip: "1111",
|
|
325
|
+
city: "Budapest",
|
|
326
|
+
address: "Próba utca 1."
|
|
327
|
+
};
|
|
328
|
+
async function eInvoiceCheck(kassza) {
|
|
329
|
+
try {
|
|
330
|
+
await kassza.invoices.preview({
|
|
331
|
+
buyer: PROBE_BUYER,
|
|
332
|
+
items: [{
|
|
333
|
+
name: "Próba",
|
|
334
|
+
netUnitPrice: 1,
|
|
335
|
+
vat: 27
|
|
336
|
+
}],
|
|
337
|
+
eInvoice: true
|
|
338
|
+
});
|
|
339
|
+
return check("e-invoice", "ok", "E-számla: engedélyezve (előnézettel ellenőrizve, bizonylat nem készült).");
|
|
340
|
+
} catch (error) {
|
|
341
|
+
if (require_errors.isSzamlazzError(error) && (error.code === 54 || error.code === 55 || error.code === 49)) return check("e-invoice", "warn", `E-számla: nem használható (${error.message}).`);
|
|
342
|
+
return check("e-invoice", "warn", `E-számla: az előnézet nem sikerült. ${error instanceof Error ? error.message : String(error)}`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
function receiptCapabilityCheck() {
|
|
346
|
+
return check("receipt", "skip", "Nyugta: a nyugtaelőtagot és a jogosultságot csak valódi kiállítás ellenőrzi (524, 8). Próbáld tesztfiókon.");
|
|
347
|
+
}
|
|
348
|
+
function environmentCheck(account, nodeEnv) {
|
|
349
|
+
if (account.status !== "ok" || !account.message.includes("éles fiók")) return void 0;
|
|
350
|
+
if (nodeEnv === "test" || nodeEnv === "development") return check("environment", "warn", `Környezet: NODE_ENV=${nodeEnv}, de az Agent kulcs éles fiókhoz tartozik. A tesztek valódi bizonylatot állíthatnak ki.`);
|
|
351
|
+
}
|
|
352
|
+
function compareVersions(a, b) {
|
|
353
|
+
const parse = (value) => value.replace(/^v/, "").split(/[.-]/).slice(0, 3).map((part) => Number.parseInt(part, 10) || 0);
|
|
354
|
+
const left = parse(a);
|
|
355
|
+
const right = parse(b);
|
|
356
|
+
for (let index = 0; index < 3; index++) {
|
|
357
|
+
const difference = (left[index] ?? 0) - (right[index] ?? 0);
|
|
358
|
+
if (difference !== 0) return difference;
|
|
359
|
+
}
|
|
360
|
+
return 0;
|
|
361
|
+
}
|
|
362
|
+
async function updateCheck(fetchImpl) {
|
|
363
|
+
try {
|
|
364
|
+
const response = await fetchImpl(NPM_LATEST_URL, { headers: { accept: "application/json" } });
|
|
365
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
366
|
+
const latest = String((await response.json()).version ?? "");
|
|
367
|
+
if (!/^\d+\.\d+\.\d+/.test(latest)) throw new Error("nincs verziószám a válaszban");
|
|
368
|
+
return compareVersions(latest, require_server.KASSZA_VERSION) > 0 ? check("update", "warn", `Frissítés: elérhető a kassza ${latest} (most: ${require_server.KASSZA_VERSION}).`) : check("update", "ok", `Frissítés: a kassza ${require_server.KASSZA_VERSION} a legfrissebb.`);
|
|
369
|
+
} catch (error) {
|
|
370
|
+
return check("update", "skip", `Frissítés: az npm nem volt elérhető (${error instanceof Error ? error.message : String(error)}).`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
320
373
|
function accountOf(test) {
|
|
321
374
|
if (test === true) return check("account", "ok", "Fiók típusa: tesztfiók.");
|
|
322
375
|
if (test === false) return check("account", "ok", "Fiók típusa: éles fiók, a kiállított bizonylatok valódiak.");
|
|
@@ -339,12 +392,18 @@ async function runDoctor(io, options = {}) {
|
|
|
339
392
|
});
|
|
340
393
|
const auth = await authCheck(kassza);
|
|
341
394
|
const account = auth.status === "ok" ? await accountCheck(kassza, options) : check("account", "skip", "Fiók típusa: sikertelen hitelesítés miatt kimaradt.");
|
|
395
|
+
const extra = [];
|
|
396
|
+
const environment = environmentCheck(account, io.env.NODE_ENV);
|
|
397
|
+
if (environment) extra.push(environment);
|
|
398
|
+
if (options.capabilities === true && auth.status === "ok") extra.push(await eInvoiceCheck(kassza), receiptCapabilityCheck());
|
|
399
|
+
if (options.checkUpdate === true) extra.push(await updateCheck(io.fetch ?? globalThis.fetch));
|
|
342
400
|
return [
|
|
343
401
|
...checks,
|
|
344
402
|
auth,
|
|
345
403
|
clockCheck(samples),
|
|
346
404
|
sessionCheck(samples),
|
|
347
|
-
account
|
|
405
|
+
account,
|
|
406
|
+
...extra
|
|
348
407
|
];
|
|
349
408
|
}
|
|
350
409
|
const SYMBOLS = {
|
|
@@ -353,13 +412,34 @@ const SYMBOLS = {
|
|
|
353
412
|
fail: "✗",
|
|
354
413
|
skip: "-"
|
|
355
414
|
};
|
|
415
|
+
function summary(checks) {
|
|
416
|
+
return `Összegzés: ${checks.filter((entry) => entry.status === "fail").length} hiba, ${checks.filter((entry) => entry.status === "warn").length} figyelmeztetés.`;
|
|
417
|
+
}
|
|
356
418
|
function formatDoctor(checks) {
|
|
357
|
-
const
|
|
358
|
-
const warnings = checks.filter((entry) => entry.status === "warn").length;
|
|
419
|
+
const healthy = !checks.some((entry) => entry.status === "fail");
|
|
359
420
|
return [
|
|
360
421
|
...checks.map((entry) => `${SYMBOLS[entry.status]} ${entry.message}`),
|
|
361
422
|
"",
|
|
362
|
-
|
|
423
|
+
summary(checks),
|
|
424
|
+
...healthy ? ["", `Használod a kasszát? Két perc, és sokat segít: ${USED_BY_URL}`] : [],
|
|
425
|
+
""
|
|
426
|
+
].join("\n");
|
|
427
|
+
}
|
|
428
|
+
function formatDoctorReport(checks, meta) {
|
|
429
|
+
return [
|
|
430
|
+
"## kassza doctor jelentés",
|
|
431
|
+
"",
|
|
432
|
+
`- kassza: ${require_server.KASSZA_VERSION}`,
|
|
433
|
+
`- Node.js: ${meta.nodeVersion}`,
|
|
434
|
+
...meta.platform ? [`- platform: ${meta.platform}`] : [],
|
|
435
|
+
"",
|
|
436
|
+
"| Ellenőrzés | Állapot | Eredmény |",
|
|
437
|
+
"| --- | --- | --- |",
|
|
438
|
+
...checks.map((entry) => `| ${entry.id} | ${entry.status} | ${entry.message.replace(/\|/g, "\\|")} |`),
|
|
439
|
+
"",
|
|
440
|
+
summary(checks),
|
|
441
|
+
"",
|
|
442
|
+
"A jelentés nem tartalmaz Agent kulcsot, vevői adatot vagy bizonylattartalmat. Átadás előtt nézd át.",
|
|
363
443
|
""
|
|
364
444
|
].join("\n");
|
|
365
445
|
}
|
|
@@ -401,8 +481,11 @@ const CLI_USAGE = `kassza ${require_server.KASSZA_VERSION}: Számlázz.hu Száml
|
|
|
401
481
|
Használat: kassza <parancs> [kapcsolók]
|
|
402
482
|
|
|
403
483
|
Parancsok:
|
|
404
|
-
doctor [--invoice <szám> | --receipt <szám>] [--json]
|
|
484
|
+
doctor [--invoice <szám> | --receipt <szám>] [--capabilities] [--check-update] [--json | --report]
|
|
405
485
|
A környezet, az Agent kulcs, az óra és a Számlázz.hu kapcsolat ellenőrzése.
|
|
486
|
+
--capabilities: e-számla engedély előnézettel (bizonylat nem készül)
|
|
487
|
+
--check-update: az npm legfrissebb verziójának lekérdezése (hálózati hívás)
|
|
488
|
+
--report: titokmentes Markdown jelentés hibajegyhez
|
|
406
489
|
verify
|
|
407
490
|
Az Agent kulcs ellenőrzése a Számlázz.hu-n.
|
|
408
491
|
xml preview <fájl.json|-> [--type invoice|receipt] [--defaults <fájl.json>]
|
|
@@ -422,7 +505,12 @@ Környezeti változók:
|
|
|
422
505
|
`;
|
|
423
506
|
const SPECS = {
|
|
424
507
|
doctor: {
|
|
425
|
-
booleans: [
|
|
508
|
+
booleans: [
|
|
509
|
+
"json",
|
|
510
|
+
"report",
|
|
511
|
+
"capabilities",
|
|
512
|
+
"check-update"
|
|
513
|
+
],
|
|
426
514
|
values: ["invoice", "receipt"]
|
|
427
515
|
},
|
|
428
516
|
verify: {},
|
|
@@ -452,9 +540,12 @@ function commandOf(argv) {
|
|
|
452
540
|
async function doctorCommand(io, args) {
|
|
453
541
|
const checks = await runDoctor(io, {
|
|
454
542
|
invoiceNumber: flagValue(args, "invoice"),
|
|
455
|
-
receiptNumber: flagValue(args, "receipt")
|
|
543
|
+
receiptNumber: flagValue(args, "receipt"),
|
|
544
|
+
capabilities: hasFlag(args, "capabilities"),
|
|
545
|
+
checkUpdate: hasFlag(args, "check-update")
|
|
456
546
|
});
|
|
457
547
|
if (hasFlag(args, "json")) printJson(io, { checks });
|
|
548
|
+
else if (hasFlag(args, "report")) io.stdout(formatDoctorReport(checks, { nodeVersion: io.nodeVersion }));
|
|
458
549
|
else io.stdout(`kassza doctor ${require_server.KASSZA_VERSION}\n${formatDoctor(checks)}`);
|
|
459
550
|
return checks.some((check) => check.status === "fail") ? 1 : 0;
|
|
460
551
|
}
|