refs #4823 Code refactor

This commit is contained in:
Guillermo Bonet 2023-04-04 20:14:20 +02:00
parent cdd2fa269f
commit ecf9ceb44b
4 changed files with 179 additions and 137 deletions

View File

@ -1,7 +1,5 @@
# Floriday # Floriday
Requires [Node.js](https://nodejs.org/en/) v15.14.0 or higher.
The Floriday service project should perform the following tasks: The Floriday service project should perform the following tasks:
1. Create / mantain the table structure to allow the storage of the data provided by the Floriday API. 1. Create / mantain the table structure to allow the storage of the data provided by the Floriday API.
@ -12,13 +10,51 @@ The Floriday service project should perform the following tasks:
This is done using the [Sequelize](https://sequelize.org/) ORM and storing the data as it is received from the API, This is done using the [Sequelize](https://sequelize.org/) ORM and storing the data as it is received from the API,
so it can be compared with the previous data. so it can be compared with the previous data.
## Requeriments
* Git
* Nodejs (v15.14.0 or higher)
## Installation
Pull from repository.
Run this commands on project root directory to install Node dependencies.
```bash
npm i
```
### .env file template
```bash
#FLORIDAY DATA
CLIENT_ID = xxxxxxxxxx
CLIENT_SECRET = xxxxxxxxxx
API_KEY = xxxxxxxxxx
#SEQUELIZE CONFIG
DB_SCHEMA = schema
DB_USER = root
DB_PWD = root
DB_HOST = localhost
DB_DIALECT = mariadb
#GENERAL CONFIG
IS_PRODUCTION = false
SECRETS = true
FORCE_SYNC = true
SYNC_SEQUENCE = true
SYNC_SUPPLIER = true
SYNC_TRADEITEM = true
```
## Guidelines ## Guidelines
- In case a new model is created, it should follow the following structure: - In case a new model is created, it should follow the following structure:
- /models - /models
- index.js - main.js
- foo.js - foo.js
### Foo.js ### Foo.js
@ -51,7 +87,7 @@ export default (sequelize) => {
}; };
``` ```
### Index.js ### main.js
```javascript ```javascript
import foo from "./foo"; import foo from "./foo";
@ -62,32 +98,7 @@ let models = {
``` ```
To install dependencies: ## Built With
```bash * [nodejs](https://nodejs.org/)
npm install * [sequalize](https://sequelize.org/)
```
To run:
```bash
npm start # run the service
npm dev-sync # run and create the db structure
```
### .env file
```bash
# FLORIDAY SERVICE CONFIG
CLIENT_ID = floriday-client_id
CLIENT_SECRET = floriday-client_secret
STATUS = production_or_development
# SEQUELIZE CONFIG
DB_SCHEMA = edi
DB_USER = root
DB_PWD = root
DB_HOST = localhost
DB_DIALECT = mariadb
FORCE_SYNC = false
```

75
main.js
View File

@ -2,42 +2,59 @@ import * as vnUtils from './utils.js';
import { models } from './models/index.js'; import { models } from './models/index.js';
import moment from 'moment'; import moment from 'moment';
console.log = (...args) => console.info(`${new moment().format('HH:mm:ss')} -`, ...args); // Añade la hora a todos los console.log
// console.log = (...args) => console.info(`${new moment().format('HH:mm:ss')} -`, ...args);
async function main() { async function main() {
let tokenExpirationDate = await vnUtils.getClientToken(models);
const env = process.env;
env.SYNC_SEQUENCE ? await vnUtils.syncSequence() : null;
env.SYNC_SUPPLIER ? await vnUtils.syncSuppliers() : null;
await vnUtils.syncConnections();
env.SYNC_TRADEITEM ? await vnUtils.syncTradeItems() : null;
console.log('Synced trade items');
try { try {
while (true) { const env = process.env;
try{ let tokenExpirationDate = await vnUtils.getClientToken(models);
console.log('Querying the API to check for new data...');
console.log('Current token expiration date: ', tokenExpirationDate); if (JSON.parse(env.SYNC_SEQUENCE)) await vnUtils.syncSequence()
if (JSON.parse(env.SYNC_SUPPLIER)) await vnUtils.syncSuppliers();
if (moment().isAfter(tokenExpirationDate)) {
console.log('Token expired, getting a new one...'); await vnUtils.syncConnections();
tokenExpirationDate = await vnUtils.getClientToken(models);
if (JSON.parse(env.SYNC_TRADEITEM)) await vnUtils.syncTradeItems();
console.log('Synced trade items');
try {
while (true) {
try{
console.log('Querying the API to check for new data...');
if (moment().isAfter(tokenExpirationDate)) {
console.log('Token expired, getting a new one...');
tokenExpirationDate = await vnUtils.getClientToken(models);
}
await vnUtils.syncSupplyLines();
} catch (err) {
console.error(err);
} }
await vnUtils.syncSupplyLines();
if (JSON.parse(env.IS_PRODUCTION))
} catch (error) { await vnUtils.sleep(300000);
console.error(error); else
} await vnUtils.sleep(120000);
if (env.STATUS == 'development') {
await vnUtils.sleep(120000);
} else {
await vnUtils.sleep(300000);
} }
} catch (err) {
myErr(err);
} }
} catch (error) { } catch (err) {
console.error('Unable to connect to the database:', error); myErr(err);
} }
} }
/**
* Creates the connection to the database.
*
* @param {err}
**/
function myErr(err) {
console.log(`[ERROR]`.red.bold, `${err.name}: ${err.message}`.red);
process.exit();
}
main() main()

View File

@ -16,7 +16,7 @@ console.log(
) )
let sequelize = createConnection(); let sequelize = createConnection();
const conSpinner = ora('Creating the connection...').start(); const conSpinner = ora('Creating connection...').start();
try { try {
await sequelize.authenticate(); await sequelize.authenticate();
conSpinner.succeed(); conSpinner.succeed();
@ -161,18 +161,18 @@ models.tradeItem.belongsTo(models.supplier, {
}); });
let action, force; let action, isForce;
if (process.env.FORCE_SYNC === 'true') { if (JSON.parse(process.env.FORCE_SYNC)) {
action = 'Forcing' action = 'Forcing'
force = true isForce = true
} else { } else {
action = 'Altering' action = 'Altering'
force = false isForce = false
} }
const modSpinner = ora(`${action} the models...`).start(); const modSpinner = ora(`${action} models...`).start();
try { try {
await sequelize.sync({ force: force }); await sequelize.sync({ force: isForce });
if (process.env.SECRETS) { if (process.env.SECRETS) {
await models.clientConfig.findOrCreate({ await models.clientConfig.findOrCreate({
where: { where: {

152
utils.js
View File

@ -24,6 +24,7 @@ async function getClientToken() {
throw colors.red.bold('No data found in the configuration table, ', throw colors.red.bold('No data found in the configuration table, ',
'if you have configured the .env file, declare the variable SECRET as true') 'if you have configured the .env file, declare the variable SECRET as true')
const spinner = ora(`Requesting token...`).start();
const now = moment().format('YYYY-MM-DD HH:mm:ss'); const now = moment().format('YYYY-MM-DD HH:mm:ss');
const tokenExpirationDate = clientConfigData[0].tokenExpiration; const tokenExpirationDate = clientConfigData[0].tokenExpiration;
@ -42,11 +43,11 @@ async function getClientToken() {
const tokenResponse = await tokenRequest.json(); const tokenResponse = await tokenRequest.json();
if (tokenRequest.status === 200) { if (tokenRequest.status === 200) {
console.log('Token request successful'); spinner.succeed();
} else { } else {
throw new Error( spinner.fail();
`Token request failed with status ${tokenRequest.status}` throw new Error(`Token request failed with status: ${tokenRequest.status} - ${tokenRequest.statusText}`);
);
} }
const accessToken = tokenResponse.access_token; const accessToken = tokenResponse.access_token;
@ -65,7 +66,8 @@ async function getClientToken() {
return tokenExpirationDate; return tokenExpirationDate;
} else { } else {
console.log('Using the current token...'); spinner.text = 'Using stored token...'
spinner.succeed();
return tokenExpirationDate; return tokenExpirationDate;
} }
} }
@ -81,7 +83,7 @@ async function getClientToken() {
*/ */
async function updateClientConfig(clientId, clientSecret, accessToken, tokenExpirationDate) { async function updateClientConfig(clientId, clientSecret, accessToken, tokenExpirationDate) {
try { try {
console.log('Updating the client config with the new token...'); const spinner = ora(`Updating config...`).start();
await models.clientConfig.upsert({ await models.clientConfig.upsert({
id: 1, id: 1,
clientId: clientId, clientId: clientId,
@ -90,9 +92,9 @@ async function updateClientConfig(clientId, clientSecret, accessToken, tokenExpi
tokenExpiration: tokenExpirationDate, tokenExpiration: tokenExpirationDate,
requestLimit: 500, requestLimit: 500,
}); });
console.log('Client config updated, new Token set'); spinner.succeed();
console.log('New token expiration date: ', tokenExpirationDate);
} catch (error) { } catch (error) {
spinner.fail();
console.log('There was a error while updating the client config'); console.log('There was a error while updating the client config');
console.log(error); console.log(error);
} }
@ -168,19 +170,23 @@ async function asyncQueue(fnArray, concurrency = 1) {
*/ */
async function syncSequence(current = 0, model = null , maximumSequenceNumber = 0){ async function syncSequence(current = 0, model = null , maximumSequenceNumber = 0){
if (model == null && current == 0){ if (model == null && current == 0){
try {
let mockModels = [ let mockModels = [
'suppliers'.green, 'suppliers',
'tradeItems'.blue, 'tradeItems',
'supplyLines'.yellow]; 'supplyLines',
];
for (let mockModel in mockModels) { const spinner = ora(`Syncing sequence...`).start();
const element = mockModels[mockModel]; for (let mockModel in mockModels) {
console.log('Syncing sequence for:', element); const element = mockModels[mockModel];
await syncSequence(0, element); await syncSequence(0, element);
}
spinner.succeed();
} catch (err) {
spinner.fail();
throw(err);
} }
} else if (current) {
} else {
let tx = await models.sequelize.transaction(); let tx = await models.sequelize.transaction();
@ -219,58 +225,69 @@ async function syncSequence(current = 0, model = null , maximumSequenceNumber =
} }
async function syncSuppliers(){ async function syncSuppliers(){
let headers = { try {
'Content-Type': 'application/json', const spinner = ora('Preparing to load suppliers...').start();
'Authorization': `Bearer ${await getJWT()}`, let headers = {
'X-Api-Key': process.env.API_KEY 'Content-Type': 'application/json',
}; 'Authorization': `Bearer ${await getJWT()}`,
'X-Api-Key': process.env.API_KEY
const response = await fetch(`${url}/organizations/current-max-sequence`, { };
method: 'GET',
headers: headers const response = await fetch(`${url}/organizations/current-max-sequence`, {
});
const maxSequenceNumber = await response.json();
let spinner;
for (let curSequenceNumber = 0; curSequenceNumber <= maxSequenceNumber; curSequenceNumber++) {
let query = `${url}/organizations/sync/${curSequenceNumber}?organizationType=SUPPLIER`;
let response = await fetch(query, {
method: 'GET', method: 'GET',
headers: headers headers: headers
}); });
const maxSequenceNumber = await response.json();
let data = await response.json(); let timeFinish, timeToGoSec, timeToGoMin, timeLeft;
for (let curSequenceNumber = 0; curSequenceNumber <= maxSequenceNumber; curSequenceNumber++) {
let suppliers = data.results; let timeStart = new moment();
for (let supplier of suppliers) {
curSequenceNumber = supplier.sequenceNumber; let query = `${url}/organizations/sync/${curSequenceNumber}?organizationType=SUPPLIER`;
if (!spinner) { let response = await fetch(query, {
spinner = ora('').start(); method: 'GET',
spinner.color = 'green'; headers: headers
}
spinner.text = `Loading suppliers ${curSequenceNumber} of ${maxSequenceNumber}`.green
await models.supplier.upsert({
sequenceNumber: supplier.sequenceNumber,
companyGln: supplier.companyGln,
name: supplier.name,
commercialName: supplier.commercialName,
email: supplier.email,
phone: supplier.phone,
website: supplier.website,
organizationId: supplier.organizationId,
rfhRelationId: supplier.rfhRelationId,
paymentProviders: `${supplier.paymentProviders}`,
endDate: supplier.endDate,
mailingAddress: supplier.mailingAddress,
physicalAddress: supplier.physicalAddress,
pythosanitaryNumber: supplier.pythosanitaryNumber,
organizationType: supplier.organizationType
}); });
let data = await response.json();
let suppliers = data.results;
for (let supplier of suppliers) {
curSequenceNumber = supplier.sequenceNumber;
spinner.text = `Loading suppliers, ${maxSequenceNumber - curSequenceNumber} are missing`
if (timeFinish)
spinner.text = spinner.text + ` (${timeLeft})`
await models.supplier.upsert({
sequenceNumber: supplier.sequenceNumber,
companyGln: supplier.companyGln,
name: supplier.name,
commercialName: supplier.commercialName,
email: supplier.email,
phone: supplier.phone,
website: supplier.website,
organizationId: supplier.organizationId,
rfhRelationId: supplier.rfhRelationId,
paymentProviders: `${supplier.paymentProviders}`,
endDate: supplier.endDate,
mailingAddress: supplier.mailingAddress,
physicalAddress: supplier.physicalAddress,
pythosanitaryNumber: supplier.pythosanitaryNumber,
organizationType: supplier.organizationType
});
}
await syncSequence(curSequenceNumber, 'suppliers', maxSequenceNumber);
timeFinish = new moment();
timeToGoSec = (timeFinish.diff(timeStart, 'seconds') * (maxSequenceNumber - curSequenceNumber) / 1000)
timeToGoMin = Math.trunc(timeToGoSec / 60)
if (!timeToGoMin)
timeLeft = `${Math.trunc(timeToGoSec)} sec`
else
timeLeft = `${timeToGoMin} min`
} }
await syncSequence(curSequenceNumber, 'suppliers', maxSequenceNumber);
}
if (spinner)
spinner.succeed() spinner.succeed()
}
catch (err) {
spinner.fail();
throw(err);
}
} }
async function syncConnections(){ async function syncConnections(){
@ -331,11 +348,8 @@ async function syncConnections(){
} }
async function syncTradeItems(){ async function syncTradeItems(){
const suppliers = await models.supplier.findAll(); const suppliers = await models.supplier.findAll();
let i = 0; let i = 0;
console.log('Syncing trade items'); console.log('Syncing trade items');
for (let supplier of suppliers) { for (let supplier of suppliers) {
i++; i++;