Commit 56bd3ec0885682fb64298e854e965a1d45312607
1 parent
0bafc887
Hito: Pre-Migración a Nomenclatura Alfanumérica (e0505_lotes)
Showing
4 changed files
with
37 additions
and
15 deletions
VERSION.txt
| ... | ... | @@ -11,3 +11,4 @@ PROYECTO GIS-GEOSERVER - 2026.04.06.13.31.00 ID DOCKER: d983a409769d. Observacià |
| 11 | 11 | PROYECTO GIS-GEOSERVER - 2026.04.07.08.18.07 ID DOCKER: d983a409769d. Observación: Optimización visual de interfaz completada: unificación de anchos al 100%, limpieza de barra superior, traslado de controles al sidebar y registro legal SIGEM-MIC/DINAPI. |
| 12 | 12 | PROYECTO GIS-GEOSERVER - 2026.04.07.20.37.47 ID DOCKER: d983a409769d. Observación: Modernización definitiva del Dashboard completada: Replicación de bloque de bienvenida legado, integración de mapa embebido en modo limpio y reestructuración de la fila inferior de gestión al 100% de ancho. Versión estable validada.Version SIG (Abril 2026) - 2026.04.07.22.30.00 ID DOCKER: d983a409769d. Observación: Éxito en implementación de Login Dinámico (SaaS), integración de logos binarios, eslóganes y responsables desde el servidor .254. |
| 13 | 13 | Version SIG (Abril 2026) - 2026.04.07.23.35.00 ID DOCKER: cb7329596324. Observación: Éxito en la implementación de EstadÃsticas Reales (formato vertical fdw_X.estadisticas_datos) y actualización forzada de FDW desde el menú Administración. |
| 14 | +Version SIG (Abril 2026) - 2026.04.08.06.45.00 ID DOCKER: cb7329596324. Observación: Inicio de migración a Nomenclatura Alfanumérica Multi-Tenant (e0505_lotes). | ... | ... |
src/main/java/com/sigem/gis/controller/GisController.java
| ... | ... | @@ -27,9 +27,9 @@ public class GisController { |
| 27 | 27 | // Consulta a la vista unificada vw_lotes_morosidad_XXX |
| 28 | 28 | String viewName = "public.vw_lotes_morosidad_" + entidad; |
| 29 | 29 | String sql = "SELECT ccc, inm_ficha, inm_ctacatastral, trb_total_deuda, trb_total_pago, ultimo_pago " + |
| 30 | - "FROM " + viewName + " WHERE ccc = ? LIMIT 1"; | |
| 30 | + "FROM " + viewName + " WHERE ccc = ? AND entidad = ? LIMIT 1"; | |
| 31 | 31 | |
| 32 | - List<Map<String, Object>> results = gisJdbcTemplate.queryForList(sql, ccc); | |
| 32 | + List<Map<String, Object>> results = gisJdbcTemplate.queryForList(sql, ccc, entidad); | |
| 33 | 33 | |
| 34 | 34 | if (results.isEmpty()) { |
| 35 | 35 | // Si no hay datos en la vista (quizás lote sin deuda), buscamos solo datos de lote |
| ... | ... | @@ -45,8 +45,8 @@ public class GisController { |
| 45 | 45 | @GetMapping("/entidad/{id}/percentiles") |
| 46 | 46 | public ResponseEntity<?> getPercentiles(@PathVariable String id) { |
| 47 | 47 | try { |
| 48 | - String sql = "SELECT * FROM public.vw_percentiles_morosidad_" + id + " LIMIT 1"; | |
| 49 | - List<Map<String, Object>> results = gisJdbcTemplate.queryForList(sql); | |
| 48 | + String sql = "SELECT * FROM public.vw_percentiles_morosidad_" + id + " WHERE entidad = ? LIMIT 1"; | |
| 49 | + List<Map<String, Object>> results = gisJdbcTemplate.queryForList(sql, id); | |
| 50 | 50 | if (results.isEmpty()) return ResponseEntity.notFound().build(); |
| 51 | 51 | return ResponseEntity.ok(results.get(0)); |
| 52 | 52 | } catch (Exception e) { |
| ... | ... | @@ -61,9 +61,9 @@ public class GisController { |
| 61 | 61 | String sql = "SELECT " + |
| 62 | 62 | " COUNT(*) as total_lotes, " + |
| 63 | 63 | " COUNT(CASE WHEN trb_total_deuda > 0 THEN 1 END) as lotes_con_deuda " + |
| 64 | - "FROM " + viewName; | |
| 64 | + "FROM " + viewName + " WHERE entidad = ?"; | |
| 65 | 65 | |
| 66 | - return ResponseEntity.ok(gisJdbcTemplate.queryForList(sql).get(0)); | |
| 66 | + return ResponseEntity.ok(gisJdbcTemplate.queryForList(sql, id).get(0)); | |
| 67 | 67 | } catch (Exception e) { |
| 68 | 68 | return ResponseEntity.status(500).body(Map.of("error", e.getMessage())); |
| 69 | 69 | } |
| ... | ... | @@ -92,8 +92,8 @@ public class GisController { |
| 92 | 92 | public ResponseEntity<?> getEstadisticas(@PathVariable String id) { |
| 93 | 93 | try { |
| 94 | 94 | String schemaName = "fdw_" + id; |
| 95 | - String sql = "SELECT descripcion, valor FROM " + schemaName + ".estadisticas_datos"; | |
| 96 | - List<Map<String, Object>> results = gisJdbcTemplate.queryForList(sql); | |
| 95 | + String sql = "SELECT descripcion, valor FROM " + schemaName + ".estadisticas_datos WHERE entidad = ?"; | |
| 96 | + List<Map<String, Object>> results = gisJdbcTemplate.queryForList(sql, id); | |
| 97 | 97 | |
| 98 | 98 | return ResponseEntity.ok(results); |
| 99 | 99 | } catch (Exception e) { | ... | ... |
src/main/java/com/sigem/gis/security/AuthController.java
| ... | ... | @@ -70,7 +70,8 @@ public class AuthController { |
| 70 | 70 | System.out.println("Validando usuario vía FDW local para entidad: " + request.getEntidad()); |
| 71 | 71 | |
| 72 | 72 | // 3. Buscar Usuario en el esquema FDW local (en el .123) |
| 73 | - String sqlUser = "SELECT usu_nom, usu_ape, activo, pgp_sym_decrypt(usu_clave_a::bytea, '510580', 'compress-algo=0, cipher-algo=aes256')::text as clave_desencriptada " + | |
| 73 | + String sqlUser = "SELECT usu_nom, usu_ape, activo, entidad, " + | |
| 74 | + "pgp_sym_decrypt(usu_clave_a::bytea, '510580', 'compress-algo=0, cipher-algo=aes256')::text as clave_desencriptada " + | |
| 74 | 75 | "FROM " + schemaName + ".usuarios " + |
| 75 | 76 | "WHERE usu_alias = ? AND ejer_fisca = date_part('year', now())"; |
| 76 | 77 | |
| ... | ... | @@ -83,7 +84,13 @@ public class AuthController { |
| 83 | 84 | |
| 84 | 85 | // 4. Validación Final y Generación de Token |
| 85 | 86 | if (isActivo && request.getPassword().equals(claveDesencriptada)) { |
| 86 | - String token = jwtUtil.generateToken(request.getUsername(), request.getEntidad()); | |
| 87 | + // Extraer la Entidad oficial desde el FDW ( character varying 8 ) | |
| 88 | + String entidadOficial = convertObjectToString(userData.get("entidad")); | |
| 89 | + if (entidadOficial == null || entidadOficial.trim().isEmpty()) { | |
| 90 | + entidadOficial = request.getEntidad(); // Fallback si el campo está vacío, aunque no debería | |
| 91 | + } | |
| 92 | + | |
| 93 | + String token = jwtUtil.generateToken(request.getUsername(), entidadOficial); | |
| 87 | 94 | String nombreCompleto = convertObjectToString(userData.get("usu_nom")) + " " + convertObjectToString(userData.get("usu_ape")); |
| 88 | 95 | |
| 89 | 96 | // Metadatos georreferenciados de la entidad |
| ... | ... | @@ -98,7 +105,7 @@ public class AuthController { |
| 98 | 105 | |
| 99 | 106 | return ResponseEntity.ok(new AuthResponse(token, nombreCompleto, "Login Exitoso", |
| 100 | 107 | lat, lng, zoom, minZoom, maxZoom, mapaBase, bounds, |
| 101 | - nombreEntidad, eslogan, logo, responsable)); | |
| 108 | + nombreEntidad, eslogan, logo, responsable, entidadOficial)); | |
| 102 | 109 | } |
| 103 | 110 | } |
| 104 | 111 | ... | ... |
src/main/java/com/sigem/gis/service/FdwService.java
| ... | ... | @@ -55,10 +55,18 @@ public class FdwService { |
| 55 | 55 | try { |
| 56 | 56 | // ... (verificación de infraestructura fdw igual hasta la creación de vistas) |
| 57 | 57 | // ... |
| 58 | - String checkSql = "SELECT count(*) FROM information_schema.tables WHERE table_schema = ? AND table_name = 'usuarios'"; | |
| 58 | + // Regla Multi-Tenant: Verificar presencia de las 5 tablas críticas | |
| 59 | + String checkSql = "SELECT count(*) FROM information_schema.tables " + | |
| 60 | + "WHERE table_schema = ? AND table_name IN " + | |
| 61 | + "('usuarios', 'estadisticas_datos', 'v_liq_entidad_percentiles', 'v_liq_entidad_totalxobjeto', 'ventanas_usuario')"; | |
| 62 | + | |
| 59 | 63 | Integer count = (forceUpdate) ? 0 : gisJdbcTemplate.queryForObject(checkSql, Integer.class, schemaName); |
| 60 | 64 | |
| 61 | - if (forceUpdate || count == null || count == 0) { | |
| 65 | + // Si falta alguna de las 5 tablas o se solicita actualización forzada | |
| 66 | + if (forceUpdate || count == null || count < 5) { | |
| 67 | + if (count != null && count > 0 && count < 5) { | |
| 68 | + System.out.println("Infraestructura incompleta para " + entidadId + " (" + count + "/5 tablas). Forzando recreación..."); | |
| 69 | + } | |
| 62 | 70 | // (creación de server, user mapping y esquema igual) |
| 63 | 71 | gisJdbcTemplate.execute("DROP SERVER IF EXISTS " + serverName + " CASCADE"); |
| 64 | 72 | gisJdbcTemplate.execute(String.format( |
| ... | ... | @@ -79,13 +87,19 @@ public class FdwService { |
| 79 | 87 | // Vista de Auditoría (MVT) - LIBERADA (Sin LIMIT) |
| 80 | 88 | String viewLotesName = "vw_lotes_morosidad_" + entidadId; |
| 81 | 89 | gisJdbcTemplate.execute(String.format( |
| 82 | - "CREATE OR REPLACE VIEW public.%s AS SELECT l.*, m.inm_ficha, m.inm_ctacatastral, m.trb_total_deuda, m.trb_total_pago, m.ultimo_pago FROM %s l LEFT JOIN %s.v_liq_entidad_totalxobjeto m ON l.ccc = m.inm_ctacatastral", | |
| 90 | + "CREATE OR REPLACE VIEW public.%s AS " + | |
| 91 | + "SELECT l.*, m.inm_ficha, m.inm_ctacatastral, m.trb_total_deuda, m.trb_total_pago, m.ultimo_pago " + | |
| 92 | + "FROM %s l " + | |
| 93 | + "LEFT JOIN %s.v_liq_entidad_totalxobjeto m ON l.ccc = m.inm_ctacatastral AND l.entidad::text = m.entidad::text", | |
| 83 | 94 | viewLotesName, tableLotes, schemaName)); |
| 84 | 95 | |
| 85 | 96 | // Vista PNG FULL (WMS) - SIN LIMIT |
| 86 | 97 | String viewWmsName = "vw_lotes_wms_" + entidadId; |
| 87 | 98 | gisJdbcTemplate.execute(String.format( |
| 88 | - "CREATE OR REPLACE VIEW public.%s AS SELECT l.*, m.inm_ficha, m.inm_ctacatastral, m.trb_total_deuda, m.trb_total_pago, m.ultimo_pago FROM %s l LEFT JOIN %s.v_liq_entidad_totalxobjeto m ON l.ccc = m.inm_ctacatastral", | |
| 99 | + "CREATE OR REPLACE VIEW public.%s AS " + | |
| 100 | + "SELECT l.*, m.inm_ficha, m.inm_ctacatastral, m.trb_total_deuda, m.trb_total_pago, m.ultimo_pago " + | |
| 101 | + "FROM %s l " + | |
| 102 | + "LEFT JOIN %s.v_liq_entidad_totalxobjeto m ON l.ccc = m.inm_ctacatastral AND l.entidad::text = m.entidad::text", | |
| 89 | 103 | viewWmsName, tableLotes, schemaName)); |
| 90 | 104 | |
| 91 | 105 | // 4. Sincronización con GeoServer | ... | ... |