413 lines
13 KiB
JavaScript
413 lines
13 KiB
JavaScript
import moment from 'moment';
|
|
import fetch from 'node-fetch';
|
|
import dotenv from 'dotenv';
|
|
import { models } from './models/index.js';
|
|
//import { v4 as uuidv4 } from 'uuid';
|
|
//import cliProgress from 'cli-progress';
|
|
import suppliersGln from './suppliersGln.js';
|
|
dotenv.config();
|
|
|
|
/**
|
|
* The Endpoint where the Access Token is requested
|
|
*/
|
|
const _accessTokenEndpoint = 'https://idm.staging.floriday.io/oauth2/ausmw6b47z1BnlHkw0h7/v1/token';
|
|
|
|
const BASE_CUSTOMER_URL = 'https://api.staging.floriday.io/customers-api/2022v2/';
|
|
|
|
/**
|
|
* Gets the Access Token from the client config table
|
|
*
|
|
* @param {sequelize.models} models
|
|
* @returns {Date} tokenExpirationDate formated as YYYY-MM-DD HH:mm:ss
|
|
*/
|
|
async function getClientToken() {
|
|
const clientConfigData = await models.clientConfig.findAll();
|
|
|
|
const now = moment().format('YYYY-MM-DD HH:mm:ss');
|
|
const tokenExpirationDate = clientConfigData[0].tokenExpiration;
|
|
|
|
if (clientConfigData[0].tokenExpiration == null || moment(now).isAfter(tokenExpirationDate)) {
|
|
let clientId = clientConfigData[0].clientId;
|
|
let clientSecret = clientConfigData[0].clientSecret;
|
|
|
|
const tokenRequest = await fetch(_accessTokenEndpoint, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
body: `grant_type=client_credentials&client_id=${clientId}&client_secret=${clientSecret}&scope=role:app catalog:read supply:read organization:read network:write network:read`,
|
|
});
|
|
|
|
const tokenResponse = await tokenRequest.json();
|
|
|
|
if (tokenRequest.status === 200) {
|
|
console.log('Token request successful');
|
|
} else {
|
|
throw new Error(
|
|
`Token request failed with status ${tokenRequest.status}`
|
|
);
|
|
}
|
|
|
|
const accessToken = tokenResponse.access_token;
|
|
let now = moment().format('YYYY-MM-DD HH:mm:ss');
|
|
|
|
let tokenExpirationDate = moment(now)
|
|
.add(tokenResponse.expires_in, 's')
|
|
.format('YYYY-MM-DD HH:mm:ss');
|
|
|
|
await updateClientConfig(
|
|
clientId,
|
|
clientSecret,
|
|
accessToken,
|
|
tokenExpirationDate
|
|
);
|
|
|
|
return tokenExpirationDate;
|
|
} else {
|
|
console.log('Using the current token...');
|
|
return tokenExpirationDate;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates the Access Token in the client config table
|
|
*
|
|
* @param {sequelize.models} models
|
|
* @param {String} clientId
|
|
* @param {String} clientSecret
|
|
* @param {String} accessToken
|
|
* @param {String} tokenExpirationDate
|
|
*/
|
|
async function updateClientConfig(clientId, clientSecret, accessToken, tokenExpirationDate) {
|
|
try {
|
|
console.log('Updating the client config with the new token...');
|
|
await models.clientConfig.update(
|
|
{
|
|
clientId: clientId,
|
|
clientSecret: clientSecret,
|
|
currentToken: accessToken,
|
|
tokenExpiration: tokenExpirationDate,
|
|
requestLimit : 500
|
|
},
|
|
{
|
|
where: {
|
|
id: 1,
|
|
},
|
|
}
|
|
);
|
|
console.log('Client config updated, new Token set');
|
|
console.log('New token expiration date: ', tokenExpirationDate);
|
|
} catch (error) {
|
|
console.log('There was a error while updating the client config');
|
|
console.log(error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* returns the current Access Token
|
|
*
|
|
* @returns
|
|
*/
|
|
async function getJWT() {
|
|
const clientConfigData = await models.clientConfig.findAll();
|
|
return clientConfigData[0].currentToken;
|
|
}
|
|
|
|
/**
|
|
* pauses the execution of the script for the given amount of milliseconds
|
|
*
|
|
* @param {integer} ms
|
|
* @returns A promise that resolves after ms milliseconds.
|
|
*/
|
|
async function sleep(ms) {
|
|
return new Promise((resolve) => {
|
|
setTimeout(resolve, ms);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Recieves an array of functions and executes them in a queue with the given concurrency
|
|
*
|
|
* @param {Array} fnArray
|
|
* @param {Number} concurrency
|
|
* @returns
|
|
*/
|
|
async function asyncQueue(fnArray, concurrency = 1) {
|
|
|
|
const results = []; // 1
|
|
|
|
const queue = fnArray.map((fn, index) => () => fn().then((result) => results[index] = result));
|
|
|
|
const run = async () => { // 2
|
|
const fn = queue.shift();
|
|
if (fn) {
|
|
await fn();
|
|
await run();
|
|
}
|
|
};
|
|
|
|
const promises = []; // 3
|
|
while (concurrency--) { // 4
|
|
promises.push(run());
|
|
}
|
|
|
|
await Promise.all(promises); // 5
|
|
|
|
return results;
|
|
|
|
}
|
|
// 1. Create an array of functions that will be executed in a queue
|
|
// 2. Create a function that will execute the functions in the queue
|
|
// 3. Create an array of promises that will execute the run function
|
|
// 4. Execute the run function while the concurrency is greater than 0
|
|
// 5. Return the results
|
|
|
|
/**
|
|
* Syncs the sequence number for the given model
|
|
* if no params are given it will reset all the sequence number to 0
|
|
*
|
|
* @param {Number} current - current sequence number
|
|
* @param {String} model - model name
|
|
* @param {Number} maximumSequenceNumber - maximum sequence number
|
|
* @returns
|
|
*/
|
|
async function syncSequence(current = 0, model = null ,maximumSequenceNumber = 0){
|
|
if (model == null && current == 0){
|
|
|
|
let mockModels = ['suppliers','tradeItems','supplyLines',];
|
|
|
|
for (let i = 0; i < mockModels.length; i++) {
|
|
const element = mockModels[i];
|
|
console.log('Syncing sequence for: ', element);
|
|
await syncSequence(0, element);
|
|
}
|
|
|
|
} else {
|
|
|
|
let tx = await models.sequelize.transaction();
|
|
|
|
try {
|
|
|
|
await models.sequenceNumber.upsert({
|
|
model: model,
|
|
sequenceNumber: current,
|
|
maximumSequenceNumber: maximumSequenceNumber
|
|
},{ transaction: tx });
|
|
|
|
await tx.commit();
|
|
|
|
} catch (error) {
|
|
await tx.rollback();
|
|
console.log('Error while syncing sequence number for: ', model);
|
|
}
|
|
}
|
|
}
|
|
|
|
async function syncSuppliers(){
|
|
|
|
let headers = {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Bearer ${await getJWT()}`,
|
|
'X-Api-Key': process.env.API_KEY
|
|
};
|
|
|
|
let rFloraHolland = suppliersGln.floraholland;
|
|
|
|
let queryConnections = `${BASE_CUSTOMER_URL}connections`;
|
|
|
|
let responseConnections = await fetch(queryConnections, {
|
|
method: 'GET',
|
|
headers: headers
|
|
});
|
|
|
|
let dataConnections = await responseConnections.json();
|
|
|
|
for(let connection of dataConnections){
|
|
await models.connections.findOrCreate({
|
|
where: {
|
|
organizationId: connection
|
|
},
|
|
defaults: {
|
|
organizationId: connection,
|
|
connect : true
|
|
}
|
|
});
|
|
}
|
|
|
|
for(let producer of rFloraHolland){
|
|
|
|
let query = `${BASE_CUSTOMER_URL}organizations/gln/${producer}`;
|
|
|
|
let response = await fetch(query, {
|
|
method: 'GET',
|
|
headers: headers
|
|
});
|
|
|
|
let data = await response.json();
|
|
|
|
if (response.status === 200) {
|
|
console.log('Supplier request successful');
|
|
|
|
let connection = await models.connections.findOne({
|
|
where: {
|
|
organizationId: data.organizationId,
|
|
connect: true
|
|
}
|
|
});
|
|
|
|
let isConnected = false;
|
|
|
|
|
|
|
|
|
|
if (connection != null) {
|
|
isConnected = true;
|
|
|
|
let where = {
|
|
companyGln: producer,
|
|
isConnected: isConnected
|
|
};
|
|
let defaults = {
|
|
isConnected: isConnected,
|
|
commercialName: data.commercialName,
|
|
email: data.email,
|
|
phone: data.phone,
|
|
website: data.website,
|
|
mailingAddress: data.mailingAddress,
|
|
physicalAddress: data.physicalAddress,
|
|
pythosanitaryNumber: data.phytosanitaryNumber,
|
|
sequenceNumber: data.sequenceNumber,
|
|
organizationId: data.organizationId,
|
|
companyGln: producer,
|
|
name: data.name,
|
|
endDate: data.endDate,
|
|
rfhRelationId: data.rfhRelationId,
|
|
organizationType: data.organizationType,
|
|
paymentProviders: JSON.stringify(data.paymentProviders),
|
|
};
|
|
|
|
await models.suppliers.destroy({
|
|
where: {
|
|
companyGln: producer,
|
|
isConnected: false
|
|
}
|
|
});
|
|
|
|
await models.suppliers.findOrCreate({
|
|
where : where,
|
|
defaults: defaults
|
|
});
|
|
} else {
|
|
let where = {
|
|
companyGln: producer,
|
|
isConnected: isConnected
|
|
};
|
|
let defaults = {
|
|
isConnected: isConnected,
|
|
commercialName: data.commercialName,
|
|
email: data.email,
|
|
phone: data.phone,
|
|
website: data.website,
|
|
mailingAddress: data.mailingAddress,
|
|
physicalAddress: data.physicalAddress,
|
|
pythosanitaryNumber: data.phytosanitaryNumber,
|
|
sequenceNumber: data.sequenceNumber,
|
|
organizationId: data.organizationId,
|
|
companyGln: producer,
|
|
name: data.name,
|
|
endDate: data.endDate,
|
|
rfhRelationId: data.rfhRelationId,
|
|
organizationType: data.organizationType,
|
|
paymentProviders: JSON.stringify(data.paymentProviders),
|
|
};
|
|
await models.suppliers.destroy({
|
|
where: {
|
|
companyGln: producer,
|
|
isConnected: true
|
|
}
|
|
});
|
|
await models.suppliers.findOrCreate({
|
|
where: where,
|
|
defaults: defaults
|
|
});
|
|
}
|
|
|
|
|
|
console.log(`DATA FOR SUPPLIER: ${data.name} OK`);
|
|
} else {
|
|
console.log('Supplier request failed with status ', response.status);
|
|
console.log('Supplier: ', data);
|
|
console.log('response: ', response);
|
|
console.log('query: ', query);
|
|
}
|
|
}
|
|
}
|
|
|
|
async function syncTradeItems(){
|
|
|
|
let suppliers = await models.suppliers.findAll({
|
|
where: {
|
|
isConnected: true
|
|
}
|
|
});
|
|
|
|
let headers = {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Bearer ${await getJWT()}`,
|
|
'X-Api-Key': process.env.API_KEY
|
|
};
|
|
|
|
for (let i = 0; i < suppliers.length; i++) {
|
|
|
|
let queryMaxSequence = `${BASE_CUSTOMER_URL}trade-items/current-max-sequence`;
|
|
|
|
let responseMaxSequence = await fetch(queryMaxSequence, {
|
|
method: 'GET',
|
|
headers: headers
|
|
});
|
|
|
|
let maximumSequenceNumber = await responseMaxSequence.json();
|
|
|
|
await syncSequence(0, 'tradeItems', maximumSequenceNumber);
|
|
|
|
let currentSequence = await models.sequenceNumber.findOne({
|
|
where: {
|
|
model: 'tradeItems'
|
|
}
|
|
});
|
|
|
|
currentSequence = currentSequence.sequenceNumber;
|
|
|
|
let estimatedIterations = Math.ceil(maximumSequenceNumber / 1000);
|
|
|
|
let supplier = suppliers[i];
|
|
|
|
console.log('Syncing trade items for: ', supplier.name);
|
|
console.log('Supplier Id: ', supplier.organizationId);
|
|
console.log('Current sequence number: ', currentSequence);
|
|
console.log('Maximum sequence number: ', maximumSequenceNumber);
|
|
console.log('Estimated iterations: ', estimatedIterations);
|
|
|
|
for (let j = 0; j < estimatedIterations; j++) {
|
|
|
|
let query = `${BASE_CUSTOMER_URL}trade-items/sync/${currentSequence}?supplierOrganizationId=${supplier.organizationId}&limit=1000`;
|
|
|
|
let request = await fetch(query, {
|
|
method: 'GET',
|
|
headers: headers
|
|
});
|
|
|
|
let data = await request.json();
|
|
|
|
let results = data.results;
|
|
|
|
if (results.length == 0) {
|
|
console.log('No more trade items to sync');
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
export { getClientToken, updateClientConfig, getJWT, sleep, asyncQueue, syncSequence, syncSuppliers, syncTradeItems }; |