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,324 @@
1
+ const VtexApi = require('../../vtex/clients/VtexApi');
2
+ // LOGGER
3
+ const Logger = require("../../common/utils/logger");
4
+ const Convert = require("../../common/MondelezCastOrder");
5
+
6
+ const ERROR_MESSAGES = {
7
+ NO_RECORDS: 'No records found in event',
8
+ INVALID_JSON: 'Invalid JSON in record body',
9
+ MISSING_ACCOUNT_CONFIG: 'Missing AccountConfig or credentials',
10
+ MISSING_ORDER_ID: 'Missing orderInfo.OrderId',
11
+ VTEX_FETCH_ERROR: 'Error fetching order from VTEX',
12
+ }
13
+
14
+
15
+ // TODO: FIELDS si no existen fields NO debe guardar en master data
16
+
17
+ module.exports.handler = async (event) => {
18
+ try {
19
+ const { isValid, error, records } = validateEvent(event);
20
+ if(!isValid && error !== null){
21
+ Logger.error('Event validation failed:', error);
22
+ return { statusCode: 400, body: JSON.stringify({ message: error }) };
23
+ }
24
+
25
+ const result = await validateRecords(records)
26
+ if (result.errors > 0) {
27
+ Logger.error(`Processing completed with ${result.errors} errors.`);
28
+ return { statusCode: 500, body: JSON.stringify({ message: `Processing completed with ${result.errors} errors.` }) };
29
+ }
30
+
31
+ return { statusCode: 200, body: JSON.stringify({ message: 'Processing completed successfully.' }) };
32
+ } catch (error) {
33
+ Logger.error('Error processing records:', error);
34
+ return { statusCode: 500, body: JSON.stringify({ message: error.message }) };
35
+ }
36
+ };
37
+
38
+ const validateEvent = (event) => {
39
+ if(!event || !Array.isArray(event.Records) || event.Records.length === 0){
40
+ return { isValid: false, error: ERROR_MESSAGES.NO_RECORDS, records:[] };
41
+ }
42
+ return { isValid: true, error: null, records: event.Records };
43
+ };
44
+
45
+ const validateRecords = async (records) => {
46
+ let errors = 0;
47
+ for (const record of records) {
48
+ try {
49
+ await processingRecords(record);
50
+ } catch (error) {
51
+ Logger.error('Error processing record', record, error);
52
+ errors++;
53
+ }
54
+ }
55
+ return { errors };
56
+ };
57
+
58
+ const processingRecords = async (record) => {
59
+ Logger.debug(`Processing record: ${record.body}`);
60
+
61
+ const data = JSON.parse(record.body);
62
+ Logger.setAccount(data?.accountConfig);
63
+
64
+ if (!data){
65
+ Logger.error('Invalid JSON in record body:', record.body);
66
+ throw new Error(ERROR_MESSAGES.INVALID_JSON);
67
+ }
68
+
69
+ const accountConfig = await validateAccountConfig(data.accountConfig);
70
+ if (!accountConfig) {
71
+ Logger.error('Invalid account configuration');
72
+ return null;
73
+ }
74
+
75
+ const orderInfoVtex = await fetchOrderFromVtex(data?.orderInfo, data);
76
+
77
+ if (!orderInfoVtex) {
78
+ Logger.error(`Failed to fetch order from VTEX for OrderId: ${data?.orderInfo?.OrderId}`);
79
+ return null;
80
+ }
81
+
82
+ const idsPromotions = await getIdsPromotionsOrder(orderInfoVtex);
83
+ const detailsPromotions = await fetchDetailPromotionProductOrder(data.accountConfigParent, idsPromotions);
84
+ Logger.debug(JSON.stringify(detailsPromotions, null, 2));
85
+
86
+ let mappedPromotions = [];
87
+ if (detailsPromotions.length > 0){
88
+ const fields = data.accountConfig?.AdditionalFieldsPromotionsInOrder?.fields;
89
+ mappedPromotions = await validatePromotionsConfiguration(fields, detailsPromotions);
90
+ }
91
+
92
+ const saveOrderVtex = await saveOrderPromotionsHistoryMD2(data, orderInfoVtex, mappedPromotions);
93
+ if (!saveOrderVtex) {
94
+ Logger.debug('Failed to save order promotions history');
95
+ return null;
96
+ }
97
+
98
+ return true;
99
+ };
100
+
101
+ const validateAccountConfig = (accountConfig) => {
102
+ if (!accountConfig || !accountConfig.AccountName || !accountConfig.Credentials) {
103
+ Logger.error(ERROR_MESSAGES.MISSING_ACCOUNT_CONFIG);
104
+ return null;
105
+ }
106
+ return accountConfig;
107
+ };
108
+
109
+ const fetchOrderFromVtex = async (orderInfo, data) => {
110
+ const orderId = orderInfo?.OrderId;
111
+
112
+ if (!orderId) {
113
+ Logger.error(ERROR_MESSAGES.MISSING_ORDER_ID);
114
+ return null;
115
+ }
116
+
117
+ const vtexApi = await initVtexApi(data.accountConfig);
118
+ const vtexParent = await initVtexApi(data.accountConfigParent);
119
+
120
+ try {
121
+
122
+ Logger.debug("FETCH seller order:", {
123
+ url: `${vtexApi.baseURL}/oms/pvt/orders/${orderId}`,
124
+ method: "GET",
125
+ account: data.accountConfig?.AccountName
126
+ });
127
+
128
+ let response = await vtexApi.fetch(`/oms/pvt/orders/${orderId}`, { method: "GET" });
129
+
130
+ const parentOrderId = response?.data?.marketplaceOrderId;
131
+ if (!parentOrderId) {
132
+ Logger.error(`No marketplace order ID found for seller order ${orderId}`);
133
+ return null;
134
+ }
135
+
136
+ Logger.debug("FETCH parent order:", {
137
+ url: `${vtexParent.baseURL}/oms/pvt/orders/${parentOrderId}`,
138
+ method: "GET",
139
+ account: data.accountConfigParent?.AccountName,
140
+ parentOrderId: parentOrderId
141
+ });
142
+
143
+ let responseParent = await vtexParent.fetch(`/oms/pvt/orders/${parentOrderId}`, {
144
+ method: "GET",
145
+ });
146
+
147
+ Logger.debug("VTEX Order Response:", responseParent?.data);
148
+ const convertedOrder = Convert.orderToJson(response.data, responseParent.data, data.accountConfig);
149
+ return convertedOrder;
150
+
151
+ } catch (error) {
152
+ Logger.error(ERROR_MESSAGES.VTEX_FETCH_ERROR, error);
153
+ return null;
154
+ }
155
+ };
156
+
157
+ const getIdsPromotionsOrder = async (orderInfoVtex) => {
158
+ Logger.debug("Order ratesAndBenefitsData:", orderInfoVtex?.ratesAndBenefitsData);
159
+
160
+ const promotions = orderInfoVtex?.ratesAndBenefitsData?.rateAndBenefitsIdentifiers;
161
+
162
+ if (!promotions || promotions.length === 0) {
163
+ Logger.debug("No promotions found in order");
164
+ return [];
165
+ }
166
+
167
+ const idsPromotions = [];
168
+ for (const promo of promotions){
169
+ idsPromotions.push(promo.id);
170
+ }
171
+
172
+ Logger.debug(`Found ${idsPromotions.length} promotion IDs:`, idsPromotions);
173
+ return idsPromotions;
174
+ }
175
+
176
+ const fetchDetailPromotionProductOrder = async (accountConfig, idsPromotions) => {
177
+ Logger.debug("Fetching promotion details for IDs:", idsPromotions);
178
+
179
+ if (!idsPromotions || idsPromotions.length === 0) {
180
+ Logger.debug("No promotion IDs to fetch");
181
+ return [];
182
+ }
183
+
184
+ const vtexApi = await initVtexApi(accountConfig);
185
+
186
+ try {
187
+ const promotionPromises = idsPromotions.map(async (id) => {
188
+ try {
189
+ const response = await vtexApi.fetch(`/rnb/pvt/calculatorconfiguration/${id}`, { method: "GET" });
190
+
191
+ if (response && response.status === 200 && response.data) {
192
+ return response.data;
193
+ }
194
+
195
+ } catch (error) {
196
+ Logger.error(`Error fetching promotion ${id}:`, error.message);
197
+ return null;
198
+ }
199
+ });
200
+
201
+ const results = await Promise.all(promotionPromises);
202
+ const validResults = results.filter(result => result !== null);
203
+ return validResults;
204
+
205
+ } catch (error) {
206
+ Logger.error('Error fetching promotion details from VTEX:', error);
207
+ return [];
208
+ }
209
+ }
210
+
211
+ const validatePromotionsConfiguration = async (fields, detailsPromotions) => {
212
+ if (!fields || !detailsPromotions || detailsPromotions.length === 0) {
213
+ Logger.debug('Fields or detailsPromotions are empty');
214
+ return [];
215
+ }
216
+
217
+ const mappedPromotions = [];
218
+
219
+ for (let i = 0; i < detailsPromotions.length; i++) {
220
+ const detail = detailsPromotions[i];
221
+ const mappedPromotion = {};
222
+
223
+ for (const [fieldName, fieldConfig] of Object.entries(fields)) {
224
+
225
+ // Caso 1: Configuración simple (mapeo directo de valores)
226
+ if (fieldConfig && typeof fieldConfig === 'object' && !fieldConfig.alias && !fieldConfig.values) {
227
+ const fieldValue = detail[fieldName];
228
+
229
+ if (fieldValue && fieldConfig[fieldValue]) {
230
+ mappedPromotion[fieldName] = fieldConfig[fieldValue];
231
+ } else {
232
+ mappedPromotion[fieldName] = fieldValue;
233
+ }
234
+ }
235
+ // Caso 2: Configuración compleja (con alias y values)
236
+ else if (fieldConfig && typeof fieldConfig === 'object' && fieldConfig.alias) {
237
+ const { alias, values } = fieldConfig;
238
+ const fieldValue = detail[fieldName];
239
+
240
+ if (fieldValue && values && values[fieldValue]) {
241
+ mappedPromotion[alias] = values[fieldValue];
242
+ } else if (fieldValue) {
243
+ mappedPromotion[alias] = fieldValue;
244
+ } else {
245
+ mappedPromotion[alias] = null;
246
+ }
247
+ }
248
+ // Caso 3: Configuración simple (campo directo)
249
+ else {
250
+ if (detail.hasOwnProperty(fieldName)) {
251
+ mappedPromotion[fieldName] = detail[fieldName];
252
+ } else {
253
+ mappedPromotion[fieldName] = null;
254
+ }
255
+ }
256
+ }
257
+
258
+ mappedPromotion.promotionId = detail?.idCalculatorConfiguration || detail?.id || null
259
+ mappedPromotions.push(mappedPromotion);
260
+ }
261
+ return mappedPromotions;
262
+ }
263
+
264
+
265
+ const saveOrderPromotionsHistoryMD2 = async (data, orderInfoVtex, mappedPromotions) => {
266
+
267
+ if (!data || !orderInfoVtex) {
268
+ Logger.debug("Data or orderInfo is missing");
269
+ return false;
270
+ }
271
+
272
+ const accountConfig = data.accountConfig;
273
+ const acronymEntity = accountConfig?.AdditionalFieldsPromotionsInOrder?.acronymEntity;
274
+
275
+ const transformedPromotions = (mappedPromotions || []).map(promotion => {
276
+ const { promotionId, ...fields } = promotion;
277
+ return {
278
+ id: promotionId,
279
+ fields: fields
280
+ };
281
+ });
282
+
283
+ const payload = {
284
+ id: orderInfoVtex?.id,
285
+ detailPromotions: transformedPromotions
286
+ };
287
+
288
+ const vtexApi = await initVtexApi(accountConfig);
289
+
290
+ try {
291
+
292
+ const result = await vtexApi.fetch(`/dataentities/${acronymEntity}/documents`, {
293
+ method: "PATCH",
294
+ data: payload
295
+ }, false);
296
+
297
+ if (!result) {
298
+ Logger.info("Order promotions history - data already exists with same content (status 304)");
299
+ return true;
300
+ }
301
+
302
+ if ((result.status >= 200 && result.status < 300) || result.status === 304) {
303
+ Logger.info("Order promotions history saved successfully");
304
+ return true;
305
+ } else if (result.status >= 400) {
306
+ Logger.error("Failed to save order promotions history:", result);
307
+ return false;
308
+ }
309
+
310
+ return true;
311
+ } catch (error) {
312
+ Logger.error("Error saving order promotions history:", error);
313
+ Logger.error("ERROR DETAILS:", error.response?.data || error.message);
314
+ return false;
315
+ }
316
+ };
317
+
318
+ const initVtexApi = async (accountConfig) => {
319
+ return new VtexApi(
320
+ accountConfig?.AccountName,
321
+ accountConfig?.Credentials?.key,
322
+ accountConfig?.Credentials?.token
323
+ );
324
+ };
@@ -0,0 +1,87 @@
1
+ const VtexApi = require("../../vtex/clients/VtexApi");
2
+ const AccountData = require("../../entities/account");
3
+ const SkuData = require("../../entities/sku");
4
+ const AWSServices = require("../../common/utils/aws-services");
5
+ const Logger = require("../../common/utils/logger");
6
+
7
+ const SQS_AFFILIATE_HOOK_QUEUE_URL = process.env.SQS_AFFILIATE_HOOK_QUEUE_URL;
8
+ const SQS_AFFILIATE_HOOK_DQL_QUEUE_URL = process.env.SQS_AFFILIATE_HOOK_DQL_QUEUE_URL;
9
+ const MAX_ATTEMPS = process.env.MAX_ATTEMPS || 5;
10
+
11
+ /**
12
+ *
13
+ * @param {import("aws-lambda").SQSEvent} event
14
+ * @returns
15
+ */
16
+ const consumer = async (event) => {
17
+ let attemps = 0;
18
+ for (const record of event.Records) {
19
+ try {
20
+ const request = JSON.parse(record.body);
21
+ attemps = request.attemps || 0;
22
+ const skuId = request.IdSku;
23
+ const accountName = request.An;
24
+ if (!skuId || !accountName) {
25
+ throw new Error("Invalid SKU or Account Name");
26
+ }
27
+ const data = await AccountData.getAccountDataByAccountName(accountName);
28
+ Logger.setAccount(data);
29
+ Logger.debug("Message Body: ", record.body, ". Type: ", typeof record.body);
30
+ Logger.debug("Data: ", data);
31
+ if (!data) {
32
+ Logger.debug("Data INVALID: ", data);
33
+ throw new Error("Account not found");
34
+ }
35
+ const apiClient = new VtexApi(data?.AccountName, data?.Credentials?.key, data?.Credentials?.token);
36
+ Logger.debug("VTEX API Client: ", apiClient);
37
+ const response = await apiClient.fetch(`/catalog_system/pvt/sku/stockkeepingunitbyid/${skuId}`, {
38
+ method: "GET",
39
+ });
40
+ if (response?.status < 200 || response?.status > 299) {
41
+ throw new Error("Error getting SKU in VTEX");
42
+ }
43
+ Logger.debug("Response: ", response.data);
44
+ const skuIdentifier = response.data?.AlternateIds?.RefId || response.data?.AlternateIds?.Ean;
45
+ const sku = {
46
+ AccountNameAndSku: `${accountName}${skuIdentifier}`,
47
+ ParentAccountName: accountName,
48
+ Sku: skuIdentifier,
49
+ Ean: response.data?.AlternateIds?.Ean,
50
+ SkuId: parseInt(skuId),
51
+ Name: response.data?.NameComplete,
52
+ Type: "SKU",
53
+ };
54
+ const saved = await SkuData.addSku(sku);
55
+ Logger.debug("Sku added: ", saved);
56
+ } catch (error) {
57
+ Logger.error(error);
58
+ if (
59
+ attemps < MAX_ATTEMPS &&
60
+ error?.message !== "Account not found" &&
61
+ error?.message !== "Invalid SKU or Account Name"
62
+ ) {
63
+ try {
64
+ await AWSServices.sendSQSMessage(SQS_AFFILIATE_HOOK_QUEUE_URL, JSON.parse(record.body));
65
+ } catch (error) {
66
+ Logger.error("Sending message to Queue: ", error);
67
+ }
68
+ } else {
69
+ try {
70
+ await AWSServices.sendSQSMessage(
71
+ SQS_AFFILIATE_HOOK_DQL_QUEUE_URL,
72
+ JSON.stringify({
73
+ body: record.body,
74
+ error: error?.message,
75
+ })
76
+ );
77
+ } catch (error) {
78
+ Logger.error("Sending message to DQL Queue: ", error);
79
+ }
80
+ }
81
+ }
82
+ }
83
+ };
84
+
85
+ module.exports = {
86
+ consumer,
87
+ };
@@ -0,0 +1,45 @@
1
+ const AWSServices = require("../../common/utils/aws-services");
2
+ const ApiResponse = require("../../common/utils/api-response");
3
+ const AFFILIATE_HOOK_QUEUE_URL = process.env.AFFILIATE_HOOK_QUEUE_URL;
4
+ const Logger = require("../../common/utils/logger");
5
+
6
+ /**
7
+ *
8
+ * @param {import("aws-lambda").APIGatewayProxyEvent} event
9
+ * @returns
10
+ */
11
+ const producer = async (event) => {
12
+ let statusCode = 200;
13
+ let message;
14
+ if (!event.body) {
15
+ return ApiResponse.response(400, "No body was found");
16
+ }
17
+ try {
18
+ Logger.debug("Event: ", event.body, typeof event.body);
19
+ const request = JSON.parse(event.body);
20
+ const skuModified = request?.HasStockKeepingUnitModified || request?.hasStockKeepingUnitModified || request?.StockModified || request?.PriceModified || 0;
21
+ if (skuModified && skuModified != 0) {
22
+ await AWSServices.sendSQSMessage(AFFILIATE_HOOK_QUEUE_URL, JSON.parse(event.body));
23
+ } else {
24
+ Logger.error(
25
+ `No SKU modified, no message sent to queue...Sku: ${request?.IdSku} and Account: ${request?.An}. Body: ${request}`
26
+ );
27
+ }
28
+ message = "Message accepted!";
29
+ } catch (error) {
30
+ Logger.error(error);
31
+ message = error;
32
+ statusCode = 500;
33
+ }
34
+
35
+ return {
36
+ statusCode,
37
+ body: JSON.stringify({
38
+ message,
39
+ }),
40
+ };
41
+ };
42
+
43
+ module.exports = {
44
+ producer,
45
+ };
@@ -0,0 +1,62 @@
1
+ const AccountData = require("../../entities/account");
2
+ const ApiResponse = require("../../common/utils/api-response");
3
+ const ClientData = require("../../entities/clients");
4
+ const AudiencePrice = require("../../integrations/audience/Audience");
5
+ const Logger = require("../../common/utils/logger");
6
+
7
+ /**
8
+ * @param {import("aws-lambda").APIGatewayProxyEvent} event
9
+ * @returns {Promise<ApiResponse>}
10
+ */
11
+ const handler = async (event) => {
12
+ const { client_id: clientId } = event.requestContext.authorizer.claims || {};
13
+ const email = event?.queryStringParameters?.email ? decodeURIComponent(event.queryStringParameters.email.trim().replace(/\s/g, "+")) : null;
14
+ const accountNameURL = event?.queryStringParameters?.an ? event?.queryStringParameters?.an : null;
15
+ const accountName = accountNameURL || null;
16
+
17
+ if (!accountName) {
18
+ return ApiResponse.response(400, { approved: false, message: "AccountName is Required" });
19
+ }
20
+
21
+ let configAccount = await AccountData.getAccountDataByAccountName(accountName);
22
+ if (!configAccount) {
23
+ Logger.error("Account not found");
24
+ return ApiResponse.response(400, { approved: false, message: "Account not found" });
25
+ }
26
+
27
+ if (!configAccount.SavePriceAudience) {
28
+ return ApiResponse.response(400, { approved: false, message: "You do not have permission to access this resource" });
29
+ }
30
+
31
+ if (!email) {
32
+ return ApiResponse.response(400, { approved: false, message: "Email is Required" });
33
+ }
34
+
35
+ const audiencePrice = new AudiencePrice(configAccount.AccountName, configAccount?.Credentials?.key, configAccount?.Credentials?.token);
36
+
37
+ try {
38
+ const audienceResponse = await audiencePrice.createAudiencePrice(email);
39
+
40
+ if (!audienceResponse) {
41
+ return ApiResponse.response(400, { approved: false, message: "Error creating audience" });
42
+ }
43
+
44
+ const priceList = await audiencePrice.getAudiencePriceById(audienceResponse);
45
+
46
+ if (!priceList || priceList?.length === 0) {
47
+ return ApiResponse.response(404, { approved: false, message: "Audience price mapping not found. Verify if the ID is correct or exists." });
48
+ }
49
+
50
+ return ApiResponse.response(200, { approved: true, priceList });
51
+ } catch (error) {
52
+ if (error.response?.status === 404) {
53
+ return ApiResponse.response(404, { approved: false, message: "Resource not found on VTEX. Please verify the endpoint or ID." });
54
+ }
55
+ Logger.error("Unexpected error:", error);
56
+ return ApiResponse.response(500, { approved: false, message: "Internal server error." });
57
+ }
58
+ };
59
+
60
+ module.exports = {
61
+ handler,
62
+ };