refs #4823 ESModule-to-CommonJS

This commit is contained in:
Guillermo Bonet 2023-03-14 13:30:54 +01:00
parent c57916815d
commit ad38daebe9
23 changed files with 406 additions and 328 deletions

18
.env_template Normal file
View File

@ -0,0 +1,18 @@
# FLORIDAY SERVICE CONFIG
clientId = floriday-client_id
clientSecret = floriday-client_secret
environment = production_or_development
# SEQUELIZE CONFIG
dbHost = localhost
dbPort = 3306
dbSchema = floriday
dbUser = root
dbPwd = root
dbDialect = mariadb
forceCreateSchema = false
forceSync = false
putSecrets = false
syncSequence = true
syncSuplier = true
syncTradeItem = true

View File

@ -7,7 +7,7 @@ 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.
This is done using the [Sequelize](https://sequelize.org/) ORM. This is done using the [Sequelize](https://sequelize.org/) ORM.
2. Query the Floriday API and store the data in the database. 2. Query the Floriday API and store the data in the database.
This is done using the [node-fetch](https://www.npmjs.com/package/node-fetch) package. This is done using the [axios](https://www.npmjs.com/package/axios) package.
2.1. The data is requested every minute, but only the data that has changed is stored in the database. 2.1. The data is requested every minute, but only the data that has changed is stored in the database.
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.
@ -59,7 +59,6 @@ import foo from "./foo";
let models = { let models = {
bar: foo(sequelize), bar: foo(sequelize),
}; };
``` ```
To install dependencies: To install dependencies:
@ -71,23 +70,9 @@ npm install
To run: To run:
```bash ```bash
npm start # run the service node main # Run the service
npm dev-sync # run and create the db structure
``` ```
### .env file ## Config file:
```bash Rename '.env_emplate' → '.env'
# 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
```

View File

@ -1,51 +0,0 @@
import moment from 'moment';
import * as vnUtils from './utils.js';
//import cliProgress from 'cli-progress';
import dotenv from 'dotenv';
dotenv.config();
import { models } from './models/index.js';
console.log = function () {
let args = Array.prototype.slice.call(arguments);
args.unshift(new moment().format('HH:mm:ss') + ' -');
console.info.apply(console, args);
};
let tokenExpirationDate = await vnUtils.getClientToken(models);
process.env.SYNC_SEQUENCE ? await vnUtils.syncSequence() : null;
process.env.SYNC_SUPPLIER ? await vnUtils.syncSuppliers() : null;
await vnUtils.syncConnections();
process.env.SYNC_TRADEITEM ? await vnUtils.syncTradeItems() : null;
console.log('Synced trade items');
try {
// eslint-disable-next-line no-constant-condition
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);
}
await vnUtils.syncSupplyLines();
} catch (error) {
console.error(error);
}
if (process.env.STATUS == 'development') {
await vnUtils.sleep(120000);
} else {
await vnUtils.sleep(300000);
}
}
} catch (error) {
console.error('Unable to connect to the database:', error);
}

51
main.js Normal file
View File

@ -0,0 +1,51 @@
const moment = require('moment');
const { models } = require('./models/index.js');
const vnUtils = require('./utils.js');
require('dotenv').config()
// const cliProgress = require('cli-progress');
async function main() {
console.log = function () {
let args = Array.prototype.slice.call(arguments);
args.unshift(new moment().format('HH:mm:ss') + ' -');
console.info.apply(console, args);
};
let tokenExpirationDate = vnUtils.getClientToken(models);
process.env.syncSequence ? await vnUtils.syncSequence() : null;
process.env.syncSupplier ? await vnUtils.syncSuppliers() : null;
await vnUtils.syncConnections();
process.env.syncTradeItem ? await vnUtils.syncTradeItems() : null;
console.log('Synced trade items');
try {
// eslint-disable-next-line no-constant-condition
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);
}
await vnUtils.syncSupplyLines();
} catch (error) {
console.error(error);
}
if (process.env.environment == 'development') {
await vnUtils.sleep(120000);
} else {
await vnUtils.sleep(300000);
}
}
} catch (error) {
console.error('Unable to connect to the database:', error);
}
}
main();

View File

