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,65 @@
|
|
|
1
|
+
const VtexApi = require("../../../vtex/clients/VtexApi");
|
|
2
|
+
const Logger = require("../logger");
|
|
3
|
+
|
|
4
|
+
const handlePutOperation = async (vtexApi, url, data) => {
|
|
5
|
+
const options = {
|
|
6
|
+
method: 'PUT',
|
|
7
|
+
data,
|
|
8
|
+
};
|
|
9
|
+
const response = await vtexApi.fetch(url, options);
|
|
10
|
+
if ((response?.status >= 200 && response?.status < 400) || !response) {
|
|
11
|
+
return {
|
|
12
|
+
status: 200,
|
|
13
|
+
message: "Record created/updated successfully",
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
Logger.error("Failed PUT operation", response);
|
|
17
|
+
throw new Error("Failed PUT operation");
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const handleDeleteOperation = async (vtexApi, url) => {
|
|
21
|
+
const options = {
|
|
22
|
+
method: 'DELETE',
|
|
23
|
+
};
|
|
24
|
+
const response = await vtexApi.fetch(url, options);
|
|
25
|
+
|
|
26
|
+
if ((response?.status >= 200 && response?.status < 400) || !response) {
|
|
27
|
+
return {
|
|
28
|
+
status: 200,
|
|
29
|
+
message: "Record deleted successfully",
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
Logger.error("Failed DELETE operation", response);
|
|
33
|
+
throw new Error("Failed DELETE operation");
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const handleSchemaVtexMD2 = async ({ id, entityName, data, origin, httpMethod }) => {
|
|
37
|
+
if (!id || !origin) {
|
|
38
|
+
Logger.error("Missing required parameters (id or origin).");
|
|
39
|
+
throw new Error("Missing required parameters (id or origin).");
|
|
40
|
+
}
|
|
41
|
+
const { AccountName, AppKey, AppToken } = origin;
|
|
42
|
+
if (!AccountName || !AppKey || !AppToken) {
|
|
43
|
+
Logger.error("Incomplete 'origin' object.");
|
|
44
|
+
throw new Error("Incomplete 'origin' object.");
|
|
45
|
+
}
|
|
46
|
+
const vtexApi = new VtexApi(AccountName, AppKey, AppToken);
|
|
47
|
+
const url = `/dataentities/${entityName}/schemas/${id}`;
|
|
48
|
+
try {
|
|
49
|
+
switch (httpMethod) {
|
|
50
|
+
case 'PUT':
|
|
51
|
+
return await handlePutOperation(vtexApi, url, data);
|
|
52
|
+
case 'DELETE':
|
|
53
|
+
return await handleDeleteOperation(vtexApi, url);
|
|
54
|
+
default:
|
|
55
|
+
return { status: 405, message: `Method ${httpMethod} not allowed to VTEX` };
|
|
56
|
+
}
|
|
57
|
+
} catch (error) {
|
|
58
|
+
Logger.error(`Error during operation ${httpMethod}:`, error.message);
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
module.exports = {
|
|
64
|
+
handleSchemaVtexMD2,
|
|
65
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const ApiResponse = require("./api-response");
|
|
2
|
+
const AccountData = require("../../entities/account");
|
|
3
|
+
const VtexApi = require("../../vtex/clients/VtexApi");
|
|
4
|
+
const Logger = require("./logger");
|
|
5
|
+
|
|
6
|
+
async function handler(event) {
|
|
7
|
+
try {
|
|
8
|
+
const accountName = event.pathParameters?.accountName;
|
|
9
|
+
|
|
10
|
+
if (!accountName) {
|
|
11
|
+
return ApiResponse.response(400, {
|
|
12
|
+
success: false,
|
|
13
|
+
message: "accountName is required in URL path"
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Consultar la configuración de la cuenta en DynamoDB
|
|
18
|
+
const accountConfig = await AccountData.getAccountDataByAccountName(accountName);
|
|
19
|
+
if (!accountConfig) {
|
|
20
|
+
return ApiResponse.response(404, {
|
|
21
|
+
success: false,
|
|
22
|
+
message: `Account ${accountName} not found`
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Validar que tenga credenciales VTEX
|
|
27
|
+
if (!accountConfig.Credentials?.key || !accountConfig.Credentials?.token) {
|
|
28
|
+
return ApiResponse.response(400, {
|
|
29
|
+
success: false,
|
|
30
|
+
message: "VTEX credentials not configured for this account"
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Crear instancia de VtexApi
|
|
35
|
+
const vtexApi = new VtexApi(
|
|
36
|
+
accountConfig.AccountName,
|
|
37
|
+
accountConfig.Credentials.key,
|
|
38
|
+
accountConfig.Credentials.token
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
// Consultar configuración del hook en VTEX
|
|
42
|
+
const hookConfig = await vtexApi.fetch('/orders/hook/config', {
|
|
43
|
+
method: 'GET'
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Formatear respuesta
|
|
47
|
+
return ApiResponse.response(200, {
|
|
48
|
+
success: true,
|
|
49
|
+
data: {
|
|
50
|
+
accountName: accountConfig.AccountName,
|
|
51
|
+
parentAccountName: accountConfig.ParentAccountName,
|
|
52
|
+
hookConfiguration: hookConfig?.data || null
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
} catch (error) {
|
|
57
|
+
Logger.error("Error checking VTEX hook configuration", {
|
|
58
|
+
error: error.message,
|
|
59
|
+
stack: error.stack,
|
|
60
|
+
accountName: event.pathParameters?.accountName
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
return ApiResponse.response(500, {
|
|
64
|
+
success: false,
|
|
65
|
+
message: "Error checking VTEX hook configuration",
|
|
66
|
+
error: error.response?.data?.message || error.message
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = { handler };
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
const VtexApi = require("../../vtex/clients/VtexApi");
|
|
2
|
+
const Logger = require("../utils/logger");
|
|
3
|
+
const GeneralRequiredError = require("./GeneralErrorValidation");
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Clase para validar coordenadas geográficas de accounts en VTEX
|
|
7
|
+
*/
|
|
8
|
+
class AccountCoordinatesValidation {
|
|
9
|
+
constructor(accountConfig) {
|
|
10
|
+
this.accountConfig = accountConfig;
|
|
11
|
+
this.vtexApi = null;
|
|
12
|
+
|
|
13
|
+
Logger.setAccount(accountConfig)
|
|
14
|
+
|
|
15
|
+
// Inicializar VtexApi si tenemos las credenciales
|
|
16
|
+
if (this.accountConfig?.Credentials?.key && this.accountConfig?.Credentials?.token) {
|
|
17
|
+
this.vtexApi = new VtexApi(
|
|
18
|
+
this.accountConfig.AccountName,
|
|
19
|
+
this.accountConfig.Credentials.key,
|
|
20
|
+
this.accountConfig.Credentials.token
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Valida si las coordenadas geográficas están configuradas correctamente
|
|
27
|
+
* @returns {Promise<{isValid: boolean, errors: string[], warnings: string[]}>}
|
|
28
|
+
*/
|
|
29
|
+
async validateCoordinates() {
|
|
30
|
+
const result = {
|
|
31
|
+
isValid: true,
|
|
32
|
+
errors: [],
|
|
33
|
+
warnings: []
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
let shouldValidateDefault = false;
|
|
38
|
+
let shouldValidateListOptions = false;
|
|
39
|
+
|
|
40
|
+
// Determinar qué validaciones necesitamos hacer
|
|
41
|
+
if (this.accountConfig.SetGeoCoordinatesGlobal === true) {
|
|
42
|
+
shouldValidateDefault = true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (this.accountConfig.SetGeoCoordinatesApp === true) {
|
|
46
|
+
shouldValidateListOptions = true;
|
|
47
|
+
// Para SetGeoCoordinatesApp también validamos default porque son independientes
|
|
48
|
+
shouldValidateDefault = true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Si no hay nada que validar, retornar éxito
|
|
52
|
+
if (!shouldValidateDefault && !shouldValidateListOptions) {
|
|
53
|
+
Logger.debug("Both SetGeoCoordinatesGlobal and SetGeoCoordinatesApp are disabled, skipping coordinates validation");
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Validar que country esté configurado para cualquier tipo de validación
|
|
58
|
+
if (!this.accountConfig.CodeCountry || this.accountConfig.CodeCountry.trim() === "") {
|
|
59
|
+
result.isValid = false;
|
|
60
|
+
result.errors.push("CodeCountry property is required when SetGeoCoordinatesGlobal or SetGeoCoordinatesApp is enabled");
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Validar coordenadas por defecto (requerido para ambos casos)
|
|
65
|
+
if (shouldValidateDefault) {
|
|
66
|
+
Logger.debug("Validating default coordinates");
|
|
67
|
+
const defaultCoordinatesValidation = await this.validateDefaultCoordinates();
|
|
68
|
+
if (!defaultCoordinatesValidation.isValid) {
|
|
69
|
+
result.isValid = false;
|
|
70
|
+
result.errors.push(...defaultCoordinatesValidation.errors);
|
|
71
|
+
}
|
|
72
|
+
result.warnings.push(...defaultCoordinatesValidation.warnings);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Validar coordenadas de listOptions si SetGeoCoordinatesApp está habilitado
|
|
76
|
+
if (shouldValidateListOptions) {
|
|
77
|
+
Logger.debug("Validating listOptions coordinates (SetGeoCoordinatesApp = true)");
|
|
78
|
+
const listOptionsValidation = await this.validateListOptionsCoordinates();
|
|
79
|
+
if (!listOptionsValidation.isValid) {
|
|
80
|
+
result.isValid = false;
|
|
81
|
+
result.errors.push(...listOptionsValidation.errors);
|
|
82
|
+
}
|
|
83
|
+
result.warnings.push(...listOptionsValidation.warnings);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
} catch (error) {
|
|
87
|
+
Logger.error("Error during coordinates validation:", error);
|
|
88
|
+
result.isValid = false;
|
|
89
|
+
result.errors.push(`Validation error: ${error.message}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Valida las coordenadas por defecto
|
|
97
|
+
* @returns {Promise<{isValid: boolean, errors: string[], warnings: string[]}>}
|
|
98
|
+
*/
|
|
99
|
+
async validateDefaultCoordinates() {
|
|
100
|
+
const result = {
|
|
101
|
+
isValid: true,
|
|
102
|
+
errors: [],
|
|
103
|
+
warnings: []
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const defaultCoords = this.accountConfig.ConditionsGeoCoordinates?.default;
|
|
107
|
+
|
|
108
|
+
if (!defaultCoords) {
|
|
109
|
+
result.errors.push("Default coordinates are not configured in ConditionsGeoCoordinates.default");
|
|
110
|
+
result.isValid = false;
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const { latitude, longitude } = defaultCoords;
|
|
115
|
+
|
|
116
|
+
// Caso 5: Ignorar validación si las coordenadas están en cero o vacías
|
|
117
|
+
if (this.isCoordinateZeroOrEmpty(latitude) && this.isCoordinateZeroOrEmpty(longitude)) {
|
|
118
|
+
result.warnings.push("Default coordinates are set to (0,0) or empty, skipping validation");
|
|
119
|
+
return result;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Convertir a número si viene como string
|
|
123
|
+
const lat = typeof latitude === 'string' ? parseFloat(latitude) : latitude;
|
|
124
|
+
const lng = typeof longitude === 'string' ? parseFloat(longitude) : longitude;
|
|
125
|
+
|
|
126
|
+
// Validar que las coordenadas sean números válidos
|
|
127
|
+
if (!this.isValidCoordinate(lat) || !this.isValidCoordinate(lng)) {
|
|
128
|
+
result.errors.push("Invalid default coordinates format");
|
|
129
|
+
result.isValid = false;
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Validar coordenadas con VTEX API
|
|
134
|
+
const vtexValidation = await this.validateCoordinatesWithVtex(
|
|
135
|
+
lat,
|
|
136
|
+
lng,
|
|
137
|
+
"default coordinates"
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
if (!vtexValidation.isValid) {
|
|
141
|
+
result.isValid = false;
|
|
142
|
+
result.errors.push(...vtexValidation.errors);
|
|
143
|
+
}
|
|
144
|
+
result.warnings.push(...vtexValidation.warnings);
|
|
145
|
+
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Valida las coordenadas de listOptions cuando SetGeoCoordinatesApp está habilitado
|
|
151
|
+
* @returns {Promise<{isValid: boolean, errors: string[], warnings: string[]}>}
|
|
152
|
+
*/
|
|
153
|
+
async validateListOptionsCoordinates() {
|
|
154
|
+
const result = {
|
|
155
|
+
isValid: true,
|
|
156
|
+
errors: [],
|
|
157
|
+
warnings: []
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const listOptions = this.accountConfig.ConditionsGeoCoordinates?.listOptions;
|
|
161
|
+
|
|
162
|
+
if (!listOptions || !Array.isArray(listOptions)) {
|
|
163
|
+
result.warnings.push("No listOptions found for SetGeoCoordinatesApp validation");
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
for (let i = 0; i < listOptions.length; i++) {
|
|
168
|
+
const option = listOptions[i];
|
|
169
|
+
const geoCoords = option?.geoCoordinates;
|
|
170
|
+
|
|
171
|
+
if (!geoCoords) {
|
|
172
|
+
result.warnings.push(`listOptions[${i}] missing geoCoordinates`);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const { latitude, longitude } = geoCoords;
|
|
177
|
+
|
|
178
|
+
// Caso 5: Ignorar si las coordenadas están en cero o vacías
|
|
179
|
+
if (this.isCoordinateZeroOrEmpty(latitude) && this.isCoordinateZeroOrEmpty(longitude)) {
|
|
180
|
+
result.warnings.push(`listOptions[${i}] coordinates are set to (0,0) or empty, skipping validation`);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Convertir a número si viene como string
|
|
185
|
+
const lat = typeof latitude === 'string' ? parseFloat(latitude) : latitude;
|
|
186
|
+
const lng = typeof longitude === 'string' ? parseFloat(longitude) : longitude;
|
|
187
|
+
|
|
188
|
+
// Validar formato de coordenadas
|
|
189
|
+
if (!this.isValidCoordinate(lat) || !this.isValidCoordinate(lng)) {
|
|
190
|
+
result.errors.push(`Invalid coordinates format in listOptions[${i}]`);
|
|
191
|
+
result.isValid = false;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Validar con VTEX API
|
|
196
|
+
const vtexValidation = await this.validateCoordinatesWithVtex(
|
|
197
|
+
lat,
|
|
198
|
+
lng,
|
|
199
|
+
`listOptions[${i}]`
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
if (!vtexValidation.isValid) {
|
|
203
|
+
result.isValid = false;
|
|
204
|
+
result.errors.push(...vtexValidation.errors.map(error =>
|
|
205
|
+
`listOptions[${i}]: ${error}`
|
|
206
|
+
));
|
|
207
|
+
}
|
|
208
|
+
result.warnings.push(...vtexValidation.warnings.map(warning =>
|
|
209
|
+
`listOptions[${i}]: ${warning}`
|
|
210
|
+
));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Valida coordenadas usando la API de regiones de VTEX
|
|
218
|
+
* @param {number} latitude - Latitud
|
|
219
|
+
* @param {number} longitude - Longitud
|
|
220
|
+
* @param {string} context - Contexto para logging
|
|
221
|
+
* @returns {Promise<{isValid: boolean, errors: string[], warnings: string[]}>}
|
|
222
|
+
*/
|
|
223
|
+
async validateCoordinatesWithVtex(latitude, longitude, context = "") {
|
|
224
|
+
const result = {
|
|
225
|
+
isValid: true,
|
|
226
|
+
errors: [],
|
|
227
|
+
warnings: []
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
if (!this.vtexApi) {
|
|
231
|
+
result.errors.push("VTEX API credentials not available for coordinates validation");
|
|
232
|
+
result.isValid = false;
|
|
233
|
+
return result;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
const country = this.accountConfig.CodeCountry;
|
|
238
|
+
const geoCoordinates = `${longitude}%3B${latitude}`; // URL encoded format: lng%3Blat
|
|
239
|
+
const salesChannel = this.accountConfig.SalesChannel || "1";
|
|
240
|
+
|
|
241
|
+
Logger.debug(`Validating coordinates ${context}:`, {
|
|
242
|
+
country,
|
|
243
|
+
geoCoordinates,
|
|
244
|
+
salesChannel,
|
|
245
|
+
accountName: this.accountConfig.AccountName
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Llamada a la API de regiones de VTEX usando formato público
|
|
249
|
+
const response = await this.vtexApi.fetch(
|
|
250
|
+
`/checkout/pub/regions?country=${country}&geoCoordinates=${geoCoordinates}&sc=${salesChannel}`,
|
|
251
|
+
{
|
|
252
|
+
method: "GET"
|
|
253
|
+
},
|
|
254
|
+
false // printLog = false para evitar logs de error innecesarios
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
if (!response || response.status !== 200) {
|
|
258
|
+
result.errors.push(`VTEX regions API returned status ${response?.status || 'unknown'} for ${context}`);
|
|
259
|
+
result.isValid = false;
|
|
260
|
+
return result;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const regions = response.data;
|
|
264
|
+
|
|
265
|
+
// Verificar que la respuesta contenga información de sellers
|
|
266
|
+
if (!regions || !Array.isArray(regions) || regions.length === 0) {
|
|
267
|
+
result.errors.push(`No regions found for coordinates ${context} (${latitude}, ${longitude})`);
|
|
268
|
+
result.isValid = false;
|
|
269
|
+
return result;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Buscar si alguna región contiene el AccountName como seller
|
|
273
|
+
let sellerFound = false;
|
|
274
|
+
let availableSellers = [];
|
|
275
|
+
|
|
276
|
+
for (const region of regions) {
|
|
277
|
+
if (region.sellers && Array.isArray(region.sellers)) {
|
|
278
|
+
const sellers = region.sellers || [];
|
|
279
|
+
availableSellers.push(...sellers.map(seller => seller.id));
|
|
280
|
+
const matchingSeller = sellers.find(seller => {
|
|
281
|
+
return seller.id && seller.id === this.accountConfig.AccountName;
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
if (matchingSeller) {
|
|
285
|
+
sellerFound = true;
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (!sellerFound) {
|
|
292
|
+
const uniqueSellers = [...new Set(availableSellers)];
|
|
293
|
+
result.errors.push(
|
|
294
|
+
`Account '${this.accountConfig.AccountName}' not found as seller for ${context} (${latitude}, ${longitude}). ` +
|
|
295
|
+
`Available sellers: ${uniqueSellers.length > 0 ? uniqueSellers.join(', ') : 'none'}`
|
|
296
|
+
);
|
|
297
|
+
result.isValid = false;
|
|
298
|
+
} else {
|
|
299
|
+
Logger.debug(`✓ Coordinates ${context} validated successfully for account ${this.accountConfig.AccountName}`);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
} catch (error) {
|
|
303
|
+
Logger.error(`Error validating coordinates ${context} with VTEX:`, error);
|
|
304
|
+
result.errors.push(`Error validating ${context}: ${error.message}`);
|
|
305
|
+
result.isValid = false;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return result;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Verifica si un valor es una coordenada válida
|
|
313
|
+
* @param {any} coordinate - Valor a validar
|
|
314
|
+
* @returns {boolean}
|
|
315
|
+
*/
|
|
316
|
+
isValidCoordinate(coordinate) {
|
|
317
|
+
return (
|
|
318
|
+
typeof coordinate === 'number' &&
|
|
319
|
+
!isNaN(coordinate) &&
|
|
320
|
+
isFinite(coordinate)
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Verifica si una coordenada es cero o está vacía (Caso 5)
|
|
326
|
+
* @param {any} coordinate - Valor a validar
|
|
327
|
+
* @returns {boolean}
|
|
328
|
+
*/
|
|
329
|
+
isCoordinateZeroOrEmpty(coordinate) {
|
|
330
|
+
return (
|
|
331
|
+
coordinate === 0 || // número 0
|
|
332
|
+
coordinate === "0" || // string "0"
|
|
333
|
+
coordinate === "" || // string vacío
|
|
334
|
+
coordinate === null || // null
|
|
335
|
+
coordinate === undefined // undefined
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Método estático para validar coordenadas de un account
|
|
341
|
+
* @param {Object} accountConfig - Configuración del account
|
|
342
|
+
* @returns {Promise<{isValid: boolean, errors: string[], warnings: string[]}>}
|
|
343
|
+
*/
|
|
344
|
+
static async validate(accountConfig) {
|
|
345
|
+
const validator = new AccountCoordinatesValidation(accountConfig);
|
|
346
|
+
return await validator.validateCoordinates();
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
module.exports = AccountCoordinatesValidation;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const MainErrorValidation = require("./MainErrorValidation");
|
|
2
|
+
|
|
3
|
+
class GeneralErrorValidation extends MainErrorValidation {
|
|
4
|
+
constructor(property) {
|
|
5
|
+
super(`${property}`);
|
|
6
|
+
this.name = "GeneralErrorValidation";
|
|
7
|
+
this.property = property;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
module.exports = GeneralErrorValidation;
|