UNPKG

nav-connect

Version:
249 lines 11 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.xmlParser = exports.XsdSchema = void 0; const path_1 = __importStar(require("path")); const axios_1 = __importDefault(require("axios")); const crypto = __importStar(require("crypto")); const libxmljs = __importStar(require("libxmljs2")); const fast_xml_parser_1 = require("fast-xml-parser"); const fs_1 = require("fs"); const xmlParser_1 = require("./xmlParser"); var XsdSchema; (function (XsdSchema) { XsdSchema["InvoiceBase"] = "invoiceBase"; XsdSchema["InvoiceApi"] = "invoiceApi"; XsdSchema["Common"] = "common"; XsdSchema["Data"] = "data"; })(XsdSchema || (exports.XsdSchema = XsdSchema = {})); var xmlParser_2 = require("./xmlParser"); Object.defineProperty(exports, "xmlParser", { enumerable: true, get: function () { return xmlParser_2.xmlParser; } }); class NavConnect { constructor(config) { this._requestCounter = 0; this._config = config; //random vmi this._requestIdPrefix = ((Date.now() + Number(config.taxNumber)) >> 2).toString(36).slice(-3).toUpperCase(); this._baseUrl = this._config.testSystem ? "https://api-test.onlineszamla.nav.gov.hu/invoiceService/v3/" : "https://api.onlineszamla.nav.gov.hu/invoiceService/v3"; this._schemaDir = path_1.default.resolve(__dirname, "..", "OSA", "xsd"); this.xsdDocs = new Map(); // Az XSD könyvtár tartalmának beolvasása const xsdFiles = (0, fs_1.readdirSync)(this._schemaDir) .filter((file) => file.endsWith(".xsd")) .map((file) => path_1.default.join(this._schemaDir, file)); // XSD-k betöltése for (const xsdPath of xsdFiles) { try { const xsdBuffer = (0, fs_1.readFileSync)(xsdPath); const baseUrl = (0, path_1.dirname)(xsdPath); // Fájlnév kinyerése és konvertálása enum-má const schemaName = path_1.default.basename(xsdPath, '.xsd'); const schemaType = Object.values(XsdSchema).find(value => value === schemaName); if (!schemaType) { throw new Error(`Invalid schema name: ${schemaName}`); } const xsdDoc = libxmljs.parseXml(xsdBuffer.toString(), { baseUrl, noblanks: true, nonet: true, huge: true, }); this.xsdDocs.set(schemaType, xsdDoc); } catch (error) { console.error(`Failed to load XSD from ${xsdPath}:`, error); throw error; } } const xmlBuilderOptions = { attributeNamePrefix: "@_", textNodeName: "#text", ignoreAttributes: false, format: true, indentBy: "\t", suppressEmptyNode: false, }; this._builder = new fast_xml_parser_1.XMLBuilder(xmlBuilderOptions); } addNamespacePrefix(obj, prefix) { if (typeof obj !== "object" || obj === null) { return obj; } const result = {}; for (const [key, value] of Object.entries(obj)) { // Ha már van prefix a kulcsban vagy speciális kulcs, ne módosítsuk if (key.includes(":") || key.startsWith("@_") || key === "#text") { result[key] = value; continue; } const newKey = `${prefix}:${key}`; result[newKey] = typeof value === "object" ? this.addNamespacePrefix(value, prefix) : value; } return result; } getRequestId() { this._requestCounter++; return this._requestIdPrefix + "+" + Date.now().toString(36) + "+" + this._requestCounter.toString(36); } getTimestamp() { return new Date().toISOString(); } sha512(msg) { return crypto.createHash("sha512").update(msg).digest("hex").toUpperCase(); } sha3_512(msg) { return crypto.createHash("sha3-512").update(msg).digest("hex").toUpperCase(); } formatNavTimestampForHash(isoTs) { const d = new Date(isoTs); const pad = (n) => n.toString().padStart(2, "0"); return (d.getUTCFullYear().toString() + pad(d.getUTCMonth() + 1) + pad(d.getUTCDate()) + pad(d.getUTCHours()) + pad(d.getUTCMinutes()) + pad(d.getUTCSeconds())); } createBasicOnlineInvoiceRequest() { const request_id = this.getRequestId(); const timestamp = this.getTimestamp(); const navTimestampForHash = this.formatNavTimestampForHash(timestamp); const basicRequest = () => { return this.addNamespacePrefix({ "@_xmlns": "http://schemas.nav.gov.hu/OSA/3.0/api", "@_xmlns:common": "http://schemas.nav.gov.hu/NTCA/1.0/common", header: { requestId: request_id, timestamp: timestamp, requestVersion: "3.0", headerVersion: "1.0", }, user: { login: this._config.technicalUser.user, passwordHash: { "@_cryptoType": "SHA-512", "#text": this.sha512(this._config.technicalUser.password), }, taxNumber: this._config.taxNumber, requestSignature: { "@_cryptoType": "SHA3-512", "#text": this.sha3_512(request_id + navTimestampForHash + this._config.technicalUser.signatureKey), }, }, }, "common"); }; return Object.assign(Object.assign({}, basicRequest()), { software: { softwareId: this._config.software.softwareId, softwareName: this._config.software.softwareName, softwareOperation: this._config.software.softwareOperation, softwareMainVersion: this._config.software.softwareMainVersion, softwareDevName: this._config.software.softwareDevName, softwareDevContact: this._config.software.softwareDevContact, softwareDevCountryCode: this._config.software.softwareDevCountryCode, softwareDevTaxNumber: this._config.software.softwareDevTaxNumber, } }); } async generateAndValidateXml(requestType, data, schemaType) { try { const xsdDoc = this.xsdDocs.get(schemaType); if (!xsdDoc) { throw new Error(`XSD schema not found for xsdDocs: ${schemaType}`); } const xml = this._builder.build({ [requestType]: data, }); const xmlDoc = libxmljs.parseXml(xml, { noblanks: true, nonet: true, }); // console.log(xml); const isValid = xmlDoc.validate(xsdDoc); if (!isValid) { const errors = xmlDoc.validationErrors.map((error) => error.message); throw new Error(`[${new Date().toISOString()}] XML validation failed for ${requestType}:\n${errors.join("\n")}`); } return xml; } catch (error) { console.error(`[${new Date().toISOString()}] Error in generateAndValidateXml for ${requestType}:`, error); throw error; } } async queryInvoiceDigest(params) { const reqObj = Object.assign(Object.assign({}, this.createBasicOnlineInvoiceRequest()), { page: params.page, invoiceDirection: params.invoiceDirectionType, invoiceQueryParams: { mandatoryQueryParams: { insDate: params.insDate, }, } }); try { const requestXml = await this.generateAndValidateXml("QueryInvoiceDigestRequest", reqObj, XsdSchema.InvoiceApi); const response = await axios_1.default.post(this._baseUrl + "/queryInvoiceDigest", requestXml, { headers: { "Content-Type": "application/xml" }, }); const result = await (0, xmlParser_1.xmlParser)(response.data); return result.QueryInvoiceDigestResponse; } catch (error) { console.error("Query invoice digest error:", error); throw error; } } async queryInvoiceData(params) { const reqObj = Object.assign(Object.assign({}, this.createBasicOnlineInvoiceRequest()), { invoiceNumberQuery: { invoiceNumber: params.invoiceNumber, invoiceDirection: params.invoiceDirection, supplierTaxNumber: params.supplierTaxNumber } }); try { const requestXml = await this.generateAndValidateXml("QueryInvoiceDataRequest", reqObj, XsdSchema.InvoiceApi); const response = await axios_1.default.post(this._baseUrl + "/queryInvoiceData", requestXml, { headers: { "Content-Type": "application/xml" }, }); const result = await (0, xmlParser_1.xmlParser)(response.data); return result.QueryInvoiceDataResponse; } catch (error) { console.error("Query invoice data error:", error); throw error; } } } exports.default = NavConnect; //# sourceMappingURL=index.js.map