refs #4823 Added methods.yml and more
This commit is contained in:
parent
5aa27e45bd
commit
79c3582bb4
19
floriday.js
19
floriday.js
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
- organizations
|
||||
- warehouses
|
||||
- tradeItems
|
||||
- supplyLines
|
||||
- clockPresalesSupply
|
File diff suppressed because it is too large
Load Diff
|
@ -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
230
utils.js
|
@ -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)}`);
|
||||
};
|
Loading…
Reference in New Issue