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,443 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const AWSServices = require("../../common/utils/aws-services");
|
|
3
|
+
const ApiResponse = require("../../common/utils/api-response");
|
|
4
|
+
const AccountData = require("../../entities/account");
|
|
5
|
+
const ClientData = require("../../entities/clients");
|
|
6
|
+
const OrderData = require("../../entities/orders");
|
|
7
|
+
const SkuData = require("../../entities/sku");
|
|
8
|
+
const VtexApi = require("../../vtex/clients/VtexApi");
|
|
9
|
+
const Constants = require("../../common/utils/constants");
|
|
10
|
+
const DistributorData = require("../distributors/distributor");
|
|
11
|
+
const Status = require("../../common/utils/status");
|
|
12
|
+
const Logger = require("../../common/utils/logger");
|
|
13
|
+
|
|
14
|
+
const ORDER_STATUS_QUEUE_URL = process.env.ORDER_STATUS_QUEUE_URL;
|
|
15
|
+
const LIMIT_ITEMS_TO_PROCESS = process?.env?.LIMIT_ITEMS_TO_PROCESS || 150;
|
|
16
|
+
const isArrayEmpty = (arr) => !Array.isArray(arr) || arr.length === 0;
|
|
17
|
+
var totalCHangesDuplicates = 0;
|
|
18
|
+
|
|
19
|
+
const producer = async (event) => {
|
|
20
|
+
let statusCode = 202;
|
|
21
|
+
let message;
|
|
22
|
+
|
|
23
|
+
const client_id = event?.requestContext?.authorizer?.claims?.client_id;
|
|
24
|
+
Logger.log(JSON.stringify(JSON.parse(event.body)), client_id);
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
// Validacon de variables iniciales
|
|
28
|
+
let listData = await validData({ event: event });
|
|
29
|
+
|
|
30
|
+
if (listData.errors.length === 0) {
|
|
31
|
+
|
|
32
|
+
const dataSend = {
|
|
33
|
+
an: listData?.data?.account?.AccountName,
|
|
34
|
+
key: listData?.data?.account?.Credentials?.key,
|
|
35
|
+
token: listData?.data?.account?.Credentials?.token,
|
|
36
|
+
request: listData?.data?.request,
|
|
37
|
+
orderId: listData?.data?.sellerOrderId,
|
|
38
|
+
SetValueInvoiceOrderForced: listData?.data?.account?.SetValueInvoiceOrderForced
|
|
39
|
+
};
|
|
40
|
+
await AWSServices.sendSQSMessage(ORDER_STATUS_QUEUE_URL, dataSend);
|
|
41
|
+
|
|
42
|
+
message = "Message accepted!";
|
|
43
|
+
} else {
|
|
44
|
+
// con errores
|
|
45
|
+
return ApiResponse.response(404, { errors: listData.errors });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
} catch (error) {
|
|
49
|
+
Logger.error("Error order status producer: ", error);
|
|
50
|
+
message = error;
|
|
51
|
+
statusCode = 500;
|
|
52
|
+
}
|
|
53
|
+
return ApiResponse.response(statusCode, message);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const validData = async ({ event = null }) => {
|
|
57
|
+
let errorInitial = await validInitial({ event: event });
|
|
58
|
+
if (errorInitial.errors.length === 0) {
|
|
59
|
+
let resData = { data: {}, errors: [] };
|
|
60
|
+
let request = event.body ? JSON.parse(event.body) : null;
|
|
61
|
+
|
|
62
|
+
resData.data.account = errorInitial?.data?.account;
|
|
63
|
+
resData.data.sellerOrderId = errorInitial?.data?.sellerOrderId;
|
|
64
|
+
resData.data.request = errorInitial?.data?.request;
|
|
65
|
+
|
|
66
|
+
// Validacion errores changes y documents
|
|
67
|
+
const apiClient = new VtexApi(errorInitial?.data?.account?.AccountName, errorInitial?.data?.account?.Credentials?.key, errorInitial?.data?.account?.Credentials?.token);
|
|
68
|
+
const orderClientVtexResponse = await apiClient.fetch(Constants.GET_ORDER.replace("{orderId}", errorInitial?.data?.sellerOrderId), {
|
|
69
|
+
method: "GET",
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (orderClientVtexResponse?.data?.status == 'cancel' || orderClientVtexResponse?.data?.status == 'canceled') {
|
|
73
|
+
resData.errors = [...resData.errors, 'order canceled'];
|
|
74
|
+
return resData;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (request?.documents?.type == 'return') {
|
|
78
|
+
// Se valida la información de los datos de devolución de la orden
|
|
79
|
+
const errors = await validReturnedItems(request, orderClientVtexResponse);
|
|
80
|
+
resData.errors = [...errors];
|
|
81
|
+
} else {
|
|
82
|
+
let errorChanges = await validChanges({ event: event, orderClientVtexResponse: orderClientVtexResponse, account: errorInitial?.data?.account });
|
|
83
|
+
let errorDocuments = await validDocuments({ event: event, orderClientVtexResponse: orderClientVtexResponse });
|
|
84
|
+
|
|
85
|
+
if (errorChanges.errors.length === 0 && resData?.data?.request?.changes?.itemsRemoved) {
|
|
86
|
+
resData.data.request.changes.itemsRemoved = errorChanges?.itemsRemoved;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (totalCHangesDuplicates > 0 && resData?.data?.request?.documents?.invoiceValue) {
|
|
90
|
+
resData.data.request.documents.invoiceValue = (parseFloat(resData.data.request.documents.invoiceValue) - parseFloat(totalCHangesDuplicates));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
for (var i = 0; i < errorChanges.errors.length; i++) {
|
|
94
|
+
resData.errors = [...resData.errors, errorChanges.errors[i]];
|
|
95
|
+
}
|
|
96
|
+
for (var i = 0; i < errorDocuments.length; i++) {
|
|
97
|
+
resData.errors = [...resData.errors, errorDocuments[i]];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return resData;
|
|
102
|
+
} else { // errores iniciales
|
|
103
|
+
return { data: {}, errors: errorInitial.errors };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const validInitial = async ({ event = null }) => {
|
|
108
|
+
let errors = { errors: [], data: {} }
|
|
109
|
+
if (event) {
|
|
110
|
+
let request = event.body ? JSON.parse(event.body) : null;
|
|
111
|
+
if (!request) {
|
|
112
|
+
Logger.error("No body was found: ", event.body);
|
|
113
|
+
errors.errors = [...errors.errors, "No body was found"];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
errors.data.request = request;
|
|
117
|
+
|
|
118
|
+
const clientId = event?.requestContext?.authorizer?.claims?.client_id;
|
|
119
|
+
const scope = event?.requestContext?.authorizer?.claims?.scope;
|
|
120
|
+
const pathParameters = event.pathParameters;
|
|
121
|
+
|
|
122
|
+
if (!pathParameters) {
|
|
123
|
+
errors.errors = [...errors.errors, "Payload request no valid."];
|
|
124
|
+
}
|
|
125
|
+
const sellerOrderId = pathParameters?.orderId;
|
|
126
|
+
|
|
127
|
+
if (!sellerOrderId) {
|
|
128
|
+
Logger.error("Parameter order id not found: ", sellerOrderId);
|
|
129
|
+
errors.errors = [...errors.errors, "Order id no specified."];
|
|
130
|
+
} else {
|
|
131
|
+
errors.data.sellerOrderId = sellerOrderId;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
const order = await OrderData.getOrderDataByOrderId(sellerOrderId);
|
|
136
|
+
if (!order || isArrayEmpty(order)) {
|
|
137
|
+
errors.errors = [...errors.errors, "Order not found"];
|
|
138
|
+
}
|
|
139
|
+
const orderAccountName = order[0]?.AccountNameForOrder;
|
|
140
|
+
|
|
141
|
+
if (!event?.internalService) {
|
|
142
|
+
if (!scope?.includes("admin")) {
|
|
143
|
+
const validateAccount = await ClientData.validateAccount(clientId, orderAccountName);
|
|
144
|
+
if (!validateAccount) {
|
|
145
|
+
errors.errors = [...errors.errors, "Invalid credentials for Account Name."];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (orderAccountName) {
|
|
151
|
+
const account = await AccountData.getAccountDataByAccountName(orderAccountName);
|
|
152
|
+
if (!account) {
|
|
153
|
+
errors.errors = [...errors.errors, "Account config not found"];
|
|
154
|
+
} else {
|
|
155
|
+
errors.data.account = account;
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
errors.errors = [...errors.errors, "Account config not found"];
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return errors;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const validChanges = async ({ event = null, orderClientVtexResponse = null, account = null }) => {
|
|
166
|
+
let errors = [], itemsRemoved = [];
|
|
167
|
+
let request = event.body ? JSON.parse(event.body) : null;
|
|
168
|
+
const pathParameters = event.pathParameters;
|
|
169
|
+
const sellerOrderId = pathParameters?.orderId;
|
|
170
|
+
const changes = request?.changes;
|
|
171
|
+
if (event && changes && typeof changes == 'object') {
|
|
172
|
+
|
|
173
|
+
if (changes && changes.discountValue && changes.discountValue < 0) {
|
|
174
|
+
errors = [...errors, "Discount value not allowed."];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (orderClientVtexResponse.status >= 200 && orderClientVtexResponse.status < 300) {
|
|
178
|
+
const packages = null;
|
|
179
|
+
|
|
180
|
+
if (typeof packages == 'object' && packages && packages.length > 0) {
|
|
181
|
+
errors = [...errors, "order already has changes applied."];
|
|
182
|
+
} else {
|
|
183
|
+
let skuRefUsed = account?.SkuRefUsed;
|
|
184
|
+
if (typeof skuRefUsed !== "boolean") {
|
|
185
|
+
Logger.error("Sku or ReferenceCode filter not defined, use default: ", skuRefUsed);
|
|
186
|
+
skuRefUsed = true;
|
|
187
|
+
}
|
|
188
|
+
let newItemsToChangeArray = [], itemsToChange = request?.changes?.itemsRemoved;
|
|
189
|
+
|
|
190
|
+
if (itemsToChange && typeof itemsToChange == 'object') {
|
|
191
|
+
for (let item of itemsToChange) {
|
|
192
|
+
if (item.sku) {
|
|
193
|
+
let skuData = null;
|
|
194
|
+
//Si esta activado el manejo de sku por código de distribuidor
|
|
195
|
+
try {
|
|
196
|
+
const skuDistributorManagement = account?.SkuDistributorManagement || false;
|
|
197
|
+
item.sku = await DistributorData.getDistributorByErpCode(account?.AccountName, item?.sku, skuDistributorManagement);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
Logger.error("Error al obtener distribuidor por sku:", error);
|
|
200
|
+
}
|
|
201
|
+
if (skuRefUsed) {
|
|
202
|
+
skuData = await SkuData.getSkuByParentAccountNameAndSku(account?.ParentAccountName, item?.sku);
|
|
203
|
+
} else {
|
|
204
|
+
skuData = await SkuData.getSkuByParentAccountNameAndEan(account?.ParentAccountName, item?.sku);
|
|
205
|
+
if (!skuData || skuData.length === 0) {
|
|
206
|
+
Logger.error("Not found sku: ", item, ". Db data:", skuData);
|
|
207
|
+
skuData = null;
|
|
208
|
+
} else if (skuData[0]) {
|
|
209
|
+
skuData = skuData[0];
|
|
210
|
+
} else {
|
|
211
|
+
skuData = null;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
let itemOrderVtex = null;
|
|
215
|
+
if (!skuData) {
|
|
216
|
+
Logger.error("Not found sku: ", item, ". Db data:", skuData);
|
|
217
|
+
errors = [...errors, `Sku ${item.sku} not found`];
|
|
218
|
+
} else {
|
|
219
|
+
itemOrderVtex = orderClientVtexResponse?.data?.items?.find(
|
|
220
|
+
(element) => Number(element?.id) === skuData?.SkuId
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
if (itemOrderVtex) {
|
|
224
|
+
if (itemOrderVtex?.quantity < item?.quantity) {
|
|
225
|
+
Logger.error("Not found sku: ", item, ". Vtex data:", itemOrderVtex, ". Sku data: ", skuData);
|
|
226
|
+
// errors= [...errors, `Sku ${item.sku} quantity is greater than the quantity in the Vtex Order ${sellerOrderId}`];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
} else {
|
|
230
|
+
Logger.error("Not found sku: ", item, ". Vtex data:", itemOrderVtex, ". Sku data: ", skuData);
|
|
231
|
+
errors = [...errors, `Sku ${item.sku} not found in Vtex Order ${sellerOrderId}`];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (!item?.quantity) {
|
|
236
|
+
errors = [...errors, `Sku ${item.sku} quantity is required.`];
|
|
237
|
+
}
|
|
238
|
+
if (item?.price === null) {
|
|
239
|
+
errors = [...errors, `Sku ${item.sku} price is required.`];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (skuData?.SkuId && item?.quantity) {
|
|
243
|
+
newItemsToChangeArray = [...newItemsToChangeArray, { id: skuData?.SkuId, price: item.price, quantity: item.quantity }]
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
} else {
|
|
247
|
+
Logger.error("Not found sku: ", item);
|
|
248
|
+
errors = [...errors, `Sku ${JSON.stringify(item)} not found`];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (itemsToChange && typeof itemsToChange == 'object' && itemsToChange.length === newItemsToChangeArray.length) {
|
|
254
|
+
itemsRemoved = newItemsToChangeArray;
|
|
255
|
+
} else if (itemsToChange && typeof itemsToChange == 'object') {
|
|
256
|
+
Logger.error("Error in itemsRemoved: ", request?.changes?.itemsRemoved, newItemsToChangeArray);
|
|
257
|
+
errors = [...errors, `Remove items error ${JSON.stringify({ itemsRemove: request?.changes?.itemsRemoved, relations: newItemsToChangeArray })}`];
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return { errors: errors, itemsRemoved: itemsRemoved };
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const validDocuments = async ({ event = null, orderClientVtexResponse = null }) => {
|
|
267
|
+
let errors = [];
|
|
268
|
+
let request = event.body ? JSON.parse(event.body) : null;
|
|
269
|
+
const documentI = request?.documents;
|
|
270
|
+
if (event && documentI) {
|
|
271
|
+
|
|
272
|
+
if (documentI && documentI.invoiceValue && documentI.invoiceValue <= 0) {
|
|
273
|
+
errors = [...errors, "Invoice value not allowed."];
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Si existe documents, validar y corregir el formato de fecha
|
|
277
|
+
if (documentI?.issuanceDate) {
|
|
278
|
+
try {
|
|
279
|
+
const date = new Date(documentI.issuanceDate);
|
|
280
|
+
if (isNaN(date.getTime())) {
|
|
281
|
+
request.documents.issuanceDate = new Date().toISOString();
|
|
282
|
+
} else {
|
|
283
|
+
request.documents.issuanceDate = date.toISOString();
|
|
284
|
+
}
|
|
285
|
+
} catch (error) {
|
|
286
|
+
request.documents.issuanceDate = new Date().toISOString();
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (orderClientVtexResponse.status >= 200 && orderClientVtexResponse.status < 300) {
|
|
291
|
+
totalCHangesDuplicates = getTotalChangesDuplicate({ order: orderClientVtexResponse?.data });
|
|
292
|
+
let totalInvoiceAddDpCg = (parseFloat(orderClientVtexResponse?.data?.value) + parseFloat(totalCHangesDuplicates));
|
|
293
|
+
if (documentI &&
|
|
294
|
+
documentI.invoiceValue &&
|
|
295
|
+
documentI.invoiceValue > totalInvoiceAddDpCg) {
|
|
296
|
+
errors = [...errors, "Invoice value is greater than the value in the Vtex Order"];
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
let totalInvoiceValue = 0;
|
|
300
|
+
const packages = orderClientVtexResponse?.data.packageAttachment?.packages || [];
|
|
301
|
+
if (packages && typeof packages == 'object') {
|
|
302
|
+
for (let pkg of packages) {
|
|
303
|
+
if (pkg.type === "Output") {
|
|
304
|
+
totalInvoiceValue += pkg.invoiceValue;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const pendingInvoiceValue = (parseFloat(totalInvoiceAddDpCg) - parseFloat(totalInvoiceValue));
|
|
310
|
+
if ((documentI && documentI.invoiceValue && documentI.invoiceValue > pendingInvoiceValue) || pendingInvoiceValue <= 0) {
|
|
311
|
+
errors = [...errors, "Invoice value is greater than the pending value to be invoiced in the Vtex Order"];
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return errors;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Valida que los datos de devolución concuerde con la información de la orden en VTEX.
|
|
320
|
+
* @param {*} request Datos enviados en la petición a la función Lambda.
|
|
321
|
+
* @param {*} orderClientVtexResponse Datos de la orden en VTEX.
|
|
322
|
+
* @returns
|
|
323
|
+
*/
|
|
324
|
+
const validReturnedItems = async (request, orderClientVtexResponse) => {
|
|
325
|
+
const { invoiceValue, returnItems } = request.documents;
|
|
326
|
+
|
|
327
|
+
if (returnItems.length == 0) {
|
|
328
|
+
return [`Return items must have at least one item`];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Se consulta las propiedades requeridas de la orden en VTEX, para luego agruparlas
|
|
332
|
+
const { status, items, packageAttachment } = orderClientVtexResponse?.data;
|
|
333
|
+
|
|
334
|
+
// Se valida si la orden se encuentra en estado Cancelado
|
|
335
|
+
if ([Status.CANCEL, Status.CANCELED].includes(status)) {
|
|
336
|
+
return [`Order is Canceled`];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Se verifica si la orden se encuentra en estado facturado
|
|
340
|
+
if (status !== Status.INVOICED) {
|
|
341
|
+
return [`Order isn't in status Invoiced (${status})`];
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Se agrupan los ítems de la lista returnItems
|
|
345
|
+
const groupReturnedItems = {};
|
|
346
|
+
for (let returnedItem of returnItems) {
|
|
347
|
+
const { sku, quantity } = returnedItem;
|
|
348
|
+
if (!groupReturnedItems.hasOwnProperty(sku)) {
|
|
349
|
+
groupReturnedItems[sku] = quantity;
|
|
350
|
+
} else {
|
|
351
|
+
groupReturnedItems[sku] += quantity;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
const groupItems = {};
|
|
356
|
+
items.forEach((item, index) => {
|
|
357
|
+
const { id, refId, sellingPrice } = item;
|
|
358
|
+
groupItems[index] = { id, refId, quantity: 0, sellingPrice };
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// Se valida las modificaciones ocurridas en la orden (adicionar o remover ítems de la orden)
|
|
362
|
+
if (packageAttachment?.packages?.length) {
|
|
363
|
+
for (let packageInfo of packageAttachment.packages) {
|
|
364
|
+
const { type, items } = packageInfo;
|
|
365
|
+
for (let item of items) {
|
|
366
|
+
const { itemIndex, quantity } = item;
|
|
367
|
+
if (groupItems.hasOwnProperty(itemIndex)) {
|
|
368
|
+
// Unidades facturadas
|
|
369
|
+
if (type == 'Output') {
|
|
370
|
+
groupItems[itemIndex].quantity += quantity;
|
|
371
|
+
}
|
|
372
|
+
// Unidades devueltas
|
|
373
|
+
if (type == 'Input') {
|
|
374
|
+
groupItems[itemIndex].quantity -= quantity;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Se obtiene el valor máximo que se puede retornar, y se agrupan las cantidades del producto
|
|
382
|
+
let maxReturned = 0, skuItems = {};
|
|
383
|
+
for (let index in groupItems) {
|
|
384
|
+
const { refId, quantity, sellingPrice } = groupItems[index];
|
|
385
|
+
maxReturned += (quantity * sellingPrice);
|
|
386
|
+
if (!skuItems.hasOwnProperty(refId)) {
|
|
387
|
+
skuItems[refId] = quantity;
|
|
388
|
+
} else {
|
|
389
|
+
skuItems[refId] += quantity;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Se valida que las unidades a retornar del producto no sea mayor a las unidades que se compraron
|
|
394
|
+
let errors = [];
|
|
395
|
+
for (let sku in groupReturnedItems) {
|
|
396
|
+
const { [sku]: qty } = groupReturnedItems;
|
|
397
|
+
if (skuItems.hasOwnProperty(sku)) {
|
|
398
|
+
const { [sku]: quantity } = skuItems;
|
|
399
|
+
if (qty == 0) {
|
|
400
|
+
errors.push(`Units for SKU ${sku} must be greater than zero`);
|
|
401
|
+
} else if (qty > quantity) {
|
|
402
|
+
errors.push(`Units for SKU ${sku} (${qty}) is greater than the buyed units (${quantity})`);
|
|
403
|
+
}
|
|
404
|
+
} else {
|
|
405
|
+
errors.push(`SKU ${sku} not found in order`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return errors;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Total de cambios con duplicidad
|
|
414
|
+
**/
|
|
415
|
+
const getTotalChangesDuplicate = ({ order = null }) => {
|
|
416
|
+
if (order) {
|
|
417
|
+
let totalChangesDuplicate = 0;
|
|
418
|
+
let changesDuplicate = [];
|
|
419
|
+
let reasonChanges = [];
|
|
420
|
+
let listChange = order?.changesAttachment?.changesData ?? [];
|
|
421
|
+
|
|
422
|
+
for (var i = 0; i < listChange.length; i++) {
|
|
423
|
+
let nameValue = `${listChange[i].reason}${listChange[i].discountValue}-${listChange[i].itemsRemoved?.map(it => `${it.id}-${it.quantity}-${it.price}`)?.join('|')}`;
|
|
424
|
+
if (!reasonChanges.includes(nameValue) && listChange[i]?.itemsRemoved?.length > 0) {
|
|
425
|
+
reasonChanges = [...reasonChanges, nameValue];
|
|
426
|
+
} else if (listChange[i]?.itemsRemoved?.length > 0) {
|
|
427
|
+
changesDuplicate = [...changesDuplicate, listChange[i]];
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
for (var i = 0; i < changesDuplicate.length; i++) {
|
|
432
|
+
totalChangesDuplicate += parseFloat(changesDuplicate[i]?.discountValue);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return totalChangesDuplicate;
|
|
436
|
+
} else {
|
|
437
|
+
return 0;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
module.exports = {
|
|
442
|
+
producer,
|
|
443
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
|
|
2
|
+
const ApiResponse = require("../../common/utils/api-response");
|
|
3
|
+
const promotionAndTax = require("./promotion-and-tax");
|
|
4
|
+
const helpperVtex = require("../vtex/vtex-helpers");
|
|
5
|
+
|
|
6
|
+
module.exports.handler= async (req,res)=>{
|
|
7
|
+
const resource= req?.resource ?? null;
|
|
8
|
+
const method= req?.httpMethod ? String(req?.httpMethod).toUpperCase() : null;
|
|
9
|
+
|
|
10
|
+
if(resource && method){
|
|
11
|
+
switch(resource){
|
|
12
|
+
case "/api/rnb/pvt/calculatorconfiguration":
|
|
13
|
+
switch(method){
|
|
14
|
+
case "POST":
|
|
15
|
+
return await promotionAndTax?.createorupdate(req,res);
|
|
16
|
+
default:
|
|
17
|
+
return ApiResponse.response(400, {error: "error method!."});
|
|
18
|
+
}
|
|
19
|
+
break;
|
|
20
|
+
case "/api/rnb/pvt/{type}/calculatorconfiguration":
|
|
21
|
+
switch(method){
|
|
22
|
+
case "GET":
|
|
23
|
+
return await promotionAndTax?.gettaxesorpromotions(req,res);
|
|
24
|
+
default:
|
|
25
|
+
return ApiResponse.response(400, {error: "error method!."});
|
|
26
|
+
}
|
|
27
|
+
break;
|
|
28
|
+
case "/api/rnb/pvt/calculatorconfiguration/{idCalculatorConfiguration}":
|
|
29
|
+
switch(method){
|
|
30
|
+
case "GET":
|
|
31
|
+
return await promotionAndTax?.gettaxorpromotion(req,res);
|
|
32
|
+
default:
|
|
33
|
+
return ApiResponse.response(400, {error: "error method!."});
|
|
34
|
+
}
|
|
35
|
+
break;
|
|
36
|
+
case "/api/rnb/pvt/archive/calculatorconfiguration/{idCalculatorConfiguration}":
|
|
37
|
+
switch(method){
|
|
38
|
+
case "POST":
|
|
39
|
+
return await promotionAndTax?.archivetaxorpromotion(req,res);
|
|
40
|
+
default:
|
|
41
|
+
return ApiResponse.response(400, {error: "error method!."});
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
case "/api/catalog_system/pub/products/search":
|
|
45
|
+
switch(method){
|
|
46
|
+
case "GET":
|
|
47
|
+
return await helpperVtex?.list_products_vtex(req,res);
|
|
48
|
+
default:
|
|
49
|
+
return ApiResponse.response(400, {error: "error method!."});
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
case "/api/catalog_system/pub/category/tree/{categoryLevels}":
|
|
53
|
+
switch(method){
|
|
54
|
+
case "GET":
|
|
55
|
+
return await helpperVtex?.list_categories_vtex(req,res);
|
|
56
|
+
default:
|
|
57
|
+
return ApiResponse.response(400, {error: "error method!."});
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
60
|
+
case "/api/catalog_system/pub/brand/list":
|
|
61
|
+
switch(method){
|
|
62
|
+
case "GET":
|
|
63
|
+
return await helpperVtex?.list_brands_vtex(req,res);
|
|
64
|
+
default:
|
|
65
|
+
return ApiResponse.response(400, {error: "error method!."});
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
|
|
69
|
+
default:
|
|
70
|
+
return ApiResponse.response(400, {error: "error resource!."});
|
|
71
|
+
}
|
|
72
|
+
}else{
|
|
73
|
+
return ApiResponse.response(400, {error: "error resource!."});
|
|
74
|
+
}
|
|
75
|
+
}
|