salix/modules/invoiceIn/back/methods/invoice-in/exchangeRateUpdate.js

139 lines
5.8 KiB
JavaScript
Raw Normal View History

2024-04-11 12:32:26 +00:00
const axios = require('axios');
const {DOMParser} = require('xmldom');
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('exchangeRateUpdate', {
description: 'Updates the exchange rates from an XML feed',
accessType: 'WRITE',
accepts: [],
http: {
path: '/exchangeRateUpdate',
verb: 'post'
}
});
Self.exchangeRateUpdate = async(options = {}) => {
const models = Self.app.models;
const myOptions = {};
Object.assign(myOptions, options);
2024-04-11 12:32:26 +00:00
let createdTx = false;
if (!myOptions.transaction) {
myOptions.transaction = await Self.beginTransaction({});
createdTx = true;
}
2024-04-11 12:32:26 +00:00
try {
const response = await axios.get('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-hist-90d.xml');
const xmlData = response.data;
const doc = new DOMParser({errorHandler: {warning: () => {}}})
.parseFromString(xmlData, 'text/xml');
const cubes = doc?.getElementsByTagName('Cube');
if (!cubes || cubes.length === 0)
throw new UserError('No cubes found. Exiting the method.');
const maxDateRecord = await models.ReferenceRate.findOne({order: 'dated DESC'}, myOptions);
const maxDate = maxDateRecord?.dated ? new Date(maxDateRecord.dated) : null;
let lastProcessedDate = maxDate;
2024-04-11 12:32:26 +00:00
for (const cube of Array.from(cubes)) {
if (cube.nodeType === doc.ELEMENT_NODE && cube.attributes.getNamedItem('time')) {
const xmlDate = new Date(cube.getAttribute('time'));
const xmlDateWithoutTime = new Date(
xmlDate.getFullYear(),
xmlDate.getMonth(),
xmlDate.getDate()
);
2024-04-11 12:32:26 +00:00
if (!maxDate || xmlDateWithoutTime > maxDate) {
if (lastProcessedDate && xmlDateWithoutTime > lastProcessedDate) {
for (const code of ['USD', 'CNY', 'GBP']) {
const currency = await models.Currency.findOne(
{where: {code}},
myOptions
);
if (!currency)
throw new UserError(`Currency not found for code: ${code}`);
2024-04-12 08:26:32 +00:00
await fillMissingDates(
models, currency, lastProcessedDate, xmlDateWithoutTime, myOptions
);
}
}
}
2024-04-13 07:05:54 +00:00
for (const rateCube of Array.from(cube.childNodes)) {
2024-04-12 08:26:32 +00:00
if (rateCube.nodeType === doc.ELEMENT_NODE) {
2024-04-11 12:32:26 +00:00
const currencyCode = rateCube.getAttribute('currency');
const rate = rateCube.getAttribute('rate');
if (['USD', 'CNY', 'GBP'].includes(currencyCode)) {
const currency = await models.Currency.findOne(
{where: {code: currencyCode}},
myOptions
);
if (!currency)
throw new UserError(`Currency not found for code: ${currencyCode}`);
2024-04-12 08:26:32 +00:00
const existingRate = await models.ReferenceRate.findOne({
where: {currencyFk: currency.id, dated: xmlDateWithoutTime}
}, myOptions);
2024-04-11 12:32:26 +00:00
2024-04-12 08:26:32 +00:00
if (existingRate) {
if (existingRate.value !== rate)
await existingRate.updateAttributes({value: rate}, myOptions);
2024-04-12 08:26:32 +00:00
} else {
await models.ReferenceRate.create({
currencyFk: currency.id,
dated: xmlDateWithoutTime,
2024-04-12 08:26:32 +00:00
value: rate
}, myOptions);
2024-05-29 09:58:13 +00:00
}
2024-04-11 12:32:26 +00:00
}
}
}
lastProcessedDate = xmlDateWithoutTime;
2024-04-11 12:32:26 +00:00
}
}
if (createdTx)
await myOptions.transaction.commit();
} catch (error) {
if (createdTx)
await myOptions.transaction.rollback();
throw error;
2024-04-11 12:32:26 +00:00
}
};
async function getLastValidRate(models, currencyId, date, myOptions) {
return models.ReferenceRate.findOne({
where: {currencyFk: currencyId, dated: {lt: date}},
order: 'dated DESC'
}, myOptions);
}
async function fillMissingDates(models, currency, startDate, endDate, myOptions) {
const cursor = new Date(startDate);
cursor.setDate(cursor.getDate() + 1);
while (cursor < endDate) {
const existingRate = await models.ReferenceRate.findOne({
where: {currencyFk: currency.id, dated: cursor}
}, myOptions);
if (!existingRate) {
const lastValid = await getLastValidRate(models, currency.id, cursor, myOptions);
if (lastValid) {
await models.ReferenceRate.create({
currencyFk: currency.id,
dated: new Date(cursor),
value: lastValid.value
}, myOptions);
}
}
cursor.setDate(cursor.getDate() + 1);
}
}
2024-04-11 12:32:26 +00:00
};