Files
Plataforma-de-desarrolladores/Supervisiones_Estructura_20260921.sql
Jorge Luis caudillo esparza e8160eefba --documentos
2026-09-27 14:44:12 -07:00

496 lines
19 KiB
Transact-SQL

/*
Supervisiones - estructura inicial
Preparado: 21/09/2026.
Base revisada: SIG_PlataformaDesarolladores.
Alcance aprobado:
Vis_Citas -> Supervisiones_Programacion
Vis_Visitas -> Supervisiones
Nuevas: Supervisiones_Lotes, Vis_EstatusProgramacion,
Vis_TiposGIS y Vis_LotesGIS.
Script de migración de una sola aplicación.
La instalación requiere autorización independiente de la edición.
DESPLIEGUE COORDINADO
El renombrado conserva identidades, datos y claves foráneas, pero no
reescribe el texto de procedimientos ni las referencias de la aplicación
o los nombres registrados en la configuración de bitácora.
Instalar junto con su adaptación posterior, sin peticiones concurrentes.
No instalar este archivo de forma aislada sobre la aplicación actual.
Ejecutar el lote completo dentro de una transacción administrada por el
instalador. Ante cualquier excepción, el instalador debe detenerse y
desechar la transacción sin confirmar. Este script no confirma cambios.
Se prepara una migración de una sola aplicación: si aparecen las tablas
destino o cambia la estructura de origen, se detiene antes de modificar.
Programaciones y visitas estaban vacías al revisar la BD.
Si se generan registros antes de instalar:
- Las visitas automáticas sin resultado necesitan conciliación previa.
- El esquema anterior sobrescribe CveUsuario al editar; no permite
reconstruir con certeza el usuario de registro de una fila editada.
- En esos casos se detiene, sin inventar autores ni borrar información.
Se conserva:
- DuracionMinutos y FechaInicio/FechaFin de la programación.
- La configuración de duración de 240 minutos y los turnos/festivos.
- CveVisita y las relaciones existentes de cuestionarios/documentos.
- Observaciones de programación con longitud 2000, sin truncarlas.
- Las restricciones existentes de duración y fechas.
- Los nombres técnicos de restricciones heredadas aún aplicables.
Implementado por el script de procedimientos y la aplicación acompañantes:
- PAs y servicios para programar, reprogramar, cancelar y registrar visitas.
- Al reprogramar: INSERT nuevo y vínculo CveProgramacionOrigen.
- Registrar resultado y motivo del intento sin crear visita al programar.
- Validar disponibilidad al guardar y actualizar estatus en la transacción.
- Listar historial del lote por COALESCE(FechaInicio, FechaRegistro) DESC,
CveVisita DESC; Aprobado NULL significa sin evaluar.
- Integrar resultados con los cuestionarios existentes de lote/etapa,
incluidas sus respuestas de agua potable y drenaje.
- Pantallas, permisos y configuración de bitácora con los nuevos nombres.
- Ofrecer programación al autorizar el trámite verificado:
12, Autorización de proyectos de redes internas.
Pendiente: el pintado dinámico GIS continúa fuera de esta primera etapa.
*/
SET NOCOUNT ON;
SET ANSI_NULLS ON;
SET QUOTED_IDENTIFIER ON;
SET ANSI_PADDING ON;
SET ANSI_WARNINGS ON;
SET ARITHABORT ON;
SET CONCAT_NULL_YIELDS_NULL ON;
SET NUMERIC_ROUNDABORT OFF;
IF DB_NAME() <> N'SIG_PlataformaDesarolladores'
BEGIN
THROW 51000, N'La base seleccionada no corresponde a la estructura revisada.', 1;
END;
IF @@TRANCOUNT = 0 OR XACT_STATE() <> 1
BEGIN
THROW 51001, N'La migración requiere una transacción activa del instalador.', 1;
END;
IF OBJECT_ID(N'dbo.Vis_Citas', N'U') IS NULL
OR OBJECT_ID(N'dbo.Vis_Visitas', N'U') IS NULL
BEGIN
THROW 51002, N'No se encontró la estructura de citas y visitas revisada.', 1;
END;
IF OBJECT_ID(N'dbo.Supervisiones_Programacion') IS NOT NULL
OR OBJECT_ID(N'dbo.Supervisiones') IS NOT NULL
OR OBJECT_ID(N'dbo.Supervisiones_Lotes') IS NOT NULL
OR OBJECT_ID(N'dbo.Vis_EstatusProgramacion') IS NOT NULL
OR OBJECT_ID(N'dbo.Vis_TiposGIS') IS NOT NULL
OR OBJECT_ID(N'dbo.Vis_LotesGIS') IS NOT NULL
BEGIN
THROW 51003, N'Ya existen objetos destino. Revise si esta migración fue aplicada.', 1;
END;
IF OBJECT_ID(N'dbo.Sis_Usuarios', N'U') IS NULL
OR OBJECT_ID(N'dbo.FraccionamientosEtapas', N'U') IS NULL
OR OBJECT_ID(N'dbo.FraccionamientosLotes', N'U') IS NULL
OR OBJECT_ID(N'dbo.Tra_Solicitudes', N'U') IS NULL
OR COL_LENGTH(N'dbo.Sis_Usuarios', N'EsSupervisor') IS NULL
OR ISNULL(COL_LENGTH(N'dbo.FraccionamientosLotes', N'GISPoligonoClave'), 0) <> 100
BEGIN
THROW 51004, N'Las dependencias no coinciden con la estructura revisada.', 1;
END;
IF OBJECT_ID(N'dbo.UQ_Vis_Visitas_Cita', N'UQ') IS NULL
OR OBJECT_ID(N'dbo.DF_Vis_Citas_Cancelada', N'D') IS NULL
OR NOT EXISTS
(
SELECT 1
FROM sys.indexes
WHERE object_id = OBJECT_ID(N'dbo.Vis_Citas')
AND name = N'IX_Vis_Citas_Agenda'
)
BEGIN
THROW 51005, N'Las restricciones o índices de origen cambiaron; revise la migración.', 1;
END;
BEGIN TRY
-- Bloquear los dos orígenes hasta concluir la transacción del instalador.
DECLARE @CantidadProgramaciones bigint;
DECLARE @CantidadVisitas bigint;
DECLARE @ObjetoProgramaciones int = OBJECT_ID(N'dbo.Vis_Citas');
DECLARE @ObjetoVisitas int = OBJECT_ID(N'dbo.Vis_Visitas');
SELECT @CantidadProgramaciones = COUNT_BIG(*)
FROM dbo.Vis_Citas WITH (TABLOCKX, HOLDLOCK);
SELECT @CantidadVisitas = COUNT_BIG(*)
FROM dbo.Vis_Visitas WITH (TABLOCKX, HOLDLOCK);
IF EXISTS
(
SELECT 1
FROM dbo.Vis_Visitas
WHERE SeRealizo IS NULL
)
BEGIN
THROW 51006, N'Existen visitas automáticas sin resultado. Concilie esos registros antes de migrar.', 1;
END;
IF EXISTS
(
SELECT 1
FROM dbo.Vis_Citas
WHERE CveUsuario IS NULL OR FechaModificacion IS NOT NULL
)
OR EXISTS
(
SELECT 1
FROM dbo.Vis_Visitas
WHERE CveUsuario IS NULL OR FechaModificacion IS NOT NULL
)
BEGIN
THROW 51007, N'Existen registros cuyo autor original requiere conciliación. No se asignarán usuarios supuestos.', 1;
END;
DECLARE @ReferenciasOriginales TABLE
(
CveRestriccion int NOT NULL PRIMARY KEY,
CveObjetoReferenciado int NOT NULL
);
INSERT INTO @ReferenciasOriginales
(CveRestriccion, CveObjetoReferenciado)
SELECT object_id, referenced_object_id
FROM sys.foreign_keys
WHERE referenced_object_id IN (@ObjetoProgramaciones, @ObjetoVisitas);
-- Cada fase se compila después de completar la anterior.
-- Así se evitan errores de columnas recién agregadas en el mismo lote.
-- Fase 1.
EXEC sys.sp_executesql N'
-- Conservar identidades y referencias: sp_rename mantiene los object_id.
EXEC sys.sp_rename N''dbo.Vis_Citas'', N''Supervisiones_Programacion'', N''OBJECT'';
EXEC sys.sp_rename N''dbo.Vis_Visitas'', N''Supervisiones'', N''OBJECT'';
EXEC sys.sp_rename
N''dbo.Supervisiones_Programacion.CveCita'',
N''CveProgramacionVisita'',
N''COLUMN'';
EXEC sys.sp_rename
N''dbo.Supervisiones_Programacion.CveSupervisor'',
N''CveUsuarioSupervisor'',
N''COLUMN'';
EXEC sys.sp_rename
N''dbo.Supervisiones_Programacion.Comentarios'',
N''Observaciones'',
N''COLUMN'';
EXEC sys.sp_rename
N''dbo.Supervisiones_Programacion.CveUsuario'',
N''CveUsuarioRegistro'',
N''COLUMN'';
EXEC sys.sp_rename
N''dbo.Supervisiones_Programacion.FechaAlta'',
N''FechaRegistro'',
N''COLUMN'';
EXEC sys.sp_rename
N''dbo.Supervisiones.CveCita'',
N''CveProgramacionVisita'',
N''COLUMN'';
EXEC sys.sp_rename
N''dbo.Supervisiones.CveUsuario'',
N''CveUsuarioRegistro'',
N''COLUMN'';
EXEC sys.sp_rename
N''dbo.Supervisiones.FechaAlta'',
N''FechaRegistro'',
N''COLUMN'';
EXEC sys.sp_rename
N''dbo.Supervisiones.FechaReal'',
N''FechaInicio'',
N''COLUMN'';
';
-- Fase 2.
EXEC sys.sp_executesql N'
CREATE TABLE dbo.Vis_EstatusProgramacion
(
CveEstatusProgramacion int IDENTITY(1, 1) NOT NULL,
EstatusProgramacion varchar(50) COLLATE Modern_Spanish_CS_AS NOT NULL,
CONSTRAINT PK_Vis_EstatusProgramacion
PRIMARY KEY (CveEstatusProgramacion),
CONSTRAINT UQ_Vis_EstatusProgramacion_Nombre
UNIQUE (EstatusProgramacion)
);
-- Las claves se generan en la BD y se resuelven por nombre.
INSERT INTO dbo.Vis_EstatusProgramacion
(EstatusProgramacion)
VALUES
(''Programada''),
(''Realizada''),
(''No realizada''),
(''Cancelada''),
(''Reprogramada'');
ALTER TABLE dbo.Supervisiones_Programacion ADD
CveUsuarioDesarrollador int NULL,
CveSolicitud int NULL,
CveEstatusProgramacion int NULL,
CveProgramacionOrigen int NULL,
CveUsuarioModificacion int NULL;
ALTER TABLE dbo.Supervisiones ADD
CveFraccionamientoEtapa int NULL,
CveSolicitud int NULL,
CveUsuarioSupervisor int NULL,
FechaFin datetime2(0) NULL,
CveUsuarioModificacion int NULL;
';
-- Fase 3.
EXEC sys.sp_executesql N'
-- Se migra únicamente información comprobable de los registros actuales.
UPDATE P
SET CveEstatusProgramacion = E.CveEstatusProgramacion
FROM dbo.Supervisiones_Programacion AS P
LEFT JOIN dbo.Supervisiones AS V ON V.CveProgramacionVisita = P.CveProgramacionVisita
INNER JOIN dbo.Vis_EstatusProgramacion AS E ON E.EstatusProgramacion =
CASE
WHEN V.SeRealizo = 1 THEN ''Realizada''
WHEN V.SeRealizo = 0 THEN ''No realizada''
WHEN P.Cancelada = 1 THEN ''Cancelada''
ELSE ''Programada''
END;
UPDATE V
SET CveFraccionamientoEtapa = P.CveFraccionamientoEtapa,
CveUsuarioSupervisor = P.CveUsuarioSupervisor
FROM dbo.Supervisiones AS V
INNER JOIN dbo.Supervisiones_Programacion AS P ON P.CveProgramacionVisita = V.CveProgramacionVisita;
ALTER TABLE dbo.Supervisiones_Programacion
ALTER COLUMN CveUsuarioSupervisor int NULL;
ALTER TABLE dbo.Supervisiones_Programacion
ALTER COLUMN CveEstatusProgramacion int NOT NULL;
ALTER TABLE dbo.Supervisiones_Programacion
ALTER COLUMN CveUsuarioRegistro int NOT NULL;
-- Cancelada queda representada por el catálogo de estatus.
-- El índice de agenda anterior incluía esa columna.
DROP INDEX IX_Vis_Citas_Agenda ON dbo.Supervisiones_Programacion;
ALTER TABLE dbo.Supervisiones_Programacion
DROP CONSTRAINT DF_Vis_Citas_Cancelada;
ALTER TABLE dbo.Supervisiones_Programacion
DROP COLUMN Cancelada;
ALTER TABLE dbo.Supervisiones_Programacion WITH CHECK ADD
CONSTRAINT FK_SupervisionesProgramacion_Desarrollador
FOREIGN KEY (CveUsuarioDesarrollador)
REFERENCES dbo.Sis_Usuarios (CveUsuario),
CONSTRAINT FK_SupervisionesProgramacion_Solicitud
FOREIGN KEY (CveSolicitud)
REFERENCES dbo.Tra_Solicitudes (CveSolicitud),
CONSTRAINT FK_SupervisionesProgramacion_Estatus
FOREIGN KEY (CveEstatusProgramacion)
REFERENCES dbo.Vis_EstatusProgramacion (CveEstatusProgramacion),
CONSTRAINT FK_SupervisionesProgramacion_Origen
FOREIGN KEY (CveProgramacionOrigen)
REFERENCES dbo.Supervisiones_Programacion (CveProgramacionVisita),
CONSTRAINT FK_SupervisionesProgramacion_UsuarioModificacion
FOREIGN KEY (CveUsuarioModificacion)
REFERENCES dbo.Sis_Usuarios (CveUsuario),
CONSTRAINT CK_SupervisionesProgramacion_Origen
CHECK
(
CveProgramacionOrigen IS NULL
OR CveProgramacionOrigen <> CveProgramacionVisita
);
CREATE INDEX IX_SupervisionesProgramacion_Agenda
ON dbo.Supervisiones_Programacion
(CveUsuarioSupervisor, CveEstatusProgramacion, FechaInicio)
INCLUDE (FechaFin, DuracionMinutos, CveFraccionamientoEtapa);
CREATE INDEX IX_SupervisionesProgramacion_Etapa
ON dbo.Supervisiones_Programacion
(CveFraccionamientoEtapa, FechaInicio DESC, CveProgramacionVisita DESC)
INCLUDE (CveSolicitud, CveEstatusProgramacion);
CREATE INDEX IX_SupervisionesProgramacion_Origen
ON dbo.Supervisiones_Programacion (CveProgramacionOrigen)
WHERE CveProgramacionOrigen IS NOT NULL;
-- UNIQUE sin filtro permitiría solamente un NULL.
-- Este índice permite visitas manuales y mantiene 0..1 visita por programación.
ALTER TABLE dbo.Supervisiones
DROP CONSTRAINT UQ_Vis_Visitas_Cita;
ALTER TABLE dbo.Supervisiones
ALTER COLUMN CveProgramacionVisita int NULL;
ALTER TABLE dbo.Supervisiones
ALTER COLUMN CveFraccionamientoEtapa int NOT NULL;
ALTER TABLE dbo.Supervisiones
ALTER COLUMN CveUsuarioSupervisor int NOT NULL;
ALTER TABLE dbo.Supervisiones
ALTER COLUMN SeRealizo bit NOT NULL;
ALTER TABLE dbo.Supervisiones
ALTER COLUMN CveUsuarioRegistro int NOT NULL;
CREATE UNIQUE INDEX UQ_Supervisiones_Programacion
ON dbo.Supervisiones (CveProgramacionVisita)
WHERE CveProgramacionVisita IS NOT NULL;
ALTER TABLE dbo.Supervisiones WITH CHECK ADD
CONSTRAINT FK_Supervisiones_Etapa
FOREIGN KEY (CveFraccionamientoEtapa)
REFERENCES dbo.FraccionamientosEtapas (CveFraccionamientoEtapa),
CONSTRAINT FK_Supervisiones_Solicitud
FOREIGN KEY (CveSolicitud)
REFERENCES dbo.Tra_Solicitudes (CveSolicitud),
CONSTRAINT FK_Supervisiones_Supervisor
FOREIGN KEY (CveUsuarioSupervisor)
REFERENCES dbo.Sis_Usuarios (CveUsuario),
CONSTRAINT FK_Supervisiones_UsuarioModificacion
FOREIGN KEY (CveUsuarioModificacion)
REFERENCES dbo.Sis_Usuarios (CveUsuario),
CONSTRAINT CK_Supervisiones_Fechas
CHECK
(
FechaFin IS NULL
OR (FechaInicio IS NOT NULL AND FechaFin >= FechaInicio)
);
CREATE INDEX IX_Supervisiones_EtapaFecha
ON dbo.Supervisiones
(CveFraccionamientoEtapa, FechaInicio DESC, CveVisita DESC)
INCLUDE (CveUsuarioSupervisor, SeRealizo, FechaRegistro, CveSolicitud);
-- Se conserva CveVisita: documentos, cuestionarios y comentarios
-- continúan enlazados por sus FK existentes al mismo object_id.
CREATE TABLE dbo.Supervisiones_Lotes
(
CveVisitaLote int IDENTITY(1, 1) NOT NULL,
CveVisita int NOT NULL,
CveFraccionamientoLote int NOT NULL,
Aprobado bit NULL,
Observaciones varchar(1000) COLLATE Modern_Spanish_CS_AS NULL,
CveUsuarioRegistro int NOT NULL,
FechaRegistro datetime2(0) NOT NULL
CONSTRAINT DF_SupervisionesLotes_FechaRegistro DEFAULT (SYSDATETIME()),
CveUsuarioModificacion int NULL,
FechaModificacion datetime2(0) NULL,
CONSTRAINT PK_Supervisiones_Lotes
PRIMARY KEY (CveVisitaLote),
CONSTRAINT UQ_SupervisionesLotes_VisitaLote
UNIQUE (CveVisita, CveFraccionamientoLote),
CONSTRAINT FK_SupervisionesLotes_Visita
FOREIGN KEY (CveVisita)
REFERENCES dbo.Supervisiones (CveVisita),
CONSTRAINT FK_SupervisionesLotes_Lote
FOREIGN KEY (CveFraccionamientoLote)
REFERENCES dbo.FraccionamientosLotes (CveFraccionamientoLote),
CONSTRAINT FK_SupervisionesLotes_UsuarioRegistro
FOREIGN KEY (CveUsuarioRegistro)
REFERENCES dbo.Sis_Usuarios (CveUsuario),
CONSTRAINT FK_SupervisionesLotes_UsuarioModificacion
FOREIGN KEY (CveUsuarioModificacion)
REFERENCES dbo.Sis_Usuarios (CveUsuario)
);
CREATE INDEX IX_SupervisionesLotes_Historial
ON dbo.Supervisiones_Lotes (CveFraccionamientoLote, CveVisita)
INCLUDE (Aprobado, FechaRegistro);
CREATE TABLE dbo.Vis_TiposGIS
(
CveTipoGIS int IDENTITY(1, 1) NOT NULL,
TipoGIS varchar(50) COLLATE Modern_Spanish_CS_AS NOT NULL,
CONSTRAINT PK_Vis_TiposGIS
PRIMARY KEY (CveTipoGIS),
CONSTRAINT UQ_Vis_TiposGIS_Nombre
UNIQUE (TipoGIS)
);
INSERT INTO dbo.Vis_TiposGIS
(TipoGIS)
VALUES
(''AguaPotable''),
(''Drenaje'');
CREATE TABLE dbo.Vis_LotesGIS
(
CveLoteGIS int IDENTITY(1, 1) NOT NULL,
CveFraccionamientoLote int NOT NULL,
CveTipoGIS int NOT NULL,
GISPoligonoClave varchar(100) COLLATE Modern_Spanish_CS_AS NOT NULL,
FechaRegistro datetime2(0) NOT NULL
CONSTRAINT DF_Vis_LotesGIS_FechaRegistro DEFAULT (SYSDATETIME()),
CONSTRAINT PK_Vis_LotesGIS
PRIMARY KEY (CveLoteGIS),
CONSTRAINT UQ_Vis_LotesGIS_LoteTipo
UNIQUE (CveFraccionamientoLote, CveTipoGIS),
CONSTRAINT FK_Vis_LotesGIS_Lote
FOREIGN KEY (CveFraccionamientoLote)
REFERENCES dbo.FraccionamientosLotes (CveFraccionamientoLote),
CONSTRAINT FK_Vis_LotesGIS_Tipo
FOREIGN KEY (CveTipoGIS)
REFERENCES dbo.Vis_TiposGIS (CveTipoGIS)
);
-- No se copia GISPoligonoClave del lote a ambos tipos:
-- la vinculación actual no indica si corresponde a agua potable o drenaje.
';
IF OBJECT_ID(N'dbo.Supervisiones_Programacion') <> @ObjetoProgramaciones
OR OBJECT_ID(N'dbo.Supervisiones') <> @ObjetoVisitas
BEGIN
THROW 51008, N'No se conservaron las identidades de los objetos originales.', 1;
END;
IF EXISTS
(
SELECT 1
FROM @ReferenciasOriginales AS R
LEFT JOIN sys.foreign_keys AS F ON F.object_id = R.CveRestriccion
WHERE F.object_id IS NULL
OR F.referenced_object_id <> R.CveObjetoReferenciado
OR F.is_disabled = 1
)
BEGIN
THROW 51009, N'No se conservaron todas las relaciones originales.', 1;
END;
EXEC sys.sp_executesql
N'
IF (SELECT COUNT_BIG(*) FROM dbo.Supervisiones_Programacion) <> @Programaciones
OR (SELECT COUNT_BIG(*) FROM dbo.Supervisiones) <> @Visitas
BEGIN
THROW 51010, N''La cantidad de registros cambió durante la migración.'', 1;
END;
SELECT
N''Supervisiones_Programacion'' AS Tabla,
COUNT_BIG(*) AS Registros
FROM dbo.Supervisiones_Programacion
UNION ALL
SELECT N''Supervisiones'', COUNT_BIG(*)
FROM dbo.Supervisiones
UNION ALL
SELECT N''Supervisiones_Lotes'', COUNT_BIG(*)
FROM dbo.Supervisiones_Lotes;
SELECT CveEstatusProgramacion, EstatusProgramacion
FROM dbo.Vis_EstatusProgramacion
ORDER BY CveEstatusProgramacion;
SELECT CveTipoGIS, TipoGIS
FROM dbo.Vis_TiposGIS
ORDER BY CveTipoGIS;',
N'@Programaciones bigint, @Visitas bigint',
@Programaciones = @CantidadProgramaciones,
@Visitas = @CantidadVisitas;
END TRY
BEGIN CATCH
-- El instalador recibe el fallo original y desecha su transacción.
THROW;
END CATCH;