From 5410aa4fb4b3a31bb9a2965b62bc54129acbd9a8 Mon Sep 17 00:00:00 2001 From: boa604 Date: Wed, 5 Aug 2026 11:53:42 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A6=D0=98=D0=A2=D0=9A-1081.=20=D0=94=D0=BE?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0=20=D0=BE=D0=B1=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8=20=D0=B7=D0=B0=D0=BF=D1=80?= =?UTF-8?q?=D0=BE=D1=81=D0=BE=D0=B2=20=D1=80=D0=B0=D1=81=D1=88=D0=B8=D1=80?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20"=D0=9E=D0=BF=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D1=82=D0=B8=D0=B2=D0=BD=D1=8B=D0=B9=20=D1=83=D1=87=D0=B5=D1=82?= =?UTF-8?q?"=20-=20=D0=BA=D0=BE=D0=B4=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D1=8C=D1=81=D0=BA=D0=BE=D0=B9=20=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=BE=D0=BA=D0=B8=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/pws.js | 45 ++------------------------ modules/rcmn.js | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 42 deletions(-) create mode 100644 modules/rcmn.js diff --git a/modules/pws.js b/modules/pws.js index 0598dcc..8c3d44f 100644 --- a/modules/pws.js +++ b/modules/pws.js @@ -9,6 +9,7 @@ const xml2js = require("xml2js"); //Конвертация XML в JSON и JSON в XML const { deepClone } = require("../core/utils"); //Вспомогательные функции +const { isRCMNRequest, prepareRCMNRequestForXml } = require("./rcmn"); //Оперативный учёт (RCMN) //--------------------- // Глобальные константы @@ -27,15 +28,6 @@ const SQUERY_RESP_CT = "SRESP_CT"; //Параметр URL-запроса для //Коды функций-обработчиков (согласно настройкам "Сервисов обмена") const SFNC_UPLOAD = "Upload"; //Функция загрузки -//Имена узлов/аргументов PWS-запроса -const SNODE_XREQUEST = "XREQUEST"; //Корневой узел запроса -const SNODE_XPAYLOAD = "XPAYLOAD"; //Полезная нагрузка запроса -const SNODE_XARGUMENTS = "XARGUMENTS"; //Коллекция аргументов -const SNODE_XARGUMENT = "XARGUMENT"; //Элемент аргумента -const SNODE_SNAME = "SNAME"; //Имя аргумента -const SNODE_VALUE = "VALUE"; //Значение аргумента -const SARG_SSEARCH = "SSEARCH"; //Аргумент строки поиска - //------------ // Тело модуля //------------ @@ -78,38 +70,6 @@ const converXMLArraysToJSON = (obj, arrayKey) => { } }; -//Кодирование строки в Base64 (UTF-8) -const encodeBase64Utf8 = sValue => Buffer.from(sValue, "utf8").toString("base64"); - -//Получение полезной нагрузки запроса -const getRequestPayload = request => { - if (!request || typeof request !== "object") return null; - const xRequest = request[SNODE_XREQUEST]; - if (!xRequest || typeof xRequest !== "object") return null; - const xPayload = xRequest[SNODE_XPAYLOAD]; - if (!xPayload || typeof xPayload !== "object") return null; - return xPayload; -}; - -//Подготовка JSON-запроса перед конвертацией в XML -const prepareRequestForXml = request => { - //Получим полезную нагрузку запроса - const xPayload = getRequestPayload(request); - if (!xPayload) return request; - //Получим коллекцию аргументов - const xArguments = xPayload[SNODE_XARGUMENTS]; - if (!Array.isArray(xArguments)) return request; - //Обработаем аргументы - for (let i = 0; i < xArguments.length; i++) { - const item = xArguments[i]; - const arg = item && (item[SNODE_XARGUMENT] || item); - if (!arg || typeof arg !== "object" || arg[SNODE_SNAME] !== SARG_SSEARCH) continue; - if (arg[SNODE_VALUE] === undefined || arg[SNODE_VALUE] === null) continue; - arg[SNODE_VALUE] = encodeBase64Utf8(arg[SNODE_VALUE]); - } - return request; -}; - //Обработчик "До" для полученного сообщения const before = async prms => { //Если пришел запрос в JSON @@ -118,7 +78,8 @@ const before = async prms => { let requestXML = ""; try { let request = JSON.parse(prms.queue.blMsg.toString()); - request = prepareRequestForXml(request); + //Если запрос относится к расширению "Оперативный учёт" - подготовим его + if (isRCMNRequest(request)) request = prepareRCMNRequestForXml(request); let builder = new xml2js.Builder(); requestXML = builder.buildObject(request); } catch (e) { diff --git a/modules/rcmn.js b/modules/rcmn.js new file mode 100644 index 0000000..1b24751 --- /dev/null +++ b/modules/rcmn.js @@ -0,0 +1,85 @@ +/* + Сервис интеграции ПП Парус 8 с WEB API + Дополнительный модуль: Оперативный учёт (RCMN) +*/ + +//--------------------- +// Глобальные константы +//--------------------- + +//Имена узлов/аргументов PWS-запроса +const SNODE_XREQUEST = "XREQUEST"; //Корневой узел запроса +const SNODE_XPAYLOAD = "XPAYLOAD"; //Полезная нагрузка запроса +const SNODE_XARGUMENTS = "XARGUMENTS"; //Коллекция аргументов +const SNODE_XARGUMENT = "XARGUMENT"; //Элемент аргумента +const SNODE_SNAME = "SNAME"; //Имя аргумента +const SNODE_VALUE = "VALUE"; //Значение аргумента +const SNODE_SSTORED = "SSTORED"; //Имя вызываемой хранимой процедуры +const SARG_SSEARCH = "SSEARCH"; //Аргумент строки поиска + +//Пакет и хранимые процедуры расширения "Оперативный учёт" +const SPACKAGE_RCMN = "PKG_EXS_EXT_RCMN"; //Пакет расширения +const SSTORED_CLASSES_GET = "PKG_EXS_EXT_RCMN.CLASSES_GET"; //Получение списка классов +const SSTORED_OBJECTS_GET = "PKG_EXS_EXT_RCMN.OBJECTS_GET"; //Получение списка объектов +const SSTORED_DICT_RECS_GET = "PKG_EXS_EXT_RCMN.DICT_RECS_GET"; //Получение данных словаря +const RSTORED_SSEARCH_BASE64 = [SSTORED_CLASSES_GET, SSTORED_OBJECTS_GET, SSTORED_DICT_RECS_GET]; //Процедуры, для которых SSEARCH кодируется в Base64 + +//------------ +// Тело модуля +//------------ + +//Кодирование строки в Base64 (UTF-8) +const encodeBase64Utf8 = sValue => Buffer.from(sValue, "utf8").toString("base64"); + +//Получение полезной нагрузки запроса +const getRequestPayload = request => { + if (!request || typeof request !== "object") return null; + const xRequest = request[SNODE_XREQUEST]; + if (!xRequest || typeof xRequest !== "object") return null; + const xPayload = xRequest[SNODE_XPAYLOAD]; + if (!xPayload || typeof xPayload !== "object") return null; + return xPayload; +}; + +//Получение имени хранимой процедуры из запроса +const getRequestStored = request => { + const xPayload = getRequestPayload(request); + if (!xPayload) return null; + const sStored = xPayload[SNODE_SSTORED]; + return typeof sStored === "string" ? sStored : null; +}; + +//Проверка, что запрос относится к пакету расширения "Оперативный учёт" +const isRCMNRequest = request => { + const sStored = getRequestStored(request); + if (!sStored) return false; + return sStored === SPACKAGE_RCMN || sStored.startsWith(SPACKAGE_RCMN + "."); +}; + +//Подготовка JSON-запроса расширения "Оперативный учёт" перед конвертацией в XML +const prepareRCMNRequestForXml = request => { + //Получим полезную нагрузку запроса + const xPayload = getRequestPayload(request); + if (!xPayload) return request; + //Проверим, что указана поддерживаемая хранимая процедура + if (RSTORED_SSEARCH_BASE64.indexOf(xPayload[SNODE_SSTORED]) < 0) return request; + //Получим коллекцию аргументов + const xArguments = xPayload[SNODE_XARGUMENTS]; + if (!Array.isArray(xArguments)) return request; + //Закодируем в Base64 значение аргумента SSEARCH (если есть) + for (let i = 0; i < xArguments.length; i++) { + const item = xArguments[i]; + const arg = item && (item[SNODE_XARGUMENT] || item); + if (!arg || typeof arg !== "object" || arg[SNODE_SNAME] !== SARG_SSEARCH) continue; + if (arg[SNODE_VALUE] === undefined || arg[SNODE_VALUE] === null) continue; + arg[SNODE_VALUE] = encodeBase64Utf8(arg[SNODE_VALUE]); + } + return request; +}; + +//----------------- +// Интерфейс модуля +//----------------- + +exports.isRCMNRequest = isRCMNRequest; +exports.prepareRCMNRequestForXml = prepareRCMNRequestForXml;