refs #4823 Many changes

This commit is contained in:
Guillermo Bonet 2023-05-15 14:19:43 +02:00
parent 2a195194b2
commit 7202a0c339
14 changed files with 285 additions and 221 deletions

View File

@ -56,8 +56,12 @@ SYNC_SUPPLIER = true
SYNC_CONN = true SYNC_CONN = true
SYNC_TRADEITEM = true SYNC_TRADEITEM = true
MAX_REQUEST_RETRIES = 3 MAX_REQUEST_RETRIES = 3
#DEV OPTIONS
SUPPLIERS_ALWAYS_CONN = false
``` ```
## 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:

View File

@ -1,4 +1,4 @@
import { models, checkConn, closeConn } from './models/sequelize.js'; import { checkConn, closeConn } from './models/sequelize.js';
import * as utils from './utils.js'; import * as utils from './utils.js';
import moment from 'moment'; import moment from 'moment';
import chalk from 'chalk'; import chalk from 'chalk';
@ -10,7 +10,7 @@ class Floriday {
async start() { async start() {
try { try {
await utils.checkConfig(); await utils.checkConfig();
this.tokenExpirationDate = await utils.requestToken(models); await utils.requestToken();
if (JSON.parse(env.SYNC_SEQUENCE)) await utils.syncSequence(); if (JSON.parse(env.SYNC_SEQUENCE)) await utils.syncSequence();
if (JSON.parse(env.SYNC_SUPPLIER)) await utils.syncSuppliers(); if (JSON.parse(env.SYNC_SUPPLIER)) await utils.syncSuppliers();
if (JSON.parse(env.SYNC_CONN)) await utils.syncConn(); if (JSON.parse(env.SYNC_CONN)) await utils.syncConn();
@ -36,8 +36,8 @@ class Floriday {
const intervalTime = JSON.parse(env.IS_PRODUCTION) const intervalTime = JSON.parse(env.IS_PRODUCTION)
? env.MS_PRODUCTION_SCHEDULE ? env.MS_PRODUCTION_SCHEDULE
: env.MS_TEST_SCHEDULE; : env.MS_TEST_SCHEDULE;
this.continueSchedule = true;
while (true) { while (this.continueSchedule) {
try { try {
await this.trunk(); await this.trunk();
await new Promise(resolve => setTimeout(resolve, intervalTime)); await new Promise(resolve => setTimeout(resolve, intervalTime));
@ -64,6 +64,7 @@ class Floriday {
} }
async stop() { async stop() {
this.continueSchedule = false;
await utils.deleteConnections(); await utils.deleteConnections();
await closeConn(); await closeConn();
console.warn(chalk.dim('Bye, come back soon 👋')) console.warn(chalk.dim('Bye, come back soon 👋'))

View File

@ -10,7 +10,7 @@ const connections = {
export default (sequelize) => { export default (sequelize) => {
const connection = sequelize.define( const connection = sequelize.define(
'connections', 'supplier_connections',
connections, connections,
{ {
timestamps: false, timestamps: false,

View File

@ -1,59 +1,71 @@
import { Sequelize } from 'sequelize'; import { Sequelize } from 'sequelize';
const suppliers = { const suppliers = {
supplierOrganizationId: { supplierOrganizationId: {
type: Sequelize.STRING, type: Sequelize.STRING,
allowNull: false, allowNull: false,
primaryKey: true, primaryKey: true,
}, },
sequenceNumber: { sequenceNumber: {
type: Sequelize.INTEGER, type: Sequelize.INTEGER,
allowNull: false, allowNull: false,
primaryKey: true, },
}, companyGln: {
companyGln: { type: Sequelize.STRING,
type: Sequelize.STRING, },
}, name: {
name: { type: Sequelize.STRING,
type: Sequelize.STRING, },
}, commercialName: {
commercialName: { type: Sequelize.STRING,
type: Sequelize.STRING, },
}, email: {
email: { type: Sequelize.STRING,
type: Sequelize.STRING, },
}, phone: {
phone: { type: Sequelize.STRING,
type: Sequelize.STRING, },
}, website: {
website: { type: Sequelize.STRING,
type: Sequelize.STRING, },
}, rfhRelationId: {
rfhRelationId: { type: Sequelize.INTEGER,
type: Sequelize.INTEGER, },
}, paymentProviders: {
paymentProviders: { type: Sequelize.JSON,
type: Sequelize.STRING, },
}, endDate: {
endDate: { type: Sequelize.DATE,
type: Sequelize.DATE, },
}, mailingAddress: {
mailingAddress: { type: Sequelize.JSON,
type: Sequelize.JSON, },
}, physicalAddress: {
physicalAddress: { type: Sequelize.JSON,
type: Sequelize.JSON, },
}, isConnected: {
isConnected: { type: Sequelize.BOOLEAN,
type: Sequelize.BOOLEAN, defaultValue: false,
defaultValue: false, },
}, lastSync: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.NOW,
},
created: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.NOW,
},
}; };
export default (sequelize) => { export default (sequelize) => {
const Suppliers = sequelize.define('supplier', suppliers, { const Suppliers = sequelize.define(
timestamps: false, 'supplier',
freezeTableName: true, suppliers, {
}); timestamps: false,
return Suppliers; freezeTableName: true,
}
);
return Suppliers;
}; };

View File

@ -55,15 +55,32 @@ const supplyLine = {
}, },
isCustomerSpecific: { isCustomerSpecific: {
type: Sequelize.BOOLEAN, type: Sequelize.BOOLEAN,
} },
tradeItemId : {
type: Sequelize.STRING,
},
supplierOrganizationId : {
type: Sequelize.STRING,
},
lastSync: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.NOW,
},
created: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.NOW,
},
}; };
export default (sequelize) => { export default (sequelize) => {
const SupplyLine = sequelize.define('supplyLine', supplyLine, { const SupplyLine = sequelize.define(
timestamps: false, 'supplyLine',
freezeTableName: true, supplyLine, {
}); timestamps: false,
return SupplyLine; freezeTableName: true,
}
);
return SupplyLine;
}; };

View File

@ -1,24 +1,27 @@
import { Sequelize } from 'sequelize'; import { Sequelize } from 'sequelize';
const volumePrices = { const volumePrices = {
supplyLineId: { supplyLineId: {
type: Sequelize.STRING, type: Sequelize.STRING,
primaryKey: true, primaryKey: true,
}, },
unit: { unit: {
type: Sequelize.STRING, type: Sequelize.STRING,
primaryKey: true, primaryKey: true,
}, },
pricePerPiece: { pricePerPiece: {
type: Sequelize.DECIMAL(10,2), type: Sequelize.DECIMAL(10,2),
primaryKey: true, primaryKey: true,
}, },
}; };
export default (sequelize) => { export default (sequelize) => {
const VolumePrices = sequelize.define('volumePrices', volumePrices, { const VolumePrices = sequelize.define(
timestamps: false, 'supplyLine_volumePrices',
freezeTableName: true, volumePrices, {
}); timestamps: false,
return VolumePrices; freezeTableName: true,
}
);
return VolumePrices;
}; };

View File

@ -1,15 +1,18 @@
import { Sequelize } from 'sequelize'; import { Sequelize } from 'sequelize';
const botanicalNames = { const botanicalNames = {
name: { name: {
type: Sequelize.STRING, type: Sequelize.STRING,
}, },
}; };
export default (sequelize) => { export default (sequelize) => {
const BotanicalNames = sequelize.define('botanicalNames', botanicalNames, { const BotanicalNames = sequelize.define(
timestamps: false, 'tradeItem_botanicalNames',
freezeTableName: true, botanicalNames, {
}); timestamps: false,
return BotanicalNames; freezeTableName: true,
}; }
);
return BotanicalNames;
};

View File

@ -11,7 +11,7 @@ const characteristics = {
export default (sequelize) => { export default (sequelize) => {
const Characteristics = sequelize.define( const Characteristics = sequelize.define(
'characteristics', 'tradeItem_characteristics',
characteristics, characteristics,
{ {
timestamps: false, timestamps: false,

View File

@ -8,7 +8,7 @@ const countryOfOriginIsoCodes = {
export default (sequelize) => { export default (sequelize) => {
const CountryOfOriginIsoCodes = sequelize.define( const CountryOfOriginIsoCodes = sequelize.define(
'countryOfOriginIsoCodes', 'tradeItem_countryOfOriginIsoCodes',
countryOfOriginIsoCodes, countryOfOriginIsoCodes,
{ {
timestamps: false, timestamps: false,

View File

@ -20,7 +20,10 @@ const packingConfigurations = {
layersPerLoadCarrier: { layersPerLoadCarrier: {
type: Sequelize.INTEGER, type: Sequelize.INTEGER,
}, },
additionalPricePerPiece: { additionalPricePerPiece_currency: {
type: Sequelize.STRING,
},
additionalPricePerPiece_value: {
type: Sequelize.STRING, type: Sequelize.STRING,
}, },
transportHeightInCm: { transportHeightInCm: {
@ -36,7 +39,7 @@ const packingConfigurations = {
export default (sequelize) => { export default (sequelize) => {
const PackingConfigurations = sequelize.define( const PackingConfigurations = sequelize.define(
'packingConfig', 'tradeItem_packingConfigurations',
packingConfigurations, packingConfigurations,
{ {
timestamps: false, timestamps: false,

View File

@ -17,7 +17,7 @@ const photos = {
}; };
export default (sequelize) => { export default (sequelize) => {
const Photos = sequelize.define('photos', photos, { const Photos = sequelize.define('tradeItem_photos', photos, {
timestamps: false, timestamps: false,
freezeTableName: true, freezeTableName: true,
}); });

View File

@ -15,7 +15,7 @@ const seasonalPeriod = {
}; };
export default (sequelize) => { export default (sequelize) => {
const SeasonalPeriod = sequelize.define('seasonalPeriod', seasonalPeriod, { const SeasonalPeriod = sequelize.define('tradeItem_seasonalPeriod', seasonalPeriod, {
timestamps: false, timestamps: false,
freezeTableName: true, freezeTableName: true,
}); });

View File

@ -5,9 +5,6 @@ const tradeItem = {
type: Sequelize.STRING, type: Sequelize.STRING,
primaryKey: true, primaryKey: true,
}, },
supplierOrganizationId: {
type: Sequelize.STRING
},
code: { code: {
type: Sequelize.STRING type: Sequelize.STRING
}, },
@ -34,7 +31,20 @@ const tradeItem = {
}, },
isHiddenInCatalog: { isHiddenInCatalog: {
type: Sequelize.BOOLEAN, type: Sequelize.BOOLEAN,
} },
supplierOrganizationId: {
type: Sequelize.STRING
},
lastSync: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.NOW,
},
created: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.NOW,
},
}; };
export default (sequelize) => { export default (sequelize) => {

251
utils.js
View File

@ -8,12 +8,11 @@ import ora from 'ora';
const env = process.env; const env = process.env;
/** /**
* Gets the Access Token from the client config table * Gets the Access Token
* *
* @param {sequelize.models} models * @param {Boolean} isForce Force to request new token
* @returns {Date} tokenExpirationDate formated as YYYY-MM-DD HH:mm:ss
*/ */
export async function requestToken() { export async function requestToken(isForce = false) {
let spinner = ora(`Requesting new token...`).start(); let spinner = ora(`Requesting new token...`).start();
try { try {
const clientConfigData = await models.clientConfig.findOne(); const clientConfigData = await models.clientConfig.findOne();
@ -23,8 +22,8 @@ export async function requestToken() {
token = clientConfigData.currentToken; token = clientConfigData.currentToken;
tokenExpirationDate = clientConfigData.tokenExpiration; tokenExpirationDate = clientConfigData.tokenExpiration;
} }
if (!token || !tokenExpirationDate || moment().isAfter(tokenExpirationDate)) { if (isForce || !token || !tokenExpirationDate || moment().isAfter(tokenExpirationDate)) {
let clientId, clientSecret let clientId, clientSecret
if (JSON.parse(env.USE_SECRETS_DB)) { if (JSON.parse(env.USE_SECRETS_DB)) {
clientId = clientConfigData.clientId; clientId = clientConfigData.clientId;
@ -45,11 +44,9 @@ export async function requestToken() {
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`) .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`)
.join('&') .join('&')
const headers = { const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
'Content-Type': 'application/x-www-form-urlencoded',
}
const response = (await vnRequest('GET', env.API_ENDPOINT, data, headers)).data; const response = (await vnRequest('POST', env.API_ENDPOINT, data, headers)).data;
if (response.statusText = 'OK') if (response.statusText = 'OK')
spinner.succeed(); spinner.succeed();
@ -67,13 +64,8 @@ export async function requestToken() {
response.access_token, response.access_token,
tokenExpirationDate tokenExpirationDate
); );
} else
return tokenExpirationDate; spinner.succeed('Using stored token...');
} else {
spinner.text = 'Using stored token...'
spinner.succeed();
return tokenExpirationDate;
}
} catch (err) { } catch (err) {
spinner.fail(); spinner.fail();
throw err; throw err;
@ -86,10 +78,7 @@ export async function requestToken() {
* @returns {string} * @returns {string}
*/ */
export async function getCurrentToken() { export async function getCurrentToken() {
if (moment().isAfter(await getCurrentTokenExpiration())) return (await models.clientConfig.findOne()).currentToken;
return await requestToken(models);
else
return (await models.clientConfig.findOne()).currentToken;
} }
/** /**
@ -289,19 +278,10 @@ export async function syncSuppliers(){
if (timeFinish) if (timeFinish)
spinner.text = spinner.text + ` (${timeLeft})` spinner.text = spinner.text + ` (${timeLeft})`
await models.supplier.upsert({ await models.supplier.upsert({
...supplier,
supplierOrganizationId: supplier.organizationId, supplierOrganizationId: supplier.organizationId,
sequenceNumber: supplier.sequenceNumber, isConnected: JSON.parse(env.SUPPLIERS_ALWAYS_CONN),
companyGln: supplier.companyGln ? supplier.companyGln : null, lastSync: moment(),
name: supplier.name ? supplier.name : null,
commercialName: supplier.commercialName ? supplier.commercialName : null,
email: supplier.email ? supplier.email : null,
phone: supplier.phone ? supplier.phone : null,
website: supplier.website ? supplier.website : null,
rfhRelationId: supplier.rfhRelationId ? supplier.rfhRelationId : null,
paymentProviders: supplier.paymentProviders.length ? `${supplier.paymentProviders}` : null,
endDate: supplier.endDate ? supplier.endDate : null,
mailingAddress: supplier.mailingAddress ? supplier.mailingAddress : null,
physicalAddress: supplier.physicalAddress ? supplier.physicalAddress : null,
}); });
}; };
await syncSequence(curSequenceNumber, 'supplier', maxSequenceNumber); await syncSequence(curSequenceNumber, 'supplier', maxSequenceNumber);
@ -337,7 +317,7 @@ export async function syncConn(){
let i = 1; let i = 1;
for (let connection of connections){ for (let connection of connections){
spinner.text = `Creating ${i++} connections...` spinner.text = `Creating ${i++} of ${connections.length} connections...`
let remoteConnection = remoteConnections.find(remoteConnection => remoteConnection == connection.supplierOrganizationId); let remoteConnection = remoteConnections.find(remoteConnection => remoteConnection == connection.supplierOrganizationId);
if (!remoteConnection){ if (!remoteConnection){
@ -378,8 +358,7 @@ export async function syncTradeItems(){
const suppliers = await models.supplier.findAll({ const suppliers = await models.supplier.findAll({
where: { isConnected: true } where: { isConnected: true }
}); });
let i = 0; let i = 0, x = 1;
let x = 0;
for (let supplier of suppliers) { for (let supplier of suppliers) {
let headers = { let headers = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -394,7 +373,7 @@ export async function syncTradeItems(){
for (let tradeItem of tradeItems) { for (let tradeItem of tradeItems) {
await insertItem(tradeItem); await insertItem(tradeItem);
spinner.text = `Syncing ${i++} trade items of [${x++}|${suppliers.length}] suppliers...` spinner.text = `Syncing ${i++} trade items of [${x}|${suppliers.length}] suppliers...`
}; };
} catch (err) { } catch (err) {
spinner.fail(); spinner.fail();
@ -452,8 +431,6 @@ export async function syncSupplyLines(){
resolve(supplyLines); resolve(supplyLines);
} catch (err) { } catch (err) {
if (err.message = 'Request failed with status code 429')
console.log('Request failed with status code 429 - Too many request');
resolve([]); resolve([]);
} }
}); });
@ -505,26 +482,8 @@ export async function syncSupplyLines(){
} }
await models.supplyLine.upsert({ await models.supplyLine.upsert({
supplyLineId: line.supplyLineId, ...supplyLine,
status: line.status, lastSync: moment(),
supplierOrganizationId: line.supplierOrganizationId,
pricePerPiece_currency: line.pricePerPiece.currency,
pricePerPiece_value: line.pricePerPiece.value,
numberOfPieces: line.numberOfPieces,
deliveryPeriod_startDateTime: line.deliveryPeriod.startDateTime,
deliveryPeriod_endDateTime: line.deliveryPeriod.endDateTime,
orderPeriod_startDateTime: line.orderPeriod.startDateTime,
orderPeriod_endDateTime: line.orderPeriod.endDateTime,
warehouseId: line.warehouseId,
sequenceNumber: line.sequenceNumber,
type: line.type,
isDeleted: line.isDeleted,
salesUnit: line.salesUnit,
agreementReference_code: line.agreementReference.code ? line.agreementReference.code : null,
agreementReference_description: line.agreementReference.description ? line.agreementReference.description : null,
isLimited: line.isLimited,
isCustomerSpecific: line.isCustomerSpecific,
tradeItemId: line.tradeItemId,
}); });
for (let volumePrice of line.volumePrices) for (let volumePrice of line.volumePrices)
@ -574,17 +533,46 @@ export async function newSyncSupplyLines() {
}); });
}).map(supplier => supplier.supplierOrganizationId); }).map(supplier => supplier.supplierOrganizationId);
let i = 1; let i = 0, x = 1;
for (let supplier of suppliers) { for (let supplier of suppliers) {
spinner.text = `(NEW) Syncing ${i++} supply lines...` spinner.text = `(NEW) Syncing ${i} supply lines of [${x++}|${suppliers.length}] suppliers...`
const params = new URLSearchParams({ const params = new URLSearchParams({
supplierOrganizationId: supplier, supplierOrganizationId: supplier,
}).toString(); }).toString();
let supplyLines = (await vnRequest('GET',`${env.API_URL}/supply-lines?${params}`, null, headers)).data; let supplyLines = (await vnRequest('GET',`${env.API_URL}/supply-lines?${params}`, null, headers)).data;
if (!supplyLines.length) continue if (!supplyLines.length) continue
for (let supplyLine of supplyLines) for (let supplyLine of supplyLines) {
console.log(supplyLine)
let tradeItem = await models.tradeItem.findOne({
where: { tradeItemId: supplyLine.tradeItemId }
});
if (!tradeItem) {
let tradeItem = (await vnRequest('GET', `${env.API_URL}/trade-items?tradeItemIds=${supplyLine.tradeItemId}`, null, headers)).data;
insertItem(tradeItem[0])
}
spinner.text = `(NEW) Syncing ${i++} supply lines of [${x}|${suppliers.length}] suppliers...`
await models.supplyLine.upsert({
...supplyLine,
pricePerPiece_currency: supplyLine.pricePerPiece ? supplyLine.pricePerPiece.currency : null,
pricePerPiece_value: supplyLine.pricePerPiece ? supplyLine.pricePerPiece.value : null,
deliveryPeriod_startDateTime: supplyLine.deliveryPeriod ? supplyLine.deliveryPeriod.startDateTime : null,
deliveryPeriod_endDateTime: supplyLine.deliveryPeriod ? supplyLine.deliveryPeriod.endDateTime : null,
orderPeriod_startDateTime: supplyLine.orderPeriod ? supplyLine.orderPeriod.startDateTime : null,
orderPeriod_endDateTime: supplyLine.orderPeriod ? supplyLine.orderPeriod.endDateTime : null,
agreementReference_code: supplyLine.agreementReference ? supplyLine.agreementReference.code : null,
agreementReference_description: supplyLine.agreementReference ? supplyLine.agreementReference.description : null,
lastSync: moment(),
});
for (let volumePrice of supplyLine.volumePrices)
await models.volumePrices.upsert({
...volumePrice,
supplyLineId: supplyLine.supplyLineId,
});
}
} }
spinner.succeed(); spinner.succeed();
} }
@ -612,72 +600,77 @@ export async function insertItem(tradeItem) {
// Upsert trade item // Upsert trade item
await models.tradeItem.upsert({ await models.tradeItem.upsert({
...tradeItem, ...tradeItem,
isDeleted: tradeItem.isDeleted, lastSync: moment(),
isCustomerSpecific: tradeItem.isCustomerSpecific,
isHiddenInCatalog: tradeItem.isHiddenInCatalog,
}, { transaction: tx }); }, { transaction: tx });
// Upsert characteristics // Upsert characteristics
if (tradeItem.characteristics) if (tradeItem.characteristics)
for (const characteristic of tradeItem.characteristics) { if (tradeItem.characteristics.length)
await models.characteristic.upsert({ for (const characteristic of tradeItem.characteristics) {
...characteristic, await models.characteristic.upsert({
tradeItemId: tradeItem.tradeItemId, ...characteristic,
}, { transaction: tx }); tradeItemId: tradeItem.tradeItemId,
} }, { transaction: tx });
}
// Upsert seasonal periods // Upsert seasonal periods
if (tradeItem.seasonalPeriods) if (tradeItem.seasonalPeriods)
for (const seasonalPeriod of tradeItem.seasonalPeriods) { if (tradeItem.seasonalPeriods.length)
await models.seasonalPeriod.upsert({ for (const seasonalPeriod of tradeItem.seasonalPeriods) {
...seasonalPeriod, await models.seasonalPeriod.upsert({
tradeItemId: tradeItem.tradeItemId, ...seasonalPeriod,
}, { transaction: tx }); tradeItemId: tradeItem.tradeItemId,
} }, { transaction: tx });
}
// Upsert photos // Upsert photos
if (tradeItem.photos) if (tradeItem.photos)
for (const photo of tradeItem.photos) { if (tradeItem.photos.length)
await models.photo.upsert({ for (const photo of tradeItem.photos) {
...photo, await models.photo.upsert({
tradeItemId: tradeItem.tradeItemId, ...photo,
}, { transaction: tx }); tradeItemId: tradeItem.tradeItemId,
} }, { transaction: tx });
}
// Upsert packing configurations // Upsert packing configurations
if (tradeItem.packingConfigurations) if (tradeItem.packingConfigurations)
for (const packingConfiguration of tradeItem.packingConfigurations) { if (tradeItem.packingConfigurations.length)
const uuid = uuidv4(); for (const packingConfiguration of tradeItem.packingConfigurations) {
const uuid = uuidv4();
await models.packingConfiguration.upsert({ await models.packingConfiguration.upsert({
packingConfigurationId: uuid, packingConfigurationId: uuid,
...packingConfiguration, ...packingConfiguration,
additionalPricePerPiece: JSON.stringify(packingConfiguration.additionalPricePerPiece), additionalPricePerPiece_currency: packingConfiguration.additionalPricePerPiece.currency,
tradeItemId: tradeItem.tradeItemId, additionalPricePerPiece_value: packingConfiguration.additionalPricePerPiece.value,
}, { transaction: tx }); tradeItemId: tradeItem.tradeItemId,
}, { transaction: tx });
await models.package.upsert({ await models.package.upsert({
...packingConfiguration.package, ...packingConfiguration.package,
packingConfigurationFk: uuid, packingConfigurationFk: uuid,
}, { transaction: tx }); }, { transaction: tx });
} }
// Upsert country of origin ISO codes // Upsert country of origin ISO codes
if (tradeItem.countryOfOriginIsoCodes) if (tradeItem.countryOfOriginIsoCodes)
for (const isoCode of tradeItem.countryOfOriginIsoCodes || []) { if (tradeItem.countryOfOriginIsoCodes.length)
await models.countryOfOriginIsoCode.upsert({ for (const isoCode of tradeItem.countryOfOriginIsoCodes || []) {
isoCode, await models.countryOfOriginIsoCode.upsert({
tradeItemId: tradeItem.tradeItemId, isoCode,
}, { transaction: tx }); tradeItemId: tradeItem.tradeItemId,
} }, { transaction: tx });
}
// Upsert botanical names // Upsert botanical names
if (tradeItem.botanicalNames) if (tradeItem.botanicalNames)
for (const botanicalName of tradeItem.botanicalNames) { if (tradeItem.botanicalNames.length)
await models.botanicalName.upsert({ for (const botanicalName of tradeItem.botanicalNames) {
...botanicalName, await models.botanicalName.upsert({
tradeItemId: tradeItem.tradeItemId, name: botanicalName,
}, { transaction: tx }); tradeItemId: tradeItem.tradeItemId,
} }, { transaction: tx });
}
await tx.commit(); await tx.commit();
} catch (err) { } catch (err) {
@ -720,24 +713,42 @@ export async function deleteConnections() {
* *
* @return {array} * @return {array}
**/ **/
export async function vnRequest(method = 'GET', url, data = null, headers = {}) { export async function vnRequest(method, url, data, headers) {
let response;
for(let i = 0; i < env.MAX_REQUEST_RETRIES; i++) { for(let i = 0; i < env.MAX_REQUEST_RETRIES; i++) {
try { try {
if (['GET', 'DELETE'].includes(method)) if (['GET', 'DELETE'].includes(method))
response = await axios({method, url, headers}); return await axios({method, url, headers});
else else
response = await axios({method, url, data, headers}); return await axios({method, url, data, headers});
break;
} catch (err) { } catch (err) {
if (err.code == 'ECONNRESET') switch (err.code) {
warning(err) case 'ECONNRESET': // Client network socket TLS
else warning(err);
criticalError(err) await sleep(1000);
await sleep(1000) break;
case 'ECONNABORTED':
case 'ECONNREFUSED':
case 'ERR_BAD_REQUEST':
switch (err.response.status) {
case 429: // Too Many Requests
warning(err);
await sleep(3400); // Stipulated by floryday
case 401: // Unauthorized
warning(err);
await requestToken(true);
headers.Authorization ?
headers.Authorization = `Bearer ${await getCurrentToken()}` :
criticalError(err);
break;
default:
criticalError(err);
}
break;
default:
criticalError(err);
}
} }
} }
return response;
} }
/** /**