@ -1,4 +1,4 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require('sequelize');
const clientConfig = { const clientConfig = {
id: { id: {
@ -23,7 +23,7 @@ const clientConfig = {
}, },
}; };
export default (sequelize) => { module.exports = function (sequelize) {
const ClientConfig = sequelize.define( const ClientConfig = sequelize.define(
'FDClientConfig', 'FDClientConfig',
clientConfig, clientConfig,

View File

@ -1,4 +1,4 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require('sequelize');
const sequenceNumber = { const sequenceNumber = {
id: { id: {
@ -21,7 +21,7 @@ const sequenceNumber = {
}, },
}; };
export default (sequelize) => { module.exports = function (sequelize) {
const sequenceNumbers = sequelize.define( const sequenceNumbers = sequelize.define(
'FDsequenceNumber', 'FDsequenceNumber',
sequenceNumber, sequenceNumber,

View File

@ -1,33 +1,35 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require ('sequelize');
import dotenv from 'dotenv'; const colors = require('colors');
dotenv.config(); require('dotenv').config()
console.clear();
const decoration = '△▽'.repeat(10);
const appName = colors.bold.green('Floriday Service');
console.log(`${decoration} ${appName} ${decoration}`);
let sequelize = createConnection(); let sequelize = createConnection();
main();
// Supply Line Models
import supplyLine from './supplyLine/supplyLine.js';
import volumePrices from './supplyLine/volumePrices.js';
// Conf Models // Conf Models
import clientConfig from './conf/clientConfig.js'; const clientConfig = require('./conf/clientConfig.js');
import sequenceNumber from './conf/sequenceNumber.js'; const sequenceNumber = require('./conf/sequenceNumber.js');
// Supply Line Models
const supplyLine = require('./supplyLine/supplyLine.js');
const volumePrices = require('./supplyLine/volumePrices.js');
// Supplier Models // Supplier Models
import suppliers from './supplier/suppliers.js'; const suppliers = require('./supplier/suppliers.js');
import connections from './supplier/connections.js'; const connections = require('./supplier/connections.js');
// TradeItem Models // TradeItem Models
import tradeItem from './tradeItem/tradeItem.js'; const tradeItem = require('./tradeItem/tradeItem.js');
import botanicalNames from './tradeItem/botanicalNames.js'; const botanicalNames = require('./tradeItem/botanicalNames.js');
import countryOfOriginIsoCodes from './tradeItem/countryOfOriginIsoCodes.js'; const countryOfOriginIsoCodes = require('./tradeItem/countryOfOriginIsoCodes.js');
import packageModel from './tradeItem/package.js'; const packageModel = require('./tradeItem/package.js');
import packingConfigurations from './tradeItem/packingConfigurations.js'; const packingConfigurations = require('./tradeItem/packingConfigurations.js');
import photos from './tradeItem/photos.js'; const photos = require('./tradeItem/photos.js');
import seasonalPeriod from './tradeItem/seasonalPeriod.js'; const seasonalPeriod = require('./tradeItem/seasonalPeriod.js');
import characteristics from './tradeItem/characteristics.js'; const characteristics = require('./tradeItem/characteristics.js');
/** /**
* Contains all the models that are related to the application. * Contains all the models that are related to the application.
@ -46,7 +48,6 @@ import characteristics from './tradeItem/characteristics.js';
* foo: 'bar', * foo: 'bar',
* }); * });
* *
*
* @type {Object.<string, Sequelize.Model>} * @type {Object.<string, Sequelize.Model>}
*/ */
let models = { let models = {
@ -80,87 +81,86 @@ models.characteristic.belongsTo(models.tradeItem, {
as: 'tradeItem_Fk', as: 'tradeItem_Fk',
targetKey: 'tradeItemId', targetKey: 'tradeItemId',
}); });
models.seasonalPeriod.belongsTo(models.tradeItem, { models.seasonalPeriod.belongsTo(models.tradeItem, {
foreignKey: 'tradeItemFk', foreignKey: 'tradeItemFk',
as: 'tradeItem_Fk', as: 'tradeItem_Fk',
targetKey: 'tradeItemId', targetKey: 'tradeItemId',
}); });
models.photo.belongsTo(models.tradeItem, { models.photo.belongsTo(models.tradeItem, {
foreignKey: 'tradeItemFk', foreignKey: 'tradeItemFk',
as: 'tradeItem_Fk', as: 'tradeItem_Fk',
targetKey: 'tradeItemId', targetKey: 'tradeItemId',
}); });
models.packingConfiguration.belongsTo(models.tradeItem, { models.packingConfiguration.belongsTo(models.tradeItem, {
foreignKey: 'tradeItemFk', foreignKey: 'tradeItemFk',
as: 'tradeItem_Fk', as: 'tradeItem_Fk',
targetKey: 'tradeItemId', targetKey: 'tradeItemId',
}); });
models.packingConfiguration.hasMany(models.package, { models.packingConfiguration.hasMany(models.package, {
foreignKey: 'packingConfigurationFk', foreignKey: 'packingConfigurationFk',
as: 'package_Fk', as: 'package_Fk',
targetKey: 'packingConfigurationId', targetKey: 'packingConfigurationId',
}); });
models.package.belongsTo(models.packingConfiguration, { models.package.belongsTo(models.packingConfiguration, {
foreignKey: 'packingConfigurationFk', foreignKey: 'packingConfigurationFk',
as: 'packingConfiguration_Fk', as: 'packingConfiguration_Fk',
targetKey: 'packingConfigurationId', targetKey: 'packingConfigurationId',
}); });
models.botanicalName.belongsTo(models.tradeItem, { models.botanicalName.belongsTo(models.tradeItem, {
foreignKey: 'tradeItemFk', foreignKey: 'tradeItemFk',
as: 'tradeItem_Fk', as: 'tradeItem_Fk',
targetKey: 'tradeItemId', targetKey: 'tradeItemId',
}); });
models.countryOfOriginIsoCode.belongsTo(models.tradeItem, { models.countryOfOriginIsoCode.belongsTo(models.tradeItem, {
foreignKey: 'tradeItemFk', foreignKey: 'tradeItemFk',
as: 'tradeItem_Fk', as: 'tradeItem_Fk',
targetKey: 'tradeItemId', targetKey: 'tradeItemId',
}); });
models.volumePrice.belongsTo(models.supplyLine, { models.volumePrice.belongsTo(models.supplyLine, {
foreignKey: 'supplyLineFk', foreignKey: 'supplyLineFk',
as: 'supplyLine_Fk', as: 'supplyLine_Fk',
targetKey: 'supplyLineId', targetKey: 'supplyLineId',
}); });
models.supplyLine.belongsTo(models.tradeItem, { models.supplyLine.belongsTo(models.tradeItem, {
foreignKey: 'tradeItemFk', foreignKey: 'tradeItemFk',
as: 'tradeItem_Fk', as: 'tradeItem_Fk',
targetKey: 'tradeItemId', targetKey: 'tradeItemId',
}); });
models.tradeItem.belongsTo(models.supplier, { models.tradeItem.belongsTo(models.supplier, {
foreignKey: 'supplierOrganizationId', foreignKey: 'supplierOrganizationId',
as: 'supplierOrganization_Id', as: 'supplierOrganization_Id',
targetKey: 'organizationId', targetKey: 'organizationId',
}); });
if (process.env.FORCE_SYNC === 'true') { async function main() {
const conf = process.env;
try {
if (conf.forceCreateSchema == 'true')
await sequelize.createSchema(conf.dbSchema, { ifNotExists: true });
if (conf.forceSync === 'true') {
console.log('Forcing the models...'); console.log('Forcing the models...');
await sequelize.sync({ force: true }); await sequelize.sync({ force: true });
} else { } else {
console.log('Altering the models...'); console.log('Altering the models...');
await sequelize.sync({ alter: true }); await sequelize.sync({ alter: true });
} }
} catch (err) {
sendError(err.original.text)
}
if (process.env.SECRETS) { if (conf.putSecrets === 'true') {
await models.clientConfig.findOrCreate({ await models.clientConfig.findOrCreate({
where: { where: {
id: 1, id: 1,
}, },
defaults: { defaults: {
clientId: process.env.CLIENT_ID, clientId: conf.clientId,
clientSecret: process.env.CLIENT_SECRET, clientSecret: conf.clientSecret,
}, },
}); });
} }
}
/** /**
* Creates the connection to the database. * Creates the connection to the database.
@ -171,10 +171,13 @@ if (process.env.SECRETS) {
* @returns {Sequelize} Sequelize instance with the connection to the database. * @returns {Sequelize} Sequelize instance with the connection to the database.
*/ */
function createConnection() { function createConnection() {
console.log('Creating the connection...'); const conf = process.env;
return new Sequelize(process.env.DB_SCHEMA, process.env.DB_USER, process.env.DB_PWD, { console.log('Creating the connection...'.green.bold);
host: process.env.DB_HOST, try {
dialect: process.env.DB_DIALECT, return new Sequelize(conf.dbSchema, conf.dbUser, conf.dbPwd, {
host: conf.dbHost,
dialect: conf.dbDialect,
port: conf.dbPort,
logging: false, logging: false,
pool: { pool: {
max: 40, max: 40,
@ -183,6 +186,16 @@ function createConnection() {
idle: 10000, idle: 10000,
}, },
}); });
} catch (err) {
sendError(err);
}
} }
export { models } ; /**
* Error message
*/
function sendError(msg) {
throw colors.red.bold(msg)
}
module.exports = { models };

View File

@ -1,4 +1,4 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require('sequelize');
const connections = { const connections = {
organizationId: { organizationId: {
@ -12,7 +12,7 @@ const connections = {
}, },
}; };
export default (sequelize) => { module.exports = function (sequelize) {
const connection = sequelize.define( const connection = sequelize.define(
'FDconnections', 'FDconnections',
connections, connections,

View File

@ -1,4 +1,4 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require('sequelize');
const suppliers = { const suppliers = {
isConnected: { isConnected: {
@ -55,10 +55,14 @@ const suppliers = {
}, },
}; };
export default (sequelize) => { module.exports = function (sequelize) {
const Suppliers = sequelize.define('FDsuppliers', suppliers, { const Suppliers = sequelize.define(
'FDsuppliers',
suppliers,
{
timestamps: false, timestamps: false,
freezeTableName: true, freezeTableName: true,
}); }
);
return Suppliers; return Suppliers;
}; };

View File

@ -1,4 +1,4 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require('sequelize');
const supplyLine = { const supplyLine = {
supplyLineId: { supplyLineId: {
@ -52,12 +52,14 @@ const supplyLine = {
} }
}; };
module.exports = function (sequelize) {
const SupplyLine = sequelize.define(
export default (sequelize) => { 'FDsupplyLine',
const SupplyLine = sequelize.define('FDsupplyLine', supplyLine, { supplyLine,
{
timestamps: false, timestamps: false,
freezeTableName: true, freezeTableName: true,
}); }
);
return SupplyLine; return SupplyLine;
}; };

View File

@ -1,4 +1,4 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require('sequelize');
const volumePrices = { const volumePrices = {
id: { id: {
@ -14,10 +14,14 @@ const volumePrices = {
}, },
}; };
export default (sequelize) => { module.exports = function (sequelize) {
const VolumePrices = sequelize.define('FDvolumePrices', volumePrices, { const VolumePrices = sequelize.define(
'FDvolumePrices',
volumePrices,
{
timestamps: false, timestamps: false,
freezeTableName: true, freezeTableName: true,
}); }
);
return VolumePrices; return VolumePrices;
}; };

View File

@ -1,4 +1,4 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require('sequelize');
const botanicalNames = { const botanicalNames = {
name: { name: {
@ -6,10 +6,14 @@ const botanicalNames = {
}, },
}; };
export default (sequelize) => { module.exports = function (sequelize) {
const BotanicalNames = sequelize.define('FDbotanicalNames', botanicalNames, { const BotanicalNames = sequelize.define(
'FDbotanicalNames',
botanicalNames,
{
timestamps: false, timestamps: false,
freezeTableName: true, freezeTableName: true,
}); }
);
return BotanicalNames; return BotanicalNames;
}; };

View File

@ -1,4 +1,4 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require('sequelize');
const characteristics = { const characteristics = {
vbnCode: { vbnCode: {
@ -9,7 +9,7 @@ const characteristics = {
}, },
}; };
export default (sequelize) => { module.exports = function (sequelize) {
const Characteristics = sequelize.define( const Characteristics = sequelize.define(
'FDcharacteristics', 'FDcharacteristics',
characteristics, characteristics,

View File

@ -1,4 +1,4 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require('sequelize');
const countryOfOriginIsoCodes = { const countryOfOriginIsoCodes = {
isoCode: { isoCode: {
@ -6,7 +6,7 @@ const countryOfOriginIsoCodes = {
}, },
}; };
export default (sequelize) => { module.exports = function (sequelize) {
const CountryOfOriginIsoCodes = sequelize.define( const CountryOfOriginIsoCodes = sequelize.define(
'FDcountryOfOriginIsoCodes', 'FDcountryOfOriginIsoCodes',
countryOfOriginIsoCodes, countryOfOriginIsoCodes,

View File

@ -1,4 +1,4 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require('sequelize');
const PackageModel = { const PackageModel = {
vbnPackageCode: { vbnPackageCode: {
@ -9,10 +9,14 @@ const PackageModel = {
}, },
}; };
export default (sequelize) => { module.exports = function (sequelize) {
const Package = sequelize.define('FDpackage', PackageModel, { const Package = sequelize.define(
'FDpackage',
PackageModel,
{
timestamps: false, timestamps: false,
freezeTableName: true, freezeTableName: true,
}); }
);
return Package; return Package;
}; };

View File

@ -1,4 +1,4 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require('sequelize');
const packingConfigurations = { const packingConfigurations = {
packingConfigurationId: { packingConfigurationId: {
@ -34,7 +34,7 @@ const packingConfigurations = {
}, },
}; };
export default (sequelize) => { module.exports = function (sequelize) {
const PackingConfigurations = sequelize.define( const PackingConfigurations = sequelize.define(
'FDpackingConfigurations', 'FDpackingConfigurations',
packingConfigurations, packingConfigurations,

View File

@ -1,4 +1,4 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require('sequelize');
const photos = { const photos = {
id: { id: {
@ -16,10 +16,14 @@ const photos = {
}, },
}; };
export default (sequelize) => { module.exports = function (sequelize) {
const Photos = sequelize.define('FDphotos', photos, { const Photos = sequelize.define(
'FDphotos',
photos,
{
timestamps: false, timestamps: false,
freezeTableName: true, freezeTableName: true,
}); }
);
return Photos; return Photos;
}; };

View File

@ -1,4 +1,4 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require('sequelize');
const seasonalPeriod = { const seasonalPeriod = {
id: { id: {
@ -14,10 +14,14 @@ const seasonalPeriod = {
}, },
}; };
export default (sequelize) => { module.exports = function (sequelize) {
const SeasonalPeriod = sequelize.define('FDseasonalPeriod', seasonalPeriod, { const SeasonalPeriod = sequelize.define(
'FDseasonalPeriod',
seasonalPeriod,
{
timestamps: false, timestamps: false,
freezeTableName: true, freezeTableName: true,
}); }
);
return SeasonalPeriod; return SeasonalPeriod;
}; };

View File

@ -1,4 +1,4 @@
import { Sequelize } from 'sequelize'; const { Sequelize } = require('sequelize');
const tradeItem = { const tradeItem = {
tradeItemId: { tradeItemId: {
@ -37,10 +37,14 @@ const tradeItem = {
} }
}; };
export default (sequelize) => { module.exports = function (sequelize) {
const TradeItem = sequelize.define('FDtradeItem', tradeItem, { const TradeItem = sequelize.define(
'FDtradeItem',
tradeItem,
{
timestamps: false, timestamps: false,
freezeTableName: true, freezeTableName: true,
}); }
);
return TradeItem; return TradeItem;
}; };

172
package-lock.json generated
View File

@ -1,22 +1,28 @@
{ {
"name": "floriday", "name": "floriday",
"version": "1.0.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "floriday", "name": "floriday",
"version": "1.0.0",
"dependencies": { "dependencies": {
"axios": "^1.3.4",
"cli-progress": "^3.11.2", "cli-progress": "^3.11.2",
"colors": "^1.4.0", "colors": "^1.4.0",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"mariadb": "^3.0.2", "mariadb": "^3.0.2",
"moment": "^2.29.4", "moment": "^2.29.4",
"node-fetch": "^3.3.0",
"sequelize": "^6.26.0", "sequelize": "^6.26.0",
"uuid": "^9.0.0" "uuid": "^9.0.0"
}, },
"devDependencies": { "devDependencies": {
"eslint": "^8.31.0" "eslint": "^8.31.0"
},
"engines": {
"node": ">=15",
"npm": ">=8"
} }
}, },
"node_modules/@eslint/eslintrc": { "node_modules/@eslint/eslintrc": {
@ -204,6 +210,21 @@
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true "dev": true
}, },
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
"integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
"dependencies": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -282,6 +303,17 @@
"node": ">=0.1.90" "node": ">=0.1.90"
} }
}, },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/concat-map": { "node_modules/concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -302,14 +334,6 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/data-uri-to-buffer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
"integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==",
"engines": {
"node": ">= 12"
}
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -332,6 +356,14 @@
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
"dev": true "dev": true
}, },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/denque": { "node_modules/denque": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
@ -573,28 +605,6 @@
"reusify": "^1.0.4" "reusify": "^1.0.4"
} }
}, },
"node_modules/fetch-blob": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "paypal",
"url": "https://paypal.me/jimmywarting"
}
],
"dependencies": {
"node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3"
},
"engines": {
"node": "^12.20 || >= 14.13"
}
},
"node_modules/file-entry-cache": { "node_modules/file-entry-cache": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@ -642,15 +652,36 @@
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
"dev": true "dev": true
}, },
"node_modules/formdata-polyfill": { "node_modules/follow-redirects": {
"version": "4.0.10", "version": "1.15.2",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": { "dependencies": {
"fetch-blob": "^3.1.2" "asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}, },
"engines": { "engines": {
"node": ">=12.20.0" "node": ">= 6"
} }
}, },
"node_modules/fs.realpath": { "node_modules/fs.realpath": {
@ -931,6 +962,25 @@
"node": ">= 12" "node": ">= 12"
} }
}, },
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": { "node_modules/minimatch": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@ -973,41 +1023,6 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true "dev": true
}, },
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
}
],
"engines": {
"node": ">=10.5.0"
}
},
"node_modules/node-fetch": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz",
"integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==",
"dependencies": {
"data-uri-to-buffer": "^4.0.0",
"fetch-blob": "^3.1.4",
"formdata-polyfill": "^4.0.10"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/node-fetch"
}
},
"node_modules/once": { "node_modules/once": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@ -1117,6 +1132,11 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/punycode": { "node_modules/punycode": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
@ -1456,14 +1476,6 @@
"node": ">= 0.10" "node": ">= 0.10"
} }
}, },
"node_modules/web-streams-polyfill": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
"engines": {
"node": ">= 8"
}
},
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@ -1,25 +1,23 @@
{ {
"name": "floriday", "name": "floriday",
"module": "index.ts", "version": "1.0.0",
"type": "module", "author": "Verdnatura Levante SL",
"scripts": { "description": "Floriday Service",
"start": "node index.js",
"dev-sync": "FORCE_SYNC=true node --max-old-space-size=4096 index.js",
"dev-secrets": "SECRETS=true node --max-old-space-size=4096 index.js",
"dev-both": "FORCE_SYNC=true SECRETS=true node --max-old-space-size=4096 index.js",
"dev-query": "QUERYSUPPLIERS=true SECRETS=true node --max-old-space-size=4096 index.js"
},
"dependencies": { "dependencies": {
"axios": "^1.3.4",
"cli-progress": "^3.11.2", "cli-progress": "^3.11.2",
"colors": "^1.4.0", "colors": "^1.4.0",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"mariadb": "^3.0.2", "mariadb": "^3.0.2",
"moment": "^2.29.4", "moment": "^2.29.4",
"node-fetch": "^3.3.0",
"sequelize": "^6.26.0", "sequelize": "^6.26.0",
"uuid": "^9.0.0" "uuid": "^9.0.0"
}, },
"devDependencies": { "devDependencies": {
"eslint": "^8.31.0" "eslint": "^8.31.0"
},
"engines": {
"node": ">=15",
"npm": ">=8"
} }
} }

View File

@ -6,4 +6,4 @@ let floraholland = [
8718288004970, 8718288004970,
]; ];
export default {floraholland}; module.exports = {floraholland};

102
utils.js
View File

@ -1,17 +1,15 @@
import moment from 'moment'; const moment = require('moment');
import fetch from 'node-fetch'; const axios = require('axios');
import dotenv from 'dotenv'; const { models } = require('./models/index.js');
import { models } from './models/index.js'; const { v4: uuidv4 } = require('uuid');
import { v4 as uuidv4 } from 'uuid'; const colors = require('colors');
import colors from 'colors'; require('dotenv').config()
//import cliProgress from 'cli-progress'; // const cliProgress = require('cli-progress');
dotenv.config();
/** /**
* The Endpoint where the Access Token is requested * The Endpoint where the Access Token is requested
*/ */
const _accessTokenEndpoint = 'https://idm.staging.floriday.io/oauth2/ausmw6b47z1BnlHkw0h7/v1/token'; const _accessTokenEndpoint = 'https://idm.staging.floriday.io/oauth2/ausmw6b47z1BnlHkw0h7/v1/token';
const BASE_CUSTOMER_URL = 'https://api.staging.floriday.io/customers-api/2022v2/'; const BASE_CUSTOMER_URL = 'https://api.staging.floriday.io/customers-api/2022v2/';
/** /**
@ -32,13 +30,18 @@ async function getClientToken() {
if (clientConfigData[0].tokenExpiration == null || moment(now).isAfter(tokenExpirationDate)) { if (clientConfigData[0].tokenExpiration == null || moment(now).isAfter(tokenExpirationDate)) {
let clientId = clientConfigData[0].clientId; let clientId = clientConfigData[0].clientId;
let clientSecret = clientConfigData[0].clientSecret; let clientSecret = clientConfigData[0].clientSecret;
let myBody = `grant_type=client_credentials&client_id=${clientId}
&client_secret=${clientSecret}
&scope=role:app catalog:read
supply:read organization:read
network:write network:read`
const tokenRequest = await fetch(_accessTokenEndpoint, { const tokenRequest = await axios(_accessTokenEndpoint, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded', '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`, body: myBody,
}); });
const tokenResponse = await tokenRequest.json(); const tokenResponse = await tokenRequest.json();
@ -101,7 +104,7 @@ async function updateClientConfig(clientId, clientSecret, accessToken, tokenExpi
} }
/** /**
* returns the current Access Token * Returns the current Access Token.
* *
* @returns * @returns
*/ */
@ -111,7 +114,7 @@ async function getJWT() {
} }
/** /**
* pauses the execution of the script for the given amount of milliseconds * Pauses the execution of the script for the given amount of milliseconds.
* *
* @param {integer} ms * @param {integer} ms
* @returns A promise that resolves after ms milliseconds. * @returns A promise that resolves after ms milliseconds.
@ -133,7 +136,9 @@ async function asyncQueue(fnArray, concurrency = 1) {
const results = []; // 1 const results = []; // 1
const queue = fnArray.map((fn, index) => () => fn().then((result) => results[index] = result)); const queue = fnArray.map(
(fn, index) => () => fn().then((result) => results[index] = result)
);
const run = async () => { // 2 const run = async () => { // 2
const fn = queue.shift(); const fn = queue.shift();
@ -170,19 +175,15 @@ 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){
let mockModels = ['suppliers','tradeItems','supplyLines',]; let mockModels = ['suppliers','tradeItems','supplyLines',];
for (let i = 0; i < mockModels.length; i++) { for (let mockModel in mockModels) {
const element = mockModels[i]; const element = mockModels[mockModel];
console.log('Syncing sequence for: ', element); console.log('Syncing sequence for: ', element);
await syncSequence(0, element); await syncSequence(0, element);
} }
} else { } else {
let tx = await models.sequelize.transaction(); let tx = await models.sequelize.transaction();
try { try {
let sequence = await models.sequenceNumber.findOrCreate({ let sequence = await models.sequenceNumber.findOrCreate({
@ -208,7 +209,6 @@ async function syncSequence(current = 0, model = null ,maximumSequenceNumber = 0
transaction: tx transaction: tx
}); });
} }
await tx.commit(); await tx.commit();
} catch (error) { } catch (error) {
@ -226,19 +226,20 @@ async function syncSuppliers(){
'X-Api-Key': process.env.API_KEY 'X-Api-Key': process.env.API_KEY
}; };
let maximumSequenceNumber = await fetch(`${BASE_CUSTOMER_URL}organizations/current-max-sequence`, { const curMaxSeqUrl = `${BASE_CUSTOMER_URL}organizations/current-max-sequence`;
let maximumSequenceNumber = await axios(curMaxSeqUrl, {
method: 'GET', method: 'GET',
headers: headers headers: headers
}); });
maximumSequenceNumber = await maximumSequenceNumber.json(); maximumSequenceNumber = await maximumSequenceNumber.json();
console.log('Maximum sequence number: ', maximumSequenceNumber); console.log('Maximum sequence number: ', maximumSequenceNumber);
for (let i = 0; i < maximumSequenceNumber; i++) { for (let i = 0; i < maximumSequenceNumber; i++) {
let query = `${BASE_CUSTOMER_URL}organizations/sync/${i}?organizationType=SUPPLIER&limit=1000`; let query = `${BASE_CUSTOMER_URL}organizations/sync/${i}?organizationType=SUPPLIER&limit=1000`;
let response = await fetch(query, { let response = await axios(query, {
method: 'GET', method: 'GET',
headers: headers headers: headers
}); });
@ -267,7 +268,10 @@ async function syncSuppliers(){
organizationType: supplier.organizationType, organizationType: supplier.organizationType,
paymentProviders: `${supplier.paymentProviders}`, paymentProviders: `${supplier.paymentProviders}`,
}); });
console.log('INSERTED:\t', supplier.commercialName, '\nsequenceNumber:\t', supplier.sequenceNumber); console.log(
'INSERTED:\t', supplier.commercialName,
'\nsequenceNumber:\t', supplier.sequenceNumber
);
} }
await syncSequence(i, 'suppliers', maximumSequenceNumber); await syncSequence(i, 'suppliers', maximumSequenceNumber);
} }
@ -282,7 +286,7 @@ async function syncConnections(){
'X-Api-Key': process.env.API_KEY 'X-Api-Key': process.env.API_KEY
}; };
let remoteConnections = await fetch(`${BASE_CUSTOMER_URL}connections`, { let remoteConnections = await axios(`${BASE_CUSTOMER_URL}connections`, {
method: 'GET', method: 'GET',
headers: headers headers: headers
}); });
@ -293,12 +297,14 @@ async function syncConnections(){
if (connection.isConnected == false){ if (connection.isConnected == false){
continue; continue;
} }
let remoteConnection = remoteConnections.find(remoteConnection => remoteConnection == connection.organizationId); let remoteConnection = remoteConnections.find(
remoteConnection => remoteConnection == connection.organizationId
);
if (remoteConnection == undefined){ if (remoteConnection == undefined){
console.log('Connection: ', connection, 'does not exist in the remote server'); console.log('Connection: ', connection, 'does not exist in the remote server');
console.log('Creating remote connection'); console.log('Creating remote connection');
await fetch(`${BASE_CUSTOMER_URL}connections/${connection.organizationId}`, { await axios(`${BASE_CUSTOMER_URL}connections/${connection.organizationId}`, {
method: 'PUT', method: 'PUT',
headers: headers headers: headers
}); });
@ -354,7 +360,7 @@ async function syncTradeItems(){
try { try {
let request = await fetch(query, { let request = await axios(query, {
method: 'GET', method: 'GET',
headers: headers headers: headers
}); });
@ -424,10 +430,13 @@ async function syncSupplyLines(){
// eslint-disable-next-line no-async-promise-executor // eslint-disable-next-line no-async-promise-executor
let promise = new Promise(async (resolve) => { let promise = new Promise(async (resolve) => {
try { try {
let url = `${BASE_CUSTOMER_URL}supply-lines/sync/0?
supplierOrganizationId=${supplier.organizationId}
&tradeItemId=${tradeItem.tradeItemId}
&limit=100
&postFilterSelectedTradeItems=false`;
let url = `${BASE_CUSTOMER_URL}supply-lines/sync/0?supplierOrganizationId=${supplier.organizationId}&tradeItemId=${tradeItem.tradeItemId}&limit=100&postFilterSelectedTradeItems=false`; let request = await axios(url, {
let request = await fetch(url, {
method: 'GET', method: 'GET',
headers: headers headers: headers
}); });
@ -435,7 +444,10 @@ async function syncSupplyLines(){
let supplyLines = await request.json(); let supplyLines = await request.json();
if (supplyLines.length == 0) { if (supplyLines.length == 0) {
console.log('No supply lines for supplier: ', supplier.commercialName, ' - ' , tradeItem.name); console.log(
'No supply lines for supplier: ', supplier.commercialName,
' - ' , tradeItem.name
);
resolve([]); resolve([]);
return; return;
} }
@ -443,7 +455,10 @@ async function syncSupplyLines(){
resolve(supplyLines); resolve(supplyLines);
} catch (error) { } catch (error) {
console.log('Error while syncing supply lines for: ', supplier.commercialName, ' - ' , tradeItem.name); console.log(
'Error while syncing supply lines for: ', supplier.commercialName,
' - ' , tradeItem.name
);
console.log(error); console.log(error);
resolve([]); resolve([]);
} }
@ -474,7 +489,7 @@ async function syncSupplyLines(){
let urlTradeItem = `${BASE_CUSTOMER_URL}trade-items?tradeItemIds=${line.tradeItemId}`; let urlTradeItem = `${BASE_CUSTOMER_URL}trade-items?tradeItemIds=${line.tradeItemId}`;
let queryTradeItem = await fetch(urlTradeItem, { let queryTradeItem = await axios(urlTradeItem, {
method: 'GET', method: 'GET',
headers: headers headers: headers
}); });
@ -550,9 +565,7 @@ async function insertItem(tradeItem, supplier) {
console.log('Syncing trade item: ', tradeItem.name); console.log('Syncing trade item: ', tradeItem.name);
try { try {
// Temporal connection to all suppliers that have trade items // Temporal connection to all suppliers that have trade items
let currentSupp = await models.supplier.findOne({ let currentSupp = await models.supplier.findOne({
where: { where: {
organizationId: tradeItem.supplierOrganizationId organizationId: tradeItem.supplierOrganizationId
@ -569,7 +582,6 @@ async function insertItem(tradeItem, supplier) {
}, {transaction: tx}); }, {transaction: tx});
// ----- // -----
await models.tradeItem.upsert({ await models.tradeItem.upsert({
tradeItemId: tradeItem.tradeItemId, tradeItemId: tradeItem.tradeItemId,
supplierOrganizationId: tradeItem.supplierOrganizationId, supplierOrganizationId: tradeItem.supplierOrganizationId,
@ -674,5 +686,15 @@ async function insertItem(tradeItem, supplier) {
} }
module.exports = {
export { getClientToken, updateClientConfig, getJWT, sleep, asyncQueue, syncSequence, syncSuppliers, syncTradeItems, syncConnections, syncSupplyLines }; getClientToken,
updateClientConfig,
getJWT,
sleep,
asyncQueue,
syncSequence,
syncSuppliers,
syncTradeItems,
syncConnections,
syncSupplyLines
};