refs #4823 Added methods.yml and more

This commit is contained in:
Guillermo Bonet 2023-06-15 11:29:19 +02:00
parent 5aa27e45bd
commit 79c3582bb4
6 changed files with 168 additions and 1211 deletions

View File

@ -1,8 +1,11 @@
import { checkCon, closeCon } from './models/sequelize.js'; import { checkCon, closeCon } from './models/sequelize.js';
import * as utils from './utils.js'; import * as utils from './utils.js';
import chalk from 'chalk'; import chalk from 'chalk';
import yml from 'js-yaml';
import fs from 'fs';
const env = process.env; const env = process.env;
const flModels = yml.load(fs.readFileSync('./models/models.yml', 'utf8'));
class Floriday { class Floriday {
async start() { async start() {
@ -46,20 +49,14 @@ class Floriday {
async trunk() { async trunk() {
try{ try{
const models = [ for (let model of flModels)
'organization',
'warehouse',
'tradeItem',
'supplyLine',
'clockPresaleSupply',
];
for (let model of models)
await utils.syncModel(model); await utils.syncModel(model);
// await utils.syncConnections(); await utils.checkConnections();
} catch (err) { } catch (err) {
if (err.name === 'SequelizeConnectionRefusedError') throw err; if (['SequelizeConnectionRefusedError', 'SequelizeConnectionError'].includes(err.name))
throw err;
utils.criticalError(err); utils.criticalError(err);
} }
}; };

49
methods.yml Normal file
View File

@ -0,0 +1,49 @@
connections:
base:
url: /connections/
sync:
url: /connections/sync/
maxSeq:
url: /connections/current-max-sequence
organizations:
base:
url: /organizations/
sync:
url: /organizations/sync/
params:
organizationType: SUPPLIER
maxSeq:
url: /organizations/current-max-sequence
warehouses:
base:
url: /warehouses/
sync:
url: /warehouses/sync/
maxSeq:
url: /warehouses/current-max-sequence
tradeItems:
base:
url: /trade-items/
sync:
url: /trade-items/sync/
params:
postFilterSelectedTradeItems: false
postFilterSelectedTradeItemPackingConfigurations: false
maxSeq:
url: /trade-items/current-max-sequence
supplyLines:
base:
url: /supply-lines/
sync:
url: /supply-lines/sync/
params:
postFilterSelectedTradeItems: false
maxSeq:
url: /supply-lines/current-max-sequence
clockPresalesSupply:
base:
url: /auction/clock-presales-supply/
sync:
url: /auction/clock-presales-supply/sync/
maxSeq:
url: /auction/clock-presales-supply/max-sequence-number

5
models/models.yml Normal file
View File

@ -0,0 +1,5 @@
- organizations
- warehouses
- tradeItems
- supplyLines
- clockPresalesSupply

1073
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,7 @@
"axios": "^1.4.0", "axios": "^1.4.0",
"chalk": "^5.2.0", "chalk": "^5.2.0",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"js-yaml": "^4.1.0",
"mariadb": "^3.1.2", "mariadb": "^3.1.2",
"moment": "^2.29.4", "moment": "^2.29.4",
"ora": "^6.3.0", "ora": "^6.3.0",

230
utils.js
View File

@ -1,12 +1,15 @@
import { models } from './models/sequelize.js'; import { models } from './models/sequelize.js';
import { Op } from 'sequelize';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import axios from 'axios'; import axios from 'axios';
import moment from 'moment'; import moment from 'moment';
import chalk from 'chalk'; import chalk from 'chalk';
import ora from 'ora'; import ora from 'ora';
import yml from 'js-yaml';
import fs from 'fs';
const env = process.env; const env = process.env;
const methods = yml.load(fs.readFileSync('./methods.yml', 'utf8'));
const flModels = yml.load(fs.readFileSync('./models/models.yml', 'utf8'));
let spinner; let spinner;
/** /**
@ -15,7 +18,7 @@ let spinner;
* @param {Boolean} isForce Force to request new token * @param {Boolean} isForce Force to request new token
*/ */
export async function requestToken(isForce = false) { export async function requestToken(isForce = false) {
await startSpin(`Requesting new token...`, true); await startSpin(`Checking token...`, true);
let optionalMsg; let optionalMsg;
try { try {
const clientConfigData = await models.config.findOne(); const clientConfigData = await models.config.findOne();
@ -27,6 +30,7 @@ export async function requestToken(isForce = false) {
} }
if (isForce || !token || !tokenExpiration || moment().isAfter(tokenExpiration)) { if (isForce || !token || !tokenExpiration || moment().isAfter(tokenExpiration)) {
await txtSpin(`Requesting new token...`, false);
const clientId = JSON.parse(env.USE_SECRETS_DB) ? clientConfigData.clientId || env.CLIENT_ID : env.CLIENT_ID; const clientId = JSON.parse(env.USE_SECRETS_DB) ? clientConfigData.clientId || env.CLIENT_ID : env.CLIENT_ID;
const clientSecret = JSON.parse(env.USE_SECRETS_DB) ? clientConfigData.clientSecret || env.CLIENT_SECRET : env.CLIENT_SECRET; const clientSecret = JSON.parse(env.USE_SECRETS_DB) ? clientConfigData.clientSecret || env.CLIENT_SECRET : env.CLIENT_SECRET;
@ -51,7 +55,6 @@ export async function requestToken(isForce = false) {
}); });
} else } else
optionalMsg = 'Using stored token...'; optionalMsg = 'Using stored token...';
await okSpin(optionalMsg, true); await okSpin(optionalMsg, true);
} catch (err) { } catch (err) {
await failSpin(err, true); await failSpin(err, true);
@ -127,7 +130,7 @@ export async function sleep(ms) {
/** /**
* Sync a model. * Sync a model.
* *
* @param {String} model Supported models (organization | warehouse | tradeItem | supplyLine | clockPresaleSupply) * @param {String} model Supported models (./models/methods.yml)
*/ */
export async function syncModel(model) { export async function syncModel(model) {
await startSpin(`Syncing ${model}...`, true); await startSpin(`Syncing ${model}...`, true);
@ -136,125 +139,72 @@ export async function syncModel(model) {
const dbSeqNum = await models.sequenceNumber.findOne({ where: { model } }) const dbSeqNum = await models.sequenceNumber.findOne({ where: { model } })
let curSeqNum = dbSeqNum?.maxSequenceNumber ?? 0; let curSeqNum = dbSeqNum?.maxSequenceNumber ?? 0;
let maxSeqUrl, syncUrl; if (!flModels.includes(model))
switch (model) { throw new Error('Unsupported model');
case 'organization':
maxSeqUrl = `${env.API_URL}/organizations/current-max-sequence`; const maxSeqNum = (await vnRequest('GET', `${env.API_URL}${methods[model].maxSeq.url}`)).data;
syncUrl = `${env.API_URL}/organizations/sync/`; for (curSeqNum; curSeqNum < maxSeqNum; curSeqNum++) {
break; let params, misSeqNum;
case 'warehouse':
maxSeqUrl = `${env.API_URL}/warehouses/current-max-sequence`; if (methods[model].sync.params) {
syncUrl = `${env.API_URL}/warehouses/sync/`; params = new URLSearchParams();
break; for (const key in methods[model].sync.params) {
case 'tradeItem': params.append(key, methods[model].sync.params[key]);
maxSeqUrl = `${env.API_URL}/trade-items/current-max-sequence`; }
syncUrl = `${env.API_URL}/trade-items/sync/`; params = params.toString();
break;
case 'supplyLine':
maxSeqUrl = `${env.API_URL}/supply-lines/current-max-sequence`;
syncUrl = `${env.API_URL}/supply-lines/sync/`;
break;
case 'clockPresaleSupply':
maxSeqUrl = `${env.API_URL}/auction/clock-presales-supply/max-sequence-number`;
syncUrl = `${env.API_URL}/auction/clock-presales-supply/sync/`;
break;
default:
throw new Error('Unsupported model');
} }
const maxSeqNum = (await vnRequest('GET', maxSeqUrl)).data; const res = (await vnRequest('GET', `${env.API_URL}${methods[model].sync.url}${curSeqNum}${params ? `?${params}` : ''}`)).data;
for (curSeqNum; curSeqNum < maxSeqNum; curSeqNum++) { const data = res.results;
let params, misSeqNum; curSeqNum = res.maximumSequenceNumber;
if (model === 'organization') misSeqNum = maxSeqNum - curSeqNum;
params = new URLSearchParams({ organizationType: 'SUPPLIER'} ).toString(); await insertModel(model, data)
else if (model === 'supplyLine' ) txtSpin(`Syncing ${i = i + data.length} ${model}, ${misSeqNum} missing...`);
params = new URLSearchParams({ postFilterSelectedTradeItems: false }).toString(); await insertSequenceNumber(model, curSeqNum);
else if (model === 'tradeItem') }
params = new URLSearchParams({ await insertSequenceNumber(model, maxSeqNum);
postFilterSelectedTradeItems: false, txtSpin((i)
postFilterSelectedTradeItemPackingConfigurations: false, ? `Syncing ${i} ${model}...`
}).toString(); : `Syncing ${model}...`);
await okSpin(null, true);
const res = (await vnRequest('GET', `${syncUrl}${curSeqNum}${params ? `?${params}` : ''}`)).data;
curSeqNum = res.maximumSequenceNumber;
const objects = res.results;
misSeqNum = maxSeqNum - curSeqNum;
txtSpin(`Syncing ${i} ${model}, ${misSeqNum} missing...`);
switch (model) {
case 'organization':
await insertOrganizations(objects);
break;
case 'warehouse':
await insertWarehouses(objects);
break;
case 'tradeItem':
await insertTradeItems(objects);
break;
case 'supplyLine':
await insertSupplyLines(objects);
break;
case 'clockPresaleSupply':
await insertClockPresalesSupply(objects);
break;
default:
throw new Error('Unsupported model');
}
txtSpin(`Syncing ${i = i + objects.length} ${model}, ${misSeqNum} missing...`);
await insertSequenceNumber(model, curSeqNum);
}
await insertSequenceNumber(model, maxSeqNum);
txtSpin((i)
? `Syncing ${i} ${model}...`
: `Syncing ${model}...`);
await okSpin(null, true);
} catch (err) { } catch (err) {
await failSpin(err, true); await failSpin(err, true);
} }
}; };
/**
* Insert a model.
*/
export async function insertModel(model, data) {
switch (model) {
case 'organizations':
await insertOrganizations(data);
break;
case 'warehouses':
await insertWarehouses(data);
break;
case 'tradeItems':
await insertTradeItems(data);
break;
case 'supplyLines':
await insertSupplyLines(data);
break;
case 'clockPresalesSupply':
await insertClockPresalesSupply(data);
break;
default:
throw new Error('Unsupported model');
}
}
/** /**
* Create the connections in Floriday. * Check (create and/or remove) the connections in Floriday.
*/ */
export async function syncConnections(){ export async function checkConnections(){
await deleteConnections();
try { try {
let connectionsInDb = await models.organization.findAll({ startSpin('Checking connections...', true);
where: { await createConnections();
isConnected: true, await deleteConnections();
companyGln: {
[Op.ne]: null
},
rfhRelationId: {
[Op.ne]: null
},
}
});
const connectionsInFloriday = (await vnRequest('GET', `${env.API_URL}/connections`)).data;
let isExists = false, connectionsToPut = [];
for (let connectionInDb of connectionsInDb) {
for (let connectionInFloriday of connectionsInFloriday)
if (connectionInFloriday == connectionInDb.organizationId) {
isExists = true;
break;
}
if (!isExists) connectionsToPut.push(connectionInDb.organizationId)
isExists = false;
}
if (connectionsToPut.length)
await startSpin(`Creating connections in Floriday...`, true);
let i = 1;
for (let connection of connectionsToPut) {
txtSpin(`Creating ${i++} of ${connectionsToPut.length} connections in Floriday...`);
await vnRequest('PUT', `${env.API_URL}/connections/${connection}`);
}
await okSpin(null, true); await okSpin(null, true);
} catch (err) { } catch (err) {
await failSpin(err, true); await failSpin(err, true);
@ -695,37 +645,52 @@ export async function insertSupplyLines(supplyLines) {
} }
}; };
/**
* Create the connections in Floriday of the connected organizations.
**/
export async function createConnections() {
try {
const flConnections = (await vnRequest('GET', `${env.API_URL}${methods.connections.base.url}`)).data;
const dbConnections = await models.organization.findAll({
where: { isConnected: true }
});
let connectionsToPut = [], i = 1;
dbConnections.forEach(valor => {
if (!flConnections.includes(valor.organizationId))
connectionsToPut.push(valor.organizationId);
});
for (let connection of connectionsToPut) {
await vnRequest('PUT', `${env.API_URL}${methods.connections.base.url}${connection}`);
txtSpin(`Creating ${i++} connections, ${connectionsToPut.length - i} missing...`);
}
} catch (err) {
throw err;
}
}
/** /**
* Removes Floriday connections that we don't have in the database. * Removes Floriday connections that we don't have in the database.
**/ **/
export async function deleteConnections() { export async function deleteConnections() {
try { try {
let i = 1; const flConnections = (await vnRequest('GET', `${env.API_URL}/connections`)).data;
const connectionsInFloriday = (await vnRequest('GET', `${env.API_URL}/connections`)).data; const dbConnections = await models.organization.findAll({
const connectionsInDb = await models.organization.findAll({
attributes: ['organizationId'], attributes: ['organizationId'],
where: { isConnected: true } where: { isConnected: true }
}); });
let isExists = false, ghostConnections = []; let ghostConnections = [], i = 1;
for (let connectionInFloriday of connectionsInFloriday) { flConnections.forEach(valor => {
for (let connectionInDb of connectionsInDb) if (!dbConnections.includes(valor))
if (connectionInFloriday == connectionInDb.organizationId) { ghostConnections.push(valor);
isExists = true; });
break;
}
if (!isExists) ghostConnections.push(connectionInFloriday)
isExists = false;
}
if (ghostConnections.length)
await startSpin(`Deleting connections that aren't in the db...`, true);
for (let connection of ghostConnections) { for (let connection of ghostConnections) {
await vnRequest('DELETE', `${env.API_URL}/connections/${connection}`); await vnRequest('DELETE', `${env.API_URL}/connections/${connection}`);
txtSpin(`Deleting ${i++} of ${ghostConnections.length} connections that aren't in the db...`); txtSpin(`Deleting ${i++} connections, ${ghostConnections.length - i} missing...`);
} }
await okSpin(null, true);
} catch (err) { } catch (err) {
await criticalSpin(err); await criticalSpin(err);
} }
@ -818,7 +783,6 @@ export async function startSpin(msg, isNew) {
? spinner.start() ? spinner.start()
: spinner = ora({ : spinner = ora({
text: msg, text: msg,
indent: 1,
spinner: 'arc', spinner: 'arc',
interval: 40, interval: 40,
color: 'white', color: 'white',
@ -908,7 +872,7 @@ export async function criticalSpin(err) {
* @param {Error} err Error object * @param {Error} err Error object
**/ **/
export async function criticalError(err) { export async function criticalError(err) {
const msg = `${chalk.red.bold(' └─────')} ${chalk.red.bold('[CRITICAL]')}`; const msg = `${chalk.red.bold('└─────')} ${chalk.red.bold('[CRITICAL]')}`;
console.log(`${msg} ${chalk.red(err.message)}`); console.log(`${msg} ${chalk.red(err.message)}`);
process.exit(); process.exit();
}; };
@ -919,6 +883,6 @@ export async function criticalError(err) {
* @param {Error} err * @param {Error} err
**/ **/
export async function warning(err) { export async function warning(err) {
const msg = `${chalk.yellow.bold(' └─────')} ${chalk.yellow.bold('[WARNING]')}`; const msg = `${chalk.yellow.bold('└─────')} ${chalk.yellow.bold('[WARNING]')}`;
console.log(`${msg} ${chalk.yellow((err.response?.status && err.response?.data?.message) ?? err.message)}`); console.log(`${msg} ${chalk.yellow((err.response?.status && err.response?.data?.message) ?? err.message)}`);
}; };