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 * as utils from './utils.js';
import chalk from 'chalk';
import yml from 'js-yaml';
import fs from 'fs';
const env = process.env;
const flModels = yml.load(fs.readFileSync('./models/models.yml', 'utf8'));
class Floriday {
async start() {
@ -46,20 +49,14 @@ class Floriday {
async trunk() {
try{
const models = [
'organization',
'warehouse',
'tradeItem',
'supplyLine',
'clockPresaleSupply',
];
for (let model of models)
for (let model of flModels)
await utils.syncModel(model);
// await utils.syncConnections();
await utils.checkConnections();
} catch (err) {
if (err.name === 'SequelizeConnectionRefusedError') throw err;
if (['SequelizeConnectionRefusedError', 'SequelizeConnectionError'].includes(err.name))
throw 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,10 +18,11 @@
"axios": "^1.4.0",
"chalk": "^5.2.0",
"dotenv": "^16.0.3",
"js-yaml": "^4.1.0",
"mariadb": "^3.1.2",
"moment": "^2.29.4",
"ora": "^6.3.0",
"sequelize": "^6.31.1",
"uuid": "^9.0.0"
}
}
}

230
utils.js
View File

@ -1,12 +1,15 @@
import { models } from './models/sequelize.js';
import { Op } from 'sequelize';
import { v4 as uuidv4 } from 'uuid';
import axios from 'axios';
import moment from 'moment';
import chalk from 'chalk';
import ora from 'ora';
import yml from 'js-yaml';
import fs from 'fs';
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;
/**
@ -15,7 +18,7 @@ let spinner;
* @param {Boolean} isForce Force to request new token
*/
export async function requestToken(isForce = false) {
await startSpin(`Requesting new token...`, true);
await startSpin(`Checking token...`, true);
let optionalMsg;
try {
const clientConfigData = await models.config.findOne();
@ -27,6 +30,7 @@ export async function requestToken(isForce = false) {
}
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 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
optionalMsg = 'Using stored token...';
await okSpin(optionalMsg, true);
} catch (err) {
await failSpin(err, true);
@ -127,7 +130,7 @@ export async function sleep(ms) {
/**
* 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) {
await startSpin(`Syncing ${model}...`, true);
@ -136,125 +139,72 @@ export async function syncModel(model) {
const dbSeqNum = await models.sequenceNumber.findOne({ where: { model } })
let curSeqNum = dbSeqNum?.maxSequenceNumber ?? 0;
let maxSeqUrl, syncUrl;
switch (model) {
case 'organization':
maxSeqUrl = `${env.API_URL}/organizations/current-max-sequence`;
syncUrl = `${env.API_URL}/organizations/sync/`;
break;
case 'warehouse':
maxSeqUrl = `${env.API_URL}/warehouses/current-max-sequence`;
syncUrl = `${env.API_URL}/warehouses/sync/`;
break;
case 'tradeItem':
maxSeqUrl = `${env.API_URL}/trade-items/current-max-sequence`;
syncUrl = `${env.API_URL}/trade-items/sync/`;
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');
if (!flModels.includes(model))
throw new Error('Unsupported model');
const maxSeqNum = (await vnRequest('GET', `${env.API_URL}${methods[model].maxSeq.url}`)).data;
for (curSeqNum; curSeqNum < maxSeqNum; curSeqNum++) {
let params, misSeqNum;
if (methods[model].sync.params) {
params = new URLSearchParams();
for (const key in methods[model].sync.params) {
params.append(key, methods[model].sync.params[key]);
}
params = params.toString();
}
const maxSeqNum = (await vnRequest('GET', maxSeqUrl)).data;
for (curSeqNum; curSeqNum < maxSeqNum; curSeqNum++) {
let params, misSeqNum;
if (model === 'organization')
params = new URLSearchParams({ organizationType: 'SUPPLIER'} ).toString();
else if (model === 'supplyLine' )
params = new URLSearchParams({ postFilterSelectedTradeItems: false }).toString();
else if (model === 'tradeItem')
params = new URLSearchParams({
postFilterSelectedTradeItems: false,
postFilterSelectedTradeItemPackingConfigurations: false,
}).toString();
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);
const res = (await vnRequest('GET', `${env.API_URL}${methods[model].sync.url}${curSeqNum}${params ? `?${params}` : ''}`)).data;
const data = res.results;
curSeqNum = res.maximumSequenceNumber;
misSeqNum = maxSeqNum - curSeqNum;
await insertModel(model, data)
txtSpin(`Syncing ${i = i + data.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) {
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(){
await deleteConnections();
export async function checkConnections(){
try {
let connectionsInDb = await models.organization.findAll({
where: {
isConnected: true,
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}`);
}
startSpin('Checking connections...', true);
await createConnections();
await deleteConnections();
await okSpin(null, true);
} catch (err) {
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.
**/
export async function deleteConnections() {
try {
let i = 1;
const connectionsInFloriday = (await vnRequest('GET', `${env.API_URL}/connections`)).data;
const connectionsInDb = await models.organization.findAll({
const flConnections = (await vnRequest('GET', `${env.API_URL}/connections`)).data;
const dbConnections = await models.organization.findAll({
attributes: ['organizationId'],
where: { isConnected: true }
});
let isExists = false, ghostConnections = [];
for (let connectionInFloriday of connectionsInFloriday) {
for (let connectionInDb of connectionsInDb)
if (connectionInFloriday == connectionInDb.organizationId) {
isExists = true;
break;
}
if (!isExists) ghostConnections.push(connectionInFloriday)
isExists = false;
}
if (ghostConnections.length)
await startSpin(`Deleting connections that aren't in the db...`, true);
let ghostConnections = [], i = 1;
flConnections.forEach(valor => {
if (!dbConnections.includes(valor))
ghostConnections.push(valor);
});
for (let connection of ghostConnections) {
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) {
await criticalSpin(err);
}
@ -818,7 +783,6 @@ export async function startSpin(msg, isNew) {
? spinner.start()
: spinner = ora({
text: msg,
indent: 1,
spinner: 'arc',
interval: 40,
color: 'white',
@ -908,7 +872,7 @@ export async function criticalSpin(err) {
* @param {Error} err Error object
**/
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)}`);
process.exit();
};
@ -919,6 +883,6 @@ export async function criticalError(err) {
* @param {Error} 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)}`);
};