导航连接器
提供与NAV在线发票服务通信接口的Node.js模块.
本单元的开发是为了满足下列要求:
在线发票接口规格
安装
以Node.js的12.18.3版本被测试.
$ npm install @angro/nav-connector
示例
const NavConnector = require('@angro/nav-connector');
/* Your technical user's data. */
const technicalUser = {
login: 'login123',
password: 'password',
taxNumber: '12345678',
signatureKey: 'signatureKey',
exchangeKey: 'exchangeKey',
};
const softwareData = {
softwareId: '123456789123456789',
softwareName: 'string',
softwareOperation: 'LOCAL_SOFTWARE',
softwareMainVersion: 'string',
softwareDevName: 'string',
softwareDevContact: 'string',
softwareDevCountryCode: 'HU',
softwareDevTaxNumber: 'string',
};
const baseURL = 'https://api-test.onlineszamla.nav.gov.hu/invoiceService/v3/';
/* Create the nav connector interface. */
const navConnector = new NavConnector({ technicalUser, softwareData, baseURL });
(async function sendInvoice() {
try {
/* On app start You can test connection to the NAV service and user given data validity.
testConnection() will throw if a tokenExchangeRequest operation is not successful. */
await navConnector.testConnection();
/* Send invoice to the NAV service.
invoiceOperations is the InvoiceOperationListType in the specification. */
const invoiceOperations = {
compressedContent: false,
invoiceOperation: [
{
index: 1,
operation: 'CREATE',
invoice: 'invoice xml in base64 encoding',
},
],
};
const transactionId = await navConnector.manageInvoice(invoiceOperations);
/* Check previously sent invoice processing status.
processingResults is the ProcessingResultListType in the specification. */
const processingResults = await navConnector.queryTransactionStatus({
transactionId,
});
/* Check processingResults.length.
If the array is empty then transactionId was invalid. */
if (processingResults.length) {
/* Handle invoice status responses. */
}
} catch (error) {
/* Handle errors. See bellow for details. */
}
})();
API 密码
导航器
类别代表NAV在线发票数据服务规范的实施.
/**
* Create a navConnector.
* @param {Object} params Constructor params.
* @param {Object} params.technicalUser Technical user data.
* @param {Object} params.softwareData Software data.
* @param {String} [params.baseURL=https://api.onlineszamla.nav.gov.hu/invoiceService/v3/] Axios baseURL.
* @param {number} [params.timeout=70000] Axios default timeout integer in milliseconds.
*/
const navConnector = new NavConnector({ technicalUser, softwareData });
需要Axios超时选项,因为在NAV服务停用期间,如果不设置Axios超时选项,请求可能永远不会超时.
根据NAV在线发票服务文件,请求超时时间设定为服务方5000 mss
但实际上可能没有超时,或者在60秒后会有网关超时.
超时设定为在轴中为70000毫秒(70秒)作为默认.
你可以很好地调谐这个值,但它强烈建议将其保持在60秒以上,以避免掉落的响应.
const navConnector = new NavConnector({
technicalUser,
softwareData,
timeout: 70000,
});
navConnector.manage 语音( )
向NAV服务发送单张或多张发票的方法. 该方法返回业务的交易id,该id可用于以后获得这一请求的发票处理状态.
/**
* Send request to NAV service to manage invoices.
* @async
* @param {Object} invoiceOperations Request object for xml conversion and send.
* @returns {Promise<string>} Manage invoice operation transaction id.
*/
const transactionId = await navConnector.manageInvoice(invoiceOperations);
发票操作参数示例:
const invoiceOperations = {
compressedContent: false,
invoiceOperation: [
{
index: 1,
invoiceOperation: 'CREATE',
invoiceData: 'invoice xml in base64 encoding',
electronicInvoiceHash: 'SHA3-512'
},
{
index: 2,
invoiceOperation: 'STORNO',
invoiceData: 'invoice xml in base64 encoding',
},
],
};
请注意 在使用管理发票方法之前,您必须自己压缩发票.
const invoiceOperations = {
compressedContent: true,
invoiceOperation: [
{
index: 1,
invoiceOperation: 'CREATE',
invoiceData: 'compressed invoice xml in base64 encoding',
electronicInvoiceHash: 'SHA3-512'
},
],
};
navConnector.manage-Annulment () (美国英语)
向NAV服务机构发送单张或多张发票废止书的方法. 该方法返回业务的交易id,该id可用于以后获得这一请求的发票处理状态.
/**
* Send request to NAV service to manage annulment invoices.
* @async
* @param {Object} annulmentOperations Request object for xml conversion and send.
* @returns {Promise<string>} Manage invoice operation transaction id.
*/
const transactionId = await navConnector.manageAnnulment(annulmentOperations);
无效操作参数示例:
const annulmentOperations = {
annulmentOperation: [
{
index: 1,
annulmentOperation: 'ANNUL',
invoiceAnnulment: 'invoice xml in base64 encoding',
},
{
index: 2,
annulmentOperation: 'ANNUL',
invoiceAnnulment: 'invoice xml in base64 encoding',
},
],
};
navConnector.query 交易状态( )
处理以前发来发票的方法。 解析后返回值是规格的处理ResultListType.
/**
* Get the result of a previously sent manage invoice request.
* @async
* @param {Object} params Function params.
* @param {string} params.transactionId Manage invoice operation transaction id.
* @param {boolean} [params.returnOriginalRequest=false] Flag for api response to contain the original invoice.
* @returns {Promise<Array>} processingResults
*/
const processingResults = await navConnector.queryTransactionStatus({
transactionId,
returnOriginalRequest: true,
});
processingResults.forEach(processingResult => {
const {
index,
invoiceStatus,
originalRequest,
compressedContentIndicator,
businessValidationMessages,
technicalValidationMessages,
} = processingResult;
/* Property businessValidationMessages and technicalValidationMessages
are always normalized to arrays even if there were no validation messages. */
});
此函数会根据NAV服务文档在响应中键入数字和布尔键入值的转换.
navConnector.testConnection () () (中文(简体) )
测试连接、 用户认证数据和密钥有效性的方法 .
/**
* Test connection, user auth data and keys validity with a tokenExchangeRequest.
* @async
* @throws {Object} Will throw an error if there was a network expectation
* or any user given auth data or key is invalid.
*/
try {
await navConnector.testConnection();
} catch (error) {
/* Log the error. */
}
navConnector.query 语音数据( )
查询以前发出的发票的方法,发票号.
/**
* Query previously sent invoices with invoice number
* @async
* @param {Object} params Function params.
* @param {Object} params.invoiceQuery Query single invoice with invoice number.
* @returns {Promise<Object>} response
*/
按发票号码查询
const invoiceQuery = {
invoiceNumber: 'invoiceNumber',
invoiceDirection: 'OUTBOUND',
};
const response = await navConnector.queryInvoiceData({
invoiceQuery,
});
const { invoiceData, auditData, compressedContentIndicator } = response;
/* If no invoice was found with the given query then queryResult is undefined. */
if (!invoiceData) {
return;
}
const { invoiceResult, invoiceDigestList } = queryResult;
此函数会根据NAV服务文档在响应中键入数字和布尔键入值的转换.
navConnector.query 语音数据( )
以查询参数查询先前发出的发票的方法.
/**
* Query previously sent invoices with query params.
* @async
* @param {Object} params Function params.
* @param {number} params.page Integer page to query.
* @param {string} params.invoiceDirection inbound or outbound request type
* @param {Object} params.queryParams Query multiple invoices with params.
* @param {string} queryParams.dateFrom - REQUIRED valid date string to search from
* @param {string} queryParams.dateTo - REQUIRED valid date string to search to
* @param {string} queryParams.taxNumber - OPTIONAL Tax number of the invoice supplier or customer
* @param {string} queryParams.groupMemberTaxNumber - OPTIONAL Tax number of group member for the invoice supplier or customer
* @param {string} queryParams.name - OPTIONAL Left side text matching for the invoice supplier or customer search parameter
* @param {string} queryParams.invoiceCategory - OPTIONAL Invoice category type
* @param {string} queryParams.paymentMethod - OPTIONAL Payment method
* @param {string} queryParams.invoiceAppearance - OPTIONAL Appearance of the invoice
* @param {string} queryParams.source - OPTIONAL Data report source
* @param {string} queryParams.currency - OPTIONAL Invoice currency
* @param {string} queryParams.transactionId - OPTIONAL The searched transaction ID
* @param {number} queryParams.index - OPTIONAL Index of the searched invoice within the transaction
* @param {string} queryParams.invoiceOperation - OPTIONAL Invoice operation search parameter
* @returns {Promise<Object>} response
*/
按参数查询
const queryParams = {
dateFrom: '2017-12-28',
dateTo: '2017-12-28',
};
const response = await navConnector.queryInvoiceDigest({
invoiceDirection: 'OUTBOUND',
page: 1,
queryParams,
});
const { currentPage, availablePage, queryResult } = response;
/* If no invoice was found with the given query then queryResult is undefined. */
if (!queryResult) {
return;
}
const { invoiceDigestList } = queryResult;
此函数会根据NAV服务文档在响应中键入数字和布尔键入值的转换.
navConnector.query 纳税人 ()
按税号取得纳税人信息的方法.
它解决包含纳税人Validity和纳税人Data属性的对象.
考虑到纳税人Data财产如果不存在税号,国家税务局将不予退还.
/**
* Get taxpayer information by tax number.
* @param {string} taxNumber Taxpayer tax number to get information for.
* @returns {Promise<Object>} Taxpayer information with taxpayerValidity, taxpayerData, incorporation fields.
*/
const { taxpayerValidity, taxpayerData, incorporation } = await navConnector.queryTaxpayer(
'12345678'
);
if (!taxpayerValidity) {
/* Taxpayer is non existent or inactive. */
} else if (taxpayerData) {
/* The taxpayerData property was returned by the service. */
}
此函数会根据NAV服务文档在响应中为布尔键入值进行类型转换.
处理错误
所有的方法都能够抛出期望,并且你可以精细地调谐如何记录这些错误,处理这些错误或者如果可能的话重试请求.
try {
await navConnector.testConnection();
} catch (error) {
/* Axios error instance.*/
const { response, request } = error;
if (response) {
if (response.status === 504) {
/* Gateway timeout, retryable. */
} else if (response.data.result.errorCode === 'OPERATION_FAILED') {
/* Server side error, retryable. */
} else {
/* Log the error and fix the request then resend it. */
}
} else if (request) {
/* http.ClientRequest instance.
Possible network error. Retryable. */
} else {
/* Something happened in setting up the request that triggered an Error.
Log the error and try to fix the problem then resend the request. */
}
}
错误. response.data 对象总是恢复正常化为以下格式:
{
result: {
funcCode: 'funcCode',
errorCode: 'errorCode',
message: 'message',
},
technicalValidationMessages: [
{
validationResultCode: 'validationResultCode',
validationErrorCode: 'validationErrorCode',
message: 'message',
},
{
validationResultCode: 'validationResultCode',
validationErrorCode: 'validationErrorCode',
message: 'message',
},
],
}
注意属性 funcCode, 错误代码和消息可以是未定义的, 技术性的ValidationMessages 长度可以是 0, 但是 响应.数据与结果总是一个对象,技术变量总是一个阵列.
测试
复制名为的文件 .env.example 并重命名为 .env 在寄存器根中,将占位符值替换为自己的技术用户数据.
⚠️永不编辑 .env.example 并且永远不要提供敏感数据!
$ npm run test
开始
目前这些项目没有支持:
- 查问InvoiceChanDigest
- 查询发票检查
- 查询交易列表
维护者
这个寄存器由 (原始内容存档于2017-10-21). ANGRO Nagykereskedelmi Kft.