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
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { r as SzamlazzError } from "./errors-DtN4g5Z9.js";
|
|
2
|
+
import { a as optionalEl, n as buildXmlDocument, r as el } from "./serialize-B2eFh3D-.js";
|
|
3
|
+
import { n as parseReceiptResponse } from "./parse-Cr7yQ3_z.js";
|
|
4
|
+
import { n as decimalPlaces, r as roundMoney } from "./rounding-BLyHjjI5.js";
|
|
5
|
+
import { i as isHuf, o as vatPercentage } from "./vat-v_dcWCto.js";
|
|
6
|
+
import { i as calculateReceiptItem } from "./money-Cw457SD6.js";
|
|
7
|
+
//#region src/receipts/types.ts
|
|
8
|
+
const RECEIPT_ONLY_VAT_CODES = [
|
|
9
|
+
"ÁKK",
|
|
10
|
+
"MAA",
|
|
11
|
+
"EU",
|
|
12
|
+
"EUK"
|
|
13
|
+
];
|
|
14
|
+
const RECEIPT_PDF_TEMPLATES = [
|
|
15
|
+
"A",
|
|
16
|
+
"N",
|
|
17
|
+
"J",
|
|
18
|
+
"L"
|
|
19
|
+
];
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/receipts/common.ts
|
|
22
|
+
const RECEIPT_XSD_BASE_URL = "https://www.szamlazz.hu/szamla/docs/xsds/";
|
|
23
|
+
function receiptValidationError(message) {
|
|
24
|
+
return new SzamlazzError(message, { category: "validation" });
|
|
25
|
+
}
|
|
26
|
+
function requireText(value, message) {
|
|
27
|
+
const trimmed = value?.trim();
|
|
28
|
+
if (!trimmed) throw receiptValidationError(message);
|
|
29
|
+
return trimmed;
|
|
30
|
+
}
|
|
31
|
+
function optionalText(value) {
|
|
32
|
+
const trimmed = value?.trim();
|
|
33
|
+
return trimmed ? trimmed : void 0;
|
|
34
|
+
}
|
|
35
|
+
const templates = new Set(RECEIPT_PDF_TEMPLATES);
|
|
36
|
+
function validateTemplate(template) {
|
|
37
|
+
if (template === void 0) return void 0;
|
|
38
|
+
if (!templates.has(template)) throw receiptValidationError(`Ismeretlen nyugta PDF sablon: ${String(template)}. Lehetséges értékek: A (normál A4), N (80 mm), J (jegy), L (jegy logóval).`);
|
|
39
|
+
return template;
|
|
40
|
+
}
|
|
41
|
+
function requireReceiptNumber(value) {
|
|
42
|
+
return requireText(value, "Add meg a nyugtaszámot (receiptNumber).");
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/receipts/create.ts
|
|
46
|
+
const CREATE_RECEIPT_NAMESPACE = "http://www.szamlazz.hu/xmlnyugtacreate";
|
|
47
|
+
const DEFAULT_CURRENCY = "HUF";
|
|
48
|
+
const DEFAULT_UNIT = "db";
|
|
49
|
+
const PREFIX_PATTERN = /^[A-Z0-9]+$/;
|
|
50
|
+
const AMOUNT_TOLERANCE = 2;
|
|
51
|
+
const MONEY_DECIMALS = 2;
|
|
52
|
+
const receiptOnlyVatCodes = new Set(RECEIPT_ONLY_VAT_CODES);
|
|
53
|
+
function calculateItem(item, currency, index) {
|
|
54
|
+
const vat = typeof item.vat === "string" && receiptOnlyVatCodes.has(item.vat) ? 0 : item.vat;
|
|
55
|
+
try {
|
|
56
|
+
return calculateReceiptItem({
|
|
57
|
+
...item,
|
|
58
|
+
vat
|
|
59
|
+
}, currency);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (!(error instanceof SzamlazzError)) throw error;
|
|
62
|
+
throw receiptValidationError(`${index + 1}. tétel (${item.name}): ${error.message}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function assertHufAmounts(amounts, label, vat) {
|
|
66
|
+
if (!Number.isInteger(amounts.grossAmount)) throw receiptValidationError(`${label}: forintos nyugtán a bruttó összegnek egész számnak kell lennie (363).`);
|
|
67
|
+
if (decimalPlaces(amounts.netAmount) > MONEY_DECIMALS) throw receiptValidationError(`${label}: forintos nyugtán a nettó összeg legfeljebb 2 tizedesjegyet tartalmazhat (364).`);
|
|
68
|
+
if (decimalPlaces(amounts.vatAmount) > MONEY_DECIMALS) throw receiptValidationError(`${label}: forintos nyugtán az áfa összeg legfeljebb 2 tizedesjegyet tartalmazhat (365).`);
|
|
69
|
+
if (roundMoney(amounts.netAmount + amounts.vatAmount, MONEY_DECIMALS) !== amounts.grossAmount) throw receiptValidationError(`${label}: a nettó és az áfa összegének pontosan ki kell adnia a bruttót (261).`);
|
|
70
|
+
if (Math.abs(amounts.netUnitPrice * amounts.quantity - amounts.netAmount) > AMOUNT_TOLERANCE) throw receiptValidationError(`${label}: a nettó egységár és a mennyiség szorzata nem egyezik a nettó összeggel (259).`);
|
|
71
|
+
const expectedVat = amounts.netAmount * vatPercentage(vat) / 100;
|
|
72
|
+
if (Math.abs(expectedVat - amounts.vatAmount) > AMOUNT_TOLERANCE) throw receiptValidationError(`${label}: az áfa összeg nem egyezik a nettó összeg és az áfakulcs szorzatával (260).`);
|
|
73
|
+
}
|
|
74
|
+
function calculateReceiptItems(items, currency) {
|
|
75
|
+
if (items.length === 0) throw receiptValidationError("A nyugtán legalább egy tételnek szerepelnie kell.");
|
|
76
|
+
return items.map((input, index) => {
|
|
77
|
+
requireText(input.name, `A(z) ${index + 1}. tétel megnevezése (name) kötelező.`);
|
|
78
|
+
const amounts = calculateItem(input, currency, index);
|
|
79
|
+
if (isHuf(currency)) assertHufAmounts(amounts, `${index + 1}. tétel (${input.name})`, input.vat);
|
|
80
|
+
if (input.dataDeletionCode !== void 0) {
|
|
81
|
+
if (!Number.isInteger(input.dataDeletionCode) || input.dataDeletionCode < 0) throw receiptValidationError(`A(z) ${index + 1}. tétel adattörlő kódja (dataDeletionCode) nemnegatív egész szám legyen.`);
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
input,
|
|
85
|
+
amounts,
|
|
86
|
+
vat: input.vat
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function formatAmount(value, currency, decimals) {
|
|
91
|
+
return isHuf(currency) ? value.toFixed(decimals) : value;
|
|
92
|
+
}
|
|
93
|
+
function itemNode(item, currency, unit) {
|
|
94
|
+
const { input, amounts } = item;
|
|
95
|
+
const ledger = input.ledger;
|
|
96
|
+
return el("tetel", [
|
|
97
|
+
el("megnevezes", input.name.trim()),
|
|
98
|
+
optionalEl("azonosito", optionalText(input.identifier)),
|
|
99
|
+
el("mennyiseg", amounts.quantity),
|
|
100
|
+
el("mennyisegiEgyseg", optionalText(input.unit) ?? unit),
|
|
101
|
+
el("nettoEgysegar", amounts.netUnitPrice),
|
|
102
|
+
el("afakulcs", String(item.vat)),
|
|
103
|
+
el("netto", formatAmount(amounts.netAmount, currency, MONEY_DECIMALS)),
|
|
104
|
+
el("afa", formatAmount(amounts.vatAmount, currency, MONEY_DECIMALS)),
|
|
105
|
+
el("brutto", formatAmount(amounts.grossAmount, currency, 0)),
|
|
106
|
+
ledger && optionalEl("fokonyv", [optionalEl("arbevetel", optionalText(ledger.revenue)), optionalEl("afa", optionalText(ledger.vat))]),
|
|
107
|
+
optionalEl("megjegyzes", optionalText(input.comment)),
|
|
108
|
+
optionalEl("torloKod", input.dataDeletionCode)
|
|
109
|
+
]);
|
|
110
|
+
}
|
|
111
|
+
function paymentNodes(payments, items) {
|
|
112
|
+
if (payments === void 0 || payments.length === 0) return void 0;
|
|
113
|
+
const nodes = payments.map((payment, index) => {
|
|
114
|
+
const method = requireText(payment.method, `A(z) ${index + 1}. kifizetés fizetési eszköze (method) kötelező.`);
|
|
115
|
+
if (!Number.isFinite(payment.amount)) throw receiptValidationError(`A(z) ${index + 1}. kifizetés összege nem érvényes szám.`);
|
|
116
|
+
return el("kifizetes", [
|
|
117
|
+
el("fizetoeszkoz", method),
|
|
118
|
+
el("osszeg", payment.amount),
|
|
119
|
+
optionalEl("leiras", optionalText(payment.description))
|
|
120
|
+
]);
|
|
121
|
+
});
|
|
122
|
+
const paid = roundMoney(payments.reduce((sum, payment) => sum + payment.amount, 0), MONEY_DECIMALS);
|
|
123
|
+
const gross = roundMoney(items.reduce((sum, item) => sum + item.amounts.grossAmount, 0), MONEY_DECIMALS);
|
|
124
|
+
if (paid !== gross) throw receiptValidationError(`A kifizetések összege (${paid}) eltér a nyugta bruttó végösszegétől (${gross}) (340).`);
|
|
125
|
+
return el("kifizetesek", nodes);
|
|
126
|
+
}
|
|
127
|
+
function resolvePrefix(value) {
|
|
128
|
+
const prefix = requireText(value, "Add meg a nyugta előtagját (prefix) a hívásban vagy a receipts alapbeállításaiban.");
|
|
129
|
+
if (!PREFIX_PATTERN.test(prefix)) throw receiptValidationError(`A nyugta előtag csak nagybetűt és számot tartalmazhat, kapott: ${prefix} (337).`);
|
|
130
|
+
return prefix;
|
|
131
|
+
}
|
|
132
|
+
function resolveExchange(currency, rate, bank) {
|
|
133
|
+
if (isHuf(currency)) return {
|
|
134
|
+
rate: void 0,
|
|
135
|
+
bank: void 0
|
|
136
|
+
};
|
|
137
|
+
if (rate === void 0 || !Number.isFinite(rate) || rate <= 0) throw receiptValidationError(`Devizás nyugtánál (${currency}) add meg az árfolyamot (exchangeRate) pozitív számként.`);
|
|
138
|
+
return {
|
|
139
|
+
rate,
|
|
140
|
+
bank: requireText(bank, `Devizás nyugtánál (${currency}) add meg az árfolyamot jegyző bankot (exchangeBank).`)
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function buildCreateReceiptXml(credentials, defaults, input) {
|
|
144
|
+
const prefix = resolvePrefix(input.prefix ?? defaults.prefix);
|
|
145
|
+
const paymentMethod = requireText(input.paymentMethod ?? defaults.paymentMethod, "Add meg a fizetési módot (paymentMethod) a hívásban vagy a receipts alapbeállításaiban.");
|
|
146
|
+
const currency = optionalText(input.currency ?? defaults.currency) ?? DEFAULT_CURRENCY;
|
|
147
|
+
const exchange = resolveExchange(currency, input.exchangeRate ?? defaults.exchangeRate, input.exchangeBank ?? defaults.exchangeBank);
|
|
148
|
+
const template = validateTemplate(input.template ?? defaults.template);
|
|
149
|
+
const items = calculateReceiptItems(input.items ?? [], currency);
|
|
150
|
+
const unit = optionalText(defaults.unit) ?? DEFAULT_UNIT;
|
|
151
|
+
const payments = paymentNodes(input.payments, items);
|
|
152
|
+
const downloadPdf = input.downloadPdf ?? defaults.downloadPdf ?? true;
|
|
153
|
+
return buildXmlDocument({
|
|
154
|
+
root: "xmlnyugtacreate",
|
|
155
|
+
namespace: CREATE_RECEIPT_NAMESPACE,
|
|
156
|
+
schemaLocation: `${RECEIPT_XSD_BASE_URL}nyugtacreate/xmlnyugtacreate.xsd`,
|
|
157
|
+
children: [
|
|
158
|
+
el("beallitasok", [...credentials, el("pdfLetoltes", downloadPdf)]),
|
|
159
|
+
el("fejlec", [
|
|
160
|
+
optionalEl("hivasAzonosito", optionalText(input.callId)),
|
|
161
|
+
el("elotag", prefix),
|
|
162
|
+
el("fizmod", paymentMethod),
|
|
163
|
+
el("penznem", currency),
|
|
164
|
+
optionalEl("devizaarf", exchange.rate),
|
|
165
|
+
optionalEl("devizabank", exchange.bank),
|
|
166
|
+
optionalEl("megjegyzes", optionalText(input.comment)),
|
|
167
|
+
optionalEl("pdfSablon", template),
|
|
168
|
+
optionalEl("fokonyvVevo", optionalText(input.customerLedgerId ?? defaults.customerLedgerId)),
|
|
169
|
+
optionalEl("rendelesSzam", optionalText(input.orderNumber))
|
|
170
|
+
]),
|
|
171
|
+
el("tetelek", items.map((item) => itemNode(item, currency, unit))),
|
|
172
|
+
payments
|
|
173
|
+
]
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
const DUPLICATE_CALL_ID_CODE = 338;
|
|
177
|
+
function enrichDuplicateError(error, input) {
|
|
178
|
+
if (!(error instanceof SzamlazzError) || error.code !== DUPLICATE_CALL_ID_CODE) return error;
|
|
179
|
+
const lookup = input.orderNumber ? ` A meglévő nyugtát a getReceipt({ orderNumber: '${input.orderNumber}' }) hívással kérdezheted le, ha a fiókban tiltva van a rendelésszám ismétlődése.` : " A Számla Agent hívásazonosító alapján nem ad lekérdezési lehetőséget, ezért a meglévő nyugtát a Számlázz.hu felületén keresd meg, vagy adj meg rendelésszámot (orderNumber) is.";
|
|
180
|
+
return new SzamlazzError(error.message, {
|
|
181
|
+
category: "duplicate",
|
|
182
|
+
code: error.code,
|
|
183
|
+
hint: `Ezzel a hívásazonosítóval (callId: ${input.callId ?? ""}) már készült nyugta, a nyugta nem jött létre újra.${lookup}`,
|
|
184
|
+
action: error.action,
|
|
185
|
+
httpStatus: error.httpStatus,
|
|
186
|
+
rawResponse: error.rawResponse,
|
|
187
|
+
cause: error
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
async function createReceipt(ctx, defaults, input, options = {}) {
|
|
191
|
+
const xml = buildCreateReceiptXml(ctx.credentials, defaults, input);
|
|
192
|
+
try {
|
|
193
|
+
return await ctx.execute({
|
|
194
|
+
action: "createReceipt",
|
|
195
|
+
xml,
|
|
196
|
+
signal: options.signal,
|
|
197
|
+
safeToRetry: optionalText(input.callId) !== void 0
|
|
198
|
+
}, parseReceiptResponse);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
throw enrichDuplicateError(error, input);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//#endregion
|
|
204
|
+
export { optionalText as a, validateTemplate as c, RECEIPT_XSD_BASE_URL as i, RECEIPT_ONLY_VAT_CODES as l, calculateReceiptItems as n, receiptValidationError as o, createReceipt as r, requireReceiptNumber as s, buildCreateReceiptXml as t };
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
const require_errors = require("./errors-EE96_6D_.cjs");
|
|
2
|
+
const require_serialize = require("./serialize-CquIsxA-.cjs");
|
|
3
|
+
const require_parse = require("./parse-DOA2XQ3e.cjs");
|
|
4
|
+
const require_rounding = require("./rounding-TxoWy2ww.cjs");
|
|
5
|
+
const require_vat = require("./vat-g35srbNG.cjs");
|
|
6
|
+
const require_money = require("./money-K9j0wPit.cjs");
|
|
7
|
+
//#region src/receipts/types.ts
|
|
8
|
+
const RECEIPT_ONLY_VAT_CODES = [
|
|
9
|
+
"ÁKK",
|
|
10
|
+
"MAA",
|
|
11
|
+
"EU",
|
|
12
|
+
"EUK"
|
|
13
|
+
];
|
|
14
|
+
const RECEIPT_PDF_TEMPLATES = [
|
|
15
|
+
"A",
|
|
16
|
+
"N",
|
|
17
|
+
"J",
|
|
18
|
+
"L"
|
|
19
|
+
];
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/receipts/common.ts
|
|
22
|
+
const RECEIPT_XSD_BASE_URL = "https://www.szamlazz.hu/szamla/docs/xsds/";
|
|
23
|
+
function receiptValidationError(message) {
|
|
24
|
+
return new require_errors.SzamlazzError(message, { category: "validation" });
|
|
25
|
+
}
|
|
26
|
+
function requireText(value, message) {
|
|
27
|
+
const trimmed = value?.trim();
|
|
28
|
+
if (!trimmed) throw receiptValidationError(message);
|
|
29
|
+
return trimmed;
|
|
30
|
+
}
|
|
31
|
+
function optionalText(value) {
|
|
32
|
+
const trimmed = value?.trim();
|
|
33
|
+
return trimmed ? trimmed : void 0;
|
|
34
|
+
}
|
|
35
|
+
const templates = new Set(RECEIPT_PDF_TEMPLATES);
|
|
36
|
+
function validateTemplate(template) {
|
|
37
|
+
if (template === void 0) return void 0;
|
|
38
|
+
if (!templates.has(template)) throw receiptValidationError(`Ismeretlen nyugta PDF sablon: ${String(template)}. Lehetséges értékek: A (normál A4), N (80 mm), J (jegy), L (jegy logóval).`);
|
|
39
|
+
return template;
|
|
40
|
+
}
|
|
41
|
+
function requireReceiptNumber(value) {
|
|
42
|
+
return requireText(value, "Add meg a nyugtaszámot (receiptNumber).");
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/receipts/create.ts
|
|
46
|
+
const CREATE_RECEIPT_NAMESPACE = "http://www.szamlazz.hu/xmlnyugtacreate";
|
|
47
|
+
const DEFAULT_CURRENCY = "HUF";
|
|
48
|
+
const DEFAULT_UNIT = "db";
|
|
49
|
+
const PREFIX_PATTERN = /^[A-Z0-9]+$/;
|
|
50
|
+
const AMOUNT_TOLERANCE = 2;
|
|
51
|
+
const MONEY_DECIMALS = 2;
|
|
52
|
+
const receiptOnlyVatCodes = new Set(RECEIPT_ONLY_VAT_CODES);
|
|
53
|
+
function calculateItem(item, currency, index) {
|
|
54
|
+
const vat = typeof item.vat === "string" && receiptOnlyVatCodes.has(item.vat) ? 0 : item.vat;
|
|
55
|
+
try {
|
|
56
|
+
return require_money.calculateReceiptItem({
|
|
57
|
+
...item,
|
|
58
|
+
vat
|
|
59
|
+
}, currency);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (!(error instanceof require_errors.SzamlazzError)) throw error;
|
|
62
|
+
throw receiptValidationError(`${index + 1}. tétel (${item.name}): ${error.message}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function assertHufAmounts(amounts, label, vat) {
|
|
66
|
+
if (!Number.isInteger(amounts.grossAmount)) throw receiptValidationError(`${label}: forintos nyugtán a bruttó összegnek egész számnak kell lennie (363).`);
|
|
67
|
+
if (require_rounding.decimalPlaces(amounts.netAmount) > MONEY_DECIMALS) throw receiptValidationError(`${label}: forintos nyugtán a nettó összeg legfeljebb 2 tizedesjegyet tartalmazhat (364).`);
|
|
68
|
+
if (require_rounding.decimalPlaces(amounts.vatAmount) > MONEY_DECIMALS) throw receiptValidationError(`${label}: forintos nyugtán az áfa összeg legfeljebb 2 tizedesjegyet tartalmazhat (365).`);
|
|
69
|
+
if (require_rounding.roundMoney(amounts.netAmount + amounts.vatAmount, MONEY_DECIMALS) !== amounts.grossAmount) throw receiptValidationError(`${label}: a nettó és az áfa összegének pontosan ki kell adnia a bruttót (261).`);
|
|
70
|
+
if (Math.abs(amounts.netUnitPrice * amounts.quantity - amounts.netAmount) > AMOUNT_TOLERANCE) throw receiptValidationError(`${label}: a nettó egységár és a mennyiség szorzata nem egyezik a nettó összeggel (259).`);
|
|
71
|
+
const expectedVat = amounts.netAmount * require_vat.vatPercentage(vat) / 100;
|
|
72
|
+
if (Math.abs(expectedVat - amounts.vatAmount) > AMOUNT_TOLERANCE) throw receiptValidationError(`${label}: az áfa összeg nem egyezik a nettó összeg és az áfakulcs szorzatával (260).`);
|
|
73
|
+
}
|
|
74
|
+
function calculateReceiptItems(items, currency) {
|
|
75
|
+
if (items.length === 0) throw receiptValidationError("A nyugtán legalább egy tételnek szerepelnie kell.");
|
|
76
|
+
return items.map((input, index) => {
|
|
77
|
+
requireText(input.name, `A(z) ${index + 1}. tétel megnevezése (name) kötelező.`);
|
|
78
|
+
const amounts = calculateItem(input, currency, index);
|
|
79
|
+
if (require_vat.isHuf(currency)) assertHufAmounts(amounts, `${index + 1}. tétel (${input.name})`, input.vat);
|
|
80
|
+
if (input.dataDeletionCode !== void 0) {
|
|
81
|
+
if (!Number.isInteger(input.dataDeletionCode) || input.dataDeletionCode < 0) throw receiptValidationError(`A(z) ${index + 1}. tétel adattörlő kódja (dataDeletionCode) nemnegatív egész szám legyen.`);
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
input,
|
|
85
|
+
amounts,
|
|
86
|
+
vat: input.vat
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function formatAmount(value, currency, decimals) {
|
|
91
|
+
return require_vat.isHuf(currency) ? value.toFixed(decimals) : value;
|
|
92
|
+
}
|
|
93
|
+
function itemNode(item, currency, unit) {
|
|
94
|
+
const { input, amounts } = item;
|
|
95
|
+
const ledger = input.ledger;
|
|
96
|
+
return require_serialize.el("tetel", [
|
|
97
|
+
require_serialize.el("megnevezes", input.name.trim()),
|
|
98
|
+
require_serialize.optionalEl("azonosito", optionalText(input.identifier)),
|
|
99
|
+
require_serialize.el("mennyiseg", amounts.quantity),
|
|
100
|
+
require_serialize.el("mennyisegiEgyseg", optionalText(input.unit) ?? unit),
|
|
101
|
+
require_serialize.el("nettoEgysegar", amounts.netUnitPrice),
|
|
102
|
+
require_serialize.el("afakulcs", String(item.vat)),
|
|
103
|
+
require_serialize.el("netto", formatAmount(amounts.netAmount, currency, MONEY_DECIMALS)),
|
|
104
|
+
require_serialize.el("afa", formatAmount(amounts.vatAmount, currency, MONEY_DECIMALS)),
|
|
105
|
+
require_serialize.el("brutto", formatAmount(amounts.grossAmount, currency, 0)),
|
|
106
|
+
ledger && require_serialize.optionalEl("fokonyv", [require_serialize.optionalEl("arbevetel", optionalText(ledger.revenue)), require_serialize.optionalEl("afa", optionalText(ledger.vat))]),
|
|
107
|
+
require_serialize.optionalEl("megjegyzes", optionalText(input.comment)),
|
|
108
|
+
require_serialize.optionalEl("torloKod", input.dataDeletionCode)
|
|
109
|
+
]);
|
|
110
|
+
}
|
|
111
|
+
function paymentNodes(payments, items) {
|
|
112
|
+
if (payments === void 0 || payments.length === 0) return void 0;
|
|
113
|
+
const nodes = payments.map((payment, index) => {
|
|
114
|
+
const method = requireText(payment.method, `A(z) ${index + 1}. kifizetés fizetési eszköze (method) kötelező.`);
|
|
115
|
+
if (!Number.isFinite(payment.amount)) throw receiptValidationError(`A(z) ${index + 1}. kifizetés összege nem érvényes szám.`);
|
|
116
|
+
return require_serialize.el("kifizetes", [
|
|
117
|
+
require_serialize.el("fizetoeszkoz", method),
|
|
118
|
+
require_serialize.el("osszeg", payment.amount),
|
|
119
|
+
require_serialize.optionalEl("leiras", optionalText(payment.description))
|
|
120
|
+
]);
|
|
121
|
+
});
|
|
122
|
+
const paid = require_rounding.roundMoney(payments.reduce((sum, payment) => sum + payment.amount, 0), MONEY_DECIMALS);
|
|
123
|
+
const gross = require_rounding.roundMoney(items.reduce((sum, item) => sum + item.amounts.grossAmount, 0), MONEY_DECIMALS);
|
|
124
|
+
if (paid !== gross) throw receiptValidationError(`A kifizetések összege (${paid}) eltér a nyugta bruttó végösszegétől (${gross}) (340).`);
|
|
125
|
+
return require_serialize.el("kifizetesek", nodes);
|
|
126
|
+
}
|
|
127
|
+
function resolvePrefix(value) {
|
|
128
|
+
const prefix = requireText(value, "Add meg a nyugta előtagját (prefix) a hívásban vagy a receipts alapbeállításaiban.");
|
|
129
|
+
if (!PREFIX_PATTERN.test(prefix)) throw receiptValidationError(`A nyugta előtag csak nagybetűt és számot tartalmazhat, kapott: ${prefix} (337).`);
|
|
130
|
+
return prefix;
|
|
131
|
+
}
|
|
132
|
+
function resolveExchange(currency, rate, bank) {
|
|
133
|
+
if (require_vat.isHuf(currency)) return {
|
|
134
|
+
rate: void 0,
|
|
135
|
+
bank: void 0
|
|
136
|
+
};
|
|
137
|
+
if (rate === void 0 || !Number.isFinite(rate) || rate <= 0) throw receiptValidationError(`Devizás nyugtánál (${currency}) add meg az árfolyamot (exchangeRate) pozitív számként.`);
|
|
138
|
+
return {
|
|
139
|
+
rate,
|
|
140
|
+
bank: requireText(bank, `Devizás nyugtánál (${currency}) add meg az árfolyamot jegyző bankot (exchangeBank).`)
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function buildCreateReceiptXml(credentials, defaults, input) {
|
|
144
|
+
const prefix = resolvePrefix(input.prefix ?? defaults.prefix);
|
|
145
|
+
const paymentMethod = requireText(input.paymentMethod ?? defaults.paymentMethod, "Add meg a fizetési módot (paymentMethod) a hívásban vagy a receipts alapbeállításaiban.");
|
|
146
|
+
const currency = optionalText(input.currency ?? defaults.currency) ?? DEFAULT_CURRENCY;
|
|
147
|
+
const exchange = resolveExchange(currency, input.exchangeRate ?? defaults.exchangeRate, input.exchangeBank ?? defaults.exchangeBank);
|
|
148
|
+
const template = validateTemplate(input.template ?? defaults.template);
|
|
149
|
+
const items = calculateReceiptItems(input.items ?? [], currency);
|
|
150
|
+
const unit = optionalText(defaults.unit) ?? DEFAULT_UNIT;
|
|
151
|
+
const payments = paymentNodes(input.payments, items);
|
|
152
|
+
const downloadPdf = input.downloadPdf ?? defaults.downloadPdf ?? true;
|
|
153
|
+
return require_serialize.buildXmlDocument({
|
|
154
|
+
root: "xmlnyugtacreate",
|
|
155
|
+
namespace: CREATE_RECEIPT_NAMESPACE,
|
|
156
|
+
schemaLocation: `${RECEIPT_XSD_BASE_URL}nyugtacreate/xmlnyugtacreate.xsd`,
|
|
157
|
+
children: [
|
|
158
|
+
require_serialize.el("beallitasok", [...credentials, require_serialize.el("pdfLetoltes", downloadPdf)]),
|
|
159
|
+
require_serialize.el("fejlec", [
|
|
160
|
+
require_serialize.optionalEl("hivasAzonosito", optionalText(input.callId)),
|
|
161
|
+
require_serialize.el("elotag", prefix),
|
|
162
|
+
require_serialize.el("fizmod", paymentMethod),
|
|
163
|
+
require_serialize.el("penznem", currency),
|
|
164
|
+
require_serialize.optionalEl("devizaarf", exchange.rate),
|
|
165
|
+
require_serialize.optionalEl("devizabank", exchange.bank),
|
|
166
|
+
require_serialize.optionalEl("megjegyzes", optionalText(input.comment)),
|
|
167
|
+
require_serialize.optionalEl("pdfSablon", template),
|
|
168
|
+
require_serialize.optionalEl("fokonyvVevo", optionalText(input.customerLedgerId ?? defaults.customerLedgerId)),
|
|
169
|
+
require_serialize.optionalEl("rendelesSzam", optionalText(input.orderNumber))
|
|
170
|
+
]),
|
|
171
|
+
require_serialize.el("tetelek", items.map((item) => itemNode(item, currency, unit))),
|
|
172
|
+
payments
|
|
173
|
+
]
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
const DUPLICATE_CALL_ID_CODE = 338;
|
|
177
|
+
function enrichDuplicateError(error, input) {
|
|
178
|
+
if (!(error instanceof require_errors.SzamlazzError) || error.code !== DUPLICATE_CALL_ID_CODE) return error;
|
|
179
|
+
const lookup = input.orderNumber ? ` A meglévő nyugtát a getReceipt({ orderNumber: '${input.orderNumber}' }) hívással kérdezheted le, ha a fiókban tiltva van a rendelésszám ismétlődése.` : " A Számla Agent hívásazonosító alapján nem ad lekérdezési lehetőséget, ezért a meglévő nyugtát a Számlázz.hu felületén keresd meg, vagy adj meg rendelésszámot (orderNumber) is.";
|
|
180
|
+
return new require_errors.SzamlazzError(error.message, {
|
|
181
|
+
category: "duplicate",
|
|
182
|
+
code: error.code,
|
|
183
|
+
hint: `Ezzel a hívásazonosítóval (callId: ${input.callId ?? ""}) már készült nyugta, a nyugta nem jött létre újra.${lookup}`,
|
|
184
|
+
action: error.action,
|
|
185
|
+
httpStatus: error.httpStatus,
|
|
186
|
+
rawResponse: error.rawResponse,
|
|
187
|
+
cause: error
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
async function createReceipt(ctx, defaults, input, options = {}) {
|
|
191
|
+
const xml = buildCreateReceiptXml(ctx.credentials, defaults, input);
|
|
192
|
+
try {
|
|
193
|
+
return await ctx.execute({
|
|
194
|
+
action: "createReceipt",
|
|
195
|
+
xml,
|
|
196
|
+
signal: options.signal,
|
|
197
|
+
safeToRetry: optionalText(input.callId) !== void 0
|
|
198
|
+
}, require_parse.parseReceiptResponse);
|
|
199
|
+
} catch (error) {
|
|
200
|
+
throw enrichDuplicateError(error, input);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//#endregion
|
|
204
|
+
Object.defineProperty(exports, "RECEIPT_ONLY_VAT_CODES", {
|
|
205
|
+
enumerable: true,
|
|
206
|
+
get: function() {
|
|
207
|
+
return RECEIPT_ONLY_VAT_CODES;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
Object.defineProperty(exports, "RECEIPT_XSD_BASE_URL", {
|
|
211
|
+
enumerable: true,
|
|
212
|
+
get: function() {
|
|
213
|
+
return RECEIPT_XSD_BASE_URL;
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
Object.defineProperty(exports, "buildCreateReceiptXml", {
|
|
217
|
+
enumerable: true,
|
|
218
|
+
get: function() {
|
|
219
|
+
return buildCreateReceiptXml;
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
Object.defineProperty(exports, "calculateReceiptItems", {
|
|
223
|
+
enumerable: true,
|
|
224
|
+
get: function() {
|
|
225
|
+
return calculateReceiptItems;
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
Object.defineProperty(exports, "createReceipt", {
|
|
229
|
+
enumerable: true,
|
|
230
|
+
get: function() {
|
|
231
|
+
return createReceipt;
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
Object.defineProperty(exports, "optionalText", {
|
|
235
|
+
enumerable: true,
|
|
236
|
+
get: function() {
|
|
237
|
+
return optionalText;
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
Object.defineProperty(exports, "receiptValidationError", {
|
|
241
|
+
enumerable: true,
|
|
242
|
+
get: function() {
|
|
243
|
+
return receiptValidationError;
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
Object.defineProperty(exports, "requireReceiptNumber", {
|
|
247
|
+
enumerable: true,
|
|
248
|
+
get: function() {
|
|
249
|
+
return requireReceiptNumber;
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
Object.defineProperty(exports, "validateTemplate", {
|
|
253
|
+
enumerable: true,
|
|
254
|
+
get: function() {
|
|
255
|
+
return validateTemplate;
|
|
256
|
+
}
|
|
257
|
+
});
|