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.
Files changed (129) hide show
  1. package/README.md +130 -0
  2. package/index.js +350 -0
  3. package/package.json +52 -0
  4. package/src/auth/handler.js +3 -0
  5. package/src/common/MondelezCastOrder.js +449 -0
  6. package/src/common/utils/AuthSecurity.js +46 -0
  7. package/src/common/utils/account-error-handler.js +279 -0
  8. package/src/common/utils/account-error-helper.js +231 -0
  9. package/src/common/utils/account-properties-handler.js +355 -0
  10. package/src/common/utils/api-response.js +62 -0
  11. package/src/common/utils/aws-services.js +186 -0
  12. package/src/common/utils/constants/account-error-codes.json +801 -0
  13. package/src/common/utils/constants.js +37 -0
  14. package/src/common/utils/convert/MondelezClientsItemsCast.js +52 -0
  15. package/src/common/utils/convert/MondelezInventoryItemsCast.js +15 -0
  16. package/src/common/utils/convert/MondelezOrderStatusCast.js +34 -0
  17. package/src/common/utils/convert/MondelezPricesItemsCast.js +37 -0
  18. package/src/common/utils/cron-ftp-get.js +143 -0
  19. package/src/common/utils/data-tables-helper.js +213 -0
  20. package/src/common/utils/date-range-calculator.js +113 -0
  21. package/src/common/utils/delay.js +17 -0
  22. package/src/common/utils/ftp-sftp.js +320 -0
  23. package/src/common/utils/logger.js +126 -0
  24. package/src/common/utils/nodemailerLib.js +61 -0
  25. package/src/common/utils/product-unit-converter.js +168 -0
  26. package/src/common/utils/schemas-utils.js +101 -0
  27. package/src/common/utils/seller-email-sharing-service.js +441 -0
  28. package/src/common/utils/sftp-utils.js +202 -0
  29. package/src/common/utils/status.js +15 -0
  30. package/src/common/utils/util.js +236 -0
  31. package/src/common/utils/validate-state-order.js +35 -0
  32. package/src/common/utils/validateProviders.js +67 -0
  33. package/src/common/utils/validation-data.js +45 -0
  34. package/src/common/utils/vtex/save-hooks.js +65 -0
  35. package/src/common/utils/vtex/save-schemas.js +65 -0
  36. package/src/common/utils/vtex-hook-handler.js +71 -0
  37. package/src/common/validation/AccountCoordinatesValidation.js +350 -0
  38. package/src/common/validation/GeneralErrorValidation.js +11 -0
  39. package/src/common/validation/MainErrorValidation.js +8 -0
  40. package/src/entities/account.js +639 -0
  41. package/src/entities/clients.js +104 -0
  42. package/src/entities/controlprice.js +196 -0
  43. package/src/entities/controlstock.js +206 -0
  44. package/src/entities/cron.js +77 -0
  45. package/src/entities/cronjob.js +71 -0
  46. package/src/entities/orders.js +195 -0
  47. package/src/entities/sftp-inbound.js +88 -0
  48. package/src/entities/sku.js +220 -0
  49. package/src/entities/taxpromotion.js +249 -0
  50. package/src/functions/account/account-get.js +262 -0
  51. package/src/functions/account/account-handler.js +299 -0
  52. package/src/functions/account/clients.js +10 -0
  53. package/src/functions/account/index.js +208 -0
  54. package/src/functions/actions/save-promotions-order-history.js +324 -0
  55. package/src/functions/affiliates/affiliates-hook-consumer.js +87 -0
  56. package/src/functions/affiliates/affiliates-hook-producer.js +45 -0
  57. package/src/functions/clients/clients-audience.js +62 -0
  58. package/src/functions/clients/clients-consumer.js +648 -0
  59. package/src/functions/clients/clients-producer.js +362 -0
  60. package/src/functions/clients/clients-suggested-product-consumer.js +166 -0
  61. package/src/functions/clients/helpers/suggested-product-mdlz.js +233 -0
  62. package/src/functions/clients_peru/email.html +129 -0
  63. package/src/functions/clients_peru/splitfile.js +357 -0
  64. package/src/functions/clients_peru/updateClients.js +1334 -0
  65. package/src/functions/clients_peru/utils.js +243 -0
  66. package/src/functions/cronjobs/cron-jobs-manager.js +40 -0
  67. package/src/functions/cronjobs/cron-jobs.js +171 -0
  68. package/src/functions/crons/cron.js +39 -0
  69. package/src/functions/distributors/distributor-handler.js +81 -0
  70. package/src/functions/distributors/distributor.js +535 -0
  71. package/src/functions/distributors/index.js +60 -0
  72. package/src/functions/financialpolicy/assign-financialpolicy.js +111 -0
  73. package/src/functions/financialpolicy/get-financialpolicy.js +91 -0
  74. package/src/functions/financialpolicy/index.js +28 -0
  75. package/src/functions/inventory/catalog-sync-consumer.js +17 -0
  76. package/src/functions/inventory/catalog-sync-handler.js +311 -0
  77. package/src/functions/inventory/inventory-consumer.js +119 -0
  78. package/src/functions/inventory/inventory-producer.js +197 -0
  79. package/src/functions/multiPresentation/multipre-queue.js +155 -0
  80. package/src/functions/multiPresentation/multipres.js +459 -0
  81. package/src/functions/nodeflow/index.js +83 -0
  82. package/src/functions/nodeflow/nodeflow-cron.js +200 -0
  83. package/src/functions/nodeflow/nodeflow-pub.js +203 -0
  84. package/src/functions/nodeflow/nodeflow-pvt.js +266 -0
  85. package/src/functions/notifications/download-leads-handler.js +67 -0
  86. package/src/functions/notifications/new-leads-notification-consumer.js +17 -0
  87. package/src/functions/notifications/new-leads-notification-handler.js +359 -0
  88. package/src/functions/notifications/order-status-notification-handler.js +482 -0
  89. package/src/functions/notifications/promotion-notification-handler.js +193 -0
  90. package/src/functions/orders/index.js +32 -0
  91. package/src/functions/orders/orders-cancel-handler.js +74 -0
  92. package/src/functions/orders/orders-handler.js +280 -0
  93. package/src/functions/orders/orders-hook-consumer.js +137 -0
  94. package/src/functions/orders/orders-hook-producer.js +170 -0
  95. package/src/functions/orders/orders-notifications-handler.js +137 -0
  96. package/src/functions/orders/orders-status-consumer.js +461 -0
  97. package/src/functions/orders/orders-status-producer.js +443 -0
  98. package/src/functions/prices/index.js +75 -0
  99. package/src/functions/prices/prices-consumer.js +236 -0
  100. package/src/functions/prices/prices-producer.js +323 -0
  101. package/src/functions/prices/promotion-and-tax.js +1284 -0
  102. package/src/functions/routesflow/assign-routeflow-queue.js +77 -0
  103. package/src/functions/schemas/vtex/handle-schemas.js +102 -0
  104. package/src/functions/security/process_gas.js +221 -0
  105. package/src/functions/security/security-handler.js +950 -0
  106. package/src/functions/sftp/sftp-consumer.js +453 -0
  107. package/src/functions/sftpIntegrations/processes/redirectServices.js +184 -0
  108. package/src/functions/sftpIntegrations/processes/validateFileSchema.js +226 -0
  109. package/src/functions/sftpIntegrations/schemas/credential-schema.js +123 -0
  110. package/src/functions/sftpIntegrations/schemas/record-schema.js +131 -0
  111. package/src/functions/sftpIntegrations/schemas/sftp_required_fields.json +3 -0
  112. package/src/functions/sftpIntegrations/sftp-config-producer.js +112 -0
  113. package/src/functions/sftpIntegrations/sftp-consumer.js +700 -0
  114. package/src/functions/sftpIntegrations/test/validateFile.test.js +122 -0
  115. package/src/functions/sftpIntegrations/utils/connect-dynamo.js +29 -0
  116. package/src/functions/sftpIntegrations/utils/split-data.js +25 -0
  117. package/src/functions/utils/index.js +130 -0
  118. package/src/functions/vtex/vtex-helpers.js +694 -0
  119. package/src/integrations/accountErrors/AccountErrorManager.js +437 -0
  120. package/src/integrations/audience/Audience.js +70 -0
  121. package/src/integrations/financialPolicy/FinancialPolicyApi.js +377 -0
  122. package/src/integrations/index.js +0 -0
  123. package/src/integrations/mobilvendor/MobilvendorApi.js +405 -0
  124. package/src/integrations/productmultipresentation/ProductMultiPresentation.js +200 -0
  125. package/src/mdlz/auth/SecretManagerApi.js +77 -0
  126. package/src/mdlz/client/MdlzApi.js +70 -0
  127. package/src/vtex/clients/ProvidersApi.js +51 -0
  128. package/src/vtex/clients/VtexApi.js +511 -0
  129. package/src/vtex/models/VtexOrder.js +87 -0
