blackcoffee2 2.1.0 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/.env.example +67 -0
  2. package/CHANGELOG.md +167 -0
  3. package/README.md +1 -3
  4. package/config/database.json +11 -0
  5. package/controllers/admin/AuthController.js +2 -1
  6. package/core/ViewHelper.js +75 -0
  7. package/core/hotReload.js +1 -1
  8. package/data/blackcoffee_admin.db-shm +0 -0
  9. package/data/blackcoffee_admin.db-wal +0 -0
  10. package/includes/adminAuth.js +5 -3
  11. package/includes/sessions.js +1 -1
  12. package/otrack.tar.gz +0 -0
  13. package/package.json +4 -2
  14. package/programatically/initFlow.js +2 -2
  15. package/test-aplicacion.con-logisession/BlackCoffee.js +0 -226
  16. package/test-aplicacion.con-logisession/SSL_SETUP.md +0 -53
  17. package/test-aplicacion.con-logisession/certs/ca-certificate.pem +0 -32
  18. package/test-aplicacion.con-logisession/certs/ca-private-key.pem +0 -52
  19. package/test-aplicacion.con-logisession/certs/certificate-2048.pem +0 -22
  20. package/test-aplicacion.con-logisession/certs/certificate.pem +0 -32
  21. package/test-aplicacion.con-logisession/certs/private-key-2048.pem +0 -28
  22. package/test-aplicacion.con-logisession/certs/private-key.pem +0 -52
  23. package/test-aplicacion.con-logisession/config/iaQueueSetup.js +0 -84
  24. package/test-aplicacion.con-logisession/config/qwen-rules.json +0 -39
  25. package/test-aplicacion.con-logisession/controllers/analyticsController.js +0 -117
  26. package/test-aplicacion.con-logisession/controllers/auth/AdminAuthController.js +0 -142
  27. package/test-aplicacion.con-logisession/controllers/auth/AuthController.js +0 -439
  28. package/test-aplicacion.con-logisession/controllers/auth/AuthViewController.js +0 -223
  29. package/test-aplicacion.con-logisession/controllers/endpointController.js +0 -66
  30. package/test-aplicacion.con-logisession/controllers/example.js +0 -183
  31. package/test-aplicacion.con-logisession/controllers/iaQueueController.js +0 -367
  32. package/test-aplicacion.con-logisession/controllers/queueController.js +0 -206
  33. package/test-aplicacion.con-logisession/controllers/qwenQueueController.js +0 -197
  34. package/test-aplicacion.con-logisession/controllers/test.js +0 -0
  35. package/test-aplicacion.con-logisession/controllers/tracking/EventsNoFinishController.js +0 -78
  36. package/test-aplicacion.con-logisession/controllers/tracking/TrackingController.js +0 -412
  37. package/test-aplicacion.con-logisession/controllers/tracking/TrackingControllerWithLoadModel.js +0 -437
  38. package/test-aplicacion.con-logisession/hooks/admin-hooks.js +0 -20
  39. package/test-aplicacion.con-logisession/hooks/general-hooks.js +0 -97
  40. package/test-aplicacion.con-logisession/hooks/queue-hooks.js +0 -64
  41. package/test-aplicacion.con-logisession/hooks/route-directory-hooks.js +0 -38
  42. package/test-aplicacion.con-logisession/hooks/security-hooks.js +0 -24
  43. package/test-aplicacion.con-logisession/insitu-admin-client/README.md +0 -69
  44. package/test-aplicacion.con-logisession/insitu-admin-client/package.json +0 -23
  45. package/test-aplicacion.con-logisession/insitu-admin-client.js +0 -257
  46. package/test-aplicacion.con-logisession/models/ExampleModel.js +0 -88
  47. package/test-aplicacion.con-logisession/models/QueueJobModel.js +0 -263
  48. package/test-aplicacion.con-logisession/models/TokenModel.js +0 -207
  49. package/test-aplicacion.con-logisession/models/auth/AuthModel.js +0 -66
  50. package/test-aplicacion.con-logisession/models/auth/UserModel.js +0 -189
  51. package/test-aplicacion.con-logisession/models/tracking/CompletedCartModel.js +0 -213
  52. package/test-aplicacion.con-logisession/models/tracking/EventModel.js +0 -366
  53. package/test-aplicacion.con-logisession/models/tracking/EventsNoFinishModel.js +0 -131
  54. package/test-aplicacion.con-logisession/models/tracking/SessionModel.js +0 -360
  55. package/test-aplicacion.con-logisession/models/tracking/SiteFlowModel.js +0 -286
  56. package/test-aplicacion.con-logisession/models/tracking/TokenModel.js +0 -207
  57. package/test-aplicacion.con-logisession/package-lock.json +0 -3313
  58. package/test-aplicacion.con-logisession/package.json +0 -32
  59. package/test-aplicacion.con-logisession/public/blackcoffee-welcome/index.html +0 -1339
  60. package/test-aplicacion.con-logisession/public/css/style.css +0 -64
  61. package/test-aplicacion.con-logisession/public/ejemplo-estatica/index.html +0 -18
  62. package/test-aplicacion.con-logisession/public/ejemplo-estatica/script.js +0 -16
  63. package/test-aplicacion.con-logisession/public/ejemplo-estatica/styles.css +0 -43
  64. package/test-aplicacion.con-logisession/public/images/logo.svg +0 -7
  65. package/test-aplicacion.con-logisession/public/js/main.js +0 -67
  66. package/test-aplicacion.con-logisession/routes/analytics-routes.json +0 -8
  67. package/test-aplicacion.con-logisession/routes/auth-routes.json +0 -98
  68. package/test-aplicacion.con-logisession/routes/blackcoffee-welcome-routes.json +0 -20
  69. package/test-aplicacion.con-logisession/routes/duplicate-test-routes.json.disabled +0 -16
  70. package/test-aplicacion.con-logisession/routes/ejemplo-estatica-routes.json +0 -11
  71. package/test-aplicacion.con-logisession/routes/endpoints-routes.json +0 -8
  72. package/test-aplicacion.con-logisession/routes/ia-queue-routes.json +0 -26
  73. package/test-aplicacion.con-logisession/routes/product-routes.json.disabled +0 -20
  74. package/test-aplicacion.con-logisession/routes/queue-routes.json +0 -32
  75. package/test-aplicacion.con-logisession/routes/qwen-routes.json +0 -14
  76. package/test-aplicacion.con-logisession/routes/static-routes.json +0 -29
  77. package/test-aplicacion.con-logisession/routes/tracking-routes.json +0 -58
  78. package/test-aplicacion.con-logisession/routes/tracking-with-loadmodel-routes.json +0 -51
  79. package/test-aplicacion.con-logisession/utils/dbAdapter.js +0 -88
  80. package/test-aplicacion.con-logisession/utils/qbWrapper.js +0 -4
  81. package/test-aplicacion.con-logisession/utils/queueProcessor.js +0 -305
  82. package/test-aplicacion.con-logisession/utils/qwenRulesService.js +0 -131
  83. package/test-aplicacion.con-logisession/utils/tokenHelper.js +0 -22
  84. package/test-aplicacion.con-logisession/views/auth/dashboard.html +0 -443
  85. package/test-aplicacion.con-logisession/views/auth/forgot-password.html +0 -200
  86. package/test-aplicacion.con-logisession/views/auth/login.html +0 -213
  87. package/test-aplicacion.con-logisession/views/auth/register.html +0 -294
  88. package/test-aplicacion.con-logisession/views/contact/form.html +0 -47
  89. package/test-aplicacion.con-logisession/views/products/index.html +0 -39
