dcos-core-monalisav2-latam 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -0
- package/index.js +350 -0
- package/package.json +52 -0
- package/src/auth/handler.js +3 -0
- package/src/common/MondelezCastOrder.js +449 -0
- package/src/common/utils/AuthSecurity.js +46 -0
- package/src/common/utils/account-error-handler.js +279 -0
- package/src/common/utils/account-error-helper.js +231 -0
- package/src/common/utils/account-properties-handler.js +355 -0
- package/src/common/utils/api-response.js +62 -0
- package/src/common/utils/aws-services.js +186 -0
- package/src/common/utils/constants/account-error-codes.json +801 -0
- package/src/common/utils/constants.js +37 -0
- package/src/common/utils/convert/MondelezClientsItemsCast.js +52 -0
- package/src/common/utils/convert/MondelezInventoryItemsCast.js +15 -0
- package/src/common/utils/convert/MondelezOrderStatusCast.js +34 -0
- package/src/common/utils/convert/MondelezPricesItemsCast.js +37 -0
- package/src/common/utils/cron-ftp-get.js +143 -0
- package/src/common/utils/data-tables-helper.js +213 -0
- package/src/common/utils/date-range-calculator.js +113 -0
- package/src/common/utils/delay.js +17 -0
- package/src/common/utils/ftp-sftp.js +320 -0
- package/src/common/utils/logger.js +126 -0
- package/src/common/utils/nodemailerLib.js +61 -0
- package/src/common/utils/product-unit-converter.js +168 -0
- package/src/common/utils/schemas-utils.js +101 -0
- package/src/common/utils/seller-email-sharing-service.js +441 -0
- package/src/common/utils/sftp-utils.js +202 -0
- package/src/common/utils/status.js +15 -0
- package/src/common/utils/util.js +236 -0
- package/src/common/utils/validate-state-order.js +35 -0
- package/src/common/utils/validateProviders.js +67 -0
- package/src/common/utils/validation-data.js +45 -0
- package/src/common/utils/vtex/save-hooks.js +65 -0
- package/src/common/utils/vtex/save-schemas.js +65 -0
- package/src/common/utils/vtex-hook-handler.js +71 -0
- package/src/common/validation/AccountCoordinatesValidation.js +350 -0
- package/src/common/validation/GeneralErrorValidation.js +11 -0
- package/src/common/validation/MainErrorValidation.js +8 -0
- package/src/entities/account.js +639 -0
- package/src/entities/clients.js +104 -0
- package/src/entities/controlprice.js +196 -0
- package/src/entities/controlstock.js +206 -0
- package/src/entities/cron.js +77 -0
- package/src/entities/cronjob.js +71 -0
- package/src/entities/orders.js +195 -0
- package/src/entities/sftp-inbound.js +88 -0
- package/src/entities/sku.js +220 -0
- package/src/entities/taxpromotion.js +249 -0
- package/src/functions/account/account-get.js +262 -0
- package/src/functions/account/account-handler.js +299 -0
- package/src/functions/account/clients.js +10 -0
- package/src/functions/account/index.js +208 -0
- package/src/functions/actions/save-promotions-order-history.js +324 -0
- package/src/functions/affiliates/affiliates-hook-consumer.js +87 -0
- package/src/functions/affiliates/affiliates-hook-producer.js +45 -0
- package/src/functions/clients/clients-audience.js +62 -0
- package/src/functions/clients/clients-consumer.js +648 -0
- package/src/functions/clients/clients-producer.js +362 -0
- package/src/functions/clients/clients-suggested-product-consumer.js +166 -0
- package/src/functions/clients/helpers/suggested-product-mdlz.js +233 -0
- package/src/functions/clients_peru/email.html +129 -0
- package/src/functions/clients_peru/splitfile.js +357 -0
- package/src/functions/clients_peru/updateClients.js +1334 -0
- package/src/functions/clients_peru/utils.js +243 -0
- package/src/functions/cronjobs/cron-jobs-manager.js +40 -0
- package/src/functions/cronjobs/cron-jobs.js +171 -0
- package/src/functions/crons/cron.js +39 -0
- package/src/functions/distributors/distributor-handler.js +81 -0
- package/src/functions/distributors/distributor.js +535 -0
- package/src/functions/distributors/index.js +60 -0
- package/src/functions/financialpolicy/assign-financialpolicy.js +111 -0
- package/src/functions/financialpolicy/get-financialpolicy.js +91 -0
- package/src/functions/financialpolicy/index.js +28 -0
- package/src/functions/inventory/catalog-sync-consumer.js +17 -0
- package/src/functions/inventory/catalog-sync-handler.js +311 -0
- package/src/functions/inventory/inventory-consumer.js +119 -0
- package/src/functions/inventory/inventory-producer.js +197 -0
- package/src/functions/multiPresentation/multipre-queue.js +155 -0
- package/src/functions/multiPresentation/multipres.js +459 -0
- package/src/functions/nodeflow/index.js +83 -0
- package/src/functions/nodeflow/nodeflow-cron.js +200 -0
- package/src/functions/nodeflow/nodeflow-pub.js +203 -0
- package/src/functions/nodeflow/nodeflow-pvt.js +266 -0
- package/src/functions/notifications/download-leads-handler.js +67 -0
- package/src/functions/notifications/new-leads-notification-consumer.js +17 -0
- package/src/functions/notifications/new-leads-notification-handler.js +359 -0
- package/src/functions/notifications/order-status-notification-handler.js +482 -0
- package/src/functions/notifications/promotion-notification-handler.js +193 -0
- package/src/functions/orders/index.js +32 -0
- package/src/functions/orders/orders-cancel-handler.js +74 -0
- package/src/functions/orders/orders-handler.js +280 -0
- package/src/functions/orders/orders-hook-consumer.js +137 -0
- package/src/functions/orders/orders-hook-producer.js +170 -0
- package/src/functions/orders/orders-notifications-handler.js +137 -0
- package/src/functions/orders/orders-status-consumer.js +461 -0
- package/src/functions/orders/orders-status-producer.js +443 -0
- package/src/functions/prices/index.js +75 -0
- package/src/functions/prices/prices-consumer.js +236 -0
- package/src/functions/prices/prices-producer.js +323 -0
- package/src/functions/prices/promotion-and-tax.js +1284 -0
- package/src/functions/routesflow/assign-routeflow-queue.js +77 -0
- package/src/functions/schemas/vtex/handle-schemas.js +102 -0
- package/src/functions/security/process_gas.js +221 -0
- package/src/functions/security/security-handler.js +950 -0
- package/src/functions/sftp/sftp-consumer.js +453 -0
- package/src/functions/sftpIntegrations/processes/redirectServices.js +184 -0
- package/src/functions/sftpIntegrations/processes/validateFileSchema.js +226 -0
- package/src/functions/sftpIntegrations/schemas/credential-schema.js +123 -0
- package/src/functions/sftpIntegrations/schemas/record-schema.js +131 -0
- package/src/functions/sftpIntegrations/schemas/sftp_required_fields.json +3 -0
- package/src/functions/sftpIntegrations/sftp-config-producer.js +112 -0
- package/src/functions/sftpIntegrations/sftp-consumer.js +700 -0
- package/src/functions/sftpIntegrations/test/validateFile.test.js +122 -0
- package/src/functions/sftpIntegrations/utils/connect-dynamo.js +29 -0
- package/src/functions/sftpIntegrations/utils/split-data.js +25 -0
- package/src/functions/utils/index.js +130 -0
- package/src/functions/vtex/vtex-helpers.js +694 -0
- package/src/integrations/accountErrors/AccountErrorManager.js +437 -0
- package/src/integrations/audience/Audience.js +70 -0
- package/src/integrations/financialPolicy/FinancialPolicyApi.js +377 -0
- package/src/integrations/index.js +0 -0
- package/src/integrations/mobilvendor/MobilvendorApi.js +405 -0
- package/src/integrations/productmultipresentation/ProductMultiPresentation.js +200 -0
- package/src/mdlz/auth/SecretManagerApi.js +77 -0
- package/src/mdlz/client/MdlzApi.js +70 -0
- package/src/vtex/clients/ProvidersApi.js +51 -0
- package/src/vtex/clients/VtexApi.js +511 -0
- package/src/vtex/models/VtexOrder.js +87 -0
|
@@ -0,0 +1,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
|
+
|