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,362 @@
|
|
|
1
|
+
const AWSServices = require("../../common/utils/aws-services");
|
|
2
|
+
const ApiResponse = require("../../common/utils/api-response");
|
|
3
|
+
|
|
4
|
+
const ClientData = require("../../entities/clients");
|
|
5
|
+
const AccountData = require("../../entities/account");
|
|
6
|
+
|
|
7
|
+
const Logger = require("../../common/utils/logger");
|
|
8
|
+
const VtexApi = require("../../vtex/clients/VtexApi");
|
|
9
|
+
|
|
10
|
+
const suggestedProductMdlz = require("./helpers/suggested-product-mdlz");
|
|
11
|
+
|
|
12
|
+
const LIMIT_ITEMS_TO_PROCESS = process?.env?.LIMIT_ITEMS_TO_PROCESS || 150;
|
|
13
|
+
const SQS_CLIENT_QUEUE_URL = process.env.SQS_CLIENT_QUEUE_URL;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
*
|
|
17
|
+
* @param {import("aws-lambda").APIGatewayProxyEvent} event
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
const producer = async (event) => {
|
|
21
|
+
// Se extrae el method y el path del endpoint asociado a la función lambda
|
|
22
|
+
const { httpMethod, resource } = event;
|
|
23
|
+
|
|
24
|
+
// Si el endpoint corresponde a la creación de registros
|
|
25
|
+
if (httpMethod == 'POST' && resource == '/clients') {
|
|
26
|
+
return handleCreateClient(event);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Si el endpoint corresponde a la consulta de registros
|
|
30
|
+
if (httpMethod == 'GET' && resource == '/clients/{an}/{method}') {
|
|
31
|
+
return handleFindClients(event);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (httpMethod == 'POST' && resource == '/internal_process/suggestedProductMdlz') {
|
|
35
|
+
return suggestedProductMdlz(event);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return ApiResponse.response(400, 'Resource not available');
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const handleCreateClient = async (event) => {
|
|
42
|
+
let statusCode = 200, message;
|
|
43
|
+
|
|
44
|
+
if (!event.body) {
|
|
45
|
+
return ApiResponse.response(400, "No body was found");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
Logger.log(JSON.stringify(event));
|
|
50
|
+
const request = JSON.parse(event.body);
|
|
51
|
+
|
|
52
|
+
const clientId = event?.requestContext?.authorizer?.claims?.client_id;
|
|
53
|
+
const scope = event?.requestContext?.authorizer?.claims?.scope;
|
|
54
|
+
const accountName = request?.an;
|
|
55
|
+
const clients = request?.clients;
|
|
56
|
+
|
|
57
|
+
if (clients?.length >= LIMIT_ITEMS_TO_PROCESS) {
|
|
58
|
+
Logger.error("Clients size INVALID: ", clients?.length);
|
|
59
|
+
return errorResponse(404, "Clients limit of items exceeded");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!event?.internalService) {
|
|
63
|
+
if (!scope?.includes("admin")) {
|
|
64
|
+
const validateAccount = await ClientData.validateAccount(clientId, accountName);
|
|
65
|
+
if (!validateAccount) {
|
|
66
|
+
Logger.error("Account not found: ", accountName, ". ClientId: ", clientId);
|
|
67
|
+
return ApiResponse.response(404, "Account not found");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const account = event?.accountData && event?.internalService === true ? event?.accountData : await AccountData.getAccountDataByAccountName(accountName);
|
|
72
|
+
const parentAccount = await AccountData.getAccountDataByAccountName(account?.ParentAccountName);
|
|
73
|
+
Logger.setAccount(account);
|
|
74
|
+
Logger.debug("Account-Data: ", account);
|
|
75
|
+
Logger.debug("Parent-Account-Data: ", parentAccount);
|
|
76
|
+
|
|
77
|
+
//for each client
|
|
78
|
+
let notProcessed = [];
|
|
79
|
+
|
|
80
|
+
for (let item of clients) {
|
|
81
|
+
try {
|
|
82
|
+
Logger.debug("Object client to process: ", item);
|
|
83
|
+
const priceTableParam = item?.additional_information?.priceTable;
|
|
84
|
+
let priceTableVtex = null;
|
|
85
|
+
if (priceTableParam && priceTableParam !== "") {
|
|
86
|
+
priceTableVtex = account?.PriceList?.[priceTableParam];
|
|
87
|
+
item.additional_information.priceTable = priceTableVtex ?? `L${priceTableParam}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const dataSend = {
|
|
91
|
+
an: accountName,
|
|
92
|
+
parentAccount: parentAccount?.AccountName,
|
|
93
|
+
key: parentAccount?.Credentials?.key,
|
|
94
|
+
token: parentAccount?.Credentials?.token,
|
|
95
|
+
...item,
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// start valid fields requerid
|
|
99
|
+
let validRequired = validFieldsRequerid({ item: item, config: account });
|
|
100
|
+
if (validRequired?.valid === false) {
|
|
101
|
+
item.error = validRequired?.error;
|
|
102
|
+
notProcessed = [...notProcessed, item];
|
|
103
|
+
} else if (validDataClientFirstLevel({ data: item, ParametersClusterClient: account?.ParametersClusterClient }) === false) {
|
|
104
|
+
item.error = `validate the following properties ${JSON.stringify(account?.ParametersClusterClient)}`;
|
|
105
|
+
notProcessed = [...notProcessed, item];
|
|
106
|
+
} else {
|
|
107
|
+
Logger.debug("Datasend for SQS: ", dataSend);
|
|
108
|
+
await AWSServices.sendSQSMessage(SQS_CLIENT_QUEUE_URL, dataSend);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
} catch (error) {
|
|
112
|
+
Logger.error("Error while client was processing: ", error);
|
|
113
|
+
notProcessed.push(item);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (notProcessed.length > 0) {
|
|
118
|
+
Logger.debug("Not Processed: ", notProcessed);
|
|
119
|
+
const message = {
|
|
120
|
+
message: "Not all items were processed.",
|
|
121
|
+
notProcessedItems: notProcessed,
|
|
122
|
+
};
|
|
123
|
+
return ApiResponse.response(207, message);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
message = "Message accepted!";
|
|
127
|
+
} catch (error) {
|
|
128
|
+
Logger.error("Error clients producer: ", error);
|
|
129
|
+
statusCode = 500;
|
|
130
|
+
}
|
|
131
|
+
return ApiResponse.response(statusCode, message);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const handleFindClients = async (event) => {
|
|
135
|
+
const { headers, pathParameters, queryStringParameters, internalService, requestContext } = event;
|
|
136
|
+
const { an: accountName, method } = pathParameters;
|
|
137
|
+
|
|
138
|
+
const { client_id: clientId, scope } = requestContext?.authorizer?.claims ?? {};
|
|
139
|
+
|
|
140
|
+
if (!internalService) {
|
|
141
|
+
if (!scope?.includes("admin")) {
|
|
142
|
+
const validateAccount = await ClientData.validateAccount(clientId, accountName);
|
|
143
|
+
if (!validateAccount) {
|
|
144
|
+
Logger.error("Account not found: ", accountName, ". ClientId: ", clientId);
|
|
145
|
+
return ApiResponse.response(404, "Account not found");
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Se valida el valor del método de búsqueda de registros
|
|
151
|
+
if (!['search', 'scroll'].includes(method)) {
|
|
152
|
+
return ApiResponse.response(400, `Method '${method}' is not allowed`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Se consulta los datos del account en DynamoDB
|
|
156
|
+
let { accountData = null } = event;
|
|
157
|
+
if (!(accountData && internalService)) {
|
|
158
|
+
accountData = await AccountData.getAccountDataByAccountName(accountName);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Se obtiene los datos del account "padre"
|
|
162
|
+
const parentAccount = await AccountData.getAccountDataByAccountName(accountData?.ParentAccountName);
|
|
163
|
+
Logger.setAccount(accountData);
|
|
164
|
+
|
|
165
|
+
const { AccountName, Credentials, AcronymClientVtex } = parentAccount;
|
|
166
|
+
const { key, token } = Credentials;
|
|
167
|
+
|
|
168
|
+
Logger.debug('AccountName', AccountName);
|
|
169
|
+
Logger.debug('Method', method);
|
|
170
|
+
|
|
171
|
+
const apiClient = new VtexApi(AccountName, key, token);
|
|
172
|
+
let requestUrl = `/dataentities/${AcronymClientVtex}/${method}`, options = {
|
|
173
|
+
// Propiedad de AXIOS que permite retornar una respuesta sin importar el código HTTP retornado en la petición
|
|
174
|
+
validateStatus: () => true
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// En caso que venga en los Query Params el atributo "an", se elimina el valor enviado
|
|
178
|
+
if (queryStringParameters.hasOwnProperty('an')) {
|
|
179
|
+
delete queryStringParameters.an;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Se establece la Query Param "_fields" para indicar los campos a retornar en la consulta, en caso que este parámetro no venga
|
|
183
|
+
if (!queryStringParameters.hasOwnProperty('_fields') || !queryStringParameters['_fields']) {
|
|
184
|
+
queryStringParameters['_fields'] = '_all';
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Se verifica la condicional definida en la consulta
|
|
188
|
+
if (queryStringParameters.hasOwnProperty('_where')) {
|
|
189
|
+
// Se valida que en el Query Params "_where" no tenga consulta por el campo "an"
|
|
190
|
+
let match = queryStringParameters['_where'].match(/\b(an)\b/g)
|
|
191
|
+
if (match) {
|
|
192
|
+
queryStringParameters['_where'] = `(an=${accountName})`;
|
|
193
|
+
} else {
|
|
194
|
+
queryStringParameters['_where'] = `${queryStringParameters['_where']} AND (an=${accountName})`
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
queryStringParameters['_where'] = `(an=${accountName})`;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (method == 'search') {
|
|
201
|
+
requestUrl = setQueryParams(requestUrl, queryStringParameters);
|
|
202
|
+
|
|
203
|
+
// Se obtiene el parámetro de Headers
|
|
204
|
+
const { 'rest-range': restRange = 'resources=0-100' } = headers;
|
|
205
|
+
Logger.debug('Header REST-Range', restRange);
|
|
206
|
+
options.headers = { 'REST-Range': restRange };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (method == 'scroll') {
|
|
210
|
+
// En caso que a la petición se envíe el Query Param "_token", se establece solamente dicha propiedad en la petición a VTEX
|
|
211
|
+
if (queryStringParameters?.token) {
|
|
212
|
+
requestUrl = setQueryParams(requestUrl, { '_token': queryStringParameters.token });
|
|
213
|
+
} else {
|
|
214
|
+
requestUrl = setQueryParams(requestUrl, queryStringParameters);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Se ejecuta la consulta a VTEX
|
|
219
|
+
let resultQuery = await apiClient.fetch(requestUrl, options, false);
|
|
220
|
+
if (resultQuery) {
|
|
221
|
+
// Se extrae el código de respuesta, cuerpo y cabecera de la respuesta de la petición
|
|
222
|
+
const { status, data, headers } = resultQuery;
|
|
223
|
+
const {
|
|
224
|
+
'x-vtex-md-token': xVtexMdToken,
|
|
225
|
+
'rest-content-range': restContentRange
|
|
226
|
+
} = headers;
|
|
227
|
+
|
|
228
|
+
// Se retorna la respuesta proveniente de VTEX
|
|
229
|
+
return ApiResponse.response(status, data, {
|
|
230
|
+
...(xVtexMdToken && { 'X-VTEX-MD-TOKEN': xVtexMdToken }),
|
|
231
|
+
...(restContentRange && { 'REST-Content-Range': restContentRange })
|
|
232
|
+
});
|
|
233
|
+
} else {
|
|
234
|
+
return ApiResponse.response(400, 'Error en handleFindClients');
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Metodo que valida campos con un texto espesifico en su valor.
|
|
240
|
+
**/
|
|
241
|
+
const validDataClientFirstLevel = ({ data = null, ParametersClusterClient = null }) => {
|
|
242
|
+
if (data && ParametersClusterClient && typeof ParametersClusterClient == 'object') {
|
|
243
|
+
let valid = true;
|
|
244
|
+
for (let index in ParametersClusterClient) {
|
|
245
|
+
try {
|
|
246
|
+
if (data[index] && typeof ParametersClusterClient[index] == 'object' && !ParametersClusterClient[index].includes(data[index])) {
|
|
247
|
+
valid = false;
|
|
248
|
+
}
|
|
249
|
+
} catch (e) {
|
|
250
|
+
Logger.error(e);
|
|
251
|
+
valid = false;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return valid;
|
|
256
|
+
} else {
|
|
257
|
+
return true;
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Metodo para realizar validacion de campos requeridos de clientes
|
|
263
|
+
* @param item -- objeto del registro cliente enviado
|
|
264
|
+
* @param config -- objeto con la informacion de configuracion del account
|
|
265
|
+
**/
|
|
266
|
+
const validFieldsRequerid = ({
|
|
267
|
+
item = null,
|
|
268
|
+
config = null
|
|
269
|
+
}) => {
|
|
270
|
+
|
|
271
|
+
// Valicadion lista de parametros requeridos por la marca para insertar registro a entidad de datos
|
|
272
|
+
if (config?.ParametersRequiredClient && typeof config?.ParametersRequiredClient === 'object') {
|
|
273
|
+
for (let key in config?.ParametersRequiredClient) {
|
|
274
|
+
if (config?.ParametersRequiredClient[key] && config?.ParametersRequiredClient[key] != '') {
|
|
275
|
+
try {
|
|
276
|
+
let exitRegister = null;
|
|
277
|
+
eval(`exitRegister= ${config?.ParametersRequiredClient[key]}`);
|
|
278
|
+
|
|
279
|
+
if (!exitRegister || exitRegister == '') {
|
|
280
|
+
return {
|
|
281
|
+
valid: false,
|
|
282
|
+
error: `validate the following properties ${config?.ParametersRequiredClient[key]} is Required.`
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
} catch (error) {
|
|
286
|
+
Logger.error(error);
|
|
287
|
+
return {
|
|
288
|
+
valid: false,
|
|
289
|
+
error: "Error configurations ParametersRequiredClient"
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// validacion parametor requiridos index
|
|
297
|
+
if (config?.IndexClientRegister && typeof config?.IndexClientRegister === 'object' && config?.IndexClientRegister?.length > 0) {
|
|
298
|
+
for (let key in config?.IndexClientRegister) {
|
|
299
|
+
if (config?.IndexClientRegister[key] && config?.IndexClientRegister[key] != '') {
|
|
300
|
+
try {
|
|
301
|
+
let valueIndex = config?.IndexClientRegister[key], validIndex = false;
|
|
302
|
+
|
|
303
|
+
if (valueIndex === 'an') {
|
|
304
|
+
validIndex = true;
|
|
305
|
+
} else if (item[valueIndex] && item[valueIndex] != '' && typeof item[valueIndex] === 'string') {
|
|
306
|
+
validIndex = true;
|
|
307
|
+
} else if (item?.address[valueIndex] && item?.address[valueIndex] != '' && typeof item?.address[valueIndex] === 'string') {
|
|
308
|
+
validIndex = true;
|
|
309
|
+
} else if (item?.additional_information[valueIndex] && item?.additional_information[valueIndex] != '' && typeof item?.additional_information[valueIndex] === 'string') {
|
|
310
|
+
validIndex = true;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (validIndex === false) {
|
|
314
|
+
return {
|
|
315
|
+
valid: false,
|
|
316
|
+
error: `validate the following properties ${valueIndex} is requerid and type string for create index.`
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
} catch (error) {
|
|
321
|
+
Logger.error(error);
|
|
322
|
+
return {
|
|
323
|
+
valid: false,
|
|
324
|
+
error: "Error configurations ParametersRequeridClient"
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
} else {
|
|
330
|
+
return {
|
|
331
|
+
valid: false,
|
|
332
|
+
error: "Error configurations IndexClientRegister is requerid"
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
valid: true,
|
|
338
|
+
error: null
|
|
339
|
+
};
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
const setQueryParams = (url, queryParams, allowEmpty = true) => {
|
|
343
|
+
let queryText = ''
|
|
344
|
+
for (let key in queryParams) {
|
|
345
|
+
if (key && (allowEmpty || !queryParams[key])) {
|
|
346
|
+
if (queryText) {
|
|
347
|
+
queryText += '&'
|
|
348
|
+
}
|
|
349
|
+
queryText += `${key}=${queryParams[key]}`
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (queryText) {
|
|
354
|
+
queryText = '?' + queryText
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return url + queryText
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
module.exports = {
|
|
361
|
+
producer
|
|
362
|
+
};
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
const Logger = require("../../common/utils/logger");
|
|
2
|
+
const VtexApi = require("../../vtex/clients/VtexApi");
|
|
3
|
+
|
|
4
|
+
const DATA_ENTITY_CLIENT_ACRONYM = process.env.DATA_ENTITY_CLIENT_ACRONYM || 'CT';
|
|
5
|
+
|
|
6
|
+
const buildProductJson = (sku, status, quantity, type, priority) => ({
|
|
7
|
+
refId: sku.sku,
|
|
8
|
+
status,
|
|
9
|
+
quantity: quantity || sku.quantity,
|
|
10
|
+
type,
|
|
11
|
+
priority: priority || sku.priority
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const getClientUserId = async (vtexApi, pdv, an) => {
|
|
15
|
+
try {
|
|
16
|
+
const clientId = pdv;
|
|
17
|
+
const searchResult = await vtexApi.fetch(`/dataentities/${DATA_ENTITY_CLIENT_ACRONYM}/search?_fields=_all&id=${clientId}`, {});
|
|
18
|
+
if (searchResult?.status === 200 && searchResult.data?.length > 0) {
|
|
19
|
+
return searchResult.data[0]?.id;
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
} catch (error) {
|
|
23
|
+
Logger.error("Error getting client userId", error);
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const getCatalogProductStatus = async (vtexApi, skuId) => {
|
|
29
|
+
try {
|
|
30
|
+
const skuData = await vtexApi.fetch(`/catalog_system/pvt/sku/stockkeepingunitbyid/${skuId}`, {});
|
|
31
|
+
|
|
32
|
+
if (skuData?.status === 200 && skuData.data) {
|
|
33
|
+
const { IsActive, ProductId } = skuData.data;
|
|
34
|
+
|
|
35
|
+
if (!IsActive) return 'inactive';
|
|
36
|
+
|
|
37
|
+
const productData = await vtexApi.fetch(`/catalog_system/pvt/products/productget/${ProductId}`, {
|
|
38
|
+
validateStatus: () => true
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (productData?.status === 200 && productData.data) {
|
|
42
|
+
const { IsVisible, IsActive: productActive } = productData.data;
|
|
43
|
+
|
|
44
|
+
if (!productActive) return 'inactive';
|
|
45
|
+
if (!IsVisible) return 'not_visible';
|
|
46
|
+
return 'active';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return 'invalid';
|
|
51
|
+
} catch (error) {
|
|
52
|
+
Logger.error("Error getting catalog product status", error);
|
|
53
|
+
return 'invalid';
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const saveSuggestedProducts = async (vtexApi, userId, productsData, an, entityProductSuggested) => {
|
|
58
|
+
try {
|
|
59
|
+
const orderDate = new Date().toISOString();
|
|
60
|
+
const data = {
|
|
61
|
+
id: `${userId}_${Date.now()}`,
|
|
62
|
+
userId,
|
|
63
|
+
orderDate,
|
|
64
|
+
type: 'suggested',
|
|
65
|
+
productsRegular: productsData?.regular,
|
|
66
|
+
productsIncremental: productsData?.incremental,
|
|
67
|
+
an
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
await vtexApi.fetch(`/dataentities/${entityProductSuggested}/documents`, {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
data,
|
|
73
|
+
headers: {
|
|
74
|
+
'authorization': 'Basic Og=='
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
Logger.log("Suggested products saved successfully", { userId, orderDate });
|
|
79
|
+
} catch (error) {
|
|
80
|
+
Logger.error("Error saving suggested products", error);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const saveOriginalDataToClient = async (vtexApi, pdv, originalData, an) => {
|
|
85
|
+
try {
|
|
86
|
+
const clientId = `${pdv}${an}dist1`;
|
|
87
|
+
const updateData = {
|
|
88
|
+
productsRegular: originalData.productsRegular || [],
|
|
89
|
+
productsIncremental: originalData.productsIncremental || [],
|
|
90
|
+
lastSuggestedProductsUpdate: new Date().toISOString()
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
await vtexApi.fetch(`/dataentities/${DATA_ENTITY_CLIENT_ACRONYM}/documents/${clientId}`, {
|
|
94
|
+
method: 'PUT',
|
|
95
|
+
data: updateData,
|
|
96
|
+
headers: {
|
|
97
|
+
'authorization': 'Basic Og=='
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
Logger.log("Original data saved to client", { pdv });
|
|
102
|
+
} catch (error) {
|
|
103
|
+
Logger.error("Error saving original data to client", error);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const consumer = async (event) => {
|
|
108
|
+
try {
|
|
109
|
+
const records = event.Records || [];
|
|
110
|
+
|
|
111
|
+
for (const record of records) {
|
|
112
|
+
const messageBody = JSON.parse(record.body);
|
|
113
|
+
const {
|
|
114
|
+
an,
|
|
115
|
+
parentAccount,
|
|
116
|
+
key,
|
|
117
|
+
token,
|
|
118
|
+
pdv,
|
|
119
|
+
productsRegular,
|
|
120
|
+
productsIncremental,
|
|
121
|
+
originalData,
|
|
122
|
+
nameEntityProductSuggested
|
|
123
|
+
} = messageBody;
|
|
124
|
+
|
|
125
|
+
Logger.log("Processing suggested products for client", { pdv, an });
|
|
126
|
+
|
|
127
|
+
const vtexApi = new VtexApi(parentAccount, key, token);
|
|
128
|
+
|
|
129
|
+
const userId = await getClientUserId(vtexApi, pdv, an);
|
|
130
|
+
console.log("Fetched userId:", userId);
|
|
131
|
+
if (!userId) {
|
|
132
|
+
Logger.error("Client userId not found", { pdv, an });
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const regularProducts = [];
|
|
137
|
+
const incrementalProducts = [];
|
|
138
|
+
|
|
139
|
+
for (const sku of productsRegular) {
|
|
140
|
+
const status = await getCatalogProductStatus(vtexApi, sku.sku);
|
|
141
|
+
regularProducts.push(buildProductJson(sku, status, sku.quantity, 'regular', sku.priority));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
for (const sku of productsIncremental) {
|
|
145
|
+
const status = await getCatalogProductStatus(vtexApi, sku.sku);
|
|
146
|
+
incrementalProducts.push(buildProductJson(sku, status, sku.quantity, 'incremental', sku.priority));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
await saveSuggestedProducts(vtexApi, userId, {
|
|
150
|
+
regular: regularProducts,
|
|
151
|
+
incremental: incrementalProducts
|
|
152
|
+
}, an, nameEntityProductSuggested);
|
|
153
|
+
|
|
154
|
+
await saveOriginalDataToClient(vtexApi, pdv, originalData, an);
|
|
155
|
+
|
|
156
|
+
Logger.log("Suggested products processed successfully", { pdv, userId });
|
|
157
|
+
}
|
|
158
|
+
} catch (error) {
|
|
159
|
+
Logger.error("Error in suggested products consumer", error);
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
module.exports = {
|
|
165
|
+
consumer
|
|
166
|
+
};
|