@@ -1,207 +0,0 @@
1
- /**
2
- * Modelo para la tabla tokens en el framework JERK
3
- * Implementación del componente MVC TokenModel.js
4
- * Utiliza MariaDB como adaptador de base de datos
5
- */
6
-
7
- const { ModelBase, hooks } = require('insitu-js');
8
- const { getSharedAdapter } = require('../utils/dbAdapter');
9
- const { QueryBuilder } = require('insitu-js');
10
-
11
- class TokenModel extends ModelBase {
12
- constructor(options = {}) {
13
- // Obtener el adaptador centralizado
14
- const adapter = getSharedAdapter();
15
-
16
- super({
17
- ...options,
18
- tableName: options.tableName || 'tokens',
19
- adapter: adapter
20
- });
21
-
22
- // Inicializar QueryBuilder con el adaptador centralizado
23
- this.queryBuilder = new QueryBuilder(adapter, 'tokens');
24
-
25
- // Definir campos del modelo
26
- this.fields = {
27
- id: { type: 'integer', primaryKey: true, autoIncrement: true },
28
- token: { type: 'string', required: true },
29
- created_at: { type: 'datetime', auto: 'create' },
30
- store_id: { type: 'integer' }
31
- };
32
- }
33
-
34
- /**
35
- * Valida un token contra la base de datos
36
- * @param {string} token - Token a validar
37
- * @returns {Promise<boolean>} - True si el token es válido y no revocado, false en caso contrario
38
- */
39
- async validateToken(token) {
40
- if (!token) {
41
- // Disparar hook de validación de token fallida
42
- hooks.doAction('token_validation_failed', { token: token, reason: 'Token vacío o nulo' });
43
- return false;
44
- }
45
-
46
- // Disparar hook de inicio de validación de token
47
- hooks.doAction('token_validation_start', { token: token });
48
-
49
- try {
50
- // Buscar el token en la base de datos usando QueryBuilder
51
- const tokenRecord = await this.queryBuilder
52
- .reset()
53
- .select('*')
54
- .where('token', token)
55
- .first();
56
-
57
- if (tokenRecord) {
58
- // Verificar si el token está revocado
59
- if (tokenRecord.revoked === 1) {
60
- // Disparar hook de validación de token fallida por revocación
61
- hooks.doAction('token_validation_failed', { token: token, reason: 'Token revocado' });
62
- return false;
63
- }
64
-
65
- // Disparar hook de validación de token exitosa
66
- hooks.doAction('token_validation_success', { token: token, tokenRecord: tokenRecord });
67
- return true;
68
- } else {
69
- // Disparar hook de validación de token fallida
70
- hooks.doAction('token_validation_failed', { token: token, reason: 'Token no encontrado en la base de datos' });
71
- return false;
72
- }
73
- } catch (error) {
74
- console.error('[ERROR] TokenModel.validateToken:', error);
75
- // Disparar hook de validación de token fallida por error
76
- hooks.doAction('token_validation_error', { token: token, error: error.message });
77
- return false;
78
- }
79
- }
80
-
81
- /**
82
- * Obtiene un token por su valor
83
- * @param {string} token - Valor del token
84
- * @returns {Promise<Object|null>} - Registro del token o null si no existe
85
- */
86
- async getToken(token) {
87
- if (!token) {
88
- return null;
89
- }
90
-
91
- try {
92
- return await this.queryBuilder
93
- .reset()
94
- .select('*')
95
- .where('token', token)
96
- .first();
97
- } catch (error) {
98
- console.error('[ERROR] TokenModel.getToken:', error);
99
- return null;
100
- }
101
- }
102
-
103
- /**
104
- * Obtiene todos los tokens
105
- * @returns {Promise<Array>} - Lista de todos los tokens
106
- */
107
- async getAllTokens() {
108
- try {
109
- return await this.queryBuilder
110
- .reset()
111
- .select('*')
112
- .get();
113
- } catch (error) {
114
- console.error('[ERROR] TokenModel.getAllTokens:', error);
115
- return [];
116
- }
117
- }
118
-
119
- /**
120
- * Crea un nuevo token
121
- * @param {Object} tokenData - Datos del token
122
- * @returns {Promise<Object>} - Token creado
123
- */
124
- async createToken(tokenData) {
125
- try {
126
- const result = await this.queryBuilder
127
- .reset()
128
- .insert(tokenData);
129
-
130
- // Obtener y devolver el token recién creado
131
- return await this.queryBuilder
132
- .reset()
133
- .select('*')
134
- .where('id', result.insertId)
135
- .first();
136
- } catch (error) {
137
- console.error('[ERROR] TokenModel.createToken:', error);
138
- throw error;
139
- }
140
- }
141
-
142
- /**
143
- * Revoca un token marcándolo como inhabilitado
144
- * @param {string} token - Token a revocar
145
- * @returns {Promise<boolean>} - True si se revocó correctamente
146
- */
147
- async revokeToken(token) {
148
- try {
149
- const result = await this.queryBuilder
150
- .reset()
151
- .update({
152
- revoked: 1,
153
- revoked_at: new Date()
154
- })
155
- .where('token', token);
156
-
157
- return result.affectedRows > 0;
158
- } catch (error) {
159
- console.error(`[ERROR] TokenModel.revokeToken:`, error);
160
- throw error;
161
- }
162
- }
163
-
164
- /**
165
- * Revoca todos los tokens de un usuario
166
- * @param {number} userId - ID del usuario
167
- * @returns {Promise<number>} - Número de tokens revocados
168
- */
169
- async revokeAllUserTokens(userId) {
170
- try {
171
- const result = await this.queryBuilder
172
- .reset()
173
- .update({
174
- revoked: 1,
175
- revoked_at: new Date()
176
- })
177
- .where('user_id', userId);
178
-
179
- return result.affectedRows;
180
- } catch (error) {
181
- console.error(`[ERROR] TokenModel.revokeAllUserTokens:`, error);
182
- throw error;
183
- }
184
- }
185
-
186
- /**
187
- * Verifica si un token está revocado
188
- * @param {string} token - Token a verificar
189
- * @returns {Promise<boolean>} - True si el token está revocado
190
- */
191
- async isTokenRevoked(token) {
192
- try {
193
- const tokenRecord = await this.queryBuilder
194
- .reset()
195
- .select(['revoked'])
196
- .where('token', token)
197
- .first();
198
-
199
- return tokenRecord ? tokenRecord.revoked === 1 : true;
200
- } catch (error) {
201
- console.error(`[ERROR] TokenModel.isTokenRevoked:`, error);
202
- return true; // En caso de error, asumir que está revocado por seguridad
203
- }
204
- }
205
- }
206
-
207
- module.exports = TokenModel;
@@ -1,66 +0,0 @@
1
- /**
2
- * Modelo de autenticación simplificado
3
- * AuthModel.js
4
- */
5
-
6
- const UserModel = require('./UserModel');
7
-
8
- class AuthModel {
9
- constructor() {
10
- this.userModel = new UserModel();
11
- }
12
-
13
- /**
14
- * Autentica un usuario
15
- * @param {string} username - Nombre de usuario o email
16
- * @param {string} password - Contraseña
17
- * @returns {Promise<Object|null>} - Usuario autenticado o null si falla
18
- */
19
- async authenticateUser(username, password) {
20
- try {
21
- return await this.userModel.validateCredentials(username, password);
22
- } catch (error) {
23
- console.error('[ERROR] AuthModel.authenticateUser:', error);
24
- return null;
25
- }
26
- }
27
-
28
- /**
29
- * Registra un nuevo usuario
30
- * @param {Object} userData - Datos del usuario
31
- * @returns {Promise<Object>} - Usuario registrado
32
- */
33
- async registerUser(userData) {
34
- try {
35
- return await this.userModel.createUser(userData);
36
- } catch (error) {
37
- console.error('[ERROR] AuthModel.registerUser:', error);
38
- throw error;
39
- }
40
- }
41
-
42
- /**
43
- * Obtiene un usuario por ID
44
- * @param {number} userId - ID del usuario
45
- * @returns {Promise<Object|null>} - Usuario o null si no existe
46
- */
47
- async getUserById(userId) {
48
- try {
49
- const user = await this.userModel.getUserById(userId);
50
- if (!user) {
51
- return null;
52
- }
53
-
54
- return {
55
- ...user,
56
- roles: [], // No hay roles en esta versión simplificada
57
- capabilities: [] // No hay capabilities en esta versión simplificada
58
- };
59
- } catch (error) {
60
- console.error('[ERROR] AuthModel.getUserById:', error);
61
- return null;
62
- }
63
- }
64
- }
65
-
66
- module.exports = AuthModel;
@@ -1,189 +0,0 @@
1
- /**
2
- * Modelo para la tabla users en el framework JERK
3
- * UserModel.js
4
- */
5
-
6
- const { ModelBase } = require('insitu-js');
7
- const { getSharedAdapter } = require('../../utils/dbAdapter');
8
- const { QueryBuilder } = require('insitu-js');
9
- const bcrypt = require('bcrypt');
10
-
11
- class UserModel extends ModelBase {
12
- constructor(options = {}) {
13
- // Obtener el adaptador centralizado
14
- const adapter = getSharedAdapter();
15
-
16
- super({
17
- ...options,
18
- tableName: options.tableName || 'users',
19
- adapter: adapter
20
- });
21
-
22
- // Inicializar QueryBuilder con el adaptador centralizado
23
- this.queryBuilder = new QueryBuilder(adapter, 'users');
24
-
25
- // Definir campos del modelo
26
- this.fields = {
27
- id: { type: 'integer', primaryKey: true, autoIncrement: true },
28
- username: { type: 'string', required: true, unique: true },
29
- password: { type: 'string', required: true },
30
- email: { type: 'string', required: true, unique: true },
31
- created_at: { type: 'datetime', auto: 'create' },
32
- updated_at: { type: 'datetime', auto: 'update' },
33
- is_active: { type: 'boolean', default: true }
34
- };
35
- }
36
-
37
- /**
38
- * Crea un nuevo usuario con contraseña encriptada
39
- * @param {Object} userData - Datos del usuario
40
- * @returns {Promise<Object>} - Usuario creado
41
- */
42
- async createUser(userData) {
43
- try {
44
- // Encriptar la contraseña
45
- const hashedPassword = await bcrypt.hash(userData.password, 10);
46
-
47
- const userDataWithHashedPassword = {
48
- ...userData,
49
- password: hashedPassword
50
- };
51
-
52
- const result = await this.queryBuilder
53
- .reset()
54
- .insert(userDataWithHashedPassword);
55
-
56
- // Obtener y devolver el usuario recién creado
57
- return await this.queryBuilder
58
- .reset()
59
- .select('*')
60
- .where('id', result.insertId)
61
- .first();
62
- } catch (error) {
63
- console.error('[ERROR] UserModel.createUser:', error);
64
- throw error;
65
- }
66
- }
67
-
68
- /**
69
- * Valida las credenciales de un usuario
70
- * @param {string} username - Nombre de usuario
71
- * @param {string} password - Contraseña sin encriptar
72
- * @returns {Promise<Object|null>} - Usuario si las credenciales son válidas, null si no
73
- */
74
- async validateCredentials(username, password) {
75
- try {
76
- const user = await this.queryBuilder
77
- .reset()
78
- .select('*')
79
- .where(function(qb) {
80
- qb.where('username', username).orWhere('email', username); // Permitir login con email o username
81
- })
82
- .where('is_active', true)
83
- .first();
84
-
85
- if (!user) {
86
- return null;
87
- }
88
-
89
- // Comparar la contraseña encriptada
90
- const isPasswordValid = await bcrypt.compare(password, user.password);
91
-
92
- if (isPasswordValid) {
93
- // No devolver la contraseña en la respuesta
94
- const { password: _, ...userWithoutPassword } = user;
95
- return userWithoutPassword;
96
- } else {
97
- return null;
98
- }
99
- } catch (error) {
100
- console.error('[ERROR] UserModel.validateCredentials:', error);
101
- return null;
102
- }
103
- }
104
-
105
- /**
106
- * Obtiene un usuario por su ID
107
- * @param {number} id - ID del usuario
108
- * @returns {Promise<Object|null>} - Usuario o null si no existe
109
- */
110
- async getUserById(id) {
111
- try {
112
- return await this.queryBuilder
113
- .reset()
114
- .select('*')
115
- .where('id', id)
116
- .first();
117
- } catch (error) {
118
- console.error('[ERROR] UserModel.getUserById:', error);
119
- return null;
120
- }
121
- }
122
-
123
- /**
124
- * Obtiene un usuario por su nombre de usuario o email
125
- * @param {string} identifier - Nombre de usuario o email
126
- * @returns {Promise<Object|null>} - Usuario o null si no existe
127
- */
128
- async getUserByIdentifier(identifier) {
129
- try {
130
- return await this.queryBuilder
131
- .reset()
132
- .select('*')
133
- .where(function(qb) {
134
- qb.where('username', identifier).orWhere('email', identifier);
135
- })
136
- .first();
137
- } catch (error) {
138
- console.error('[ERROR] UserModel.getUserByIdentifier:', error);
139
- return null;
140
- }
141
- }
142
-
143
- /**
144
- * Actualiza un usuario
145
- * @param {number} id - ID del usuario
146
- * @param {Object} updateData - Datos a actualizar
147
- * @returns {Promise<Object>} - Usuario actualizado
148
- */
149
- async updateUser(id, updateData) {
150
- try {
151
- // Si se está actualizando la contraseña, encriptarla
152
- if (updateData.password) {
153
- updateData.password = await bcrypt.hash(updateData.password, 10);
154
- }
155
-
156
- await this.queryBuilder
157
- .reset()
158
- .update(updateData)
159
- .where('id', id);
160
-
161
- // Devolver el usuario actualizado
162
- return await this.getUserById(id);
163
- } catch (error) {
164
- console.error('[ERROR] UserModel.updateUser:', error);
165
- throw error;
166
- }
167
- }
168
-
169
- /**
170
- * Elimina un usuario
171
- * @param {number} id - ID del usuario
172
- * @returns {Promise<boolean>} - True si se eliminó correctamente
173
- */
174
- async deleteUser(id) {
175
- try {
176
- const result = await this.queryBuilder
177
- .reset()
178
- .delete()
179
- .where('id', id);
180
-
181
- return result.affectedRows > 0;
182
- } catch (error) {
183
- console.error('[ERROR] UserModel.deleteUser:', error);
184
- throw error;
185
- }
186
- }
187
- }
188
-
189
- module.exports = UserModel;
@@ -1,213 +0,0 @@
1
- /**
2
- * Modelo para la tabla de completed_carts en el framework JERK
3
- * Implementación del componente MVC CompletedCartModel.js
4
- * Utiliza MariaDB como adaptador de base de datos
5
- */
6
-
7
- const { ModelBase } = require('insitu-js');
8
- const { getSharedAdapter } = require('../../utils/dbAdapter');
9
- const { QueryBuilder } = require('insitu-js');
10
-
11
- class CompletedCartModel extends ModelBase {
12
- constructor(options = {}) {
13
- // Obtener el adaptador centralizado
14
- const adapter = getSharedAdapter();
15
-
16
- super({
17
- ...options,
18
- tableName: options.tableName || 'completed_carts', // Tabla por defecto
19
- adapter: adapter
20
- });
21
-
22
- // Inicializar QueryBuilder con el adaptador centralizado
23
- this.queryBuilder = new QueryBuilder(adapter, 'completed_carts');
24
-
25
- // Definir campos del modelo
26
- this.fields = {
27
- id: { type: 'integer', primaryKey: true, autoIncrement: true },
28
- session_header_id: { type: 'integer' },
29
- event_type: { type: 'string', required: true },
30
- created_at: { type: 'datetime' },
31
- qty: { type: 'integer' },
32
- product_id: { type: 'integer' },
33
- sku: { type: 'string' },
34
- product_name: { type: 'string' },
35
- url: { type: 'string' },
36
- price: { type: 'decimal' },
37
- old_qty: { type: 'integer' },
38
- new_qty: { type: 'integer' },
39
- compressed_data: { type: 'text' },
40
- data_hash: { type: 'string' },
41
- event_timestamp: { type: 'datetime' },
42
- session_id: { type: 'string' },
43
- wtf_session: { type: 'string' },
44
- site_url: { type: 'string' }
45
- };
46
- }
47
-
48
- /**
49
- * Consulta personalizada con paginación, filtros y búsqueda global
50
- * @param {Object} filters - Filtros para la consulta
51
- * @param {Object} pagination - Parámetros de paginación
52
- * @param {string} search - Término de búsqueda global
53
- * @returns {Promise<Object>} - Resultados con información de paginación
54
- */
55
- async queryWithFilters(filters = {}, pagination = {}, search = '') {
56
- try {
57
- // Mostrar parámetros de filtro para depuración
58
- console.log('Filtros recibidos en CompletedCartModel queryWithFilters:', filters);
59
-
60
- // Extraer parámetros de paginación
61
- const offset = pagination.offset !== undefined ? parseInt(pagination.offset) : 0;
62
- const limit = pagination.limit ? parseInt(pagination.limit) : 10;
63
-
64
- // Extraer parámetros de filtro específicos para fechas
65
- const { date_from, date_to, event_type, session_id, wtf_session, url, site_url } = filters;
66
-
67
- // Construir condiciones WHERE dinámicamente
68
- let whereConditions = [];
69
- let whereParams = [];
70
-
71
- // Filtro por fecha desde (date_from) - para event_timestamp
72
- if (date_from) {
73
- // Si la fecha no tiene hora (es solo YYYY-MM-DD), agregar hora mínima del día
74
- let startDate = date_from;
75
- if (date_from.length === 10) { // Formato YYYY-MM-DD
76
- startDate = `${date_from} 00:00:00`;
77
- }
78
- console.log('Aplicando filtro: event_timestamp >=', startDate);
79
- whereConditions.push('event_timestamp >= ?');
80
- whereParams.push(startDate);
81
- }
82
-
83
- // Filtro por fecha hasta (date_to) - para event_timestamp
84
- if (date_to) {
85
- // Si la fecha de fin no tiene hora (es solo YYYY-MM-DD), agregar hora 23:59:59 para incluir todo el día
86
- let endDate = date_to;
87
- if (date_to.length === 10) { // Formato YYYY-MM-DD
88
- endDate = `${date_to} 23:59:59`;
89
- }
90
- console.log('Aplicando filtro: event_timestamp <=', endDate);
91
- whereConditions.push('event_timestamp <= ?');
92
- whereParams.push(endDate);
93
- }
94
-
95
- // Filtros por campos específicos
96
- if (event_type) {
97
- whereConditions.push('event_type = ?');
98
- whereParams.push(event_type);
99
- }
100
-
101
- if (session_id) {
102
- whereConditions.push('session_id = ?');
103
- whereParams.push(session_id);
104
- }
105
-
106
- if (wtf_session) {
107
- whereConditions.push('wtf_session = ?');
108
- whereParams.push(wtf_session);
109
- }
110
-
111
- if (url) {
112
- whereConditions.push('url LIKE ?');
113
- whereParams.push(`%${url}%`);
114
- }
115
-
116
- if (site_url) {
117
- whereConditions.push('site_url = ?');
118
- whereParams.push(site_url);
119
- }
120
-
121
- // Aplicar búsqueda global si se proporciona
122
- if (search) {
123
- // Campos en los que se realiza la búsqueda global
124
- const searchFields = ['event_type', 'product_name', 'sku', 'url', 'session_id', 'wtf_session', 'site_url'];
125
-
126
- const searchConditions = searchFields.map(field => `${field} LIKE ?`).join(' OR ');
127
- whereConditions.push(`(${searchConditions})`);
128
-
129
- // Agregar parámetros de búsqueda
130
- searchFields.forEach(() => {
131
- whereParams.push(`%${search}%`);
132
- });
133
- }
134
-
135
- // Construir la cláusula WHERE completa
136
- const whereClause = whereConditions.length > 0
137
- ? 'WHERE ' + whereConditions.join(' AND ')
138
- : 'WHERE 1=1'; // Asegurar que siempre haya una condición
139
-
140
- // Consulta SQL para obtener los registros
141
- const query = `
142
- SELECT *
143
- FROM completed_carts
144
- ${whereClause}
145
- ORDER BY id DESC
146
- LIMIT ? OFFSET ?
147
- `;
148
-
149
- // Agregar parámetros de paginación
150
- const allParams = [...whereParams, limit, offset];
151
-
152
- // Usar el método complexQuery del QueryBuilder
153
- const { QueryBuilder } = require('insitu-js');
154
- const qb = new QueryBuilder(this.queryBuilder.adapter);
155
- qb.complexQuery(query, allParams);
156
-
157
- // Obtener los resultados
158
- const rows = await qb.get();
159
-
160
- // Consulta para obtener el conteo total con los mismos filtros
161
- const countQuery = `
162
- SELECT COUNT(*) as total
163
- FROM completed_carts
164
- ${whereClause}
165
- `;
166
-
167
- // Usar el método complexQuery del QueryBuilder para la consulta de conteo
168
- const countQb = new QueryBuilder(this.queryBuilder.adapter);
169
- countQb.complexQuery(countQuery, whereParams); // Sin parámetros de paginación
170
-
171
- const countResult = await countQb.first();
172
- const total = countResult ? countResult.total : 0;
173
-
174
- return {
175
- total: parseInt(total),
176
- rows: rows
177
- };
178
- } catch (error) {
179
- console.error(`Error en queryWithFilters para ${this.tableName}:`, error.message);
180
- throw error;
181
- }
182
- }
183
-
184
- /**
185
- * Obtiene completed carts con paginación, filtros y búsqueda
186
- * @param {Object} queryParams - Parámetros de consulta (offset, limit, search, filtros)
187
- * @returns {Promise<Object>} - Resultados con información de paginación
188
- */
189
- async getCompletedCarts(queryParams = {}) {
190
- // Obtener parámetros de paginación
191
- const offset = parseInt(queryParams.offset) || 0;
192
- const limit = parseInt(queryParams.limit) || 10;
193
- const search = queryParams.search || '';
194
-
195
- // Obtener otros parámetros de filtro excluyendo los de paginación y búsqueda
196
- const filters = {};
197
- for (const [key, value] of Object.entries(queryParams)) {
198
- if (!['offset', 'limit', 'search', 'sort', 'order'].includes(key)) {
199
- if (value !== '') { // Solo añadir filtros que no estén vacíos
200
- filters[key] = value;
201
- }
202
- }
203
- }
204
-
205
- return await this.queryWithFilters(
206
- filters,
207
- { offset, limit },
208
- search
209
- );
210
- }
211
- }
212
-
213
- module.exports = CompletedCartModel;