@@ -0,0 +1,694 @@
1
+ const VtexApi = require("../../vtex/clients/VtexApi");
2
+ const ApiResponse = require("../../common/utils/api-response");
3
+ const AccountData = require("../../entities/account");
4
+ const ClientData = require("../../entities/clients");
5
+ const Logger = require("../../common/utils/logger");
6
+
7
+ /**
8
+ * @param {import("aws-lambda").APIGatewayProxyEvent} event
9
+ * @returns
10
+ */
11
+ const list_products_vtex = async (event) => {
12
+ const clientId = event?.requestContext?.authorizer?.claims?.client_id;
13
+ let statusCode = 200;
14
+ let responseService = [];
15
+
16
+ const anRequest = event?.queryStringParameters?.an ?? null;
17
+ if(anRequest){
18
+ const validAccount = await ClientData.validateAccount(clientId, anRequest);
19
+ if (!validAccount) {
20
+ Logger.error("Data INVALID: ", validAccount);
21
+ return ApiResponse.response(404, "Account not found");
22
+ }
23
+ }
24
+
25
+ const listAccounts = anRequest ? null : await ClientData.getClient(clientId);
26
+ const an = listAccounts ? listAccounts?.AccountNames?.values[0] : anRequest;
27
+ if (!an) {
28
+ Logger.error("Error service: ", "AccountName not found");
29
+ return ApiResponse.response(statusCode, []);
30
+ }
31
+ const configAccount = await AccountData.getAccountDataByAccountName(an);
32
+
33
+ if (!configAccount) {
34
+ Logger.error("Error service: ", "Account not found");
35
+ return ApiResponse.response(statusCode, []);
36
+ }
37
+ const configAccountParent = configAccount?.AccountName === configAccount?.ParentAccountName ? configAccount : await AccountData.getAccountDataByAccountName(configAccount?.ParentAccountName);
38
+
39
+ if (!configAccountParent) {
40
+ Logger.error("Error service: ", "Parent Account not found");
41
+ return ApiResponse.response(statusCode, []);
42
+ }
43
+
44
+ try {
45
+ let productAll= event?.queryStringParameters?.ProductsAll ?? null;
46
+
47
+ if(typeof productAll === "string"){
48
+ productAll= productAll.toLowerCase();
49
+ }
50
+
51
+ const apiClient = new VtexApi(configAccountParent?.AccountName, configAccountParent?.Credentials?.key, configAccountParent?.Credentials?.token);
52
+ const isActive= event?.queryStringParameters?.isActive ?? null;
53
+ const isVisible= event?.queryStringParameters?.isVisible ?? null;
54
+ const sc= event?.queryStringParameters?.sc ?? "1";
55
+ const lengthData= event?.queryStringParameters?.rows ?? 2000;
56
+
57
+ if(productAll && (productAll===true || productAll==='true')){
58
+ responseService= await apiClient.getProductsAll(isActive, isVisible, sc, lengthData);
59
+ }else{
60
+ responseService= await apiClient.getProducts(event, isActive, isVisible, sc, lengthData);
61
+ }
62
+ } catch (error) {
63
+ Logger.error("Error service: ", error);
64
+ statusCode = 500;
65
+ }
66
+
67
+ return ApiResponse.response(statusCode, responseService);
68
+ };
69
+
70
+ /**
71
+ * @param {import("aws-lambda").APIGatewayProxyEvent} event
72
+ * @returns
73
+ */
74
+ const list_categories_vtex = async (event) => {
75
+ const clientId = event?.requestContext?.authorizer?.claims?.client_id;
76
+ const anRequest = event?.queryStringParameters?.an ?? null;
77
+ if(anRequest){
78
+ const validAccount = await ClientData.validateAccount(clientId, anRequest);
79
+ if (!validAccount) {
80
+ Logger.error("Data INVALID: ", validAccount);
81
+ return ApiResponse.response(404, "Account not found");
82
+ }
83
+ }
84
+
85
+ const listAccounts = anRequest ? null : await ClientData.getClient(clientId);
86
+ const categoryLevels = event?.pathParameters?.categoryLevels;
87
+ let statusCode = 200;
88
+ let responseService = [];
89
+ const an = listAccounts ? listAccounts?.AccountNames?.values[0] : anRequest;
90
+ if (!an) {
91
+ Logger.error("Error service: ", "AccountName not found");
92
+ return ApiResponse.response(statusCode, []);
93
+ }
94
+ const configAccount = await AccountData.getAccountDataByAccountName(an);
95
+
96
+ if (!configAccount) {
97
+ Logger.error("Error service: ", "Account not found");
98
+ return ApiResponse.response(statusCode, []);
99
+ }
100
+ const configAccountParent = configAccount?.AccountName === configAccount?.ParentAccountName ? configAccount : await AccountData.getAccountDataByAccountName(configAccount?.ParentAccountName);
101
+
102
+ if (!configAccountParent) {
103
+ Logger.error("Error service: ", "Parent Account not found");
104
+ return ApiResponse.response(statusCode, []);
105
+ }
106
+
107
+ try {
108
+ const apiClient = new VtexApi(configAccountParent?.AccountName, configAccountParent?.Credentials?.key, configAccountParent?.Credentials?.token);
109
+ const response = await apiClient.fetch(`/catalog_system/pub/category/tree/${categoryLevels}`, {
110
+ method: "GET",
111
+ params: event?.queryStringParameters
112
+ });
113
+
114
+ if (response?.data) {
115
+ responseService = response?.data ?? [];
116
+ }
117
+ } catch (error) {
118
+ Logger.error("Error service: ", error);
119
+ statusCode = 500;
120
+ }
121
+
122
+ return ApiResponse.response(statusCode, responseService);
123
+ };
124
+
125
+ /**
126
+ * @param {import("aws-lambda").APIGatewayProxyEvent} event
127
+ * @returns
128
+ */
129
+ const list_brands_vtex = async (event) => {
130
+ const clientId = event?.requestContext?.authorizer?.claims?.client_id;
131
+ const anRequest = event?.queryStringParameters?.an ?? null;
132
+ if(anRequest){
133
+ const validAccount = await ClientData.validateAccount(clientId, anRequest);
134
+ if (!validAccount) {
135
+ Logger.error("Data INVALID: ", validAccount);
136
+ return ApiResponse.response(404, "Account not found");
137
+ }
138
+ }
139
+
140
+ const listAccounts = anRequest ? null : await ClientData.getClient(clientId);
141
+ let statusCode = 200;
142
+ let responseService = [];
143
+ const an = listAccounts ? listAccounts?.AccountNames?.values[0] : anRequest;
144
+ if (!an) {
145
+ Logger.error("Error service: ", "AccountName not found");
146
+ return ApiResponse.response(statusCode, []);
147
+ }
148
+ const configAccount = await AccountData.getAccountDataByAccountName(an);
149
+
150
+ if (!configAccount) {
151
+ Logger.error("Error service: ", "Account not found");
152
+ return ApiResponse.response(statusCode, []);
153
+ }
154
+ const configAccountParent = configAccount?.AccountName === configAccount?.ParentAccountName ? configAccount : await AccountData.getAccountDataByAccountName(configAccount?.ParentAccountName);
155
+
156
+ if (!configAccountParent) {
157
+ Logger.error("Error service: ", "Parent Account not found");
158
+ return ApiResponse.response(statusCode, []);
159
+ }
160
+
161
+ try {
162
+ const apiClient = new VtexApi(configAccountParent?.AccountName, configAccountParent?.Credentials?.key, configAccountParent?.Credentials?.token);
163
+ const response = await apiClient.fetch(`/catalog_system/pub/brand/list`, {
164
+ method: "GET",
165
+ params: event?.queryStringParameters
166
+ });
167
+
168
+ if (response?.data) {
169
+ responseService = response?.data ?? [];
170
+ }
171
+ } catch (error) {
172
+ Logger.error("Error service: ", error);
173
+ statusCode = 500;
174
+ }
175
+
176
+ return ApiResponse.response(statusCode, responseService);
177
+ };
178
+
179
+ /**
180
+ * Retrieves an order form by its unique identifier
181
+ * @param {string} orderFormId - Unique identifier of the order form
182
+ * @param {string} accountName - VTEX account name
183
+ * @param {string} key - API authentication key
184
+ * @param {string} token - API authentication token
185
+ * @returns {Promise<Object|null>} Order form details or null if not found
186
+ * @throws {Error} Network or API connection errors
187
+ * @description Fetches complete order form details from VTEX using the provided order form ID
188
+ * @example
189
+ * const orderForm = await getOrderFormById('123456', 'myAccount', 'apiKey', 'apiToken');
190
+ * // Returns order form object or null
191
+ */
192
+ async function getOrderFormById(orderFormId, accountName, key, token) {
193
+ try {
194
+ const vtexApi = new VtexApi(accountName, key, token);
195
+ const responseOrderForm = await vtexApi.fetch(`/checkout/pub/orderForm/${orderFormId}?refreshOutdatedData=true`, { method: "GET" });
196
+
197
+ if (responseOrderForm.status !== 200){
198
+ Logger.error("Error getOrderFormById: ", responseOrderForm);
199
+ ApiResponse.response(404, { approved: false, message: "orderForm is not found" });
200
+ }
201
+
202
+ const { data } = responseOrderForm;
203
+
204
+ return data;
205
+ } catch (error) {
206
+ Logger.error("Error getOrderFormById: ", error);
207
+ return null;
208
+ }
209
+ };
210
+
211
+ /**
212
+ * Retrieves client information by email
213
+ * @param {string} email - Client's email address
214
+ * @param {string} accountName - VTEX account name
215
+ * @param {string} key - API authentication key
216
+ * @param {string} token - API authentication token
217
+ * @param {string} acronymClientVtex - Client data entity acronym in VTEX
218
+ * @returns {Promise<Object|null>} Client details or null if not found
219
+ * @throws {Error} Network or API connection errors
220
+ * @description Extracts client ID from email and fetches client details from VTEX master data
221
+ * @example
222
+ * const clientDetails = await getClientById('user@example.com', 'myAccount', 'apiKey', 'apiToken', 'CL');
223
+ * // Returns client object or null
224
+ */
225
+ async function getClientById(email, accountName, key, token, acronymClientVtex) {
226
+ try {
227
+ const vtexApi = new VtexApi(accountName, key, token);
228
+ const clientId = email?.split("+")[1]?.split("@")[0];
229
+ const responseMasterDataCT = await vtexApi.fetch(
230
+ `/dataentities/${acronymClientVtex}/search?_fields=_all&id=${clientId}`, { method: "GET" }
231
+ );
232
+
233
+ if (responseMasterDataCT.status >= 200 && responseMasterDataCT.status < 300) {
234
+ return responseMasterDataCT.data[0];
235
+ } else {
236
+ Logger.error("Error getClientById: ", responseMasterDataCT);
237
+ return null;
238
+ }
239
+ } catch (error) {
240
+ Logger.error(error);
241
+ return null;
242
+ }
243
+ }
244
+
245
+ /**
246
+ * Deletes custom data from an order form
247
+ * @param {string} orderFormId - Unique identifier of the order form
248
+ * @param {string} accountName - VTEX account name
249
+ * @param {string} key - API authentication key
250
+ * @param {string} token - API authentication token
251
+ * @param {Object} configVtex - VTEX configuration object
252
+ * @param {Object} attachmentCredit - Credit attachment configuration
253
+ * @param {Object} customData - Custom data to be deleted
254
+ * @returns {Promise<boolean>} Indicates successful deletion
255
+ * @throws {Error} Deletion process errors
256
+ * @description Removes specific custom data and credit attachments from an order form
257
+ * @example
258
+ * const deleted = await deleteCustomData('123456', 'myAccount', 'apiKey', 'apiToken', configVtex, attachmentCredit, customData);
259
+ * // Returns true if deletion is successful
260
+ */
261
+ async function deleteCustomData(orderFormId, accountName, key, token, configVtex, attachmentCredit, customData) {
262
+ try {
263
+ if (!customData) {
264
+ return true;
265
+ }
266
+ const vtexApi = new VtexApi(accountName, key, token);
267
+ const customApps = customData?.customApps ?? [];
268
+ const financialPolicy = customApps?.find(app => app.id === configVtex.id);
269
+ const fields = financialPolicy?.fields;
270
+
271
+ if (attachmentCredit && attachmentCredit?.name && attachmentCredit?.value) {
272
+ await vtexApi.fetchPub(`/checkout/pub/orderForm/${orderFormId}/attachments/${attachmentCredit?.name}`, { method: "POST" }, { value: null });
273
+ }
274
+
275
+ for (const field in fields) {
276
+ await vtexApi.fetchPub(`/checkout/pub/orderForm/${orderFormId}/customData/${configVtex.id}/${field}`, { method: "DELETE" });
277
+ }
278
+
279
+ return true;
280
+ } catch (error) {
281
+ Logger.error(error);
282
+ return ApiResponse.response(401, { approved: false, message: "Error deleting customData orderForm" });
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Updates custom data in an order form
288
+ * @param {string} orderFormId - Unique identifier of the order form
289
+ * @param {string} accountName - VTEX account name
290
+ * @param {string} key - API authentication key
291
+ * @param {string} token - API authentication token
292
+ * @param {string} idConfigVtex - VTEX configuration ID
293
+ * @param {Object} customData - Custom data to be updated
294
+ * @param {Object} attachmentCredit - Credit attachment configuration
295
+ * @returns {Promise<Object|Error>} Updated order form data or error response
296
+ * @throws {Error} Update process errors
297
+ * @description Updates custom data and credit attachments in an order form
298
+ * @example
299
+ * const updatedData = await updateOrderFormCustomData('123456', 'myAccount', 'apiKey', 'apiToken', 'configId', customData, attachmentCredit);
300
+ * // Returns updated data or error response
301
+ */
302
+ async function updateOrderFormCustomData(orderFormId, accountName, key, token, idConfigVtex, customData, attachmentCredit) {
303
+ try {
304
+ const vtexApi = new VtexApi(accountName, key, token);
305
+ const response = await vtexApi.fetchPub(
306
+ `/checkout/pub/orderForm/${orderFormId}/customData/${idConfigVtex}`,
307
+ { method: "PUT" },
308
+ customData
309
+ );
310
+
311
+ if (attachmentCredit && attachmentCredit?.name && attachmentCredit?.value) {
312
+ await vtexApi.fetchPub(`/checkout/pub/orderForm/${orderFormId}/attachments/${attachmentCredit?.name}`, { method: "POST" }, attachmentCredit?.value);
313
+ }
314
+
315
+ if (response.status !== 200){
316
+ Logger.error("Error updateOrderFormCustomData: ", response);
317
+ return ApiResponse.response(401, { approved: false, message: "Error updating customData orderForm" });
318
+ }
319
+
320
+ return response.data;
321
+ } catch (error) {
322
+ Logger.error(error);
323
+ return ApiResponse.response(401, { approved: false, message: "Error updating customData orderForm" });
324
+ }
325
+ }
326
+
327
+ /**
328
+ * Cleans custom data in an order form by resetting to default values
329
+ * @param {string} orderFormId - Unique identifier of the order form
330
+ * @param {string} accountName - VTEX account name
331
+ * @param {string} key - API authentication key
332
+ * @param {string} token - API authentication token
333
+ * @param {string} idConfigVtex - VTEX configuration ID for custom data
334
+ * @returns {Promise<Object>} Updated order form data or error response
335
+ * @throws {Error} API connection or update errors
336
+ * @description Resets custom data fields to default "clean" state
337
+ * @example
338
+ * const cleanedData = await cleanOrderFormCustomData('123456', 'myAccount', 'apiKey', 'apiToken', 'configId');
339
+ * // Returns cleaned order form data
340
+ */
341
+ async function cleanOrderFormCustomData(orderFormId, accountName, key, token, idConfigVtex) {
342
+ try {
343
+ const vtexApi = new VtexApi(accountName, key, token,);
344
+ const customData = {
345
+ "approved": "false",
346
+ "withCredit": "false",
347
+ "paymentTerm": "-",
348
+ "maximumCreditAmount": "-",
349
+ "paymentMethodCode": "-",
350
+ "creditDays": "-",
351
+ "paymentMethodName": "-"
352
+ };
353
+ const response = await vtexApi.fetchPub(
354
+ `/checkout/pub/orderForm/${orderFormId}/customData/${idConfigVtex}`,
355
+ { method: "PUT" },
356
+ customData
357
+ );
358
+
359
+ if (response.status !== 200){
360
+ Logger.error("Error cleanOrderFormCustomData: ", response);
361
+ return ApiResponse.response(401, { approved: false, message: "Error deleting customData orderForm" });
362
+ }
363
+
364
+ return response.data;
365
+ } catch (error) {
366
+ Logger.error(error);
367
+ return ApiResponse.response(401, { approved: false, message: "Error cleaning customData orderForm" });
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Formats and validates financial policy service response
373
+ * @param {Object} rawResponse - Original service response
374
+ * @param {boolean} rawResponse.approved - Approval status
375
+ * @param {boolean} rawResponse.withCredit - Credit eligibility
376
+ * @param {number|string} rawResponse.creditDays - Credit days
377
+ * @param {number|string} rawResponse.maximumCreditAmount - Maximum credit amount
378
+ * @param {string} [rawResponse.paymentMethodCode] - Payment method code
379
+ * @param {string} [rawResponse.paymentMethodName] - Payment method name
380
+ * @returns {Object} Formatted response with standardized types
381
+ * @description Transforms raw financial policy response to a consistent format
382
+ * @example
383
+ * const formatted = formatFinancialPolicyResponse({
384
+ * approved: true,
385
+ * withCredit: true,
386
+ * creditDays: 30,
387
+ * maximumCreditAmount: 10000
388
+ * });
389
+ * // Returns standardized response object
390
+ */
391
+ function formatFinancialPolicyResponse(rawResponse) {
392
+ try {
393
+ const formattedResponse = {
394
+ approved: Boolean(rawResponse.approved),
395
+ withCredit: Boolean(rawResponse.withCredit),
396
+ paymentTerm: Number(rawResponse.creditDays) || 0,
397
+ maximumCreditAmount: parseFloat(rawResponse.maximumCreditAmount) || 0,
398
+ paymentMethodCode: rawResponse.withCredit ? String(rawResponse.paymentMethodCode || 'CONTADO') : 'CONTADO',
399
+ creditDays: Number(rawResponse.creditDays) || 0,
400
+ paymentMethodName: rawResponse.withCredit ? String(rawResponse.paymentMethodName || 'CONTADO') : 'CONTADO'
401
+ };
402
+
403
+ return formattedResponse;
404
+ } catch (error) {
405
+ return getDefaultResponse();
406
+ }
407
+ }
408
+
409
+ /**
410
+ * Collection of base data transformation functions
411
+ * @type {Object}
412
+ * @description Utility functions for converting values between types
413
+ */
414
+ const baseTransforms = {
415
+ toString: value => String(value || ''),
416
+ toNumber: value => Number(value || 0),
417
+ toBoolean: value => Boolean(value),
418
+ toFloat: value => parseFloat(value || 0),
419
+ toInt: value => parseInt(value || 0, 10),
420
+ toOrderValue: value => Number(value || 0) / 100
421
+ };
422
+
423
+ /**
424
+ * Applies a specified transformation to a value
425
+ * @param {*} value - Input value to transform
426
+ * @param {string} transformType - Type of transformation to apply
427
+ * @returns {*} Transformed value
428
+ * @description Applies a predefined transformation if the type exists
429
+ * @example
430
+ * applyTransform('123', 'toNumber'); // Returns 123
431
+ * applyTransform('true', 'toBoolean'); // Returns true
432
+ */
433
+ function applyTransform(value, transformType) {
434
+ if (!transformType || !baseTransforms[transformType]) return value;
435
+ return baseTransforms[transformType](value);
436
+ }
437
+
438
+ /**
439
+ * Updates the schema for a VTEX data entity
440
+ * @param {string} accountName - VTEX account name
441
+ * @param {string} entityName - Name of the data entity
442
+ * @param {Object} schemaData - Schema configuration object
443
+ * @returns {Promise<Object>} Updated schema details
444
+ */
445
+ async function updateDataEntitySchema(accountName, key, token, entityName, schemaData) {
446
+ try {
447
+ const vtexApi = new VtexApi(accountName, key, token);
448
+ const response = await vtexApi.fetch(
449
+ `/dataentities/${entityName}/schemas/default`,
450
+ {
451
+ method: "PUT",
452
+ headers: {
453
+ 'Content-Type': 'application/json',
454
+ 'Accept': 'application/vnd.vtex.ds.v2+json'
455
+ },
456
+ body: schemaData
457
+ }
458
+ );
459
+
460
+ return response.data;
461
+ } catch (error) {
462
+ Logger.error(`Error updating schema for ${entityName}:`, error);
463
+ throw error;
464
+ }
465
+ }
466
+
467
+ /**
468
+ * Creates a document in a VTEX data entity
469
+ * @param {string} accountName - VTEX account name
470
+ * @param {string} entityName - Name of the data entity
471
+ * @param {Object} documentData - Document data to create
472
+ * @returns {Promise<Object>} Created document details
473
+ */
474
+ async function createDataEntityDocument(vtexApi, config, fileData) {
475
+ const documentData = {
476
+ fileName: fileData.fileName,
477
+ fileContent: fileData.fileContent,
478
+ isPublic: true,
479
+ contentType: 'text/csv'
480
+ };
481
+
482
+ try {
483
+ const response = await vtexApi.fetch(
484
+ `/dataentities/${config.fileUploadEntity}/documents`,
485
+ {
486
+ method: 'POST',
487
+ data: documentData,
488
+ headers: {
489
+ 'Cache-Control': 'no-cache',
490
+ 'Accept': 'application/vnd.vtex.ds.v10+json',
491
+ 'Content-Type': 'application/json'
492
+ }
493
+ }
494
+ );
495
+
496
+ if (response.status !== 201) {
497
+ Logger.error(`Failed to create document: ${response.statusText}`);
498
+ throw new Error(`Failed to create document: ${response.statusText}`);
499
+ }
500
+
501
+ // Generar URL pública
502
+ const publicUrl = `https://${config.AccountName}.vtexcommercestable.com.br/api/dataentities/${config.fileUploadEntity}/documents/${response.data.DocumentId}/attachments/${fileData.fileName}`;
503
+
504
+ return {
505
+ ...response.data,
506
+ publicUrl
507
+ };
508
+ } catch (error) {
509
+ Logger.error(`Error creating document in ${config.fileUploadEntity}:`, error);
510
+ throw error;
511
+ }
512
+ }
513
+
514
+ /**
515
+ * Updates a specific document in a VTEX data entity
516
+ * @param {string} accountName - VTEX account name
517
+ * @param {string} entityName - Name of the data entity
518
+ * @param {string} documentId - ID of the document to update
519
+ * @param {Object} updateData - Data to update
520
+ * @returns {Promise<Object>} Updated document details
521
+ */
522
+ async function updateDataEntityDocument(accountName, key, token, entityName, documentId, updateData) {
523
+ try {
524
+ const vtexApi = new VtexApi(accountName, key, token);
525
+ const response = await vtexApi.fetch(
526
+ `/dataentities/${entityName}/documents/${documentId}`,
527
+ {
528
+ method: "PATCH",
529
+ headers: {
530
+ 'Content-Type': 'application/json',
531
+ 'Accept': 'application/vnd.vtex.ds.v2+json'
532
+ },
533
+ body: updateData
534
+ }
535
+ );
536
+
537
+ return response.data;
538
+ } catch (error) {
539
+ Logger.error(`Error updating document in ${entityName}:`, error);
540
+ throw error;
541
+ }
542
+ }
543
+
544
+ /**
545
+ * Formatea y valida campos para la entidad de leads
546
+ * @param {Object} lead - Los datos del lead a formatear
547
+ * @param {Object} fieldMapping - El mapeo de campos configurado
548
+ * @returns {Object} Lead formateado y validado
549
+ */
550
+ const formatLeadFields = (lead, fieldMapping) => {
551
+ let formattedLead = {};
552
+
553
+ // Procesar cada campo según el mapeo
554
+ for (const [outputField, inputConfig] of Object.entries(fieldMapping)) {
555
+ try {
556
+ if (typeof inputConfig === 'string') {
557
+ formattedLead[outputField] = baseTransforms.toString(lead[inputConfig] || '');
558
+ } else if (typeof inputConfig === 'object') {
559
+ const value = lead[inputConfig.field];
560
+ const transformer = new Function('value', `return ${inputConfig.transform}`);
561
+ formattedLead[outputField] = transformer(value);
562
+ }
563
+ } catch (error) {
564
+ Logger.error(`Error formatting field ${outputField}:`, error);
565
+ formattedLead[outputField] = '';
566
+ }
567
+ }
568
+
569
+ return formattedLead;
570
+ };
571
+
572
+ /**
573
+ * Genera una URL de descarga para un documento en MasterData
574
+ * @param {string} accountName - Nombre de la cuenta VTEX
575
+ * @param {string} documentId - ID del documento
576
+ * @param {string} entity - Nombre de la entidad
577
+ * @param {string} [environment='vtexcommercestable'] - Ambiente VTEX
578
+ * @returns {string} URL de descarga del documento
579
+ */
580
+ const generateMasterDataDownloadUrl = (accountName, documentId, entity, environment = 'vtexcommercestable') => {
581
+ return `https://${accountName}.${environment}.com.br/api/dataentities/${entity}/documents/${documentId}/file`;
582
+ };
583
+
584
+ /**
585
+ * Función para transformar datos entre diferentes formatos
586
+ * @param {*} value - Valor a transformar
587
+ * @param {string} transformType - Tipo de transformación a aplicar
588
+ * @returns {*} Valor transformado
589
+ */
590
+ const transformLeadData = (value, transformType) => {
591
+ if (!transformType || !baseTransforms[transformType]) {
592
+ return value;
593
+ }
594
+ return baseTransforms[transformType](value);
595
+ };
596
+
597
+ /**
598
+ * Valida el formato y la estructura de un lead
599
+ * @param {Object} lead - Lead a validar
600
+ * @param {Object} requiredFields - Campos requeridos y sus validaciones
601
+ * @returns {Object} Resultado de la validación
602
+ */
603
+ const validateLead = (lead, requiredFields) => {
604
+ const errors = [];
605
+
606
+ for (const [field, validation] of Object.entries(requiredFields)) {
607
+ const value = lead[field];
608
+
609
+ if (validation.required && !value) {
610
+ errors.push(`Campo ${field} es requerido`);
611
+ continue;
612
+ }
613
+
614
+ if (validation.regex && value) {
615
+ const regex = new RegExp(validation.regex);
616
+ if (!regex.test(value)) {
617
+ errors.push(`Campo ${field} tiene formato inválido`);
618
+ }
619
+ }
620
+
621
+ if (validation.maxLength && value && value.length > validation.maxLength) {
622
+ errors.push(`Campo ${field} excede el máximo de ${validation.maxLength} caracteres`);
623
+ }
624
+ }
625
+
626
+ return {
627
+ isValid: errors.length === 0,
628
+ errors
629
+ };
630
+ };
631
+
632
+ /**
633
+ * Función para generar el nombre del archivo CSV de leads
634
+ * @param {string} accountName - Nombre de la cuenta
635
+ * @param {string} dateRange - Rango de fechas del reporte
636
+ * @returns {string} Nombre del archivo formateado
637
+ */
638
+ const generateLeadReportFileName = (accountName, dateRange) => {
639
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
640
+ return `new-leads-${accountName}-${dateRange}-${timestamp}.csv`;
641
+ };
642
+
643
+ /**
644
+ * Función para validar la configuración de leads de una cuenta
645
+ * @param {Object} config - Configuración a validar
646
+ * @returns {Object} Resultado de la validación
647
+ */
648
+ const validateLeadsConfig = (config) => {
649
+ const requiredFields = [
650
+ 'newLeadsEntity',
651
+ 'fileUploadEntity',
652
+ 'leadMap'
653
+ ];
654
+
655
+ const errors = [];
656
+
657
+ for (const field of requiredFields) {
658
+ if (!config[field]) {
659
+ errors.push(`Missing required field: ${field}`);
660
+ }
661
+ }
662
+
663
+ if (config.leadMap && typeof config.leadMap !== 'object') {
664
+ errors.push('leadMap must be an object');
665
+ }
666
+
667
+ return {
668
+ isValid: errors.length === 0,
669
+ errors
670
+ };
671
+ };
672
+
673
+ module.exports = {
674
+ list_products_vtex,
675
+ list_categories_vtex,
676
+ list_brands_vtex,
677
+ getOrderFormById,
678
+ getClientById,
679
+ deleteCustomData,
680
+ updateOrderFormCustomData,
681
+ cleanOrderFormCustomData,
682
+ formatFinancialPolicyResponse,
683
+ baseTransforms,
684
+ applyTransform,
685
+ updateDataEntitySchema,
686
+ createDataEntityDocument,
687
+ updateDataEntityDocument,
688
+ formatLeadFields,
689
+ generateMasterDataDownloadUrl,
690
+ transformLeadData,
691
+ validateLead,
692
+ generateLeadReportFileName,
693
+ validateLeadsConfig
694
+ };