/* Сервис интеграции ПП Парус 8 с WEB API Дополнительный модуль: Интеграция с ЭДО "ДИАДОК" (DIADOC) */ //------------------------------ // Подключение внешних библиотек //------------------------------ const xml2js = require("xml2js"); //Конвертация XML в JSON и JSON в XML const _ = require("lodash"); //Работа с коллекциями и объектами const rqp = require("request-promise"); //Работа с HTTP/HTTPS запросами const config = require("../config"); //Параметры сервера const { SDDAUTH_API_CLIENT_ID, SDEPARTMENT_NAME, SDEPARTMENT_ID } = require("./diadoc_config"); //Ключ разработчика //--------------------- // Глобальные константы //--------------------- // Список тегов которые должны содержать массив const tag = [ "DocumentAttachments", "Metadata", "Signatures", "CorrectionRequests", "Receipts", "Resolutions", "XmlSignatureRejections", "RecipientTitles", "Requests" ]; //------------ // Тело модуля //------------ //формирования адреса запроса для получения данных о текущей организации пользователя const buildMyOrganizationURL = srvRoot => { return `${srvRoot.replace(/\/+$/, "")}/GetMyOrganizations`; }; //формирования адреса запроса для получения данных о организации по идентификатору ящика const buildOrganizationBoxIdURL = srvRoot => { return `${srvRoot.replace(/\/+$/, "")}/GetBox`; }; //формирования адреса запроса для получения данных о организации по ИНН/КПП const buildOrganizationURL = srvRoot => { return `${srvRoot.replace(/\/+$/, "")}/GetOrganization`; }; //формирования адреса запроса для получения данных о организации по ИНН/КПП const buildOrganizationsByInnKppURL = srvRoot => { return `${srvRoot.replace(/\/+$/, "")}/GetOrganizationsByInnKpp`; }; //Обернуть содержимое тега в массив const toArray = (obj, tags) => { for (const prop in obj) { let value = obj[prop]; if (typeof value === "object") { obj[prop] = toArray(value, tag); } if (tags.indexOf(prop) != -1 && !_.isArray(obj[prop])) { obj[prop] = JSON.parse("[" + JSON.stringify(value) + "]"); } } return obj; }; //Конвертация в XML const toXML = obj => { const builder = new xml2js.Builder(); return builder.buildObject(obj); }; //Конвертация в XML const parseXML = xmlDoc => { return new Promise((resolve, reject) => { xml2js.parseString(xmlDoc, { explicitArray: false, mergeAttrs: true }, (err, result) => { if (err) reject(err); else resolve(result); }); }); }; //Конвертация в JSON const toJSON = async obj => { let result = await parseXML(obj); result = result.root; toArray(result, tag); return result; }; //Добавление определённого количетсва часов к дате const addHours = (dDate, nHours) => { dDate.setTime(dDate.getTime() + nHours * 60 * 60 * 1000); return new Date(dDate); }; //Получение ключа разработчика по организации/принадлежности const getAPIClientId = (nCompany, nJurPers = null) => { //Ключи в diadoc_conf.js заданы if (SDDAUTH_API_CLIENT_ID) { //И это массив if (Array.isArray(SDDAUTH_API_CLIENT_ID)) { //Найдем значение в массиве let keyFound = SDDAUTH_API_CLIENT_ID.find(keyItem => keyItem.nCompany === nCompany && keyItem.nJurPers === nJurPers); //Найдено совпадение в массиве if (keyFound) return keyFound.sAPIClientId; else { //Ищем с принадлежностью по умолчанию keyFound = SDDAUTH_API_CLIENT_ID.find(keyItem => keyItem.nCompany === nCompany && !keyItem.nJurPers); //Найдено совпадение в массиве if (keyFound) return keyFound.sAPIClientId; else return null; } } else return SDDAUTH_API_CLIENT_ID; } else return null; }; //Проверка ключа разработчика const checkAPIClientId = sAPIClientId => { if (!sAPIClientId) { throw new Error('Не задан ключ разработчика. Запросите его у поставщика услуг ЭДО "ДИАДОК" и укажите в "./modules/diadoc_config.js".'); } }; //Формиорвание заголовка сообщения const buildHeaders = (sAPIClientId, sToken = null) => ({ "Content-type": "application/json", "X-Solution-Info": `PARUS_${config.common.sRelease}`, Authorization: `DiadocAuth ddauth_api_client_id=${sAPIClientId}${sToken ? `,ddauth_token=${sToken}` : ""}`, Accept: "application/json" }); //Отбор организций const getOrganizations = organizations => { //Параметры отбора let isRoaming = false; let isActive = true; //Итоговая выборка let organization = { Organizations: [] }; //Найдем активную организацию не в роуминге organization.Organizations[0] = organizations.Organizations.find(org => (org.IsRoaming === isRoaming) && (org.IsActive === isActive)); //Если не удалось получить организацию не в роуминге if (!organization.Organizations[0]) { //Если нет организации не в роуминге и найдено более одной организации if (organizations.Organizations.length > 1) { throw Error(`Найдено несколько организаций в роуминге.`); } else { //Вернем единственную найденую организацию return organizations[0]; } } else { //Вернем найденую организацию return organization; } }; //Получение организации по ИНН/КПП контрагента const getOrganization = async (sSrvRoot, headers, nInn, nKpp) => { //Параметры запроса let rqpOptions; let serverResp; //Формируем запрос для получения BoxId rqpOptions = { uri: buildOrganizationURL(sSrvRoot), qs: { inn: nInn, kpp: nKpp }, headers: headers, json: true }; //Выполним запрос serverResp = { Organizations: [await rqp(rqpOptions)] }; return serverResp; }; //Получение ящика организации по ИНН/КПП контрагента const getOrganizationBoxId = async (sSrvRoot, headers, nInn, nKpp) => { //Параметры запроса let rqpOptions; let serverResp; let organization = {}; //Формируем запрос для получения BoxId по ИНН/КПП rqpOptions = { uri: buildOrganizationsByInnKppURL(sSrvRoot), qs: { inn: nInn, kpp: nKpp }, headers: headers, json: true }; try { //Выполним запрос serverResp = await rqp(rqpOptions); try { //Получим организацию не в роуминге (или единственную организацию в роуминге) serverResp = getOrganizations(serverResp); if (!serverResp?.Organizations[0]) { throw Error(`Не удалось получить ящик получателя для контрагента с ИНН: ${nInn} и КПП: ${nKpp}`); } } catch (e) { //Получим головную организацию по ИНН/КПП serverResp = await getOrganization(sSrvRoot, headers, nInn, nKpp); }; //Проверим соответствие КПП организации if ((serverResp?.Organizations[0]?.Kpp != nKpp) && (serverResp?.Organizations[0])) { //Если КПП не соответстует заданному - проверим, что в полученной организации есть департамент с заданным КПП for (let i in serverResp.Organizations[0].Departments) { //Если найден подходящий департамент - запомним идентификатор и выходим из цикла if (serverResp.Organizations[0].Departments[i]?.Kpp == nKpp) { //Сохраняем полученный ответ organization.DepartmentId = serverResp.Organizations[0].Departments[i].DepartmentId; break; }; }; }; //Не удалось получить ящик получателя или полученая организация не соответствует заданному ИНН if ((!serverResp?.Organizations[0]?.Boxes[0]?.BoxId) || (serverResp?.Organizations[0]?.Inn != nInn)) { throw new Error(`Не удалось получить ящик получателя для контрагента с ИНН: ${nInn} и КПП: ${nKpp}`); } //Не удалось получить департаментом с соответствующим КПП if ((serverResp?.Organizations[0]?.Kpp != nKpp) && (!organization?.DepartmentId)) { throw new Error(`Не удалось получить ящик получателя для контрагента с ИНН: ${nInn} и КПП: ${nKpp}, у головной организации отсутствует подразделение с КПП: ${nKpp}`); } //Сохраняем полученный ответ organization.BoxId = serverResp.Organizations[0].Boxes[0].BoxId; return organization; } catch (e) { throw Error(`Ошибка при получении ящика получателя: ${e.message}`); }; }; //Обработчик "До" подключения к сервису const beforeConnect = async prms => { //Подготовим параметры аутентификации const loginAtribute = "login"; const passAtribute = "password"; let surl = prms.options.url; surl = `${surl}?type=password`; //Получим ключ разработчика let sAPIClientId = getAPIClientId(prms.options.nCompany, prms.options.nJurPers); //Проверим ключ разработчика checkAPIClientId(sAPIClientId); //Сформируем запрос на аутентификацию return { options: { headers: buildHeaders(sAPIClientId), url: surl, body: JSON.stringify({ [loginAtribute]: prms.service.sSrvUser, [passAtribute]: prms.service.sSrvPass }), simple: false } }; }; //Обработчик "После" подключения к сервису const afterConnect = async prms => { //Если пришла ошибка if (prms.optionsResp.statusCode != 200) { throw new Error(prms.queue.blResp.toString()); } else { //Сохраним полученный токен доступа в контекст сервиса return { blResp: Buffer.from(prms.queue.blResp), sCtx: prms.queue.blResp.toString(), dCtxExp: addHours(new Date(), 23) }; } }; //Обработчик "До" отправки запроса на экспорт документа к сервису "ДИАДОК" const beforeMessagePost = async prms => { //Получим ключ разработчика let sAPIClientId = getAPIClientId(prms.options.nCompany, prms.options.nJurPers); //Проверим ключ разработчика checkAPIClientId(sAPIClientId); //Формируем запрос try { //Считаем токен доступа из контекста сервиса let sToken = null; if (prms.service.sCtx) { sToken = prms.service.sCtx; } //Если не достали из контекста токен доступа - значит нет аутентификации на сервере if (!sToken) return { bUnAuth: true }; //Конвертируем XML из "Парус 8" в JSON let obj = await toJSON(prms.queue.blMsg.toString()); //Формируем запрос для получения FromBoxId let rqpOptions = { uri: buildMyOrganizationURL(prms.service.sSrvRoot), headers: buildHeaders(sAPIClientId, sToken), json: true }; //Переменные для запросов let serverResp; let organization; try { //Выполним запрос serverResp = await rqp(rqpOptions); //Получим идентификатор организации по ИНН/КПП поставщика документа for (let i in serverResp.Organizations) { //Если найдена подходящая организация - запомним идентификатор и выходим из цикла if (serverResp.Organizations[i].Inn == prms.options.inn_pr && serverResp.Organizations[i].Kpp == prms.options.kpp_pr) { //Сохраняем полученный ответ obj.FromBoxId = serverResp.Organizations[i].Boxes[0].BoxId; break; } } //Не удалось получить ящик отправителя if (!obj.FromBoxId) { throw new Error(`Не удалось получить ящик текущей организации с ИНН: ${prms.options.inn_pr} и КПП: ${prms.options.kpp_pr}`); } } catch (e) { throw Error(`Ошибка при получении ящика текущей организации: ${e.message}`); } //Получим ящик получателя organization = await getOrganizationBoxId(prms.service.sSrvRoot, buildHeaders(sAPIClientId, sToken), prms.options.inn_cs, prms.options.kpp_cs); obj.ToBoxId = organization.BoxId; //Если не заполнен идентификатор подразделения и при получении ящика удалось его подобрать if ((!obj.ToDepartmentId) && (organization.DepartmentId)) { obj.ToDepartmentId = organization.DepartmentId; }; //Если пришел ответ if (prms.queue.blResp && serverResp.statusCode == 200) { //Вернем загруженный документ return { blResp: prms.queue.blResp }; } //Собираем и отдаём общий результат работы return { options: { headers: buildHeaders(sAPIClientId, sToken), simple: false }, blMsg: Buffer.from(JSON.stringify(obj)) }; } catch (e) { throw Error(e); } }; //Обработчик "После" запроса на экспорт документа к сервису "ДИАДОК" const afterMessagePost = async prms => { //Преобразуем JSON ответ сервиса "ДИАДОК" в XML, понятный "Парус 8" let resu = null; //Действие выполнено успешно if (prms.optionsResp.statusCode == 200) { try { resu = toXML(JSON.parse(prms.queue.blResp.toString())); } catch (e) { throw new Error(`Неожиданный ответ сервера ЭДО "ДИАДОК". Ошибка интерпретации: ${e.message}`); } } else { //Если пришел текст ошибки if (prms.queue.blResp) { throw new Error(`Неожиданный ответ сервера ЭДО "ДИАДОК": ${prms.queue.blResp.toString()}`); } else { throw new Error('Сервер ЭДО "ДИАДОК" не вернул ответ'); } } //Возврат результата return { blResp: Buffer.from(resu) }; }; //Обработчик "До" отправки запроса на экспорт патча документа к сервису "ДИАДОК" const beforeMessagePatchPost = async prms => { //Получим ключ разработчика let sAPIClientId = getAPIClientId(prms.options.nCompany, prms.options.nJurPers); //Проверим ключ разработчика checkAPIClientId(sAPIClientId); //Формируем запрос try { //Считаем токен доступа из контекста сервиса let sToken = null; if (prms.service.sCtx) { sToken = prms.service.sCtx; } //Если не достали из контекста токен доступа - значит нет аутентификации на сервере if (!sToken) return { bUnAuth: true }; //Конвертируем XML из "Парус 8" в понятный "ДИАДОК" JSON let obj = await toJSON(prms.queue.blMsg.toString()); //Собираем и отдаём общий результат работы return { options: { headers: buildHeaders(sAPIClientId, sToken), simple: false }, blMsg: Buffer.from(JSON.stringify(obj)) }; } catch (e) { throw Error(e); } }; //Обработчик "После" запроса на экспорт патча документа к сервису "ДИАДОК" const afterMessagePatchPost = async prms => { let resu = null; //Действие выполнено успешно if (prms.optionsResp.statusCode == 200) { try { //Преобразуем JSON ответ сервиса "ДИАДОК" в XML, понятный "Парус 8" resu = toXML(JSON.parse(prms.queue.blResp.toString())); } catch (e) { throw new Error(`Неожиданный ответ сервера ЭДО "ДИАДОК". Ошибка интерпретации: ${e.message}`); } } else { //Если пришел текст ошибки if (prms.queue.blResp) { throw new Error(`Неожиданный ответ сервера ЭДО "ДИАДОК": ${prms.queue.blResp.toString()}`); } else { throw new Error('Сервер ЭДО "ДИАДОК" не вернул ответ'); } } //Возврат результата return { blResp: Buffer.from(resu) }; }; //Обработчик "До" отправки запроса на получение новых событий к сервису "ДИАДОК" const beforeEvent = async prms => { //Получим ключ разработчика let sAPIClientId = getAPIClientId(prms.options.nCompany, prms.options.nJurPers); //Проверим ключ разработчика checkAPIClientId(sAPIClientId); //Формируем запрос try { let sToken = null; //Токен доступа let surl = prms.options.url; //Адрес запрос let serverResp; //Результат запроса информации по текущей организации let obj; //Тело запроса (JSON) let rblMsg; //Буфер тела запроса let sBoxId; //Идентификатор ящика текущей организации let sDepartmentId; //Идентификатор подразделения //Считаем токен доступа из контекста сервиса if (prms.service.sCtx) { sToken = prms.service.sCtx; } //Если не достали из контекста токен доступа - значит нет аутентификации на сервере if (!sToken) return { bUnAuth: true }; //Формируем запрос для получения BoxId let rqpOptions = { uri: buildMyOrganizationURL(prms.service.sSrvRoot), headers: buildHeaders(sAPIClientId, sToken), json: true }; try { //Выполним запрос serverResp = await rqp(rqpOptions); //Получим идентификатор организации по ИНН/КПП контрагента организации for (let i in serverResp.Organizations) { //Если найдена подходящая организация - запомним идентификатор и выходим из цикла if (serverResp.Organizations[i].Inn == prms.options.inn && serverResp.Organizations[i].Kpp == prms.options.kpp) { //Сохраняем полученный ответ sBoxId = serverResp.Organizations[i].Boxes[0].BoxId; //Если задано подразделение if (prms.options.sdepartment_name) { if (prms.options.sdepartment_name == SDEPARTMENT_NAME) { sDepartmentId = SDEPARTMENT_ID; } else { //Получим идентификатор подразделения for (let j in serverResp.Organizations[i].Departments) { //Если нашлось подразделение - запомним идентификатор и выходим из цикла if (serverResp.Organizations[i].Departments[j].Name == prms.options.sdepartment_name) { sDepartmentId = serverResp.Organizations[i].Departments[j].DepartmentId; break; } } //Не удалось получить идентификатор подразделения if (!sDepartmentId) { throw new Error(`Не удалось получить идентификатор подразделения с наименованием "${prms.options.sdepartment_name}"`); } } } break; } } //Не удалось получить ящик текущей организации if (!sBoxId) { throw new Error(`Не удалось получить ящик текущей организации с ИНН: ${prms.options.inn} и КПП: ${prms.options.kpp}`); } } catch (e) { throw Error(`Ошибка при получении ящика текущей организации: ${e.message}`); } //Сформируем адрес запроса surl = `${surl}?boxId=${sBoxId}`; //Если действие не "Документооборот" if (prms.options.saction != "DOCFLOWS") { //Заполним параметры для отбора последних событий if (prms.options.aftereventid) { surl = `${surl}&afterEventId=${prms.options.aftereventid}`; } else { surl = `${surl}×tampFromTicks=${prms.options.timestampfromticks}`; } //Заполним идентификатор подразделения if (prms.options.sdepartment_name && sDepartmentId) { surl = `${surl}&departmentId=${sDepartmentId}`; } } else { if (prms.queue.blMsg) { //Конвертируем XML из "Парус 8" в понятный "ДИАДОК" JSON obj = await toJSON(prms.queue.blMsg.toString()); rblMsg = Buffer.from(JSON.stringify(obj)); } } //Собираем и отдаём общий результат работы return { options: { headers: buildHeaders(sAPIClientId, sToken), simple: false, url: surl, boxId: sBoxId }, blMsg: rblMsg }; } catch (e) { throw Error(e); } }; //Обработчик "После" запроса на получение новых событий к сервису "ДИАДОК" const afterEvent = async prms => { let sAPIClientId = null; //Ключ разработчика let sToken = null; //Токен доступа let resu = null; //Ответ сервера let rqpOptions = null; //Параметры для запроса информации по ящику let serverResp; //Результат запроса информации по организации let resp = null; //Ответ сервера let box = null; //Информация ящика let boxIds = { boxIds: [] }; //Список уникальных ящиков контрагентов //Действие выполнено успешно if (prms.optionsResp.statusCode == 200) { //Получим ключ разработчика sAPIClientId = getAPIClientId(prms.options.nCompany, prms.options.nJurPers); //Проверим ключ разработчика checkAPIClientId(sAPIClientId); //Разберем ответ сервера resp = JSON.parse(prms.queue.blResp.toString()); //Получим список уникальных ящиков for (let i in resp.Events) { if (resp.Events[i]?.Message) { if ((!boxIds.boxIds.find(box => box.boxId === resp.Events[i]?.Message.FromBoxId)) && (resp.Events[i]?.Message.FromBoxId)) { boxIds.boxIds.push({ boxId: resp.Events[i]?.Message.FromBoxId }); } if ((!boxIds.boxIds.find(box => box.boxId === resp.Events[i]?.Message.ToBoxId)) && (resp.Events[i]?.Message.ToBoxId)) { boxIds.boxIds.push({ boxId: resp.Events[i]?.Message.ToBoxId }); } } } //Если требуется выполнить запросы доп. информации по ящикам организации if (boxIds.boxIds.length) { //Считаем токен доступа из контекста сервиса if (prms.service.sCtx) { sToken = prms.service.sCtx; } //Если не достали из контекста токен доступа - значит нет аутентификации на сервере if (!sToken) return { bUnAuth: true }; for (let i in boxIds.boxIds) { rqpOptions = null; //Формируем запрос для получения BoxId rqpOptions = { uri: buildOrganizationBoxIdURL(prms.service.sSrvRoot), headers: buildHeaders(sAPIClientId, sToken), qs: { boxId: boxIds.boxIds[i].boxId }, json: true }; try { //Выполним запрос serverResp = await rqp(rqpOptions); if (serverResp?.Organization) { //Запишем полученную информацию о контрагенте boxIds.boxIds[i].Inn = serverResp?.Organization?.Inn; boxIds.boxIds[i].Kpp = serverResp?.Organization?.Kpp; boxIds.boxIds[i].FullName = serverResp?.Organization?.FullName; boxIds.boxIds[i].ShortName = serverResp?.Organization?.ShortName; boxIds.boxIds[i].FnsParticipantId = serverResp?.Organization?.FnsParticipantId; } else { //Не удалось получить информацию о контрагенте по ящику организации throw new Error(`Не удалось получить информацию о контрагенте по ящику организации ${boxIds.boxIds[i].boxId}`); } } catch (e) { throw Error(`Ошибка при получении информации о контрагенте по ящику организации: ${e.message}`); } } //Добавим к ответу информацию о контрагентах ящика for (let i in resp.Events) { if (resp.Events[i]?.Message) { //Если надо добавить информацию по ящику-отправителю box = boxIds.boxIds.find(box => box.boxId === resp.Events[i]?.Message.FromBoxId); if (box) { resp.Events[i].Message.FromInn = box.Inn; resp.Events[i].Message.FromKpp = box.Kpp; resp.Events[i].Message.FromFullName = box.FullName; resp.Events[i].Message.FromShortName = box.ShortName; resp.Events[i].Message.FromFnsParticipantId = box.FnsParticipantId; } //Если надо добавить информацию по ящику-получателю box = boxIds.boxIds.find(box => box.boxId === resp.Events[i]?.Message.ToBoxId); if (box) { resp.Events[i].Message.ToInn = box.Inn; resp.Events[i].Message.ToKpp = box.Kpp; resp.Events[i].Message.ToFullName = box.FullName; resp.Events[i].Message.ToShortName = box.ShortName; resp.Events[i].Message.ToFnsParticipantId = box.FnsParticipantId; } } } } try { //Преобразуем JSON ответ сервиса "ДИАДОК" в XML, понятный "Парус 8" resu = toXML({ root: resp }); } catch (e) { throw new Error(`Неожиданный ответ сервера ЭДО "ДИАДОК". Ошибка интерпретации: ${e.message}`); } } else { //Если пришел текст ошибки if (prms.queue.blResp) { throw new Error(`Неожиданный ответ сервера ЭДО "ДИАДОК": ${prms.queue.blResp.toString()}`); } else { throw new Error('Сервер ЭДО "ДИАДОК" не вернул ответ'); } } //Возврат результата return { blResp: Buffer.from(resu) }; }; //Обработчик "До" отправки запроса на загрузку вложения const beforeDocLoad = async prms => { //Получим ключ разработчика let sAPIClientId = getAPIClientId(prms.options.nCompany, prms.options.nJurPers); //Проверим ключ разработчика checkAPIClientId(sAPIClientId); //Формируем запрос try { //Считаем токен доступа из контекста сервиса let sToken = null; if (prms.service.sCtx) { sToken = prms.service.sCtx; } //Если не достали из контекста токен доступа - значит нет аутентификации на сервере if (!sToken) return { bUnAuth: true }; let surl = prms.options.url; let entId; let msgId = "messageId="; //В зависимости от режима загрузки определим наименование узла switch (prms.options.type) { //Загрузка файла case 0: entId = "entityId="; break; //Загрузка PDF case 1: entId = "documentId="; break; //Загрузка Извещения о получении case 2: entId = "attachmentId="; break; //Загрузка Уведомления об уточнении case 3: entId = "attachmentId="; break; //Загрузка Титул отказа от подписи документа case 4: entId = "attachmentId="; break; //Загрузка Титула покупателя документа case 5: entId = "documentId="; msgId = "letterId="; break; default: } surl = `${surl}?${msgId}${prms.options.smsgid}&${entId}${prms.options.sentid}`; let obj; let rblMsg; if (prms.queue.blMsg && prms.options.type != 5) { //Конвертируем XML из "Парус 8" в понятный "ДИАДОК" JSON obj = await toJSON(prms.queue.blMsg.toString()); rblMsg = Buffer.from(JSON.stringify(obj)); } else { if (prms.queue.blMsg) { rblMsg = prms.queue.blMsg; } } //Собираем и отдаём общий результат работы return { options: { qs: { boxId: prms.options.sboxid, documentTypeNamedId: prms.options.documentTypeNamedId, documentFunction: prms.options.documentFunction, documentVersion: prms.options.documentVersion, titleIndex: prms.options.titleIndex }, headers: buildHeaders(sAPIClientId, sToken), url: surl, simple: false }, blMsg: rblMsg }; } catch (e) { throw Error(e); } }; //Обработчик "После" отправки запроса на загрузку вложения const afterDocLoad = async prms => { if (prms.queue.blResp) { //Если выполнено без ошибок и не требуется повторный запрос if ((prms.optionsResp.statusCode == 200 || prms.optionsResp.statusCode == 404) && !prms.optionsResp.headers["retry-after"]) { return; } else { let iterable = [1, 2, 3, 4, 5]; let serverResp; //Если не превышает лимита запросов for (let value of iterable) { if (prms.optionsResp.statusCode != 200 || prms.optionsResp.headers["retry-after"]) { //Если загружаем PDF if (prms.options.type == 1 && prms.optionsResp.headers["retry-after"]) { await new Promise(resolve => setTimeout(resolve, (Number(prms.optionsResp.headers["retry-after"]) + 1) * 1000)); } else { await new Promise(resolve => setTimeout(resolve, 2000)); } //Выполним повторный запрос serverResp = await rqp(prms.options); //Сохраняем полученный ответ prms.queue.blResp = Buffer.from(serverResp.body || ""); prms.optionsResp.statusCode = serverResp.statusCode; prms.optionsResp.headers = serverResp.headers; //Если пришел ответ if (prms.queue.blResp && serverResp.statusCode == 200) { //Вернем загруженный документ return { optionsResp: prms.optionsResp, blResp: prms.queue.blResp }; } } } //Если был ответ от сервера с ошибкой (иначе мы сюда не попадём) if (prms.queue.blResp) { //Разберем сообщение об ошибке throw new Error(`Неожиданный ответ сервера ЭДО "ДИАДОК": ${prms.queue.blResp.toString()}`); } } } else { throw new Error('Сервер ЭДО "ДИАДОК" не вернул ответ'); } //Возврат результата return; }; //Обработчик "До" отправки запроса на удаление документа к сервису "ДИАДОК" const beforeDocDelete = async prms => { //Получим ключ разработчика let sAPIClientId = getAPIClientId(prms.options.nCompany, prms.options.nJurPers); //Проверим ключ разработчика checkAPIClientId(sAPIClientId); //Формируем запрос try { //Считаем токен доступа из контекста сервиса let sToken = null; if (prms.service.sCtx) { sToken = prms.service.sCtx; } //Если не достали из контекста токен доступа - значит нет аутентификации на сервере if (!sToken) return { bUnAuth: true }; //Собираем и отдаём общий результат работы return { options: { headers: buildHeaders(sAPIClientId, sToken), simple: false } }; } catch (e) { throw Error(e); } }; //Обработчик "До" отправки запроса на получение списка подразделений контрагента к сервису "ДИАДОК" const beforeDepartmentIdGet = async prms => { //Получим ключ разработчика let sAPIClientId = getAPIClientId(prms.options.nCompany, prms.options.nJurPers); //Проверим ключ разработчика checkAPIClientId(sAPIClientId); //Формируем запрос try { //Считаем токен доступа из контекста сервиса let sToken = null; if (prms.service.sCtx) { sToken = prms.service.sCtx; } //Если не достали из контекста токен доступа - значит нет аутентификации на сервере if (!sToken) return { bUnAuth: true }; //Собираем и отдаём общий результат работы return { options: { headers: buildHeaders(sAPIClientId, sToken), simple: false } }; } catch (e) { throw Error(e); } }; //Обработчик "После" отправки запроса на получение списка подразделений контрагента к сервису "ДИАДОК" const afterDepartmentIdGet = async prms => { let resu = null; let organization = {}; //Действие выполнено успешно if (prms.optionsResp.statusCode == 200) { try { try { //Получим организацию не в роуминге (или единственную организацию в роуминге) organization = getOrganizations(JSON.parse(prms.queue.blResp.toString())); if (!organization) { throw Error(`Не удалось получить ящик для контрагента с ИНН: ${prms.options.nINN} и КПП: ${prms.options.nKPP}`); } } catch (e) { //Получим ключ разработчика let sAPIClientId = getAPIClientId(prms.options.nCompany, prms.options.nJurPers); //Считаем токен доступа из контекста сервиса let sToken = prms.service.sCtx; //Получим головную организацию по ИНН/КПП organization = await getOrganization(prms.service.sSrvRoot, buildHeaders(sAPIClientId, sToken), prms.options.nINN, prms.options.nKPP); }; //Преобразуем JSON ответ сервиса "ДИАДОК" в XML, понятный "Парус 8" resu = toXML({ root: organization }); } catch (e) { throw new Error(`Неожиданный ответ сервера ЭДО "ДИАДОК". Ошибка интерпретации: ${e.message}`); } } else { //Если пришел текст ошибки if (prms.queue.blResp) { throw new Error(`Неожиданный ответ сервера ЭДО "ДИАДОК": ${prms.queue.blResp.toString()}`); } else { throw new Error('Сервер ЭДО "ДИАДОК" не вернул ответ'); } } //Возврат результата return { blResp: Buffer.from(resu) }; }; //Обработчик "До" отправки запроса на получение списка документов в сообщении к сервису "ДИАДОК" const beforeDocumentsByMessageIdGet = async prms => { //Получим ключ разработчика let sAPIClientId = getAPIClientId(prms.options.nCompany, prms.options.nJurPers); //Проверим ключ разработчика checkAPIClientId(sAPIClientId); //Формируем запрос try { //Считаем токен доступа из контекста сервиса let sToken = null; if (prms.service.sCtx) { sToken = prms.service.sCtx; } //Если не достали из контекста токен доступа - значит нет аутентификации на сервере if (!sToken) return { bUnAuth: true }; //Собираем и отдаём общий результат работы return { options: { headers: buildHeaders(sAPIClientId, sToken), simple: false } }; } catch (e) { throw Error(e); } }; //Обработчик "После" отправки запроса на получение списка документов в сообщении к сервису "ДИАДОК" const afterDocumentsByMessageIdGet = async prms => { let resu = null; //Действие выполнено успешно if (prms.optionsResp.statusCode == 200) { try { //Разберем ответ сервера resp = JSON.parse(prms.queue.blResp.toString()); //Преобразуем JSON ответ сервиса "ДИАДОК" в XML, понятный "Парус 8" resu = toXML({ root: resp }); } catch (e) { throw new Error(`Неожиданный ответ сервера ЭДО "ДИАДОК". Ошибка интерпретации: ${e.message}`); } } else { //Если пришел текст ошибки if (prms.queue.blResp) { throw new Error(`Неожиданный ответ сервера ЭДО "ДИАДОК": ${prms.queue.blResp.toString()}`); } else { throw new Error('Сервер ЭДО "ДИАДОК" не вернул ответ'); } } //Возврат результата return { blResp: Buffer.from(resu) }; }; //----------------- // Интерфейс модуля //----------------- exports.beforeConnect = beforeConnect; exports.afterConnect = afterConnect; exports.beforeMessagePost = beforeMessagePost; exports.afterMessagePost = afterMessagePost; exports.beforeMessagePatchPost = beforeMessagePatchPost; exports.afterMessagePatchPost = afterMessagePatchPost; exports.beforeEvent = beforeEvent; exports.afterEvent = afterEvent; exports.beforeDocLoad = beforeDocLoad; exports.afterDocLoad = afterDocLoad; exports.beforeDocDelete = beforeDocDelete; exports.beforeDepartmentIdGet = beforeDepartmentIdGet; exports.afterDepartmentIdGet = afterDepartmentIdGet; exports.beforeDocumentsByMessageIdGet = beforeDocumentsByMessageIdGet; exports.afterDocumentsByMessageIdGet = afterDocumentsByMessageIdGet;