diff --git a/README.md b/README.md index 5c34937..7ed8355 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # Floriday -Requires [Node.js](https://nodejs.org/en/) v15.14.0 or higher. - 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. @@ -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, 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 - In case a new model is created, it should follow the following structure: - /models - - index.js + - main.js - foo.js ### Foo.js @@ -51,7 +87,7 @@ export default (sequelize) => { }; ``` -### Index.js +### main.js ```javascript import foo from "./foo"; @@ -62,32 +98,7 @@ let models = { ``` -To install dependencies: +## Built With -```bash -npm install -``` - -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 -``` +* [nodejs](https://nodejs.org/) +* [sequalize](https://sequelize.org/) \ No newline at end of file diff --git a/main.js b/main.js index ca9c7f6..875b02c 100644 --- a/main.js +++ b/main.js @@ -2,42 +2,59 @@ import * as vnUtils from './utils.js'; import { models } from './models/index.js'; 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() { - 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 { - while (true) { - try{ - console.log('Querying the API to check for new data...'); - console.log('Current token expiration date: ', tokenExpirationDate); - - if (moment().isAfter(tokenExpirationDate)) { - console.log('Token expired, getting a new one...'); - tokenExpirationDate = await vnUtils.getClientToken(models); + const env = process.env; + let tokenExpirationDate = await vnUtils.getClientToken(models); + + if (JSON.parse(env.SYNC_SEQUENCE)) await vnUtils.syncSequence() + if (JSON.parse(env.SYNC_SUPPLIER)) await vnUtils.syncSuppliers(); + + await vnUtils.syncConnections(); + + 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(); - - } catch (error) { - console.error(error); - } - - if (env.STATUS == 'development') { - await vnUtils.sleep(120000); - } else { - await vnUtils.sleep(300000); + + if (JSON.parse(env.IS_PRODUCTION)) + await vnUtils.sleep(300000); + else + await vnUtils.sleep(120000); } + } catch (err) { + myErr(err); } - } catch (error) { - console.error('Unable to connect to the database:', error); + } catch (err) { + 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() \ No newline at end of file diff --git a/models/index.js b/models/index.js index 698c151..2301831 100644 --- a/models/index.js +++ b/models/index.js @@ -16,7 +16,7 @@ console.log( ) let sequelize = createConnection(); -const conSpinner = ora('Creating the connection...').start(); +const conSpinner = ora('Creating connection...').start(); try { await sequelize.authenticate(); conSpinner.succeed(); @@ -161,18 +161,18 @@ models.tradeItem.belongsTo(models.supplier, { }); -let action, force; -if (process.env.FORCE_SYNC === 'true') { +let action, isForce; +if (JSON.parse(process.env.FORCE_SYNC)) { action = 'Forcing' - force = true + isForce = true } else { action = 'Altering' - force = false + isForce = false } -const modSpinner = ora(`${action} the models...`).start(); +const modSpinner = ora(`${action} models...`).start(); try { - await sequelize.sync({ force: force }); + await sequelize.sync({ force: isForce }); if (process.env.SECRETS) { await models.clientConfig.findOrCreate({ where: { diff --git a/utils.js b/utils.js index a714aa3..1c0d85a 100644 --- a/utils.js +++ b/utils.js @@ -24,6 +24,7 @@ async function getClientToken() { throw colors.red.bold('No data found in the configuration table, ', '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 tokenExpirationDate = clientConfigData[0].tokenExpiration; @@ -42,11 +43,11 @@ async function getClientToken() { const tokenResponse = await tokenRequest.json(); if (tokenRequest.status === 200) { - console.log('Token request successful'); + spinner.succeed(); + } else { - throw new Error( - `Token request failed with status ${tokenRequest.status}` - ); + spinner.fail(); + throw new Error(`Token request failed with status: ${tokenRequest.status} - ${tokenRequest.statusText}`); } const accessToken = tokenResponse.access_token; @@ -65,7 +66,8 @@ async function getClientToken() { return tokenExpirationDate; } else { - console.log('Using the current token...'); + spinner.text = 'Using stored token...' + spinner.succeed(); return tokenExpirationDate; } } @@ -81,7 +83,7 @@ async function getClientToken() { */ async function updateClientConfig(clientId, clientSecret, accessToken, tokenExpirationDate) { try { - console.log('Updating the client config with the new token...'); + const spinner = ora(`Updating config...`).start(); await models.clientConfig.upsert({ id: 1, clientId: clientId, @@ -90,9 +92,9 @@ async function updateClientConfig(clientId, clientSecret, accessToken, tokenExpi tokenExpiration: tokenExpirationDate, requestLimit: 500, }); - console.log('Client config updated, new Token set'); - console.log('New token expiration date: ', tokenExpirationDate); + spinner.succeed(); } catch (error) { + spinner.fail(); console.log('There was a error while updating the client config'); console.log(error); } @@ -168,19 +170,23 @@ async function asyncQueue(fnArray, concurrency = 1) { */ async function syncSequence(current = 0, model = null , maximumSequenceNumber = 0){ if (model == null && current == 0){ - - let mockModels = [ - 'suppliers'.green, - 'tradeItems'.blue, - 'supplyLines'.yellow]; - - for (let mockModel in mockModels) { - const element = mockModels[mockModel]; - console.log('Syncing sequence for:', element); - await syncSequence(0, element); + try { + let mockModels = [ + 'suppliers', + 'tradeItems', + 'supplyLines', + ]; + const spinner = ora(`Syncing sequence...`).start(); + for (let mockModel in mockModels) { + const element = mockModels[mockModel]; + await syncSequence(0, element); + } + spinner.succeed(); + } catch (err) { + spinner.fail(); + throw(err); } - - } else { + } else if (current) { let tx = await models.sequelize.transaction(); @@ -219,58 +225,69 @@ async function syncSequence(current = 0, model = null , maximumSequenceNumber = } async function syncSuppliers(){ - let headers = { - '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 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, { + try { + const spinner = ora('Preparing to load suppliers...').start(); + let headers = { + '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 }); - - let data = await response.json(); - - let suppliers = data.results; - for (let supplier of suppliers) { - curSequenceNumber = supplier.sequenceNumber; - if (!spinner) { - spinner = ora('').start(); - spinner.color = 'green'; - } - 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 + const maxSequenceNumber = await response.json(); + let timeFinish, timeToGoSec, timeToGoMin, timeLeft; + for (let curSequenceNumber = 0; curSequenceNumber <= maxSequenceNumber; curSequenceNumber++) { + let timeStart = new moment(); + + let query = `${url}/organizations/sync/${curSequenceNumber}?organizationType=SUPPLIER`; + let response = await fetch(query, { + method: 'GET', + headers: headers }); + 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() + } + catch (err) { + spinner.fail(); + throw(err); + } } async function syncConnections(){ @@ -331,11 +348,8 @@ async function syncConnections(){ } async function syncTradeItems(){ - const suppliers = await models.supplier.findAll(); - let i = 0; - console.log('Syncing trade items'); for (let supplier of suppliers) { i++;