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,137 @@
1
+ "use strict";
2
+ const ClientData = require("../../entities/clients");
3
+ const OrderData = require("../../entities/orders");
4
+ const ApiResponse = require("../../common/utils/api-response");
5
+ const Logger = require("../../common/utils/logger");
6
+ /**
7
+ *
8
+ * @param {import("aws-lambda").APIGatewayProxyEvent} event
9
+ * @returns
10
+ */
11
+ module.exports.notifications = async (event) => {
12
+ try {
13
+ const account = event?.queryStringParameters?.an;
14
+ var from = event?.queryStringParameters?.from;
15
+ var to = event?.queryStringParameters?.to;
16
+ const state = event?.queryStringParameters?.state;
17
+ const minutesWaiting = event?.queryStringParameters?.minutesWaiting ?? 6;
18
+ const limitPerPage = event?.queryStringParameters?.limit;
19
+ const page = parseInt(event?.queryStringParameters?.p); // || 1
20
+ const clientId = event?.requestContext?.authorizer?.claims?.client_id;
21
+
22
+ Logger.log("Event: ", account, from, to, state, page, clientId);
23
+
24
+ ApiResponse.validateRequiredParam("account parameter 'an'", account);
25
+ ApiResponse.validateRequiredParam("from parameter 'from'", from);
26
+ ApiResponse.validateRequiredParam("to parameter 'to'", to);
27
+
28
+ if (page < 1) {
29
+ return ApiResponse.response(400, "The page starts with '1'.");
30
+ }
31
+
32
+ if (validarFecha(from)) {
33
+ from = obtenerFechaDesdeCadena(from, 0, null).toISOString();
34
+ } else {
35
+ return ApiResponse.response(400, "El formato de fecha 'from' no es válido");
36
+ }
37
+ if (validarFecha(to)) {
38
+ to = obtenerFechaDesdeCadena(to, parseInt(minutesWaiting), state).toISOString();
39
+ } else {
40
+ return ApiResponse.response(400, "El formato de fecha 'to' no es válido");
41
+ }
42
+
43
+ const dateFrom = new Date(from);
44
+ const dateTo = new Date(to);
45
+
46
+ if (isNaN(dateFrom) || isNaN(dateTo)) {
47
+ return ApiResponse.response(400, "Una o ambas fechas no están en un formato válido");
48
+ } else if (dateFrom >= dateTo) {
49
+ return ApiResponse.response(400, "La fecha 'from' debe ser menor que la fecha 'to'");
50
+ }
51
+ const validAccount = await ClientData.validateAccount(clientId, account);
52
+ if (!validAccount) {
53
+ Logger.error("Data INVALID: ", validAccount);
54
+ return ApiResponse.response(404, "Account not found");
55
+ }
56
+
57
+ let limitPage= limitPerPage && Number.isNaN(parseInt(limitPerPage))==false ? parseInt(limitPerPage) : 100;
58
+
59
+ const total = await OrderData.getOrdersByAccountNameBetweenDatesCountTotals(account, from, to, state);
60
+ let countPageT= parseInt((total/limitPage));
61
+ if((parseInt(countPageT)*limitPage) < total){
62
+ countPageT++;
63
+ }
64
+ if(countPageT < page && page > 1){
65
+ return {
66
+ statusCode: 200,
67
+ body: JSON.stringify(tranformedData([], page, total, limitPage), null, 2),
68
+ };
69
+ }
70
+ const orders = await OrderData.getOrdersByAccountNameBetweenDates(account, from, to, state, page, total, limitPage);
71
+ const response = tranformedData(orders, page, total, limitPage);
72
+ return {
73
+ statusCode: 200,
74
+ body: JSON.stringify(response, null, 2),
75
+ };
76
+ } catch (error) {
77
+ Logger.error(error);
78
+ }
79
+ ApiResponse.response(500, "Internal Server Error");
80
+ };
81
+
82
+ function validarFecha(fecha) {
83
+ const regex = /^\d{14}$/; // Expresión regular para validar que la cadena tenga exactamente 14 dígitos
84
+ return regex.test(fecha);
85
+ }
86
+
87
+ function obtenerFechaDesdeCadena(cadena, minutesPrevNow=null, state=null) {
88
+ const anio = parseInt(cadena.substring(0, 4));
89
+ const mes = parseInt(cadena.substring(4, 6));
90
+ const dia = parseInt(cadena.substring(6, 8));
91
+ const hora = parseInt(cadena.substring(8, 10));
92
+ const minuto = parseInt(cadena.substring(10, 12));
93
+ const segundo = parseInt(cadena.substring(12, 14));
94
+
95
+ if(minutesPrevNow && minutesPrevNow > 0 && state != 'cancel' && state != 'canceled' ){
96
+ let minutesMinus= 1000*60*minutesPrevNow;
97
+ let dateNow= ((new Date()).getTime()-minutesMinus);
98
+ let dateService= (new Date(anio, mes - 1, dia, hora, minuto, segundo)).getTime();
99
+ if( dateNow < dateService ){
100
+ return new Date(dateNow);
101
+ }else{
102
+ return new Date(anio, mes - 1, dia, hora, minuto, segundo);
103
+ }
104
+ }else{
105
+ return new Date(anio, mes - 1, dia, hora, minuto, segundo);
106
+ }
107
+ }
108
+
109
+ function tranformedData(items, page, total, limitPage=100) {
110
+ if(total < items?.length ){
111
+ total=items?.length;
112
+ }
113
+
114
+ let countPageT= parseInt((total/limitPage));
115
+ if((parseInt(countPageT)*limitPage) < total){
116
+ countPageT++;
117
+ }
118
+
119
+ return {
120
+ properties: {
121
+ current_page: !page ? 1 : page,
122
+ current_page_count: countPageT,
123
+ total_count: total,
124
+ },
125
+ notifications: transformedOrders(items),
126
+ };
127
+ }
128
+
129
+ function transformedOrders(orders) {
130
+ return orders.map((order) => ({
131
+ id: order.Id,
132
+ orderId: order.OrderId,
133
+ accountName: order.AccountNameForOrder,
134
+ status: order.OrderState,
135
+ changeDate: order.StatusDate,
136
+ }));
137
+ }
@@ -0,0 +1,461 @@
1
+ "use strict";
2
+ const VtexApi = require("../../vtex/clients/VtexApi");
3
+ const AWSServices = require("../../common/utils/aws-services");
4
+ const Constants = require("../../common/utils/constants");
5
+ const Status = require("../../common/utils/status");
6
+ const Logger = require("../../common/utils/logger");
7
+
8
+ const SQS_ORDERS_STATUS_DQL_QUEUE_URL = process.env.SQS_ORDERS_STATUS_DQL_QUEUE_URL;
9
+ const SQS_ORDERS_STATUS_QUEUE_URL = process.env.SQS_ORDERS_STATUS_QUEUE_URL;
10
+ const MAX_ATTEMPTS = process.env.MAX_ATTEMPTS || 3;
11
+
12
+ /**
13
+ * Autorizacion de pagos dentro de whitelabel VTEX
14
+ * @param transactions -listado de transsacciones order vtex
15
+ **/
16
+ const setPaymentVtex = async ({ transactions = null, status = null, vtexApi = null }) => {
17
+ return new Promise(async function (resolve, reject) {
18
+ let responsePayment = { status: 200 };
19
+ if (transactions && status && vtexApi) {
20
+ for (const transaction of transactions) {
21
+ for (const paymentParent of transaction?.payments) {
22
+ if (paymentParent.id) {
23
+
24
+ if (status === Status.WAITING_FFMTT_AUTHORIZATION) {
25
+ const relativePaymentUrl = Constants.APPROVE_PAYMENT.replace("{paymentId}", paymentParent.id);
26
+ responsePayment = await vtexApi.fetch(relativePaymentUrl, {
27
+ method: "POST",
28
+ });
29
+ }
30
+ await delayStatusProcess(5);
31
+ }
32
+ }
33
+ }
34
+ }
35
+ resolve(responsePayment);
36
+ });
37
+ };
38
+
39
+ /**
40
+ * Autorizacion de pagos dentro de whitelabel VTEX
41
+ * @param transactions -listado de transsacciones order vtex
42
+ **/
43
+ const setStartHandlingVtex = async ({ sellerOrderId = null, status = null, vtexApi = null }) => {
44
+ return new Promise(async function (resolve, reject) {
45
+ let responseHandling = { status: 200 };
46
+ if (sellerOrderId && status && vtexApi) {
47
+ if (status === Status.READY_FOR_HANDLING) {
48
+ const relativeHandlingUrl = Constants.START_HANDLING_ORDER.replace("{orderId}", sellerOrderId);
49
+ responseHandling = await vtexApi.fetch(relativeHandlingUrl, {
50
+ method: "POST",
51
+ });
52
+ await delayStatusProcess(5);
53
+ }
54
+ }
55
+ resolve(responseHandling);
56
+ });
57
+ };
58
+
59
+ /**
60
+ * Reenviar cola
61
+ * @param record cuerpo de la cola
62
+ **/
63
+ const resendSqs = async ({ record = null }) => {
64
+ return new Promise(async function (resolve, reject) {
65
+ if (record) {
66
+ const attempts = JSON.parse(record.body)?.attempts || 0;
67
+ let clientVtexBody = JSON.parse(record.body);
68
+ clientVtexBody.attempts = attempts + 1;
69
+
70
+ if (attempts < MAX_ATTEMPTS) {
71
+ await delayStatusProcess(3);
72
+ await AWSServices.sendSQSMessage(SQS_ORDERS_STATUS_QUEUE_URL, clientVtexBody);
73
+ } else {
74
+ throw new Error("Max attempts reached.");
75
+ }
76
+ }
77
+ resolve(true);
78
+ });
79
+ };
80
+
81
+ /**
82
+ * Reenviar canbios orden VTEX
83
+ * @param changes
84
+ * @param orderVtex
85
+ * @param vtexApi
86
+ **/
87
+ const setChangesVtex = async ({ changes = null, orderVtex = null, vtexApi = null, sellerOrderId = null }) => {
88
+ return new Promise(async function (resolve, reject) {
89
+ if (changes && orderVtex && vtexApi && sellerOrderId) {
90
+ let itemsChangesRemovedArray = [];
91
+ for (const itemRemove of changes?.itemsRemoved) {
92
+ itemsChangesRemovedArray = [...itemsChangesRemovedArray, {
93
+ id: itemRemove.id,
94
+ price: itemRemove.price,
95
+ quantity: itemRemove.quantity
96
+ }];
97
+ }
98
+ let requestId = `${changes?.discountValue}-${itemsChangesRemovedArray?.map(it => `${it.id}-${it.quantity}-${it.price}`)?.join('')}-changes`;
99
+ let registerChangeOnOrderPayload = {
100
+ requestId: requestId.substring(0, 30),
101
+ itemsRemoved: itemsChangesRemovedArray,
102
+ reason: changes?.reason,
103
+ discountValue: changes?.discountValue,
104
+ incrementValue: 0,
105
+ itemsAdded: [],
106
+ };
107
+
108
+ const relativeChangeUrl = Constants.REGISTER_CHANGE_ON_ORDER.replace("{orderId}", sellerOrderId);
109
+ let responseChange = {};
110
+ let validChangeOrder = validChangesOrder({ order: orderVtex, change: registerChangeOnOrderPayload });
111
+ if (itemsChangesRemovedArray.length > 0 && validChangeOrder?.valid == true && validChangeOrder?.changes) {
112
+ responseChange = await vtexApi.fetch(relativeChangeUrl, {
113
+ method: "POST",
114
+ data: validChangeOrder?.changes,
115
+ });
116
+ } else {
117
+ responseChange = { status: 200 };
118
+ }
119
+ }
120
+ resolve(true);
121
+ });
122
+ };
123
+
124
+ /**
125
+ * Reenviar facturacion VTEX
126
+ * @param documents
127
+ * @param orderVtex
128
+ * @param vtexApi
129
+ **/
130
+ const setInvoicedVtex = async ({ documents = null, orderVtex = null, vtexApi = null, sellerOrderId = null, SetValueInvoiceOrderForced = false }) => {
131
+ let invoiceValue = documents?.invoiceValue;
132
+ if (SetValueInvoiceOrderForced && SetValueInvoiceOrderForced != false) {
133
+ let sumaInvoiced = 0;
134
+
135
+ if (orderVtex?.packageAttachment?.packages) {
136
+ for (let inr = 0; inr < orderVtex?.packageAttachment?.packages?.length; inr++) {
137
+ sumaInvoiced += parseFloat(orderVtex?.packageAttachment?.packages[inr]?.invoiceValue);
138
+ }
139
+ }
140
+
141
+ if (sumaInvoiced === 0 || parseFloat(sumaInvoiced) != parseFloat(invoiceValue)) {
142
+ invoiceValue = parseFloat(orderVtex?.value) - parseFloat(sumaInvoiced);
143
+ }
144
+ }
145
+
146
+ return new Promise(async function (resolve, reject) {
147
+ let responseNotification = { status: 500 };
148
+ if (documents && orderVtex && vtexApi && sellerOrderId) {
149
+ const invoiceNotificationOrderPayload = {
150
+ type: "Output",
151
+ issuanceDate: documents?.issuanceDate,
152
+ invoiceNumber: documents?.invoiceNumber,
153
+ invoiceValue: invoiceValue,
154
+ invoiceKey: null,
155
+ invoiceUrl: documents?.invoiceUrl,
156
+ embeddedInvoice: null,
157
+ courier: "mdlz",
158
+ trackingNumber: documents?.invoiceNumber,
159
+ trackingUrl: null,
160
+ dispatchedDate: null,
161
+ items: orderVtex.items.map((item) => ({ id: item.id, quantity: item.quantity, price: item.sellingPrice }))
162
+ };
163
+
164
+ const relativeNotificationUrl = Constants.INVOICE_NOTIFICATION_ORDER.replace("{orderId}", sellerOrderId);
165
+ responseNotification = await vtexApi.fetch(relativeNotificationUrl, {
166
+ method: "POST",
167
+ data: invoiceNotificationOrderPayload,
168
+ });
169
+ }
170
+ resolve(responseNotification);
171
+ });
172
+ };
173
+
174
+ /**
175
+ * Validacion de aplicaion de changes en vtex
176
+ * @param order -- objeto de la orden dentro de vtex
177
+ * @param change -- cambios a aplicar dentro de la orden
178
+ **/
179
+ const validChangesOrder = ({ order = null, change = null }) => {
180
+ if (order && change) {
181
+ if (order?.changesAttachment && order?.changesAttachment?.changesData && typeof order?.changesAttachment?.changesData == 'object' && order?.changesAttachment?.changesData.length > 0) {
182
+
183
+ if (change?.itemsRemoved && typeof change?.itemsRemoved == 'object' && change?.itemsRemoved.length > 0 && change?.reason && change?.discountValue) {
184
+ let itemsRemovedChange = [];
185
+ let validItemsChange = false;
186
+ let changepervalid = null;
187
+
188
+ for (let i = 0; i < order?.changesAttachment?.changesData.length; i++) {
189
+ if (order?.changesAttachment?.changesData[i]?.reason == change?.reason && order?.changesAttachment?.changesData[i]?.discountValue == change?.discountValue) {
190
+ validItemsChange = true;
191
+ changepervalid = order?.changesAttachment?.changesData[i];
192
+ }
193
+ }
194
+
195
+ if (validItemsChange == false) {
196
+ itemsRemovedChange = change?.itemsRemoved;
197
+ } else if (changepervalid && validItemsChange) {
198
+ let listFirts = [];
199
+ for (let j = 0; j < changepervalid?.itemsRemoved.length; j++) {
200
+ for (let x = 0; x < change?.itemsRemoved.length; x++) {
201
+ if (!listFirts.includes(change?.itemsRemoved[x]?.id) &&
202
+ ((changepervalid?.itemsRemoved[j]?.id != change?.itemsRemoved[x]?.id && changepervalid?.itemsRemoved[j]?.quantity == change?.itemsRemoved[x]?.quantity) ||
203
+ (changepervalid?.itemsRemoved[j]?.id == change?.itemsRemoved[x]?.id && changepervalid?.itemsRemoved[j]?.quantity != change?.itemsRemoved[x]?.quantity))
204
+ ) {
205
+ itemsRemovedChange = [...itemsRemovedChange, change?.itemsRemoved[x]];
206
+ }
207
+ listFirts = [...listFirts, change?.itemsRemoved[x]?.id]
208
+ }
209
+ }
210
+ }
211
+ if (itemsRemovedChange.length > 0) {
212
+ change.itemsRemoved = itemsRemovedChange;
213
+ return { valid: true, changes: change, log: 'success' };
214
+ } else {
215
+ return { valid: false, changes: null, log: 'Not items removed!' };
216
+ }
217
+ } else {
218
+ return { valid: false, changes: null, log: 'not items removed' };
219
+ }
220
+
221
+ } else {
222
+ return { valid: true, changes: change, log: 'success' };
223
+ }
224
+ } else {
225
+ return { valid: false, changes: null, log: 'error in order or changes' };
226
+ }
227
+ };
228
+
229
+ /**
230
+ * Dar delay antes de iniciar un proceso
231
+ * @param time // tiempo en segundos para esperar
232
+ **/
233
+ const delayStatusProcess = (time) => {
234
+ if (!time || time < 1) {
235
+ return true;
236
+ }
237
+ return new Promise((resolve, reject) => {
238
+ setTimeout(function () {
239
+ resolve(true);
240
+ }, (time * 1000));
241
+ })
242
+ };
243
+
244
+ const setChangesOrInvoiced = async (an, key, token, changes, documents, orderVtex, sellerOrderId, record) => {
245
+ const vtexApi = new VtexApi(an, key, token);
246
+ let clientVtexBody = JSON.parse(record.body);
247
+
248
+ // Aprobacion de pago
249
+ let responsePayment = await setPaymentVtex({ transactions: orderVtex?.paymentData?.transactions, status: orderVtex?.status, vtexApi: vtexApi });
250
+
251
+ if (
252
+ responsePayment?.status < 200 ||
253
+ responsePayment?.status > 300
254
+ ) {
255
+ Logger.error(
256
+ "Error updating client. Status: ",
257
+ responsePayment.status,
258
+ ". Message: ",
259
+ responsePayment?.data?.message
260
+ );
261
+ await resendSqs({ record: record });
262
+ throw new Error("Payment approve no processed for orderId: ", sellerOrderId);
263
+ return false;
264
+ } else {
265
+ }
266
+ //fin aprobacion pago
267
+
268
+ await delayStatusProcess(5);
269
+
270
+ const orderSellerVtexResponse5 = await vtexApi.fetch(Constants.GET_ORDER.replace("{orderId}", sellerOrderId), {
271
+ method: "GET",
272
+ });
273
+
274
+ const orderSellerVtexData5 = orderSellerVtexResponse5.data;
275
+
276
+ if (orderSellerVtexData5.status != Status.CANCEL &&
277
+ orderSellerVtexData5.status != Status.CANCELED) {
278
+
279
+ // StartHanling VTEX
280
+ let responseHandling = await setStartHandlingVtex({ sellerOrderId: sellerOrderId, status: orderSellerVtexData5.status, vtexApi: vtexApi });
281
+
282
+ if (
283
+ responseHandling?.status < 200 ||
284
+ responseHandling?.status > 300
285
+ ) {
286
+ await resendSqs({ record: record });
287
+ throw new Error("Start Handling no processed correctly.");
288
+ return false;
289
+ } else {
290
+ }
291
+ // Fin StartHanling VTEX
292
+
293
+ const orderSellerVtexResponse6 = await vtexApi.fetch(
294
+ Constants.GET_ORDER.replace("{orderId}", sellerOrderId),
295
+ {
296
+ method: "GET",
297
+ }
298
+ );
299
+ const orderSellerVtexData6 = orderSellerVtexResponse6.data;
300
+
301
+ if (changes) {
302
+ // Cambios en la orden
303
+ const resChanges = await setChangesVtex({ changes: changes, orderVtex: orderSellerVtexData6, vtexApi: vtexApi, sellerOrderId: sellerOrderId });
304
+ await delayStatusProcess(5);
305
+ }
306
+
307
+ if (documents && documents.type === "invoice") {
308
+ // facturacion orden VTEX
309
+ const body2 = JSON.parse(record.body)
310
+ const SetValueInvoiceOrderForced = body2?.SetValueInvoiceOrderForced ?? false;
311
+ const resInvoice = await setInvoicedVtex({ documents: documents, orderVtex: orderSellerVtexData6, vtexApi: vtexApi, sellerOrderId: sellerOrderId, SetValueInvoiceOrderForced: SetValueInvoiceOrderForced });
312
+ if (resInvoice?.status >= 200 && resInvoice?.status < 300) {
313
+ } else {
314
+ await resendSqs({ record: record });
315
+ throw new Error("Invoiced not processed correctly.");
316
+ }
317
+ }
318
+ }
319
+ };
320
+
321
+ /**
322
+ *
323
+ * @param {import("aws-lambda").APIGatewayProxyEvent} event
324
+ * @returns
325
+ */
326
+ const consumer = async (event) => {
327
+ for (const record of event.Records) {
328
+ const body = JSON.parse(record.body);
329
+ Logger.debug("Message Body: ", body);
330
+ if (body) {
331
+ try {
332
+ const { an, key, token, request, orderId } = body;
333
+ const apiClient = new VtexApi(an, key, token);
334
+ const orderClientVtexResponse = await apiClient.fetch(Constants.GET_ORDER.replace("{orderId}", orderId), {
335
+ method: "GET",
336
+ });
337
+ if (orderClientVtexResponse?.status < 200 || orderClientVtexResponse?.status >= 300) {
338
+ Logger.error("Order not found: ", orderClientVtexResponse);
339
+ throw new Error("Order not found");
340
+ }
341
+ const orderVtex = await orderClientVtexResponse.data;
342
+
343
+ // Se valida si la petición corresponde a una devolución de productos
344
+ if (request?.documents?.type == 'return') {
345
+ await setReturnedItems(apiClient, request, orderVtex, orderId);
346
+ } else {
347
+ // En caso contrario, se procede a ejecutar la facturación
348
+ const changes = request?.changes;
349
+ const documents = request?.documents;
350
+
351
+ await setChangesOrInvoiced(an, key, token, changes, documents, orderVtex, orderId, record);
352
+ }
353
+ } catch (error) {
354
+ Logger.error("Register Orders status Consumer: ", error);
355
+ try {
356
+ await resendSqs({ record: record });
357
+ Logger.error("AxiosError: ", error?.response?.data);
358
+ } catch (error) {
359
+ Logger.error("Sending message from orders status consumer to DQL Queue:", error);
360
+ }
361
+ }
362
+ }
363
+ }
364
+ };
365
+
366
+ async function setReturnedItems(apiClient, request, orderVtex, sellerOrderId) {
367
+ const { documents } = request;
368
+ const { invoiceValue, issuanceDate, invoiceNumber, returnItems } = documents;
369
+ const { items, packageAttachment } = orderVtex;
370
+
371
+ const invoiceNotificationOrderPayload = {
372
+ type: "Input",
373
+ issuanceDate: issuanceDate,
374
+ invoiceNumber: invoiceNumber,
375
+ invoiceValue: invoiceValue,
376
+ invoiceKey: null,
377
+ invoiceUrl: null,
378
+ embeddedInvoice: null,
379
+ courier: "mdlz",
380
+ trackingNumber: invoiceNumber,
381
+ trackingUrl: null,
382
+ dispatchedDate: null,
383
+ items: []
384
+ };
385
+
386
+ // Se agrupan los ítems de la lista returnItems
387
+ const groupReturnedItems = {};
388
+ for (let returnedItem of returnItems) {
389
+ const { sku, quantity } = returnedItem;
390
+ if (!groupReturnedItems.hasOwnProperty(sku)) {
391
+ groupReturnedItems[sku] = quantity;
392
+ } else {
393
+ groupReturnedItems[sku] += quantity;
394
+ }
395
+ }
396
+
397
+ const groupItems = {};
398
+ items.forEach((item, index) => {
399
+ const { id, refId, sellingPrice } = item;
400
+ groupItems[index] = { id, refId, quantity: 0, sellingPrice };
401
+ });
402
+
403
+ // Se valida las modificaciones ocurridas en la orden (adicionar o remover ítems de la orden)
404
+ if (packageAttachment?.packages?.length) {
405
+ for (let packageInfo of packageAttachment.packages) {
406
+ const { type, items } = packageInfo;
407
+ for (let item of items) {
408
+ const { itemIndex, quantity } = item;
409
+ if (groupItems.hasOwnProperty(itemIndex)) {
410
+ // Unidades facturadas
411
+ if (type == 'Output') {
412
+ groupItems[itemIndex].quantity += quantity;
413
+ }
414
+ // Unidades devueltas
415
+ if (type == 'Input') {
416
+ groupItems[itemIndex].quantity -= quantity;
417
+ }
418
+ }
419
+ }
420
+ }
421
+ }
422
+
423
+ // Se recorre en un primer nivel los productos a devolver
424
+ for (let sku in groupReturnedItems) {
425
+ // Se recorre la lista de productos de la orden, para descontar las unidades del producto
426
+ for (let index in groupItems) {
427
+ const { [sku]: qty } = groupReturnedItems;
428
+ const { id, refId, quantity, sellingPrice } = groupItems[index];
429
+ if (sku == refId) {
430
+ if (qty > 0 && quantity > 0) {
431
+ // Si las unidades a devolver es menor o igual a las unidades del ítem, no se necesita buscar en otro ítem de la orden
432
+ if (qty <= quantity) {
433
+ invoiceNotificationOrderPayload.items.push({ id, quantity: qty, price: sellingPrice });
434
+ // Se actualiza a cero las unidades a devolver, para no tener que descontar unidades de otro ítem del mismo producto
435
+ groupReturnedItems[sku] = 0;
436
+ } else {
437
+ // En este caso, se entiende por devuelto todos las unidades del ítem
438
+ groupReturnedItems[sku] = qty - quantity;
439
+ invoiceNotificationOrderPayload.items.push({ id, quantity, price: sellingPrice });
440
+ groupItems[index].quantity = 0;
441
+ }
442
+ }
443
+ }
444
+ }
445
+ }
446
+
447
+ return new Promise(function (resolve, reject) {
448
+ const relativeNotificationUrl = Constants.INVOICE_NOTIFICATION_ORDER.replace("{orderId}", sellerOrderId);
449
+ apiClient.fetch(relativeNotificationUrl, {
450
+ method: "POST",
451
+ data: invoiceNotificationOrderPayload,
452
+ }).then(res => {
453
+ resolve(res)
454
+ }).catch(reject);
455
+ });
456
+ }
457
+
458
+ module.exports = {
459
+ consumer
460
+ };
461
+