dcos-core-monalisav2-latam 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -0
- package/index.js +350 -0
- package/package.json +52 -0
- package/src/auth/handler.js +3 -0
- package/src/common/MondelezCastOrder.js +449 -0
- package/src/common/utils/AuthSecurity.js +46 -0
- package/src/common/utils/account-error-handler.js +279 -0
- package/src/common/utils/account-error-helper.js +231 -0
- package/src/common/utils/account-properties-handler.js +355 -0
- package/src/common/utils/api-response.js +62 -0
- package/src/common/utils/aws-services.js +186 -0
- package/src/common/utils/constants/account-error-codes.json +801 -0
- package/src/common/utils/constants.js +37 -0
- package/src/common/utils/convert/MondelezClientsItemsCast.js +52 -0
- package/src/common/utils/convert/MondelezInventoryItemsCast.js +15 -0
- package/src/common/utils/convert/MondelezOrderStatusCast.js +34 -0
- package/src/common/utils/convert/MondelezPricesItemsCast.js +37 -0
- package/src/common/utils/cron-ftp-get.js +143 -0
- package/src/common/utils/data-tables-helper.js +213 -0
- package/src/common/utils/date-range-calculator.js +113 -0
- package/src/common/utils/delay.js +17 -0
- package/src/common/utils/ftp-sftp.js +320 -0
- package/src/common/utils/logger.js +126 -0
- package/src/common/utils/nodemailerLib.js +61 -0
- package/src/common/utils/product-unit-converter.js +168 -0
- package/src/common/utils/schemas-utils.js +101 -0
- package/src/common/utils/seller-email-sharing-service.js +441 -0
- package/src/common/utils/sftp-utils.js +202 -0
- package/src/common/utils/status.js +15 -0
- package/src/common/utils/util.js +236 -0
- package/src/common/utils/validate-state-order.js +35 -0
- package/src/common/utils/validateProviders.js +67 -0
- package/src/common/utils/validation-data.js +45 -0
- package/src/common/utils/vtex/save-hooks.js +65 -0
- package/src/common/utils/vtex/save-schemas.js +65 -0
- package/src/common/utils/vtex-hook-handler.js +71 -0
- package/src/common/validation/AccountCoordinatesValidation.js +350 -0
- package/src/common/validation/GeneralErrorValidation.js +11 -0
- package/src/common/validation/MainErrorValidation.js +8 -0
- package/src/entities/account.js +639 -0
- package/src/entities/clients.js +104 -0
- package/src/entities/controlprice.js +196 -0
- package/src/entities/controlstock.js +206 -0
- package/src/entities/cron.js +77 -0
- package/src/entities/cronjob.js +71 -0
- package/src/entities/orders.js +195 -0
- package/src/entities/sftp-inbound.js +88 -0
- package/src/entities/sku.js +220 -0
- package/src/entities/taxpromotion.js +249 -0
- package/src/functions/account/account-get.js +262 -0
- package/src/functions/account/account-handler.js +299 -0
- package/src/functions/account/clients.js +10 -0
- package/src/functions/account/index.js +208 -0
- package/src/functions/actions/save-promotions-order-history.js +324 -0
- package/src/functions/affiliates/affiliates-hook-consumer.js +87 -0
- package/src/functions/affiliates/affiliates-hook-producer.js +45 -0
- package/src/functions/clients/clients-audience.js +62 -0
- package/src/functions/clients/clients-consumer.js +648 -0
- package/src/functions/clients/clients-producer.js +362 -0
- package/src/functions/clients/clients-suggested-product-consumer.js +166 -0
- package/src/functions/clients/helpers/suggested-product-mdlz.js +233 -0
- package/src/functions/clients_peru/email.html +129 -0
- package/src/functions/clients_peru/splitfile.js +357 -0
- package/src/functions/clients_peru/updateClients.js +1334 -0
- package/src/functions/clients_peru/utils.js +243 -0
- package/src/functions/cronjobs/cron-jobs-manager.js +40 -0
- package/src/functions/cronjobs/cron-jobs.js +171 -0
- package/src/functions/crons/cron.js +39 -0
- package/src/functions/distributors/distributor-handler.js +81 -0
- package/src/functions/distributors/distributor.js +535 -0
- package/src/functions/distributors/index.js +60 -0
- package/src/functions/financialpolicy/assign-financialpolicy.js +111 -0
- package/src/functions/financialpolicy/get-financialpolicy.js +91 -0
- package/src/functions/financialpolicy/index.js +28 -0
- package/src/functions/inventory/catalog-sync-consumer.js +17 -0
- package/src/functions/inventory/catalog-sync-handler.js +311 -0
- package/src/functions/inventory/inventory-consumer.js +119 -0
- package/src/functions/inventory/inventory-producer.js +197 -0
- package/src/functions/multiPresentation/multipre-queue.js +155 -0
- package/src/functions/multiPresentation/multipres.js +459 -0
- package/src/functions/nodeflow/index.js +83 -0
- package/src/functions/nodeflow/nodeflow-cron.js +200 -0
- package/src/functions/nodeflow/nodeflow-pub.js +203 -0
- package/src/functions/nodeflow/nodeflow-pvt.js +266 -0
- package/src/functions/notifications/download-leads-handler.js +67 -0
- package/src/functions/notifications/new-leads-notification-consumer.js +17 -0
- package/src/functions/notifications/new-leads-notification-handler.js +359 -0
- package/src/functions/notifications/order-status-notification-handler.js +482 -0
- package/src/functions/notifications/promotion-notification-handler.js +193 -0
- package/src/functions/orders/index.js +32 -0
- package/src/functions/orders/orders-cancel-handler.js +74 -0
- package/src/functions/orders/orders-handler.js +280 -0
- package/src/functions/orders/orders-hook-consumer.js +137 -0
- package/src/functions/orders/orders-hook-producer.js +170 -0
- package/src/functions/orders/orders-notifications-handler.js +137 -0
- package/src/functions/orders/orders-status-consumer.js +461 -0
- package/src/functions/orders/orders-status-producer.js +443 -0
- package/src/functions/prices/index.js +75 -0
- package/src/functions/prices/prices-consumer.js +236 -0
- package/src/functions/prices/prices-producer.js +323 -0
- package/src/functions/prices/promotion-and-tax.js +1284 -0
- package/src/functions/routesflow/assign-routeflow-queue.js +77 -0
- package/src/functions/schemas/vtex/handle-schemas.js +102 -0
- package/src/functions/security/process_gas.js +221 -0
- package/src/functions/security/security-handler.js +950 -0
- package/src/functions/sftp/sftp-consumer.js +453 -0
- package/src/functions/sftpIntegrations/processes/redirectServices.js +184 -0
- package/src/functions/sftpIntegrations/processes/validateFileSchema.js +226 -0
- package/src/functions/sftpIntegrations/schemas/credential-schema.js +123 -0
- package/src/functions/sftpIntegrations/schemas/record-schema.js +131 -0
- package/src/functions/sftpIntegrations/schemas/sftp_required_fields.json +3 -0
- package/src/functions/sftpIntegrations/sftp-config-producer.js +112 -0
- package/src/functions/sftpIntegrations/sftp-consumer.js +700 -0
- package/src/functions/sftpIntegrations/test/validateFile.test.js +122 -0
- package/src/functions/sftpIntegrations/utils/connect-dynamo.js +29 -0
- package/src/functions/sftpIntegrations/utils/split-data.js +25 -0
- package/src/functions/utils/index.js +130 -0
- package/src/functions/vtex/vtex-helpers.js +694 -0
- package/src/integrations/accountErrors/AccountErrorManager.js +437 -0
- package/src/integrations/audience/Audience.js +70 -0
- package/src/integrations/financialPolicy/FinancialPolicyApi.js +377 -0
- package/src/integrations/index.js +0 -0
- package/src/integrations/mobilvendor/MobilvendorApi.js +405 -0
- package/src/integrations/productmultipresentation/ProductMultiPresentation.js +200 -0
- package/src/mdlz/auth/SecretManagerApi.js +77 -0
- package/src/mdlz/client/MdlzApi.js +70 -0
- package/src/vtex/clients/ProvidersApi.js +51 -0
- package/src/vtex/clients/VtexApi.js +511 -0
- package/src/vtex/models/VtexOrder.js +87 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
const { SQS } = require('aws-sdk');
|
|
2
|
+
const { AxiosError } = require('axios');
|
|
3
|
+
const Logger = require('../../common/utils/logger');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Envia un mensaje a una cola SQS.
|
|
7
|
+
* @param {string} url URL de la cola SQS a la que se enviará el mensaje.
|
|
8
|
+
* @param {object} message Objeto JSON con los datos a enviar a la cola.
|
|
9
|
+
* @returns
|
|
10
|
+
*/
|
|
11
|
+
module.exports.sendSqsMessage = (url, message) => {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const sqs = new SQS()
|
|
14
|
+
message = JSON.stringify(message);
|
|
15
|
+
const params = { MessageBody: message, QueueUrl: url };
|
|
16
|
+
if (process?.env?.SQS_DELAY_SECONDS) {
|
|
17
|
+
params.DelaySeconds = process.env.SQS_DELAY_SECONDS;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Se ejecuta la tarea de enviar el mensaje a SQS
|
|
21
|
+
sqs.sendMessage(params, (err, data) => {
|
|
22
|
+
if (err) {
|
|
23
|
+
reject(err);
|
|
24
|
+
} else {
|
|
25
|
+
const { MessageId } = data;
|
|
26
|
+
Logger.info(`Message sent with id: ${MessageId}`, message);
|
|
27
|
+
resolve(data);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Establece en una URL base los parámetros GET.
|
|
35
|
+
* @param {string} url Url base a la que se adicionará los Query Params.
|
|
36
|
+
* @param {object} queryParams Objeto con los Query Params a definir como método GET.
|
|
37
|
+
* @returns Url con los Query Params.
|
|
38
|
+
*/
|
|
39
|
+
module.exports.setQueryParams = (url, queryParams) => {
|
|
40
|
+
let queryText = ''
|
|
41
|
+
for (let key in queryParams) {
|
|
42
|
+
if (queryText) {
|
|
43
|
+
queryText += '&'
|
|
44
|
+
}
|
|
45
|
+
queryText += `${key}=${queryParams[key]}`
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (queryText) {
|
|
49
|
+
queryText = '?' + queryText
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return url + queryText
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Obtiene el valor de REST-Range para consultar registros en una entidad de Master Data.
|
|
57
|
+
* @param {number} page Página de registros a consultar en Master Data
|
|
58
|
+
* @param {number} limit Número máximo de registros a retornar.
|
|
59
|
+
* @returns Texto con el parámetro REST-Range de VTEX.
|
|
60
|
+
* @see {@link https://developers.vtex.com/docs/api-reference/masterdata-api#get-/api/dataentities/-acronym-/search|Search documents - Master Data V1}
|
|
61
|
+
*/
|
|
62
|
+
module.exports.getRestRange = (page, limit) => {
|
|
63
|
+
let start = (page - 1) * limit, end = page * limit;
|
|
64
|
+
return `resources=${start}-${end}`;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Genera los valores basados en una determinada fecha para utilizarse en
|
|
69
|
+
* el nombre de archivos y/o carpetas.
|
|
70
|
+
* @param {Date} currentDate Fecha de la cual se extrae la información
|
|
71
|
+
* @returns Valores generados a partir de la fecha.
|
|
72
|
+
*/
|
|
73
|
+
module.exports.getDateValues = (currentDate = new Date()) => {
|
|
74
|
+
let year = currentDate.getFullYear(),
|
|
75
|
+
month = String(currentDate.getMonth() + 1).padStart(2, '0'),
|
|
76
|
+
day = String(currentDate.getDate()).padStart(2, '0'),
|
|
77
|
+
hour = String(currentDate.getHours()).padStart(2, '0'),
|
|
78
|
+
minute = String(currentDate.getMinutes()).padStart(2, '0'),
|
|
79
|
+
second = String(currentDate.getSeconds()).padStart(2, '0');
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
// Marca de tiempo de la fecha y hora actual.
|
|
83
|
+
'timestamp': year + month + day + hour + minute + second,
|
|
84
|
+
// Marca de tiempo de la fecha actual.
|
|
85
|
+
'timestampMin': year + month + day,
|
|
86
|
+
// Subcarpeta donde se moveran los archivos grandes que ya fueron divididos
|
|
87
|
+
'processedSubfolder': `${year}/${month}`
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Ajusta las reglas de validación en Validate.js.
|
|
93
|
+
* @param {*} validate Instancia de la librería validate.js
|
|
94
|
+
*/
|
|
95
|
+
module.exports.setValidateOptions = (validate) => {
|
|
96
|
+
// Se ajusta la opción message de error para el parámetro 'format'
|
|
97
|
+
validate.validators.format.options = {
|
|
98
|
+
message: (value, attribute, validatorOptions, attributes, globalOptions) => {
|
|
99
|
+
// Se obtiene el tipo de dato del parámetro 'format' definido en las reglas de validación
|
|
100
|
+
let type = Object.prototype.toString.call(validatorOptions);
|
|
101
|
+
switch (type) {
|
|
102
|
+
case '[object String]':
|
|
103
|
+
return `doesn't match with the pattern '${validatorOptions ?? ''}'`;
|
|
104
|
+
case '[object Object]':
|
|
105
|
+
return `doesn't match with the pattern '${validatorOptions.pattern ?? ''}'`;
|
|
106
|
+
default:
|
|
107
|
+
return `doesn't match with the pattern`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Se ajusta las validaciones para el parámetro 'presence'
|
|
113
|
+
validate.validators.presence = (value, options, attribute, attributes) => {
|
|
114
|
+
// Se valida si el atributo no está definido
|
|
115
|
+
if (!attributes.hasOwnProperty(attribute)) {
|
|
116
|
+
return `is't defined`;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Se obtiene el tipo de dato del parámetro 'format' definido en las reglas de validación
|
|
120
|
+
let type = Object.prototype.toString.call(options);
|
|
121
|
+
|
|
122
|
+
// Si en la opción se para un valor booleano (presence=true o presence=false)
|
|
123
|
+
if (type == '[object Boolean]') {
|
|
124
|
+
return options && !value ? `can't be blank` : null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Si se define un valor de texto (condicional con la variable 'attributes')
|
|
128
|
+
if (type == '[object String]') {
|
|
129
|
+
try {
|
|
130
|
+
let result;
|
|
131
|
+
eval('result=' + options);
|
|
132
|
+
return result && !value ? `can't be blank` : null;
|
|
133
|
+
} catch (ex) {
|
|
134
|
+
Logger.error(ex);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (type == '[object Object]') {
|
|
139
|
+
const { allowEmpty, message } = options;
|
|
140
|
+
|
|
141
|
+
let subType = Object.prototype.toString.call(allowEmpty);
|
|
142
|
+
if (subType == '[object Boolean]') {
|
|
143
|
+
return !allowEmpty && !value ? (message ?? `can't be blank`) : null;
|
|
144
|
+
}
|
|
145
|
+
if (subType == '[object String]') {
|
|
146
|
+
try {
|
|
147
|
+
let result;
|
|
148
|
+
eval('result=' + allowEmpty);
|
|
149
|
+
return !result && !value ? (message ?? `can't be blank`) : null;
|
|
150
|
+
} catch (ex) {
|
|
151
|
+
Logger.error(ex);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return 'has an validation error';
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
validate.validators.inclusion = (value, options, attribute, attributes) => {
|
|
160
|
+
// Si no se definió un valor se retorna null
|
|
161
|
+
if (!value) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Se obtiene el tipo de dato del parámetro 'format' definido en las reglas de validación
|
|
166
|
+
let type = Object.prototype.toString.call(options);
|
|
167
|
+
|
|
168
|
+
if (type == '[object Array]') {
|
|
169
|
+
return !options.includes(value) ? `is not included in the list` : null;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (type == '[object Object]') {
|
|
173
|
+
const { within, message, sensiitiveCase } = options;
|
|
174
|
+
|
|
175
|
+
switch (sensiitiveCase) {
|
|
176
|
+
case 'U':
|
|
177
|
+
value = value.toUpperCase();
|
|
178
|
+
break;
|
|
179
|
+
case 'L':
|
|
180
|
+
value = value.toLowerCase();
|
|
181
|
+
break
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return !within.includes(value) ? (message ?? `is not included in the list`) : null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return 'has an validation error';
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Extrae la información básica de un error capturado en un try...catch.
|
|
193
|
+
* @param {*} ex Objeto de datos del error.
|
|
194
|
+
* @returns Información del error presentado.
|
|
195
|
+
*/
|
|
196
|
+
module.exports.getErrorData = ex => {
|
|
197
|
+
let error = { message: '', status: 500, info: {} };
|
|
198
|
+
if (ex instanceof AxiosError) {
|
|
199
|
+
const { request = {}, response = {} } = ex;
|
|
200
|
+
const { path, method, host } = request;
|
|
201
|
+
const { status = 500, statusText = '', data = null } = response;
|
|
202
|
+
|
|
203
|
+
let message;
|
|
204
|
+
if (data?.Message) {
|
|
205
|
+
message = data.Message;
|
|
206
|
+
} else if (data) {
|
|
207
|
+
switch (Object.prototype.toString.call(data)) {
|
|
208
|
+
case '[object String]':
|
|
209
|
+
message = data;
|
|
210
|
+
break;
|
|
211
|
+
case '[object Object]':
|
|
212
|
+
message = JSON.stringify(data);
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
} else if (statusText) {
|
|
216
|
+
message = statusText;
|
|
217
|
+
} else {
|
|
218
|
+
Logger.error(ex);
|
|
219
|
+
message = 'Error in Axios request';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
error.status = status;
|
|
223
|
+
error.message = message;
|
|
224
|
+
error.info = { status, data, message, request: { path, method, host } };
|
|
225
|
+
} else {
|
|
226
|
+
const { message } = ex;
|
|
227
|
+
error.message = message;
|
|
228
|
+
error.info = { message };
|
|
229
|
+
}
|
|
230
|
+
return error;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Actualiza el valor de una propiedad adicionando el posfijo '_XXX';
|
|
235
|
+
* @param {object} objectData Objeto de datos.
|
|
236
|
+
* @param {string} key Nombre de la propiedad a afectar.
|
|
237
|
+
* @param {number} attemp Posfijo a definir.
|
|
238
|
+
*/
|
|
239
|
+
module.exports.addSuffixToTimestamp = (objectData, key, attemp) => {
|
|
240
|
+
if (objectData.hasOwnProperty(key) && objectData[key]) {
|
|
241
|
+
objectData[key] = objectData[key].replace(/(_\d+)?$/, '_' + attemp);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const ApiResponse = require('../../common/utils/api-response');
|
|
2
|
+
const Logger = require('../../common/utils/logger');
|
|
3
|
+
const { getErrorData } = require('../../common/utils/util');
|
|
4
|
+
const Cronjob = require('../../entities/cronjob');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param {*} event Objeto que contiene información de una petición como: el body, path y método de una petición HTTP, o la lista de registros en una cola SQS.
|
|
9
|
+
* @param {*} context Objeto que contiene información sobre la invocación, la función y el entorno de ejecución.
|
|
10
|
+
*/
|
|
11
|
+
module.exports.create = async (event, context) => {
|
|
12
|
+
// ID de la petición en AWS
|
|
13
|
+
const { awsRequestId } = context;
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
let { body, pathParameters } = event;
|
|
17
|
+
const { cronId } = pathParameters;
|
|
18
|
+
|
|
19
|
+
body = JSON.parse(body);
|
|
20
|
+
if (!body) {
|
|
21
|
+
throw new Error('Body request is not defined');
|
|
22
|
+
}
|
|
23
|
+
if (!cronId) {
|
|
24
|
+
throw new Error('Cron Id is required');
|
|
25
|
+
}
|
|
26
|
+
const result = await Cronjob.addRegisterPerId(cronId, {
|
|
27
|
+
CronId: cronId,
|
|
28
|
+
Crons: body
|
|
29
|
+
});
|
|
30
|
+
if (!result) {
|
|
31
|
+
throw new Error('Cron could not be created');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return ApiResponse.response(200, { message: 'Cron jobs saved successfully', data: result });
|
|
35
|
+
} catch (ex) {
|
|
36
|
+
const { message, info } = getErrorData(ex);
|
|
37
|
+
Logger.error(info);
|
|
38
|
+
return ApiResponse.response(500, { 'error': message, awsRequestId });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
const nodeCron = require('node-cron');
|
|
2
|
+
const parser = require('cron-parser');
|
|
3
|
+
const ApiResponse = require('../../common/utils/api-response');
|
|
4
|
+
const { sendMessageToSqs } = require('../../common/utils/aws-services');
|
|
5
|
+
const { processNewLeadsNotification } = require('../notifications/new-leads-notification-consumer');
|
|
6
|
+
const { getErrorData } = require('../../common/utils/util');
|
|
7
|
+
const Cronjob = require('../../entities/cronjob');
|
|
8
|
+
const { callback: executeSftpProcess, reprocessFailed } = require('../sftpIntegrations/sftp-consumer');
|
|
9
|
+
const { handler: catalogSyncHandler } = require('../inventory/catalog-sync-handler');
|
|
10
|
+
const { handleExecute } = require('../multiPresentation/multipres');
|
|
11
|
+
const { handleConsumer } = require('../clients_peru/updateClients');
|
|
12
|
+
const Logger = require('../../common/utils/logger');
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
SQS_CRON_JOBS_QUEUE_URL,
|
|
16
|
+
SQS_CRON_JOBS_DLQ_QUEUE_URL,
|
|
17
|
+
CRONJOB_ID
|
|
18
|
+
} = process?.env ?? {};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Función que se invoca desde el schedule definido en la propiedad 'cron_jobs' del archivo 'functions.yml'.
|
|
22
|
+
* @param {*} event Objeto que contiene información de una petición como: el body, path y método de una petición HTTP, o la lista de registros en una cola SQS.
|
|
23
|
+
* @param {*} context Objeto que contiene información sobre la invocación, la función y el entorno de ejecución.
|
|
24
|
+
*/
|
|
25
|
+
module.exports.run = async (event, context) => {
|
|
26
|
+
// Se obtiene la propiedad 'httpMethod' para determinar si la función se ejecutó desde una petición HTTP
|
|
27
|
+
const { httpMethod } = event;
|
|
28
|
+
// Se consulta la lista de cron jobs configurados
|
|
29
|
+
const promises = [];
|
|
30
|
+
const cronJobs = await getCronJobs();
|
|
31
|
+
for (let cronJob of cronJobs) {
|
|
32
|
+
const { Actived = false, Name, Cron, TimeZone = 'America/Bogota', ...jobData } = cronJob;
|
|
33
|
+
// Se define la zona horaria para que la fecha y hora del sistema sea acorde a la misma
|
|
34
|
+
setTimeZone(TimeZone);
|
|
35
|
+
let currentDate = new Date();
|
|
36
|
+
// Se valida si el job se encuentra activo y el cron definido sea válido
|
|
37
|
+
if (Actived && Cron && nodeCron.validate(Cron)) {
|
|
38
|
+
if (timeMatch(Cron, currentDate)) {
|
|
39
|
+
promises.push(jobData);
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
Logger.warn(`Job ${Name} is inactived and/or cron is not valid`, { Actived, Cron });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (promises.length) {
|
|
46
|
+
Logger.log(`Cron jobs to execute: ${promises.length}`);
|
|
47
|
+
await Promise.allSettled(promises.map(jobData => {
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
if (!jobData || jobData === "") {
|
|
50
|
+
return resolve(null); // O reject si prefieres fallar en este caso
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
sendMessageToSqs(SQS_CRON_JOBS_QUEUE_URL, jobData).then(e => {
|
|
54
|
+
resolve(jobData);
|
|
55
|
+
}).catch(error => {
|
|
56
|
+
Logger.error(`Error sending message to SQS`, {
|
|
57
|
+
error: error.message,
|
|
58
|
+
jobData: jobData
|
|
59
|
+
});
|
|
60
|
+
reject(new Error(error.message)); // Propaga el error a Promise.allSettled
|
|
61
|
+
})
|
|
62
|
+
});
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Si la función se ejecutó desde una petición HTTP se retorna una respuesta
|
|
67
|
+
if (httpMethod) {
|
|
68
|
+
return ApiResponse.response(200, { message: 'Cron jobs executed successfully', promises });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Función que se invoca desde el trigger de la cola SQS definida en la propiedad 'cronjobs-queue' del archivo 'constructs.yml'.
|
|
74
|
+
* @param {*} event Objeto que contiene información de una petición como: el body, path y método de una petición HTTP, o la lista de registros en una cola SQS.
|
|
75
|
+
* @param {*} context Objeto que contiene información sobre la invocación, la función y el entorno de ejecución.
|
|
76
|
+
*/
|
|
77
|
+
module.exports.queue = async (event, context) => {
|
|
78
|
+
// ID de la petición en AWS
|
|
79
|
+
const { awsRequestId } = context;
|
|
80
|
+
|
|
81
|
+
// Se recorre la lista de registros de la cola
|
|
82
|
+
for (const record of event.Records) {
|
|
83
|
+
// Se obtiene el objeto enviado a la cola
|
|
84
|
+
let { body } = record;
|
|
85
|
+
body = JSON.parse(body);
|
|
86
|
+
|
|
87
|
+
const { AccountName, ActionProcess, Values } = body;
|
|
88
|
+
try {
|
|
89
|
+
switch (ActionProcess) {
|
|
90
|
+
case 'new-leads':
|
|
91
|
+
await processNewLeadsNotification(AccountName, ActionProcess, Values);
|
|
92
|
+
break;
|
|
93
|
+
case 'catalog-sync':
|
|
94
|
+
await catalogSyncHandler({
|
|
95
|
+
pathParameters: { accountName: AccountName },
|
|
96
|
+
...Values
|
|
97
|
+
});
|
|
98
|
+
break;
|
|
99
|
+
case 'multiPresentation':
|
|
100
|
+
await handleExecute(AccountName);
|
|
101
|
+
break
|
|
102
|
+
case 'clientsPeru':
|
|
103
|
+
await handleConsumer(AccountName, Values);
|
|
104
|
+
break
|
|
105
|
+
case 'reprocessSftpFailed':
|
|
106
|
+
await reprocessFailed(body);
|
|
107
|
+
break
|
|
108
|
+
default:
|
|
109
|
+
// Se pasa el cuerpo del mensaje SQS completo, para contemplar el tema de los reitentos dentro de la función.
|
|
110
|
+
await executeSftpProcess(body);
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
} catch (ex) {
|
|
114
|
+
const { message, info } = getErrorData(ex);
|
|
115
|
+
Logger.error('Error in Cron Job queue', info);
|
|
116
|
+
|
|
117
|
+
await sendMessageToSqs(SQS_CRON_JOBS_DLQ_QUEUE_URL, {
|
|
118
|
+
AccountName, ActionProcess,
|
|
119
|
+
Values,
|
|
120
|
+
reason: message,
|
|
121
|
+
awsRequestId
|
|
122
|
+
}).catch(Logger.error);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Consulta la lista de jobs configurados.
|
|
129
|
+
* @returns Lista de jobs.
|
|
130
|
+
*/
|
|
131
|
+
async function getCronJobs() {
|
|
132
|
+
try {
|
|
133
|
+
// Se consulta en DynamoDB la lista de Jobs configurados
|
|
134
|
+
const cronJobsData = await Cronjob.getPerId(CRONJOB_ID);
|
|
135
|
+
return cronJobsData?.Crons ?? [];
|
|
136
|
+
} catch (ex) {
|
|
137
|
+
const { info } = getErrorData(ex);
|
|
138
|
+
Logger.error('Error in getCronJobs', info)
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Establece la zona horaria en el servidor para obtener fecha y hora del sistema.
|
|
145
|
+
* @param {string} timeZone Zona horaria.
|
|
146
|
+
*/
|
|
147
|
+
function setTimeZone(timeZone) {
|
|
148
|
+
if (timeZone) {
|
|
149
|
+
process.env.TZ = timeZone;
|
|
150
|
+
} else {
|
|
151
|
+
delete process.env.TZ;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Valida si una fecha corresponde a un cron job.
|
|
157
|
+
* @param {string} cron Valor del cron.
|
|
158
|
+
* @param {Date} date Fecha a validar.
|
|
159
|
+
* @return Valor de verdad que indica si la fecha corresponde o no al cron (TRUE o FALSE).
|
|
160
|
+
*/
|
|
161
|
+
function timeMatch(cron, date) {
|
|
162
|
+
let interval = parser.parseExpression(cron);
|
|
163
|
+
|
|
164
|
+
const { minute, hour, dayOfMonth, month, dayOfWeek } = interval.fields;
|
|
165
|
+
|
|
166
|
+
return minute.includes(date.getMinutes()) &&
|
|
167
|
+
hour.includes(date.getHours()) &&
|
|
168
|
+
dayOfMonth.includes(date.getDate()) &&
|
|
169
|
+
month.includes(date.getMonth() + 1) &&
|
|
170
|
+
dayOfWeek.includes(date.getDay());
|
|
171
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const Crons = require("../../entities/cron");
|
|
4
|
+
const ApiResponse = require("../../common/utils/api-response");
|
|
5
|
+
const Logger = require("../../common/utils/logger");
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param {import("aws-lambda")} event
|
|
9
|
+
*/
|
|
10
|
+
const create = async (event) => {
|
|
11
|
+
try {
|
|
12
|
+
let message = "Cron created successfully";
|
|
13
|
+
Logger.log(event);
|
|
14
|
+
if (!event.body) {
|
|
15
|
+
return ApiResponse.response(400, "No body was found");
|
|
16
|
+
}
|
|
17
|
+
const body = JSON.parse(event.body);
|
|
18
|
+
const cronId = event?.pathParameters?.cronId;
|
|
19
|
+
if (!cronId || cronId === "") {
|
|
20
|
+
return ApiResponse.response(400, "Cron Id is required");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const cron = await Crons.addRegisterPerId({
|
|
24
|
+
CronId: cronId,
|
|
25
|
+
Crons: body
|
|
26
|
+
}, cronId);
|
|
27
|
+
if (!cron) {
|
|
28
|
+
return ApiResponse.response(400, "Cron could not be created");
|
|
29
|
+
}
|
|
30
|
+
return ApiResponse.response(200, { message: message, data: cron });
|
|
31
|
+
} catch (error) {
|
|
32
|
+
Logger.error(error);
|
|
33
|
+
return ApiResponse.response(500, error);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
module.exports = {
|
|
38
|
+
create
|
|
39
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const VtexApi = require('../../vtex/clients/VtexApi');
|
|
2
|
+
const DistributorData = require('./distributor');
|
|
3
|
+
const Logger = require("../../common/utils/logger");
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Handles the event triggered by the Lambda function.
|
|
7
|
+
*
|
|
8
|
+
* @param {Object} event - The event object containing the request details.
|
|
9
|
+
* @returns {Promise<Object>} - A promise that resolves to the response object.
|
|
10
|
+
* @throws {Error} - If an error occurs during the execution.
|
|
11
|
+
*/
|
|
12
|
+
module.exports.handler = async (event) => {
|
|
13
|
+
let statusCode = 200;
|
|
14
|
+
let response = {};
|
|
15
|
+
for (const record of event.Records) {
|
|
16
|
+
try {
|
|
17
|
+
const order = JSON.parse(record.body);
|
|
18
|
+
const AccountConfig = order?.accountConfig;
|
|
19
|
+
Logger.setAccount(AccountConfig);
|
|
20
|
+
const orderId = order?.orderInfo?.OrderId;
|
|
21
|
+
const vtexApi = new VtexApi(AccountConfig.AccountName, AccountConfig.Credentials.key, AccountConfig.Credentials.token);
|
|
22
|
+
const responseOrder = await vtexApi.fetch(`/oms/pvt/orders/${orderId}`, { method: "GET" });
|
|
23
|
+
Logger.debug("Response Order Info: ", responseOrder?.data);
|
|
24
|
+
//get only items from responseOrder
|
|
25
|
+
const items = responseOrder?.data?.items;
|
|
26
|
+
Logger.debug("Items: ", items);
|
|
27
|
+
let itemsSkuDist = {};
|
|
28
|
+
let skuRefUsed = AccountConfig?.SkuRefUsed;
|
|
29
|
+
if (typeof skuRefUsed !== "boolean") {
|
|
30
|
+
Logger.warn("Sku or ReferenceCode filter not defined, use default: ", skuRefUsed);
|
|
31
|
+
skuRefUsed = true;
|
|
32
|
+
}
|
|
33
|
+
if (!items) {
|
|
34
|
+
Logger.error("Orders without items.");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
// Create a set to track unique search values
|
|
38
|
+
const uniqueSearchValues = new Set();
|
|
39
|
+
const filteredItems = items.filter(item => {
|
|
40
|
+
const searchValue = skuRefUsed ? item.refId : item.ean;
|
|
41
|
+
if (!uniqueSearchValues.has(searchValue)) {
|
|
42
|
+
uniqueSearchValues.add(searchValue);
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
});
|
|
47
|
+
Logger.debug("Filtered Items: ", filteredItems);
|
|
48
|
+
itemsSkuDist = await getItemsSkuDist(responseOrder, filteredItems, skuRefUsed, AccountConfig);
|
|
49
|
+
const updateAdditionalFields = await vtexApi.fetch(
|
|
50
|
+
`/dataentities/${AccountConfig.SkuDistributorManagementAdditionalInfo.entityName}/documents/`, { method: "PATCH", data: itemsSkuDist });
|
|
51
|
+
Logger.debug("Update Additional Fields: ", updateAdditionalFields);
|
|
52
|
+
if (!updateAdditionalFields && (updateAdditionalFields.status !== 200 || updateAdditionalFields.status !== 201 || updateAdditionalFields.status !== 204)) {
|
|
53
|
+
statusCode = 404;
|
|
54
|
+
response = { error: updateAdditionalFields };
|
|
55
|
+
Logger.error(statusCode, response);
|
|
56
|
+
}
|
|
57
|
+
Logger.info(statusCode, { itemsSkuDist });
|
|
58
|
+
} catch (error) {
|
|
59
|
+
Logger.error(error);
|
|
60
|
+
statusCode = 500;
|
|
61
|
+
response = { error };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
async function getItemsSkuDist(responseOrder, filteredItems, skuRefUsed, AccountConfig) {
|
|
67
|
+
return {
|
|
68
|
+
id: responseOrder?.data?.orderId,
|
|
69
|
+
items: await Promise.all(filteredItems.map(async (item) => {
|
|
70
|
+
const searchValue = skuRefUsed ? item.refId : item.ean;
|
|
71
|
+
const distributorData = await DistributorData.getDistributorByRefId(AccountConfig.AccountName, searchValue, AccountConfig.SkuDistributorManagement);
|
|
72
|
+
Logger.info(`Distributor Data for ${searchValue}: `, distributorData);
|
|
73
|
+
return {
|
|
74
|
+
id: item.id,
|
|
75
|
+
ean: item.ean,
|
|
76
|
+
refId: item.refId,
|
|
77
|
+
ERPCode: distributorData, // Include distributor data in the item
|
|
78
|
+
};
|
|
79
|
+
}))
|
|
80
|
+
};
|
|
81
|
+
}
|