nav-connect
Version:
Nav Online Invoice client
249 lines • 11 kB
JavaScript
;
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