934 lines
45 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
Сервис интеграции ПП Парус 8 с WEB API
Дополнительный модуль: Интеграция с ЭДО "ДИАДОК" (DIADOC)
*/
//------------------------------
// Подключение внешних библиотек
//------------------------------
const xml2js = require("xml2js"); //Конвертация XML в JSON и JSON в XML
const _ = require("lodash"); //Работа с коллекциями и объектами
const rqp = require("request-promise"); //Работа с HTTP/HTTPS запросами
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",
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}&timestampFromTicks=${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;