P8-ExchangeService/modules/parus_atol_v4_ffd1.05.js

251 lines
9.4 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
Дополнительный модуль: Взаимодействие с "АТОЛ-Онлайн" (v4) в формате ФФД 1.05
*/
//----------------------
// Подключение библиотек
//----------------------
const util = require("util"); //Встроенные вспомогательные утилиты
const parseString = require("xml2js").parseString; //Конвертация XML в JSON
const _ = require("lodash"); //Работа с массивами и коллекциями
//---------------------
// Глобальные константы
//---------------------
//Словарь - Признак способа расчёта
const paymentMethod = {
sName: "Признак способа расчёта",
vals: {
"1": "full_prepayment",
"2": "prepayment",
"3": "advance",
"4": "full_payment",
"5": "partial_payment",
"6": "credit",
"7": "credit_payment"
}
};
//Словарь - Признак предмета расчёта
const paymentObject = {
sName: "Признак предмета расчёта",
vals: {
"1": "commodity",
"2": "excise",
"3": "job",
"4": "service",
"5": "gambling_bet",
"6": "gambling_prize",
"7": "lottery",
"8": "lottery_prize",
"9": "intellectual_activity",
"10": "payment",
"11": "agent_commission",
"12": "composite",
"13": "another",
"14": "property_right",
"15": "non-operating_gain",
"16": "insurance_premium",
"17": "sales_tax",
"18": "resort_fee"
}
};
//------------
// Тело модуля
//------------
//Разбор XML
const parseXML = xmlDoc => {
return new Promise((resolve, reject) => {
parseString(xmlDoc, { explicitArray: false, mergeAttrs: true }, function(err, result) {
if (err) reject(err);
else resolve(result);
});
});
};
//Конвертация значений в ожидаемые систеой АТОЛ-онлайн
const mapDictionary = (dict, sValue) => {
if (!dict) throw Error(`Словарь не определен`);
if (!dict.sName || !dict.vals || !(dict.vals instanceof Object)) throw Error(`Словарь имеет некорректный формат`);
if (typeof sValue === "undefined" || sValue === null || sValue === "")
throw Error(`Не указано значение для привязки к словарю "${dict.sName}"`);
const res = dict.vals[sValue];
if (typeof res === "undefined") throw Error(`Значение "${sValue}" отсутствует в словаре "${dict.sName}"`);
return res;
};
//Поиск значения в составе свойств фискального документа по коду свойства
const getPropValueByCode = (props, sCode, sValType = "STR", sValField = "VALUE") => {
if (!["STR", "NUM", "DATE"].includes(sValType)) throw Error(`Тип данных "${sValType}" не поддерживается`);
let res = null;
let prop = _.find(props, { SCODE: sCode });
if (typeof prop !== "undefined") {
res = prop[sValField];
if (typeof res === "undefined") res = null;
else if (res === "") res = null;
if (res !== null) {
switch (sValType) {
case "STR": {
try {
res = res.toString();
} catch (e) {
throw Error(`Ошибка конвертации значения "${res}" в строку: ${e.message}`);
}
break;
}
case "NUM": {
if (isNaN(res)) throw Error(`Значение "${res}" не является числом`);
try {
res = Number(res);
} catch (e) {
throw Error(`Ошибка конвертации значения "${res}" в число: ${e.message}`);
}
break;
}
case "DATE": {
const resTmp = res;
try {
res = new Date(res);
} catch (e) {
throw Error(`Ошибка конвертации значения "${resTmp}" в дату: ${e.message}`);
}
if (res instanceof Date && isNaN(res))
throw Error(`Значение "${resTmp}" не является корректной датой`);
break;
}
default:
throw Error(`Тип данных "${sValType}" не поддерживается`);
}
}
}
return res;
};
//Обработчик "До" отправки запроса на регистрацию чека (приход, расход, возврат) серверу "АТОЛ-Онлайн"
const beforeRegBillSIR = async prms => {
try {
const parseRes = await parseXML(prms.queue.blMsg.toString());
const doc = parseRes.FISCDOC;
const docProps = parseRes.FISCDOC.FISCDOC_PROPS.FISCDOC_PROP;
let reqBody = {
timestamp: doc.SDDOC_DATE,
external_id: doc.NRN,
/*
service: {
callback_url: ""
},
*/
receipt: {
client: {
email: getPropValueByCode(docProps, "1008"),
phone: ""
},
company: {
email: getPropValueByCode(docProps, "1117"),
sno: getPropValueByCode(docProps, "1117"),
inn: getPropValueByCode(docProps, "1018"),
payment_address: getPropValueByCode(docProps, "1187")
},
/*
agent_info: {
type: "",
paying_agent: {
operation: "",
phones: [""]
},
receive_payments_operator: {
phones: [""]
},
money_transfer_operator: {
phones: [""],
name: "",
address: "",
inn: ""
}
},
supplier_info: {
phones: [""]
},
*/
items: [
{
name: getPropValueByCode(docProps, "1030"),
price: getPropValueByCode(docProps, "1079", "NUM"),
quantity: getPropValueByCode(docProps, "1023", "NUM"),
sum: getPropValueByCode(docProps, "1043", "NUM"),
measurement_unit: getPropValueByCode(docProps, "1197"),
payment_method: mapDictionary(paymentMethod, getPropValueByCode(docProps, "1214")),
payment_object: mapDictionary(paymentObject, getPropValueByCode(docProps, "1212")),
vat: {
type: "none",
sum: getPropValueByCode(docProps, "1200", "NUM")
} /*,
agent_info: {
type: "",
paying_agent: {
operation: "",
phones: [""]
},
receive_payments_operator: {
phones: [""]
},
money_transfer_operator: {
phones: [""],
name: "",
address: "",
inn: ""
}
},
supplier_info: {
phones: [""],
name: "",
address: "",
inn: ""
},
user_data: ""
*/
}
],
payments: [
{
type: 0,
sum: 0
}
],
vats: [
{
type: "",
sum: 0
}
],
total: 0 /*,
additional_check_props: "",
cashier: "",
additional_user_props: {
name: "",
value: ""
}
*/
}
};
console.log(util.inspect(reqBody, false, null));
} catch (e) {
throw Error(e);
}
};
//Обработчик "После" отправки запроса на регистрацию чека (приход, расход, возврат) серверу "АТОЛ-Онлайн"
const afterRegBillSIR = async prms => {};
//-----------------
// Интерфейс модуля
//-----------------
exports.beforeRegBillSIR = beforeRegBillSIR;
exports.afterRegBillSIR = afterRegBillSIR;