Cambios en Gis lotes

This commit is contained in:
Jorge Luis caudillo esparza
2026-10-03 14:43:42 -07:00
parent d2b7b982f3
commit 0776ed8c59
69 changed files with 9889 additions and 1521 deletions

View File

@@ -1,4 +1,4 @@
# AGENTS_MANTENIMIENTO_PROYECTO.md
# AGENTS_MANTENIMIENTO_PROYECTO.md
These rules complement `AGENTS.md` and are mandatory whenever the task involves commands, security, error handling, user feedback, grids, PDF migration, file delivery, verification, or project evolution.
@@ -74,6 +74,8 @@ Controlled outcomes and technical failures must use different logs.
## Grid display rules
- Los valores numéricos de negocio (hectáreas, superficies, avances, porcentajes, cantidades, importes y saldos) deben alinearse a la derecha tanto en los campos de captura como en las celdas y resúmenes donde se muestran. Usar las clases visuales existentes o la alineación del control; esta regla no convierte claves, folios ni códigos en cantidades.
- Every new or modified `asp:GridView` must declare `GridLines="None"`.
- Its `CssClass` must include the exact utility class `Widthall` so the grid uses the full available width.
- Do not add `table-bordered` to a GridView. Existing visual classes such as `table`, `table-striped`, and `table-hover` may be retained when appropriate.

View File

@@ -0,0 +1,649 @@
/*
Preparado a partir de las definiciones instaladas; no ejecutado.
Instalar junto con la aplicación. No modifica conceptos, recibos ni pagos.
CveSolicitud se conserva únicamente como referencia histórica.
Los convenios históricos sin una solicitud conservan CveTipoTramite NULL:
su asignación requiere una decisión de negocio; no se elige un trámite arbitrario.
*/
SET NOCOUNT ON;
IF COL_LENGTH('dbo.Convenios', 'CveTipoTramite') IS NULL
ALTER TABLE dbo.Convenios ADD CveTipoTramite int NULL;
GO
UPDATE C
SET CveTipoTramite = S.CveTipoTramite
FROM dbo.Convenios AS C
INNER JOIN dbo.Tra_Solicitudes AS S ON S.CveSolicitud = C.CveSolicitud
WHERE C.CveTipoTramite IS NULL;
IF NOT EXISTS
(
SELECT 1
FROM sys.foreign_keys
WHERE name = 'FK_Convenios_TipoTramite'
)
ALTER TABLE dbo.Convenios WITH CHECK
ADD CONSTRAINT FK_Convenios_TipoTramite
FOREIGN KEY (CveTipoTramite)
REFERENCES dbo.Tra_TiposTramite (CveTipoTramite);
IF NOT EXISTS
(
SELECT 1
FROM sys.indexes
WHERE object_id = OBJECT_ID('dbo.Convenios')
AND name = 'IX_Convenios_Etapa_TipoTramite'
)
CREATE INDEX IX_Convenios_Etapa_TipoTramite
ON dbo.Convenios (CveFraccionamientoEtapa, CveTipoTramite);
DECLARE @QuitarRelacion nvarchar(max) = N'';
SELECT @QuitarRelacion = @QuitarRelacion
+ N'ALTER TABLE dbo.Convenios DROP CONSTRAINT ' + QUOTENAME(F.name) + N';'
FROM sys.foreign_keys AS F
WHERE F.parent_object_id = OBJECT_ID('dbo.Convenios')
AND F.referenced_object_id = OBJECT_ID('dbo.Tra_Solicitudes');
IF @QuitarRelacion <> N''
EXEC sys.sp_executesql @QuitarRelacion;
-- Resultado de diagnóstico; no cambia la clasificación de estos convenios.
SELECT CveConvenio, NumeroConvenio, CveFraccionamientoEtapa
FROM dbo.Convenios
WHERE CveTipoTramite IS NULL;
GO
CREATE OR ALTER PROCEDURE dbo.PA_Tra_ConvenioAdd
@CveCliente int,
@CveFraccionamientoEtapa int,
@CveTipoTramite int,
@NumeroConvenio varchar(100),
@NumeroOficio varchar(100) = NULL,
@ViviendasAutorizadas int = NULL,
@ViviendasEnConvenio int,
@ViviendasPendientes int = NULL,
@ViviendasContratadas int = NULL,
@FechaConvenio date,
@Observaciones varchar(1000) = NULL,
@ConceptosXml xml,
@CveUsuarioEjecuta int,
@ErrorMostrar varchar(max) OUTPUT,
@ErrorTipo int OUTPUT,
@Return bit OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT
@ErrorMostrar = NULL,
@ErrorTipo = 0,
@Return = 0;
BEGIN TRY
SET @NumeroConvenio = NULLIF(LTRIM(RTRIM(@NumeroConvenio)), '');
SET @NumeroOficio = NULLIF(LTRIM(RTRIM(@NumeroOficio)), '');
SET @Observaciones = NULLIF(LTRIM(RTRIM(@Observaciones)), '');
IF @CveCliente <= 0
BEGIN
SET @ErrorMostrar = 'Seleccione el desarrollador del convenio.';
SET @ErrorTipo = 2;
RETURN;
END;
IF @CveFraccionamientoEtapa <= 0
BEGIN
SET @ErrorMostrar = 'Seleccione el fraccionamiento y etapa del convenio.';
SET @ErrorTipo = 2;
RETURN;
END;
IF ISNULL(@CveTipoTramite, 0) <= 0
BEGIN
SET @ErrorMostrar = 'Seleccione el tipo de trámite del convenio.';
SET @ErrorTipo = 2;
RETURN;
END;
IF @NumeroConvenio IS NULL
BEGIN
SET @ErrorMostrar = 'Capture el número de convenio.';
SET @ErrorTipo = 2;
RETURN;
END;
IF @ViviendasEnConvenio < 0
OR ISNULL(@ViviendasAutorizadas, 0) < 0
OR ISNULL(@ViviendasPendientes, 0) < 0
OR ISNULL(@ViviendasContratadas, 0) < 0
BEGIN
SET @ErrorMostrar = 'Las cantidades de viviendas no son válidas.';
SET @ErrorTipo = 2;
RETURN;
END;
IF NOT EXISTS
(
SELECT 1
FROM dbo.FraccionamientosEtapas AS E
INNER JOIN dbo.Fraccionamientos AS F ON F.CveFraccionamiento = E.CveFraccionamiento
WHERE E.CveFraccionamientoEtapa = @CveFraccionamientoEtapa
AND F.CveCliente = @CveCliente
)
BEGIN
SET @ErrorMostrar = 'La etapa seleccionada no pertenece al desarrollador indicado.';
SET @ErrorTipo = 2;
RETURN;
END;
IF EXISTS
(
SELECT 1
FROM dbo.Convenios AS C
WHERE C.NumeroConvenio = @NumeroConvenio
)
BEGIN
SET @ErrorMostrar = 'Ya existe un convenio con ese número.';
SET @ErrorTipo = 2;
RETURN;
END;
DECLARE @Conceptos TABLE
(
Orden int NOT NULL PRIMARY KEY,
CveConvenioConcepto int NOT NULL,
Importe decimal(18,6) NOT NULL,
Tipo varchar(20) NOT NULL,
NumeroPagos int NOT NULL
);
DECLARE @Recibos TABLE
(
OrdenConcepto int NOT NULL,
Orden int NOT NULL,
Importe decimal(18,6) NOT NULL,
FechaVencimiento date NOT NULL,
Estatus varchar(30) NOT NULL,
PRIMARY KEY (OrdenConcepto, Orden)
);
IF @ConceptosXml IS NOT NULL
BEGIN
INSERT INTO @Conceptos
(
Orden,
CveConvenioConcepto,
Importe,
Tipo,
NumeroPagos
)
SELECT
C.value('@Orden', 'int'),
C.value('@CveConvenioConcepto', 'int'),
C.value('@Importe', 'decimal(18,6)'),
C.value('@Tipo', 'varchar(20)'),
C.value('@NumeroPagos', 'int')
FROM @ConceptosXml.nodes('/Conceptos/Concepto') AS X(C);
INSERT INTO @Recibos
(
OrdenConcepto,
Orden,
Importe,
FechaVencimiento,
Estatus
)
SELECT
C.value('@Orden', 'int'),
R.value('@Orden', 'int'),
R.value('@Importe', 'decimal(18,6)'),
R.value('@FechaVencimiento', 'date'),
COALESCE(
NULLIF(R.value('@Estatus', 'varchar(30)'), ''),
'PENDIENTE'
)
FROM @ConceptosXml.nodes('/Conceptos/Concepto') AS CX(C)
CROSS APPLY C.nodes('Recibos/Recibo') AS RX(R);
END;
IF NOT EXISTS (SELECT 1 FROM @Conceptos)
BEGIN
SET @ErrorMostrar = 'Agregue al menos un concepto al convenio.';
SET @ErrorTipo = 2;
RETURN;
END;
IF EXISTS
(
SELECT 1
FROM @Conceptos AS C
LEFT JOIN dbo.ConveniosConceptos AS CC ON CC.CveConvenioConcepto = C.CveConvenioConcepto
AND CC.EsActivo = 1
WHERE CC.CveConvenioConcepto IS NULL
OR C.Importe <= 0
OR NULLIF(LTRIM(RTRIM(C.Tipo)), '') IS NULL
OR C.NumeroPagos NOT BETWEEN 1 AND 12
)
BEGIN
SET @ErrorMostrar = 'Uno de los conceptos del convenio no es válido.';
SET @ErrorTipo = 2;
RETURN;
END;
IF EXISTS
(
SELECT 1
FROM @Recibos AS R
WHERE R.Importe <= 0
OR R.FechaVencimiento IS NULL
)
BEGIN
SET @ErrorMostrar = 'Todas las parcialidades deben tener importe y vencimiento válidos.';
SET @ErrorTipo = 2;
RETURN;
END;
IF EXISTS
(
SELECT 1
FROM @Conceptos AS C
OUTER APPLY
(
SELECT
COUNT(*) AS NumeroRecibos,
SUM(R.Importe) AS ImporteRecibos
FROM @Recibos AS R
WHERE R.OrdenConcepto = C.Orden
) AS R
WHERE ISNULL(R.NumeroRecibos, 0) <> C.NumeroPagos
OR ISNULL(R.ImporteRecibos, 0) <> C.Importe
)
BEGIN
SET @ErrorMostrar =
'La cantidad y suma de las parcialidades debe coincidir con cada concepto.';
SET @ErrorTipo = 2;
RETURN;
END;
INSERT INTO dbo.Convenios
(
CveCliente,
NumeroConvenio,
NumeroOficio,
CveFraccionamientoEtapa,
CveTipoTramite,
ViviendasAutorizadas,
ViviendasEnConvenio,
ViviendasPendientes,
ViviendasContratadas,
FechaConvenio,
Observaciones,
Estatus,
CveConvenioOrigen,
CveUsuario
)
VALUES
(
@CveCliente,
@NumeroConvenio,
@NumeroOficio,
@CveFraccionamientoEtapa,
@CveTipoTramite,
@ViviendasAutorizadas,
@ViviendasEnConvenio,
@ViviendasPendientes,
@ViviendasContratadas,
@FechaConvenio,
@Observaciones,
'ACTIVO',
NULL,
@CveUsuarioEjecuta
);
DECLARE @CveConvenio int = CONVERT(int, SCOPE_IDENTITY());
DECLARE @OrdenConcepto int = 0;
DECLARE @CveConvenioConcepto int;
DECLARE @ImporteConcepto decimal(18,6);
DECLARE @Tipo varchar(20);
DECLARE @NumeroPagos int;
DECLARE @CveConvenioDetalle int;
WHILE EXISTS
(
SELECT 1
FROM @Conceptos
WHERE Orden > @OrdenConcepto
)
BEGIN
SELECT TOP (1)
@OrdenConcepto = C.Orden,
@CveConvenioConcepto = C.CveConvenioConcepto,
@ImporteConcepto = C.Importe,
@Tipo = C.Tipo,
@NumeroPagos = C.NumeroPagos
FROM @Conceptos AS C
WHERE C.Orden > @OrdenConcepto
ORDER BY C.Orden;
INSERT INTO dbo.ConveniosDetalle
(
CveConvenio,
CveConvenioConcepto,
Importe,
Tipo,
NumeroPagos,
Observaciones
)
VALUES
(
@CveConvenio,
@CveConvenioConcepto,
@ImporteConcepto,
@Tipo,
@NumeroPagos,
NULL
);
SET @CveConvenioDetalle = CONVERT(int, SCOPE_IDENTITY());
INSERT INTO dbo.ConveniosRecibos
(
CveConvenioDetalle,
NumeroRecibo,
Importe,
FechaVencimiento,
Estatus
)
SELECT
@CveConvenioDetalle,
CONCAT(
'RD',
CONVERT(char(8), GETDATE(), 112),
@CveConvenio,
'-',
RIGHT('000' + CONVERT(varchar(3), @OrdenConcepto), 3),
'-',
RIGHT('000' + CONVERT(varchar(3), R.Orden), 3)
),
R.Importe,
R.FechaVencimiento,
R.Estatus
FROM @Recibos AS R
WHERE R.OrdenConcepto = @OrdenConcepto
ORDER BY R.Orden;
END;
SELECT @CveConvenio AS CveConvenio;
SET @Return = 1;
END TRY
BEGIN CATCH
SET @ErrorMostrar =
'Ocurrió un error al guardar el convenio; favor de contactar a Sistemas.';
SET @ErrorTipo = 1;
SET @Return = 0;
DECLARE @ErrorTecnico nvarchar(2048) = CONCAT(
'Número: ', ERROR_NUMBER(),
'; Procedimiento: ', COALESCE(
ERROR_PROCEDURE(),
'PA_Tra_ConvenioAdd'
),
'; Línea: ', ERROR_LINE(),
'; Detalle: ', ERROR_MESSAGE()
);
RAISERROR(N'%s', 10, 1, @ErrorTecnico);
END CATCH;
END;
GO
/*
Se vuelven a definir List/Get únicamente para alinear la salida
con Clientes.Nombre y devolver el encabezado completo del modal.
*/
CREATE OR ALTER PROCEDURE dbo.PA_Tra_ConvenioList
@CveTipoTramite int = NULL,
@CveCliente int = NULL,
@CveFraccionamiento int = NULL,
@CveFraccionamientoEtapa int = NULL,
@Estatus varchar(30) = NULL,
@ConSaldoPendiente bit = NULL,
@CveUsuarioEjecuta int,
@ErrorMostrar varchar(max) OUTPUT,
@ErrorTipo int OUTPUT,
@Return bit OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT
@ErrorMostrar = NULL,
@ErrorTipo = 0,
@Return = 0;
BEGIN TRY
;WITH PagadoRecibo AS
(
SELECT
PR.CveConvenioRecibo,
SUM(PR.ImporteAplicado) AS ImportePagado
FROM dbo.ConveniosPagosRecibos AS PR
GROUP BY PR.CveConvenioRecibo
),
Totales AS
(
SELECT
D.CveConvenio,
SUM(R.Importe) AS ImporteConvenio,
SUM(ISNULL(P.ImportePagado, 0)) AS ImportePagado,
SUM(R.Importe - ISNULL(P.ImportePagado, 0)) AS SaldoPendiente,
MAX(CASE WHEN P.CveConvenioRecibo IS NULL THEN 0 ELSE 1 END) AS TienePagos
FROM dbo.ConveniosDetalle AS D
LEFT JOIN dbo.ConveniosRecibos AS R ON R.CveConvenioDetalle = D.CveConvenioDetalle
LEFT JOIN PagadoRecibo AS P ON P.CveConvenioRecibo = R.CveConvenioRecibo
GROUP BY D.CveConvenio
)
SELECT
C.CveConvenio,
C.CveTipoTramite,
TT.TipoTramite,
C.CveCliente,
CL.Nombre AS Cliente,
F.CveFraccionamiento,
F.Fraccionamiento,
FE.CveFraccionamientoEtapa,
FE.Etapa,
C.NumeroConvenio,
C.NumeroOficio,
C.Estatus,
C.FechaConvenio,
ISNULL(T.ImporteConvenio, 0) AS ImporteConvenio,
ISNULL(T.ImportePagado, 0) AS ImportePagado,
ISNULL(T.SaldoPendiente, 0) AS SaldoPendiente,
CONVERT(bit, ISNULL(T.TienePagos, 0)) AS TienePagos
FROM dbo.Convenios AS C
LEFT JOIN dbo.Tra_TiposTramite AS TT ON TT.CveTipoTramite = C.CveTipoTramite
INNER JOIN dbo.FraccionamientosEtapas AS FE ON FE.CveFraccionamientoEtapa = C.CveFraccionamientoEtapa
INNER JOIN dbo.Fraccionamientos AS F ON F.CveFraccionamiento = FE.CveFraccionamiento
INNER JOIN dbo.Clientes AS CL ON CL.CveCliente = C.CveCliente
LEFT JOIN Totales AS T ON T.CveConvenio = C.CveConvenio
WHERE (@CveCliente IS NULL OR C.CveCliente = @CveCliente)
AND (@CveTipoTramite IS NULL OR C.CveTipoTramite = @CveTipoTramite)
AND (@CveFraccionamiento IS NULL OR F.CveFraccionamiento = @CveFraccionamiento)
AND (@CveFraccionamientoEtapa IS NULL OR C.CveFraccionamientoEtapa = @CveFraccionamientoEtapa)
AND (NULLIF(@Estatus, '') IS NULL OR C.Estatus = @Estatus)
AND
(
@ConSaldoPendiente IS NULL
OR @ConSaldoPendiente = CASE
WHEN ISNULL(T.SaldoPendiente, 0) > 0 THEN 1
ELSE 0
END
)
ORDER BY
C.FechaConvenio DESC,
C.CveConvenio DESC;
SET @Return = 1;
END TRY
BEGIN CATCH
SET @ErrorMostrar =
'Ocurrió un error al consultar los convenios; favor de contactar a Sistemas.';
SET @ErrorTipo = 1;
SET @Return = 0;
DECLARE @ErrorTecnico nvarchar(2048) = CONCAT(
'Número: ', ERROR_NUMBER(),
'; Procedimiento: ', COALESCE(
ERROR_PROCEDURE(),
'PA_Tra_ConvenioList'
),
'; Línea: ', ERROR_LINE(),
'; Detalle: ', ERROR_MESSAGE()
);
RAISERROR(N'%s', 10, 1, @ErrorTecnico);
END CATCH;
END;
GO
CREATE OR ALTER PROCEDURE dbo.PA_Tra_ConvenioGet
@CveConvenio int,
@CveUsuarioEjecuta int,
@ErrorMostrar varchar(max) OUTPUT,
@ErrorTipo int OUTPUT,
@Return bit OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT
@ErrorMostrar = NULL,
@ErrorTipo = 0,
@Return = 0;
BEGIN TRY
IF NOT EXISTS
(
SELECT 1
FROM dbo.Convenios
WHERE CveConvenio = @CveConvenio
)
BEGIN
SET @ErrorMostrar = 'No se encontró el convenio solicitado.';
SET @ErrorTipo = 2;
RETURN;
END;
;WITH PagadoRecibo AS
(
SELECT
PR.CveConvenioRecibo,
SUM(PR.ImporteAplicado) AS ImportePagado
FROM dbo.ConveniosPagosRecibos AS PR
GROUP BY PR.CveConvenioRecibo
),
Totales AS
(
SELECT
D.CveConvenio,
SUM(R.Importe) AS ImporteConvenio,
SUM(ISNULL(P.ImportePagado, 0)) AS ImportePagado,
SUM(R.Importe - ISNULL(P.ImportePagado, 0)) AS SaldoPendiente
FROM dbo.ConveniosDetalle AS D
LEFT JOIN dbo.ConveniosRecibos AS R ON R.CveConvenioDetalle = D.CveConvenioDetalle
LEFT JOIN PagadoRecibo AS P ON P.CveConvenioRecibo = R.CveConvenioRecibo
GROUP BY D.CveConvenio
)
SELECT
C.CveConvenio,
C.CveTipoTramite,
TT.TipoTramite,
C.CveCliente,
C.CveFraccionamientoEtapa,
C.NumeroConvenio,
C.NumeroOficio,
CL.Nombre AS Cliente,
F.Fraccionamiento,
FE.Etapa,
C.Estatus,
C.FechaConvenio,
C.ViviendasAutorizadas,
C.ViviendasEnConvenio,
C.ViviendasPendientes,
C.ViviendasContratadas,
C.Observaciones,
ISNULL(T.ImporteConvenio, 0) AS ImporteConvenio,
ISNULL(T.ImportePagado, 0) AS ImportePagado,
ISNULL(T.SaldoPendiente, 0) AS SaldoPendiente
FROM dbo.Convenios AS C
LEFT JOIN dbo.Tra_TiposTramite AS TT ON TT.CveTipoTramite = C.CveTipoTramite
INNER JOIN dbo.FraccionamientosEtapas AS FE ON FE.CveFraccionamientoEtapa = C.CveFraccionamientoEtapa
INNER JOIN dbo.Fraccionamientos AS F ON F.CveFraccionamiento = FE.CveFraccionamiento
INNER JOIN dbo.Clientes AS CL ON CL.CveCliente = C.CveCliente
LEFT JOIN Totales AS T ON T.CveConvenio = C.CveConvenio
WHERE C.CveConvenio = @CveConvenio;
SELECT
D.CveConvenioDetalle,
D.CveConvenioConcepto,
CC.Concepto,
D.Importe,
D.Tipo,
D.NumeroPagos
FROM dbo.ConveniosDetalle AS D
INNER JOIN dbo.ConveniosConceptos AS CC ON CC.CveConvenioConcepto = D.CveConvenioConcepto
WHERE D.CveConvenio = @CveConvenio
ORDER BY D.CveConvenioDetalle;
;WITH Pagado AS
(
SELECT
PR.CveConvenioRecibo,
SUM(PR.ImporteAplicado) AS ImportePagado
FROM dbo.ConveniosPagosRecibos AS PR
GROUP BY PR.CveConvenioRecibo
)
SELECT
R.CveConvenioRecibo,
R.CveConvenioDetalle,
R.NumeroRecibo,
R.Importe,
ISNULL(P.ImportePagado, 0) AS ImportePagado,
R.Importe - ISNULL(P.ImportePagado, 0) AS SaldoPendiente,
R.FechaVencimiento,
R.Estatus
FROM dbo.ConveniosRecibos AS R
INNER JOIN dbo.ConveniosDetalle AS D ON D.CveConvenioDetalle = R.CveConvenioDetalle
LEFT JOIN Pagado AS P ON P.CveConvenioRecibo = R.CveConvenioRecibo
WHERE D.CveConvenio = @CveConvenio
ORDER BY
R.CveConvenioDetalle,
R.FechaVencimiento,
R.CveConvenioRecibo;
SET @Return = 1;
END TRY
BEGIN CATCH
SET @ErrorMostrar =
'Ocurrió un error al consultar el detalle del convenio; favor de contactar a Sistemas.';
SET @ErrorTipo = 1;
SET @Return = 0;
DECLARE @ErrorTecnico nvarchar(2048) = CONCAT(
'Número: ', ERROR_NUMBER(),
'; Procedimiento: ', COALESCE(
ERROR_PROCEDURE(),
'PA_Tra_ConvenioGet'
),
'; Línea: ', ERROR_LINE(),
'; Detalle: ', ERROR_MESSAGE()
);
RAISERROR(N'%s', 10, 1, @ErrorTecnico);
END CATCH;
END;
GO

View File

@@ -0,0 +1,146 @@
/*
Consolidación de documentos compartidos por etapa y tipo de documento.
Preparado para revisión; no ejecutado.
Requiere la migración Etapa_TipoTramite_20261002 ya instalada.
Ejecutar estructura y procedimientos en la misma transacción de instalación,
detenerse ante errores y confirmar sólo tras verificar los resultados.
No borra archivos ni filas históricas de documentos.
Las copias idénticas quedan como versiones históricas; se conserva una vigente.
Las configuraciones particulares idénticas se consolidan en una por etapa.
Si hubo ediciones diferentes por trámite, se detiene para no elegir una
aprobación, nota o marca de requerido arbitraria.
Convenios no se modifican.
*/
SET NOCOUNT ON;
IF @@TRANCOUNT = 0
THROW 51000, 'Abrir una transacción de instalación antes de ejecutar y revertirla ante cualquier error.', 1;
IF EXISTS
(
SELECT 1
FROM dbo.Tra_DocumentosSolicitud AS D
INNER JOIN dbo.Tra_DocumentosSolicitud AS O ON O.CveFraccionamientoEtapa = D.CveFraccionamientoEtapa
AND O.CveTipoDocumento = D.CveTipoDocumento
AND O.CveDocumentoSolicitud < D.CveDocumentoSolicitud
WHERE D.EsActivo = 1
AND O.EsActivo = 1
AND EXISTS
(
SELECT D.NombreArchivo, D.NombreArchivoFisico, D.RutaArchivo,
D.ContentType, D.TamanoBytes, D.ComentarioCliente,
D.ComentarioAdministrativo, D.EsAprobado, D.CveUsuarioCarga,
D.CveUsuarioRevisa, D.FechaRevision, D.FechaAlta, D.UltimaNota,
D.FechaDocumento, D.FechaVencimiento, D.Vencido
EXCEPT
SELECT O.NombreArchivo, O.NombreArchivoFisico, O.RutaArchivo,
O.ContentType, O.TamanoBytes, O.ComentarioCliente,
O.ComentarioAdministrativo, O.EsAprobado, O.CveUsuarioCarga,
O.CveUsuarioRevisa, O.FechaRevision, O.FechaAlta, O.UltimaNota,
O.FechaDocumento, O.FechaVencimiento, O.Vencido
)
)
THROW 51000, 'Hay versiones vigentes con datos distintos por trámite. Revisarlas antes de consolidar; no se eliminaron documentos.', 1;
IF EXISTS
(
SELECT 1
FROM dbo.Tra_SolicitudDocumentoConfiguracion
GROUP BY CveFraccionamientoEtapa, CveTipoDocumento
HAVING MIN(CONVERT(int, EsRequerido)) <> MAX(CONVERT(int, EsRequerido))
OR MIN(CONVERT(int, EsCliente)) <> MAX(CONVERT(int, EsCliente))
OR MIN(CONVERT(int, TieneVigencia)) <> MAX(CONVERT(int, TieneVigencia))
OR MIN(CONVERT(int, EsActivo)) <> MAX(CONVERT(int, EsActivo))
OR MIN(Orden) <> MAX(Orden)
)
THROW 51000, 'Hay configuraciones manuales distintas por trámite. Resolverlas antes de consolidar la marca de la etapa.', 1;
IF EXISTS
(
SELECT 1 FROM sys.indexes
WHERE object_id = OBJECT_ID('dbo.Tra_DocumentosSolicitud')
AND name = 'UX_Tra_DocumentosSolicitud_Etapa_Tramite_Documento'
)
DROP INDEX UX_Tra_DocumentosSolicitud_Etapa_Tramite_Documento
ON dbo.Tra_DocumentosSolicitud;
IF EXISTS
(
SELECT 1 FROM sys.indexes
WHERE object_id = OBJECT_ID('dbo.Tra_SolicitudDocumentoConfiguracion')
AND name = 'UX_Tra_ConfiguracionDocumento_Etapa_Tramite_Documento'
)
DROP INDEX UX_Tra_ConfiguracionDocumento_Etapa_Tramite_Documento
ON dbo.Tra_SolicitudDocumentoConfiguracion;
-- Las columnas se conservan por compatibilidad de esquema; ya no son propietarias.
ALTER TABLE dbo.Tra_DocumentosSolicitud ALTER COLUMN CveTipoTramite int NULL;
ALTER TABLE dbo.Tra_SolicitudDocumentoConfiguracion ALTER COLUMN CveTipoTramite int NULL;
;WITH Versiones AS
(
SELECT
CveDocumentoSolicitud,
ROW_NUMBER() OVER
(
PARTITION BY CveFraccionamientoEtapa, CveTipoDocumento
ORDER BY CveDocumentoSolicitud
) AS NumeroVersion
FROM dbo.Tra_DocumentosSolicitud
WHERE EsActivo = 1
)
UPDATE D
SET EsActivo = 0
FROM dbo.Tra_DocumentosSolicitud AS D
INNER JOIN Versiones AS V ON V.CveDocumentoSolicitud = D.CveDocumentoSolicitud
WHERE V.NumeroVersion > 1;
-- Sólo se retiran copias de configuración cuyos valores son idénticos.
;WITH Configuraciones AS
(
SELECT
CveConfiguracionDocumento,
ROW_NUMBER() OVER
(
PARTITION BY CveFraccionamientoEtapa, CveTipoDocumento
ORDER BY CveConfiguracionDocumento
) AS NumeroConfiguracion
FROM dbo.Tra_SolicitudDocumentoConfiguracion
)
DELETE C
FROM dbo.Tra_SolicitudDocumentoConfiguracion AS C
INNER JOIN Configuraciones AS O ON O.CveConfiguracionDocumento = C.CveConfiguracionDocumento
WHERE O.NumeroConfiguracion > 1;
UPDATE dbo.Tra_DocumentosSolicitud
SET CveTipoTramite = NULL
WHERE CveTipoTramite IS NOT NULL;
UPDATE dbo.Tra_SolicitudDocumentoConfiguracion
SET CveTipoTramite = NULL
WHERE CveTipoTramite IS NOT NULL;
IF NOT EXISTS
(
SELECT 1 FROM sys.indexes
WHERE object_id = OBJECT_ID('dbo.Tra_DocumentosSolicitud')
AND name = 'UX_Tra_DocumentosSolicitud_Etapa_TipoDocumento'
)
CREATE UNIQUE INDEX UX_Tra_DocumentosSolicitud_Etapa_TipoDocumento
ON dbo.Tra_DocumentosSolicitud (CveFraccionamientoEtapa, CveTipoDocumento)
WHERE EsActivo = 1;
IF NOT EXISTS
(
SELECT 1 FROM sys.indexes
WHERE object_id = OBJECT_ID('dbo.Tra_SolicitudDocumentoConfiguracion')
AND name = 'UX_Tra_ConfiguracionDocumento_Etapa_Documento'
)
CREATE UNIQUE INDEX UX_Tra_ConfiguracionDocumento_Etapa_Documento
ON dbo.Tra_SolicitudDocumentoConfiguracion (CveFraccionamientoEtapa, CveTipoDocumento);
IF EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_Tra_DocumentosSolicitud_TipoTramite')
ALTER TABLE dbo.Tra_DocumentosSolicitud DROP CONSTRAINT FK_Tra_DocumentosSolicitud_TipoTramite;
IF EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_Tra_ConfiguracionDocumento_TipoTramite')
ALTER TABLE dbo.Tra_SolicitudDocumentoConfiguracion DROP CONSTRAINT FK_Tra_ConfiguracionDocumento_TipoTramite;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,340 @@
/*
Preparación únicamente; no ejecutado.
Requiere Documentos_Etapa_Estructura_20260927.sql ya instalado.
Instalar estructura, procedimientos y aplicación en una ventana coordinada.
El ejecutor debe abrir una transacción, detenerse y revertir ante cualquier
error, y confirmar sólo después de instalar y verificar todos los scripts.
Los registros sin solicitud se conservan en todos los tipos activos aplicables.
Se duplica únicamente la metadata: archivos, fechas, revisiones y versiones
conservan su contenido. El identificador original queda en el menor tipo;
no significa que ese tipo tenga prioridad funcional.
GIS histórico 2 se normaliza al documento configurado 1016 / trámite 12.
Las asignaciones directas existentes no vuelven a expandirse al reinstalar.
*/
SET NOCOUNT ON;
IF @@TRANCOUNT = 0
THROW 51000, 'Abrir una transacción de instalación antes de ejecutar este script y revertirla ante cualquier error.', 1;
SELECT
D.CveDocumentoSolicitud,
D.CveFraccionamientoEtapa,
CASE WHEN D.CveTipoDocumento = 2 THEN 1016 ELSE D.CveTipoDocumento END AS CveTipoDocumento,
S.CveTipoTramite AS TipoSolicitud,
CONVERT(int, NULL) AS TipoDirecto
INTO #OrigenDocumentos
FROM dbo.Tra_DocumentosSolicitud AS D
LEFT JOIN dbo.Tra_Solicitudes AS S ON S.CveSolicitud = D.CveSolicitud;
IF COL_LENGTH('dbo.Tra_DocumentosSolicitud', 'CveTipoTramite') IS NOT NULL
EXEC sys.sp_executesql N'
UPDATE O
SET TipoDirecto = D.CveTipoTramite,
CveTipoDocumento = D.CveTipoDocumento
FROM #OrigenDocumentos AS O
INNER JOIN dbo.Tra_DocumentosSolicitud AS D ON D.CveDocumentoSolicitud = O.CveDocumentoSolicitud
WHERE D.CveTipoTramite IS NOT NULL;';
SELECT DISTINCT
O.CveDocumentoSolicitud,
O.CveFraccionamientoEtapa,
O.CveTipoDocumento,
COALESCE(O.TipoDirecto, O.TipoSolicitud, T.CveTipoTramite) AS CveTipoTramite
INTO #TiposDocumentos
FROM #OrigenDocumentos AS O
LEFT JOIN dbo.Tra_TiposTramiteDocumento AS T ON T.CveTipoDocumento = O.CveTipoDocumento
AND T.EsActivo = 1
AND O.TipoDirecto IS NULL
AND O.TipoSolicitud IS NULL;
IF EXISTS (SELECT 1 FROM #TiposDocumentos WHERE CveTipoTramite IS NULL)
BEGIN
SELECT *
FROM #TiposDocumentos
WHERE CveTipoTramite IS NULL;
THROW 51000, 'Hay documentos sin tipo de trámite aplicable. Resolver su correspondencia y revertir la instalación.', 1;
END;
SELECT
D.CveConfiguracionDocumento,
D.CveFraccionamientoEtapa,
CASE WHEN D.CveTipoDocumento = 2 THEN 1016 ELSE D.CveTipoDocumento END AS CveTipoDocumento,
S.CveTipoTramite AS TipoSolicitud,
CONVERT(int, NULL) AS TipoDirecto
INTO #OrigenConfiguraciones
FROM dbo.Tra_SolicitudDocumentoConfiguracion AS D
LEFT JOIN dbo.Tra_Solicitudes AS S ON S.CveSolicitud = D.CveSolicitud;
IF COL_LENGTH('dbo.Tra_SolicitudDocumentoConfiguracion', 'CveTipoTramite') IS NOT NULL
EXEC sys.sp_executesql N'
UPDATE O
SET TipoDirecto = D.CveTipoTramite,
CveTipoDocumento = D.CveTipoDocumento
FROM #OrigenConfiguraciones AS O
INNER JOIN dbo.Tra_SolicitudDocumentoConfiguracion AS D ON D.CveConfiguracionDocumento = O.CveConfiguracionDocumento
WHERE D.CveTipoTramite IS NOT NULL;';
SELECT DISTINCT
O.CveConfiguracionDocumento,
O.CveFraccionamientoEtapa,
O.CveTipoDocumento,
COALESCE(O.TipoDirecto, O.TipoSolicitud, T.CveTipoTramite) AS CveTipoTramite
INTO #TiposConfiguraciones
FROM #OrigenConfiguraciones AS O
LEFT JOIN dbo.Tra_TiposTramiteDocumento AS T ON T.CveTipoDocumento = O.CveTipoDocumento
AND T.EsActivo = 1
AND O.TipoDirecto IS NULL
AND O.TipoSolicitud IS NULL;
IF EXISTS (SELECT 1 FROM #TiposConfiguraciones WHERE CveTipoTramite IS NULL)
BEGIN
SELECT *
FROM #TiposConfiguraciones
WHERE CveTipoTramite IS NULL;
THROW 51000, 'Hay configuraciones sin tipo de trámite aplicable. Resolver su correspondencia y revertir la instalación.', 1;
END;
-- Nunca reemplazar una configuración específica con otra compartida.
IF EXISTS
(
SELECT 1
FROM #TiposConfiguraciones
GROUP BY CveFraccionamientoEtapa, CveTipoTramite, CveTipoDocumento
HAVING COUNT(*) > 1
)
BEGIN
SELECT CveFraccionamientoEtapa, CveTipoTramite, CveTipoDocumento
FROM #TiposConfiguraciones
GROUP BY CveFraccionamientoEtapa, CveTipoTramite, CveTipoDocumento
HAVING COUNT(*) > 1;
THROW 51000, 'Hay configuraciones que convergen al mismo destino. Resolverlas conservando sus valores antes de instalar.', 1;
END;
IF EXISTS
(
SELECT 1
FROM #TiposDocumentos AS T
INNER JOIN dbo.Tra_DocumentosSolicitud AS D ON D.CveDocumentoSolicitud = T.CveDocumentoSolicitud
WHERE D.EsActivo = 1
GROUP BY T.CveFraccionamientoEtapa, T.CveTipoTramite, T.CveTipoDocumento
HAVING COUNT(*) > 1
)
THROW 51000, 'Hay versiones vigentes que convergen al mismo destino. Resolver su vigencia antes de instalar.', 1;
IF EXISTS
(
SELECT 1
FROM sys.indexes
WHERE object_id = OBJECT_ID('dbo.Tra_DocumentosSolicitud')
AND name = 'UX_Tra_DocumentosSolicitud_Etapa_TipoDocumento'
)
DROP INDEX UX_Tra_DocumentosSolicitud_Etapa_TipoDocumento ON dbo.Tra_DocumentosSolicitud;
IF EXISTS
(
SELECT 1
FROM sys.indexes
WHERE object_id = OBJECT_ID('dbo.Tra_SolicitudDocumentoConfiguracion')
AND name = 'UX_Tra_ConfiguracionDocumento_Solicitud'
)
DROP INDEX UX_Tra_ConfiguracionDocumento_Solicitud ON dbo.Tra_SolicitudDocumentoConfiguracion;
IF EXISTS
(
SELECT 1
FROM sys.indexes
WHERE object_id = OBJECT_ID('dbo.Tra_SolicitudDocumentoConfiguracion')
AND name = 'UX_Tra_ConfiguracionDocumento_Etapa'
)
DROP INDEX UX_Tra_ConfiguracionDocumento_Etapa ON dbo.Tra_SolicitudDocumentoConfiguracion;
IF COL_LENGTH('dbo.Tra_DocumentosSolicitud', 'CveTipoTramite') IS NULL
ALTER TABLE dbo.Tra_DocumentosSolicitud ADD CveTipoTramite int NULL;
-- El SQL dinámico compila después de agregar la columna.
EXEC sys.sp_executesql N'
;WITH DestinoOriginal AS
(
SELECT CveDocumentoSolicitud, MIN(CveTipoTramite) AS CveTipoTramite
FROM #TiposDocumentos
GROUP BY CveDocumentoSolicitud
)
UPDATE D
SET CveTipoTramite = T.CveTipoTramite,
CveTipoDocumento = T.CveTipoDocumento
FROM dbo.Tra_DocumentosSolicitud AS D
INNER JOIN DestinoOriginal AS O ON O.CveDocumentoSolicitud = D.CveDocumentoSolicitud
INNER JOIN #TiposDocumentos AS T ON T.CveDocumentoSolicitud = O.CveDocumentoSolicitud
AND T.CveTipoTramite = O.CveTipoTramite;
INSERT INTO dbo.Tra_DocumentosSolicitud
(
CveFraccionamientoEtapa,
CveTipoDocumento,
CveTipoTramite,
CveSolicitud,
NombreArchivo,
NombreArchivoFisico,
RutaArchivo,
ContentType,
TamanoBytes,
ComentarioCliente,
ComentarioAdministrativo,
EsAprobado,
CveUsuarioCarga,
CveUsuarioRevisa,
FechaRevision,
FechaAlta,
UltimaNota,
FechaDocumento,
FechaVencimiento,
EsActivo,
Vencido
)
SELECT
T.CveFraccionamientoEtapa,
T.CveTipoDocumento,
T.CveTipoTramite,
D.CveSolicitud,
D.NombreArchivo,
D.NombreArchivoFisico,
D.RutaArchivo,
D.ContentType,
D.TamanoBytes,
D.ComentarioCliente,
D.ComentarioAdministrativo,
D.EsAprobado,
D.CveUsuarioCarga,
D.CveUsuarioRevisa,
D.FechaRevision,
D.FechaAlta,
D.UltimaNota,
D.FechaDocumento,
D.FechaVencimiento,
D.EsActivo,
D.Vencido
FROM dbo.Tra_DocumentosSolicitud AS D
INNER JOIN #TiposDocumentos AS T ON T.CveDocumentoSolicitud = D.CveDocumentoSolicitud
WHERE T.CveTipoTramite <> D.CveTipoTramite;
ALTER TABLE dbo.Tra_DocumentosSolicitud ALTER COLUMN CveTipoTramite int NOT NULL;';
IF COL_LENGTH('dbo.Tra_SolicitudDocumentoConfiguracion', 'CveTipoTramite') IS NULL
ALTER TABLE dbo.Tra_SolicitudDocumentoConfiguracion ADD CveTipoTramite int NULL;
-- El SQL dinámico compila después de agregar la columna.
EXEC sys.sp_executesql N'
;WITH DestinoOriginal AS
(
SELECT CveConfiguracionDocumento, MIN(CveTipoTramite) AS CveTipoTramite
FROM #TiposConfiguraciones
GROUP BY CveConfiguracionDocumento
)
UPDATE D
SET CveTipoTramite = T.CveTipoTramite,
CveTipoDocumento = T.CveTipoDocumento
FROM dbo.Tra_SolicitudDocumentoConfiguracion AS D
INNER JOIN DestinoOriginal AS O ON O.CveConfiguracionDocumento = D.CveConfiguracionDocumento
INNER JOIN #TiposConfiguraciones AS T ON T.CveConfiguracionDocumento = O.CveConfiguracionDocumento
AND T.CveTipoTramite = O.CveTipoTramite;
INSERT INTO dbo.Tra_SolicitudDocumentoConfiguracion
(
CveFraccionamientoEtapa,
CveTipoDocumento,
CveTipoTramite,
CveSolicitud,
EsRequerido,
EsCliente,
TieneVigencia,
Orden,
EsActivo
)
SELECT
T.CveFraccionamientoEtapa,
T.CveTipoDocumento,
T.CveTipoTramite,
D.CveSolicitud,
D.EsRequerido,
D.EsCliente,
D.TieneVigencia,
D.Orden,
D.EsActivo
FROM dbo.Tra_SolicitudDocumentoConfiguracion AS D
INNER JOIN #TiposConfiguraciones AS T ON T.CveConfiguracionDocumento = D.CveConfiguracionDocumento
WHERE T.CveTipoTramite <> D.CveTipoTramite;
ALTER TABLE dbo.Tra_SolicitudDocumentoConfiguracion ALTER COLUMN CveTipoTramite int NOT NULL;';
IF NOT EXISTS
(
SELECT 1
FROM sys.indexes
WHERE object_id = OBJECT_ID('dbo.Tra_DocumentosSolicitud')
AND name = 'UX_Tra_DocumentosSolicitud_Etapa_Tramite_Documento'
)
EXEC sys.sp_executesql N'
CREATE UNIQUE INDEX UX_Tra_DocumentosSolicitud_Etapa_Tramite_Documento
ON dbo.Tra_DocumentosSolicitud (CveFraccionamientoEtapa, CveTipoTramite, CveTipoDocumento)
WHERE EsActivo = 1;';
IF NOT EXISTS
(
SELECT 1
FROM sys.indexes
WHERE object_id = OBJECT_ID('dbo.Tra_SolicitudDocumentoConfiguracion')
AND name = 'UX_Tra_ConfiguracionDocumento_Etapa_Tramite_Documento'
)
EXEC sys.sp_executesql N'
CREATE UNIQUE INDEX UX_Tra_ConfiguracionDocumento_Etapa_Tramite_Documento
ON dbo.Tra_SolicitudDocumentoConfiguracion
(CveFraccionamientoEtapa, CveTipoTramite, CveTipoDocumento);';
IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_Tra_DocumentosSolicitud_TipoTramite')
EXEC sys.sp_executesql N'
ALTER TABLE dbo.Tra_DocumentosSolicitud WITH CHECK
ADD CONSTRAINT FK_Tra_DocumentosSolicitud_TipoTramite
FOREIGN KEY (CveTipoTramite) REFERENCES dbo.Tra_TiposTramite (CveTipoTramite);';
IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_Tra_ConfiguracionDocumento_TipoTramite')
EXEC sys.sp_executesql N'
ALTER TABLE dbo.Tra_SolicitudDocumentoConfiguracion WITH CHECK
ADD CONSTRAINT FK_Tra_ConfiguracionDocumento_TipoTramite
FOREIGN KEY (CveTipoTramite) REFERENCES dbo.Tra_TiposTramite (CveTipoTramite);';
-- CveSolicitud se conserva sólo como referencia histórica, sin dependencia relacional.
DECLARE @QuitarRelaciones nvarchar(max) = N'';
SELECT @QuitarRelaciones = @QuitarRelaciones
+ N'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(F.parent_object_id))
+ N'.' + QUOTENAME(OBJECT_NAME(F.parent_object_id))
+ N' DROP CONSTRAINT ' + QUOTENAME(F.name) + N';'
FROM sys.foreign_keys AS F
WHERE F.parent_object_id IN
(OBJECT_ID('dbo.Tra_DocumentosSolicitud'), OBJECT_ID('dbo.Tra_SolicitudDocumentoConfiguracion'))
AND F.referenced_object_id = OBJECT_ID('dbo.Tra_Solicitudes');
IF @QuitarRelaciones <> N''
EXEC sys.sp_executesql @QuitarRelaciones;
INSERT INTO dbo.Bit_Campos
(CveTabla, NombreCampoSQL, NombreMostrar, MostrarEnBitacora, TipoDatoSQL, Activo)
SELECT
T.CveTabla,
'CveTipoTramite',
'Tipo de trámite',
1,
'int',
1
FROM dbo.Bit_Tablas AS T
WHERE T.NombreTablaSQL IN ('Tra_DocumentosSolicitud', 'Tra_SolicitudDocumentoConfiguracion')
AND NOT EXISTS
(
SELECT 1
FROM dbo.Bit_Campos AS C
WHERE C.CveTabla = T.CveTabla
AND C.NombreCampoSQL = 'CveTipoTramite'
);
DROP TABLE #TiposDocumentos;
DROP TABLE #OrigenDocumentos;
DROP TABLE #TiposConfiguraciones;
DROP TABLE #OrigenConfiguraciones;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,110 @@
-- Preparado para revisión. La instalación requiere autorización independiente.
-- La configuración se conserva por etapa y nombre de capa del archivo original.
IF OBJECT_ID(N'dbo.FraccionamientosEtapasGISCapas', N'U') IS NULL
BEGIN
CREATE TABLE dbo.FraccionamientosEtapasGISCapas
(
CveFraccionamientoEtapa int NOT NULL,
NombreCapa nvarchar(250) COLLATE Modern_Spanish_CS_AS NOT NULL,
TipoCapa nvarchar(20) COLLATE Modern_Spanish_CS_AS NOT NULL,
Color nvarchar(7) COLLATE Modern_Spanish_CS_AS NOT NULL,
EsVisible bit NOT NULL,
CveUsuarioModifica int NOT NULL,
FechaModificacion datetime2 NOT NULL,
CONSTRAINT PK_FraccionamientosEtapasGISCapas
PRIMARY KEY (CveFraccionamientoEtapa, NombreCapa),
CONSTRAINT FK_FraccionamientosEtapasGISCapas_Etapa
FOREIGN KEY (CveFraccionamientoEtapa)
REFERENCES dbo.FraccionamientosEtapas (CveFraccionamientoEtapa),
CONSTRAINT CK_FraccionamientosEtapasGISCapas_Tipo
CHECK (TipoCapa IN (N'Agua', N'Drenaje', N'Lotificacion', N'Pozos', N'Otros')),
CONSTRAINT CK_FraccionamientosEtapasGISCapas_Color
CHECK (LEN(Color) = 7 AND Color COLLATE Latin1_General_BIN2
LIKE N'#[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]')
);
END;
GO
CREATE OR ALTER PROCEDURE dbo.PA_Fraccionamientos_EtapaGISCapasList
@CveFraccionamientoEtapa int,
@CveUsuarioEjecuta int,
@ErrorMostrar varchar(max) OUTPUT,
@ErrorTipo int OUTPUT,
@Return bit OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT @ErrorMostrar = NULL, @ErrorTipo = 0, @Return = 0;
BEGIN TRY
SELECT NombreCapa, TipoCapa, Color, EsVisible
FROM dbo.FraccionamientosEtapasGISCapas
WHERE CveFraccionamientoEtapa = @CveFraccionamientoEtapa;
SET @Return = 1;
END TRY
BEGIN CATCH
SELECT
@ErrorMostrar = 'No fue posible consultar la configuración de capas GIS.',
@ErrorTipo = 1,
@Return = 0;
DECLARE @ErrorTecnico nvarchar(2048) = CONCAT(
'Número: ', ERROR_NUMBER(), '; Procedimiento: ', ERROR_PROCEDURE(),
'; Línea: ', ERROR_LINE(), '; Detalle: ', ERROR_MESSAGE());
RAISERROR(N'%s', 10, 1, @ErrorTecnico);
END CATCH;
END;
GO
CREATE OR ALTER PROCEDURE dbo.PA_Fraccionamientos_EtapaGISCapasSave
@CveFraccionamientoEtapa int,
@NombreCapa nvarchar(250),
@TipoCapa nvarchar(20),
@Color nvarchar(7),
@EsVisible bit,
@CveUsuarioEjecuta int,
@ErrorMostrar varchar(max) OUTPUT,
@ErrorTipo int OUTPUT,
@Return bit OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT @ErrorMostrar = NULL, @ErrorTipo = 0, @Return = 0;
BEGIN TRY
-- El servicio mantiene la transacción ambiental para proteger este upsert.
UPDATE dbo.FraccionamientosEtapasGISCapas WITH (UPDLOCK, HOLDLOCK)
SET TipoCapa = @TipoCapa,
Color = @Color,
EsVisible = @EsVisible,
CveUsuarioModifica = @CveUsuarioEjecuta,
FechaModificacion = SYSDATETIME()
WHERE CveFraccionamientoEtapa = @CveFraccionamientoEtapa
AND NombreCapa = @NombreCapa;
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO dbo.FraccionamientosEtapasGISCapas
(
CveFraccionamientoEtapa, NombreCapa, TipoCapa, Color,
EsVisible, CveUsuarioModifica, FechaModificacion
)
VALUES
(
@CveFraccionamientoEtapa, @NombreCapa, @TipoCapa, @Color,
@EsVisible, @CveUsuarioEjecuta, SYSDATETIME()
);
END;
SET @Return = 1;
END TRY
BEGIN CATCH
SELECT
@ErrorMostrar = 'No fue posible guardar la configuración de la capa GIS.',
@ErrorTipo = 1,
@Return = 0;
DECLARE @ErrorTecnico nvarchar(2048) = CONCAT(
'Número: ', ERROR_NUMBER(), '; Procedimiento: ', ERROR_PROCEDURE(),
'; Línea: ', ERROR_LINE(), '; Detalle: ', ERROR_MESSAGE());
RAISERROR(N'%s', 10, 1, @ErrorTecnico);
END CATCH;
END;
GO

View File

@@ -70,6 +70,7 @@ namespace SIG.Web.AppCode.Configuration
"~/Scripts/scrollsig.js",
"~/Scripts/sig-grid-agrupado.js",
"~/Scripts/Convenios.js",
"~/Scripts/VisorGis.js",
"~/Scripts/LotesEtapa.js"
));
bundles.Add(new ScriptBundle("~/bundles/WebFormsJs").Include(
@@ -140,6 +141,7 @@ namespace SIG.Web.AppCode.Configuration
"~/Styles/scrollsig.css",
"~/Styles/sig-grid-agrupado.css",
"~/Styles/Convenios.css",
"~/Styles/VisorGis.css",
"~/Styles/LotesEtapa.css",
"~/Metronic/assets/global/plugins/bootstrap-switch/css/bootstrap-switch.min.css",
"~/Metronic/assets/global/plugins/bootstrap-toastr/toastr.min.css",

View File

@@ -1,10 +1,13 @@
using System;
using System;
using System.Collections.Generic;
using SIG.Web.AppCode.Models.Common;
using SIG.Web.AppCode.Models.Documentos;
namespace SIG.Web.AppCode.Contracts.Documentos
{
// Los documentos y sus marcas particulares pertenecen a etapa y tipo de documento.
// Los parámetros de trámite en carga se conservan por compatibilidad;
// sólo los listados de requisitos utilizan el trámite como filtro.
public interface ITramiteDocumentoRepository
{
DbResult<List<SolicitudDocumentoConfiguracionModel>> ListarConfiguracionSolicitud(
@@ -12,7 +15,8 @@ namespace SIG.Web.AppCode.Contracts.Documentos
int cveSolicitud,
int cveUsuarioEjecuta,
string nombreDominio,
int? cveFraccionamientoEtapa = null);
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null);
DbResult<bool> ActualizarVencimientoEtapa(
int cveFraccionamientoEtapa,
@@ -30,7 +34,8 @@ namespace SIG.Web.AppCode.Contracts.Documentos
int cveTipoDocumento,
int cveUsuarioEjecuta,
string nombreDominio,
int? cveFraccionamientoEtapa = null);
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null);
DbResult<List<TramiteDocumentoSolicitudModel>> ListForDevelopment(
int developmentId,
@@ -52,7 +57,8 @@ namespace SIG.Web.AppCode.Contracts.Documentos
int documentTypeId,
int executingUser,
string domainName,
int? cveFraccionamientoEtapa = null);
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null);
DbResult<TramiteDocumentoUploadContextModel> GetStageUploadContext(
int stageId,
@@ -76,7 +82,8 @@ namespace SIG.Web.AppCode.Contracts.Documentos
DateTime? fechaDocumento = null,
DateTime? fechaVencimiento = null,
bool actualizarFechas = false,
int? cveFraccionamientoEtapa = null);
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null);
DbResult<TramiteDocumentoVencimientoResultModel> ActualizarFechaVencimiento(
int cveFraccionamiento,

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using SIG.Web.AppCode.Models.Common;
@@ -7,6 +7,9 @@ using SIG.Web.AppCode.Models.Documentos;
namespace SIG.Web.AppCode.Contracts.Documentos
{
// Los documentos y sus marcas particulares pertenecen a etapa y tipo de documento.
// Los parámetros de trámite en carga se conservan por compatibilidad;
// sólo los listados de requisitos utilizan el trámite como filtro.
public interface ITramiteDocumentoService
{
DbResult<List<SolicitudDocumentoConfiguracionModel>> ListarConfiguracionSolicitud(
@@ -14,7 +17,8 @@ namespace SIG.Web.AppCode.Contracts.Documentos
int cveSolicitud,
int cveUsuarioEjecuta,
string nombreDominio,
int? cveFraccionamientoEtapa = null);
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null);
DbResult<bool> ActualizarVencimientoEtapa(
int cveFraccionamientoEtapa,
@@ -32,7 +36,8 @@ namespace SIG.Web.AppCode.Contracts.Documentos
int cveTipoDocumento,
int cveUsuarioEjecuta,
string nombreDominio,
int? cveFraccionamientoEtapa = null);
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null);
DbResult<List<TramiteDocumentoSolicitudModel>> ListForDevelopment(
int developmentId,
@@ -54,7 +59,8 @@ namespace SIG.Web.AppCode.Contracts.Documentos
int documentTypeId,
int executingUser,
string domainName,
int? cveFraccionamientoEtapa = null);
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null);
DbResult<TramiteDocumentoSaveResultModel> Upload(
int developmentId,
@@ -69,7 +75,8 @@ namespace SIG.Web.AppCode.Contracts.Documentos
string domainName,
DateTime? fechaDocumento = null,
DateTime? fechaVencimiento = null,
int? cveFraccionamientoEtapa = null);
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null);
DbResult<bool> Eliminar(
int cveFraccionamiento,

View File

@@ -6,6 +6,17 @@ namespace SIG.Web.AppCode.Contracts.Fraccionamientos
{
public interface IRepositorioGisFraccionamiento
{
DbResult<List<CapaGisFraccionamiento>> ListarCapas(
int cveFraccionamientoEtapa,
int cveUsuarioEjecuta,
string nombreDominio);
DbResult<bool> GuardarCapa(
int cveFraccionamientoEtapa,
CapaGisFraccionamiento capa,
int cveUsuarioEjecuta,
string nombreDominio);
DbResult<ContextoGisFraccionamiento> ObtenerContexto(
int cveFraccionamientoEtapa,
int cveUsuarioEjecuta,

View File

@@ -7,6 +7,31 @@ namespace SIG.Web.AppCode.Contracts.Fraccionamientos
{
public interface IServicioGisFraccionamiento
{
DbResult<ResultadoGuardadoGisFraccionamiento> DesvincularLote(
int cveFraccionamientoEtapa,
int cveFraccionamientoLote,
string clavePoligono,
int cveUsuarioEjecuta,
string nombreDominio);
DbResult<ResultadoGuardadoGisFraccionamiento> VincularLote(
int cveFraccionamientoEtapa,
int cveFraccionamientoLote,
string clavePoligono,
int cveUsuarioEjecuta,
string nombreDominio);
DbResult<List<CapaGisFraccionamiento>> ListarCapas(
int cveFraccionamientoEtapa,
int cveUsuarioEjecuta,
string nombreDominio);
DbResult<bool> GuardarCapa(
int cveFraccionamientoEtapa,
CapaGisFraccionamiento capa,
int cveUsuarioEjecuta,
string nombreDominio);
DbResult<VistaGisFraccionamiento> Obtener(
int cveFraccionamientoEtapa,
int cveUsuarioEjecuta,

View File

@@ -53,6 +53,24 @@ namespace SIG.Web.Pages.Fraccionamientos
"POST",
StringComparison.OrdinalIgnoreCase))
{
if (string.Equals(metodo, "DesvincularLote", StringComparison.OrdinalIgnoreCase))
{
DesvincularLote(contexto, actualUsuario);
return;
}
if (string.Equals(metodo, "VincularLote", StringComparison.OrdinalIgnoreCase))
{
VincularLote(contexto, actualUsuario);
return;
}
if (string.Equals(metodo, "GuardarCapa", StringComparison.OrdinalIgnoreCase))
{
GuardarCapa(contexto, actualUsuario);
return;
}
if (string.Equals(metodo, "Save", StringComparison.OrdinalIgnoreCase) ||
string.Equals(metodo, "GuardarArchivo", StringComparison.OrdinalIgnoreCase) ||
string.Equals(metodo, "GuardarVinculos", StringComparison.OrdinalIgnoreCase))
@@ -94,6 +112,21 @@ namespace SIG.Web.Pages.Fraccionamientos
return;
}
if (string.Equals(metodo, "Capas", StringComparison.OrdinalIgnoreCase))
{
DbResult<List<CapaGisFraccionamiento>> capas =
AppServices.ServicioGisFraccionamiento.ListarCapas(
cveFraccionamientoEtapa, actualUsuario.CveUsuario, actualUsuario.NombreDominio);
if (!capas.Success)
{
EscribirFalloResultado(contexto, capas, 400);
return;
}
EscribirJson(contexto, 200, new { success = true, data = capas.Data });
return;
}
if (string.Equals(metodo, "Context", StringComparison.OrdinalIgnoreCase))
{
ObtenerContexto(contexto, actualUsuario, cveFraccionamientoEtapa);
@@ -162,6 +195,86 @@ namespace SIG.Web.Pages.Fraccionamientos
});
}
private static void VincularLote(HttpContext contexto, UserSessionModel actualUsuario)
{
int etapa;
int lote;
if (!IntentarObtenerCveEtapa(contexto, out etapa) ||
!int.TryParse(contexto.Request.Form["CveFraccionamientoLote"], out lote))
{
EscribirJson(contexto, 400, new { success = false, message = "Seleccione una etapa y un lote válidos." });
return;
}
DbResult<ResultadoGuardadoGisFraccionamiento> resultado =
AppServices.ServicioGisFraccionamiento.VincularLote(
etapa, lote, contexto.Request.Form["ClavePoligono"],
actualUsuario.CveUsuario, actualUsuario.NombreDominio);
if (!resultado.Success)
{
EscribirFalloResultado(contexto, resultado, 400);
return;
}
EscribirJson(contexto, 200, new { success = true, message = "Lote vinculado correctamente." });
}
private static void DesvincularLote(HttpContext contexto, UserSessionModel actualUsuario)
{
int etapa;
int lote;
if (!IntentarObtenerCveEtapa(contexto, out etapa) ||
!int.TryParse(contexto.Request.Form["CveFraccionamientoLote"], out lote))
{
EscribirJson(contexto, 400, new { success = false, message = "Seleccione una etapa y un lote válidos." });
return;
}
var resultado = AppServices.ServicioGisFraccionamiento.DesvincularLote(
etapa, lote, contexto.Request.Form["ClavePoligono"],
actualUsuario.CveUsuario, actualUsuario.NombreDominio);
if (!resultado.Success)
{
EscribirFalloResultado(contexto, resultado, 400);
return;
}
EscribirJson(contexto, 200, new { success = true, message = "Lote desvinculado correctamente." });
}
private static void GuardarCapa(HttpContext contexto, UserSessionModel actualUsuario)
{
int etapa;
bool visible;
if (!IntentarObtenerCveEtapa(contexto, out etapa) ||
!bool.TryParse(contexto.Request.Form["EsVisible"], out visible))
{
EscribirJson(contexto, 400, new
{
success = false,
message = "Indique una etapa y configuración válidas."
});
return;
}
CapaGisFraccionamiento capa = new CapaGisFraccionamiento
{
NombreCapa = contexto.Request.Form["NombreCapa"],
TipoCapa = contexto.Request.Form["TipoCapa"],
Color = contexto.Request.Form["Color"],
EsVisible = visible
};
DbResult<bool> resultado = AppServices.ServicioGisFraccionamiento.GuardarCapa(
etapa, capa, actualUsuario.CveUsuario, actualUsuario.NombreDominio);
if (!resultado.Success)
{
EscribirFalloResultado(contexto, resultado, 400);
return;
}
EscribirJson(contexto, 200, new { success = true, message = "Capa guardada." });
}
private static void Guardar(
HttpContext contexto,
UserSessionModel actualUsuario,

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
namespace SIG.Web.AppCode.Models.Convenios
@@ -9,6 +9,7 @@ namespace SIG.Web.AppCode.Models.Convenios
public int? CveCliente { get; set; }
public int? CveFraccionamiento { get; set; }
public int? CveFraccionamientoEtapa { get; set; }
public int? CveTipoTramite { get; set; }
public string Estatus { get; set; }
public bool? ConSaldoPendiente { get; set; }
}
@@ -21,6 +22,8 @@ namespace SIG.Web.AppCode.Models.Convenios
public int CveFraccionamiento { get; set; }
public string Fraccionamiento { get; set; }
public int CveFraccionamientoEtapa { get; set; }
public int CveTipoTramite { get; set; }
public string TipoTramite { get; set; }
public string Etapa { get; set; }
public string NumeroConvenio { get; set; }
public string NumeroOficio { get; set; }
@@ -38,6 +41,8 @@ namespace SIG.Web.AppCode.Models.Convenios
public int CveConvenio { get; set; }
public int CveCliente { get; set; }
public int CveFraccionamientoEtapa { get; set; }
public int CveTipoTramite { get; set; }
public string TipoTramite { get; set; }
public string NumeroConvenio { get; set; }
public string NumeroOficio { get; set; }
public string Cliente { get; set; }
@@ -97,6 +102,8 @@ namespace SIG.Web.AppCode.Models.Convenios
{
public int CveCliente { get; set; }
public int CveFraccionamientoEtapa { get; set; }
public int CveTipoTramite { get; set; }
public string TipoTramite { get; set; }
public string NumeroConvenio { get; set; }
public string NumeroOficio { get; set; }
public int? ViviendasAutorizadas { get; set; }

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
namespace SIG.Web.AppCode.Models.Documentos
@@ -6,6 +6,7 @@ namespace SIG.Web.AppCode.Models.Documentos
[Serializable]
public sealed class SolicitudDocumentoConfiguracionModel
{
public int CveTipoTramite { get; set; }
public int CveSolicitud { get; set; }
public int CveTipoDocumento { get; set; }
public int CveCliente { get; set; }
@@ -94,6 +95,16 @@ namespace SIG.Web.AppCode.Models.Documentos
{
get { return EsRequerido && !TieneArchivo; }
}
public bool ImpideAvanzar
{
get
{
return EsRequerido &&
(!TieneArchivo || EsAprobado != true || FechaExpirada ||
(TieneVigencia && !FechaVencimiento.HasValue));
}
}
}
public sealed class TramiteDocumentoUploadContextModel

View File

@@ -4,6 +4,16 @@ using System.IO;
namespace SIG.Web.AppCode.Models.Fraccionamientos
{
public sealed class CapaGisFraccionamiento
{
public string NombreCapa { get; set; }
public string TipoCapa { get; set; }
public string Color { get; set; }
public bool EsVisible { get; set; }
public string Geometria { get; set; }
public int Elementos { get; set; }
}
public sealed class ContextoGisFraccionamiento
{
public int CveCliente { get; set; }

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
@@ -56,6 +56,11 @@ namespace SIG.Web.AppCode.Repositories.Convenios
"@CveFraccionamientoEtapa",
filtro.CveFraccionamientoEtapa,
DbType.Int32);
StoredProcedureCommand.AddInput(
comando,
"@CveTipoTramite",
filtro.CveTipoTramite,
DbType.Int32);
StoredProcedureCommand.AddInput(
comando,
"@Estatus",
@@ -150,6 +155,11 @@ namespace SIG.Web.AppCode.Repositories.Convenios
"@CveFraccionamientoEtapa",
solicitud.CveFraccionamientoEtapa,
DbType.Int32);
StoredProcedureCommand.AddInput(
comando,
"@CveTipoTramite",
solicitud.CveTipoTramite,
DbType.Int32);
StoredProcedureCommand.AddInput(
comando,
"@NumeroConvenio",

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Data;
using SIG.Web.AppCode.Contracts.Database;
@@ -22,7 +22,8 @@ namespace SIG.Web.AppCode.Repositories.Documentos
int cveSolicitud,
int cveUsuarioEjecuta,
string nombreDominio,
int? cveFraccionamientoEtapa = null)
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null)
{
return QueryList<SolicitudDocumentoConfiguracionModel>(
"dbo.PA_Tramites_SolicitudDocumentoConfiguracionList",
@@ -31,6 +32,7 @@ namespace SIG.Web.AppCode.Repositories.Documentos
comando =>
{
StoredProcedureCommand.AddInput(comando, "@CveFraccionamientoEtapa", cveFraccionamientoEtapa, DbType.Int32);
StoredProcedureCommand.AddInput(comando, "@CveTipoTramite", null, DbType.Int32);
StoredProcedureCommand.AddInput(
comando, "@CveFraccionamiento", cveFraccionamiento, DbType.Int32);
StoredProcedureCommand.AddInput(
@@ -68,6 +70,8 @@ namespace SIG.Web.AppCode.Repositories.Documentos
comando, "@CveFraccionamiento", configuracion.CveFraccionamiento, DbType.Int32);
StoredProcedureCommand.AddInput(
comando, "@CveSolicitud", configuracion.CveSolicitud, DbType.Int32);
StoredProcedureCommand.AddInput(
comando, "@CveTipoTramite", null, DbType.Int32);
StoredProcedureCommand.AddInput(
comando, "@CveTipoDocumento", configuracion.CveTipoDocumento, DbType.Int32);
StoredProcedureCommand.AddInput(
@@ -89,7 +93,8 @@ namespace SIG.Web.AppCode.Repositories.Documentos
int cveTipoDocumento,
int cveUsuarioEjecuta,
string nombreDominio,
int? cveFraccionamientoEtapa = null)
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null)
{
return Execute(
"dbo.PA_Tramites_SolicitudDocumentoConfiguracionDelete",
@@ -98,6 +103,7 @@ namespace SIG.Web.AppCode.Repositories.Documentos
comando =>
{
StoredProcedureCommand.AddInput(comando, "@CveFraccionamientoEtapa", cveFraccionamientoEtapa, DbType.Int32);
StoredProcedureCommand.AddInput(comando, "@CveTipoTramite", null, DbType.Int32);
StoredProcedureCommand.AddInput(
comando, "@CveFraccionamiento", cveFraccionamiento, DbType.Int32);
StoredProcedureCommand.AddInput(
@@ -171,7 +177,8 @@ namespace SIG.Web.AppCode.Repositories.Documentos
int documentTypeId,
int executingUser,
string domainName,
int? cveFraccionamientoEtapa = null)
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null)
{
return QueryOne<TramiteDocumentoUploadContextModel>(
"dbo.PA_Tramites_DocumentoSolicitudUploadContextGet",
@@ -180,6 +187,7 @@ namespace SIG.Web.AppCode.Repositories.Documentos
command =>
{
StoredProcedureCommand.AddInput(command, "@CveFraccionamientoEtapa", cveFraccionamientoEtapa, DbType.Int32);
StoredProcedureCommand.AddInput(command, "@CveTipoTramite", null, DbType.Int32);
StoredProcedureCommand.AddInput(
command,
"@CveFraccionamiento",
@@ -244,7 +252,8 @@ namespace SIG.Web.AppCode.Repositories.Documentos
DateTime? fechaDocumento = null,
DateTime? fechaVencimiento = null,
bool actualizarFechas = false,
int? cveFraccionamientoEtapa = null)
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null)
{
return QueryOne<TramiteDocumentoSaveResultModel>(
"dbo.PA_Tramites_DocumentoSolicitudSave",
@@ -253,6 +262,7 @@ namespace SIG.Web.AppCode.Repositories.Documentos
command =>
{
StoredProcedureCommand.AddInput(command, "@CveFraccionamientoEtapa", cveFraccionamientoEtapa, DbType.Int32);
StoredProcedureCommand.AddInput(command, "@CveTipoTramite", null, DbType.Int32);
StoredProcedureCommand.AddInput(command, "@CveFraccionamiento", developmentId, DbType.Int32);
StoredProcedureCommand.AddInput(command, "@CveSolicitud", requestId, DbType.Int32);
StoredProcedureCommand.AddInput(command, "@CveTipoDocumento", documentTypeId, DbType.Int32);

View File

@@ -18,6 +18,44 @@ namespace SIG.Web.AppCode.Repositories.Fraccionamientos
{
}
public DbResult<List<CapaGisFraccionamiento>> ListarCapas(
int cveFraccionamientoEtapa,
int cveUsuarioEjecuta,
string nombreDominio)
{
return QueryList<CapaGisFraccionamiento>(
"dbo.PA_Fraccionamientos_EtapaGISCapasList",
cveUsuarioEjecuta,
nombreDominio,
comando => StoredProcedureCommand.AddInput(
comando, "@CveFraccionamientoEtapa", cveFraccionamientoEtapa, DbType.Int32));
}
public DbResult<bool> GuardarCapa(
int cveFraccionamientoEtapa,
CapaGisFraccionamiento capa,
int cveUsuarioEjecuta,
string nombreDominio)
{
return Execute(
"dbo.PA_Fraccionamientos_EtapaGISCapasSave",
cveUsuarioEjecuta,
nombreDominio,
comando =>
{
StoredProcedureCommand.AddInput(
comando, "@CveFraccionamientoEtapa", cveFraccionamientoEtapa, DbType.Int32);
StoredProcedureCommand.AddInput(
comando, "@NombreCapa", capa.NombreCapa, DbType.String);
StoredProcedureCommand.AddInput(
comando, "@TipoCapa", capa.TipoCapa, DbType.String);
StoredProcedureCommand.AddInput(
comando, "@Color", capa.Color, DbType.String);
StoredProcedureCommand.AddInput(
comando, "@EsVisible", capa.EsVisible, DbType.Boolean);
});
}
public DbResult<ContextoGisFraccionamiento> ObtenerContexto(
int cveFraccionamientoEtapa,
int cveUsuarioEjecuta,

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Transactions;
@@ -208,6 +208,11 @@ namespace SIG.Web.AppCode.Services.Convenios
return "Seleccione el desarrollador del convenio.";
}
if (solicitud.CveTipoTramite <= 0)
{
return "Seleccione el tipo de trámite del convenio.";
}
if (solicitud.CveFraccionamientoEtapa <= 0)
{
return "Seleccione el fraccionamiento y etapa del convenio.";

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using SIG.Web.AppCode.Models.Bitacora;
using SIG.Web.AppCode.Models.Documentos;
@@ -16,16 +16,15 @@ namespace SIG.Web.AppCode.Services.Documentos
? BitacoraTipoMovimiento.Eliminado
: (anterior.EsParticular ? BitacoraTipoMovimiento.Editado : BitacoraTipoMovimiento.Agregado);
var evento = BaseEvent(
0, datos.CveSolicitud, datos.CveCliente, datos.CveFraccionamiento,
0, datos.CveTipoTramite, datos.CveCliente, datos.CveFraccionamiento,
datos.CveFraccionamientoEtapa, movimiento,
actual == null
? "Se retiró la configuración particular del documento; vuelve a aplicar la configuración general."
: "Se configuró el documento para esta solicitud.");
: "Se configuró el documento para esta etapa.");
evento.NombreTablaSQL = "Tra_SolicitudDocumentoConfiguracion";
evento.LlaveRegistro = null;
evento.LlaveRegistroTexto = datos.CveFraccionamientoEtapa.ToString(System.Globalization.CultureInfo.InvariantCulture) + "|" +
datos.CveSolicitud.ToString(System.Globalization.CultureInfo.InvariantCulture) +
"|" + datos.CveTipoDocumento.ToString(System.Globalization.CultureInfo.InvariantCulture);
datos.CveTipoDocumento.ToString(System.Globalization.CultureInfo.InvariantCulture);
evento.Relaciones.RemoveAt(0);
evento.Relaciones.Add(Relation(
BitacoraTipoRelacion.Directa, evento.NombreTablaSQL, "CveFraccionamientoEtapa",
@@ -36,7 +35,6 @@ namespace SIG.Web.AppCode.Services.Documentos
evento.Campos = new List<BitacoraCampoEventoModel>
{
Field("CveFraccionamientoEtapa", anterior.CveFraccionamientoEtapa, actual == null ? null : (object)actual.CveFraccionamientoEtapa),
Field("CveSolicitud", anterior.CveSolicitud, actual == null ? null : (object)actual.CveSolicitud),
Field("CveTipoDocumento", anterior.CveTipoDocumento, actual == null ? null : (object)actual.CveTipoDocumento),
Field("EsRequerido", anterior.EsRequerido, actual == null ? null : (object)actual.EsRequerido),
Field("EsCliente", anterior.EsCliente, actual == null ? null : (object)actual.EsCliente),
@@ -57,7 +55,7 @@ namespace SIG.Web.AppCode.Services.Documentos
var auditEvent = BaseEvent(
change.CveDocumentoSolicitud,
change.CveSolicitud,
change.CveTipoTramite,
change.CveCliente,
change.CveFraccionamiento,
change.CveFraccionamientoEtapa,
@@ -67,8 +65,6 @@ namespace SIG.Web.AppCode.Services.Documentos
auditEvent.DiscriminarCamposSinCambios = false;
auditEvent.Campos = new List<BitacoraCampoEventoModel>
{
Field("CveSolicitud", change.EsNuevo || change.CveSolicitud == 0 ? null : (object)change.CveSolicitud,
change.CveSolicitud == 0 ? null : (object)change.CveSolicitud),
Field("CveTipoDocumento", change.EsNuevo ? null : (object)change.CveTipoDocumento, change.CveTipoDocumento),
Field("NombreArchivo", change.NombreArchivoAnterior, change.NombreArchivo),
Field("NombreArchivoFisico", change.NombreArchivoFisicoAnterior, change.NombreArchivoFisico),
@@ -96,7 +92,7 @@ namespace SIG.Web.AppCode.Services.Documentos
var auditEvent = BaseEvent(
change.CveDocumentoSolicitud,
change.CveSolicitud,
change.CveTipoTramite,
change.CveCliente,
change.CveFraccionamiento,
change.CveFraccionamientoEtapa,
@@ -121,7 +117,7 @@ namespace SIG.Web.AppCode.Services.Documentos
{
ModeloRegistroBitacora evento = BaseEvent(
cambio.CveDocumentoSolicitud,
cambio.CveSolicitud,
cambio.CveTipoTramite,
cambio.CveCliente,
cambio.CveFraccionamiento,
cambio.CveFraccionamientoEtapa,
@@ -145,7 +141,7 @@ namespace SIG.Web.AppCode.Services.Documentos
{
ModeloRegistroBitacora evento = BaseEvent(
cambio.CveDocumentoSolicitud,
cambio.CveSolicitud,
cambio.CveTipoTramite,
cambio.CveCliente,
cambio.CveFraccionamiento,
cambio.CveFraccionamientoEtapa,
@@ -169,7 +165,7 @@ namespace SIG.Web.AppCode.Services.Documentos
{
return BaseEvent(
change.CveDocumentoSolicitud,
change.CveSolicitud,
change.CveTipoTramite,
change.CveCliente,
change.CveFraccionamiento,
change.CveFraccionamientoEtapa,
@@ -203,7 +199,7 @@ namespace SIG.Web.AppCode.Services.Documentos
private static ModeloRegistroBitacora BaseEvent(
int documentRequestId,
int requestId,
int cveTipoTramite,
int clientId,
int developmentId,
int stageId,
@@ -225,38 +221,28 @@ namespace SIG.Web.AppCode.Services.Documentos
"Tra_DocumentosSolicitud",
"CveDocumentoSolicitud",
documentRequestId,
"Documento de la solicitud."));
if (requestId > 0)
{
auditEvent.Relaciones.Add(
Relation(
BitacoraTipoRelacion.Relacionada,
"Tra_Solicitudes",
"CveSolicitud",
requestId,
"Solicitud del documento."));
}
"Documento de la etapa."));
auditEvent.Relaciones.Add(
Relation(
BitacoraTipoRelacion.Relacionada,
"Clientes",
"CveCliente",
clientId,
"Cliente propietario de la solicitud."));
"Cliente propietario de la etapa."));
auditEvent.Relaciones.Add(
Relation(
BitacoraTipoRelacion.Relacionada,
"Fraccionamientos",
"CveFraccionamiento",
developmentId,
"Fraccionamiento de la solicitud."));
"Fraccionamiento de la etapa."));
auditEvent.Relaciones.Add(
Relation(
BitacoraTipoRelacion.Relacionada,
"FraccionamientosEtapas",
"CveFraccionamientoEtapa",
stageId,
"Etapa de la solicitud."));
"Etapa de la etapa."));
return auditEvent;
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -20,7 +20,7 @@ namespace SIG.Web.AppCode.Services.Documentos
public sealed class TramiteDocumentoService
: ITramiteDocumentoService
{
private const int GisDocumentTypeId = 2;
private const int GisDocumentTypeId = 1016;
private readonly ITramiteDocumentoRepository _repository;
private readonly ITramiteSolicitudRepository _repositorioSolicitud;
@@ -65,7 +65,8 @@ namespace SIG.Web.AppCode.Services.Documentos
int cveSolicitud,
int cveUsuarioEjecuta,
string nombreDominio,
int? cveFraccionamientoEtapa = null)
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null)
{
UserSessionModel usuario = _contextoUsuario.GetCurrentUser();
if (usuario == null || usuario.CveUsuario != cveUsuarioEjecuta)
@@ -94,7 +95,7 @@ namespace SIG.Web.AppCode.Services.Documentos
}
return _repository.ListarConfiguracionSolicitud(
cveFraccionamiento, cveSolicitud, cveUsuarioEjecuta, nombreDominio, cveFraccionamientoEtapa);
cveFraccionamiento, cveSolicitud, cveUsuarioEjecuta, nombreDominio, cveFraccionamientoEtapa, cveTipoTramite);
}
public DbResult<bool> GuardarConfiguracionSolicitud(
@@ -114,7 +115,8 @@ namespace SIG.Web.AppCode.Services.Documentos
configuracion.CveSolicitud,
cveUsuarioEjecuta,
nombreDominio,
configuracion.CveFraccionamientoEtapa == 0 ? (int?)null : configuracion.CveFraccionamientoEtapa);
configuracion.CveFraccionamientoEtapa == 0 ? (int?)null : configuracion.CveFraccionamientoEtapa,
configuracion.CveTipoTramite);
if (!consulta.Success)
{
return CopyFailure<List<SolicitudDocumentoConfiguracionModel>, bool>(
@@ -128,6 +130,8 @@ namespace SIG.Web.AppCode.Services.Documentos
return Fail<bool>("El tipo de documento ya no está disponible.");
}
configuracion.CveTipoTramite = 0;
var resultado = _repository.GuardarConfiguracionSolicitud(
configuracion, cveUsuarioEjecuta, nombreDominio);
if (!resultado.Success)
@@ -170,12 +174,13 @@ namespace SIG.Web.AppCode.Services.Documentos
int cveTipoDocumento,
int cveUsuarioEjecuta,
string nombreDominio,
int? cveFraccionamientoEtapa = null)
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null)
{
using (var transaccion = new TransactionLogic(IsolationLevel.Serializable))
{
var consulta = ListarConfiguracionSolicitud(
cveFraccionamiento, cveSolicitud, cveUsuarioEjecuta, nombreDominio, cveFraccionamientoEtapa);
cveFraccionamiento, cveSolicitud, cveUsuarioEjecuta, nombreDominio, cveFraccionamientoEtapa, cveTipoTramite);
if (!consulta.Success)
{
return CopyFailure<List<SolicitudDocumentoConfiguracionModel>, bool>(
@@ -190,7 +195,7 @@ namespace SIG.Web.AppCode.Services.Documentos
}
var resultado = _repository.EliminarConfiguracionSolicitud(
cveFraccionamiento, cveSolicitud, cveTipoDocumento, cveUsuarioEjecuta, nombreDominio, cveFraccionamientoEtapa);
cveFraccionamiento, cveSolicitud, cveTipoDocumento, cveUsuarioEjecuta, nombreDominio, cveFraccionamientoEtapa, cveTipoTramite);
if (!resultado.Success)
{
return resultado;
@@ -291,7 +296,7 @@ namespace SIG.Web.AppCode.Services.Documentos
foreach (TramiteDocumentoSolicitudModel documento in documentos)
{
documento.PuedeActualizarArchivo =
!documento.EsGis && (esAdministrador || !documento.EsFinalSolicitud);
!documento.EsGis;
documento.PuedeRevisar = esAdministrador && documento.TieneArchivo;
}
@@ -313,11 +318,6 @@ namespace SIG.Web.AppCode.Services.Documentos
return "El documento corresponde al administrador.";
}
if (documento.EsFinalSolicitud && usuario.EsDesarrollador)
{
return "La solicitud ya está finalizada; no es posible modificar sus documentos.";
}
return null;
}
@@ -327,7 +327,8 @@ namespace SIG.Web.AppCode.Services.Documentos
int documentTypeId,
int executingUser,
string domainName,
int? cveFraccionamientoEtapa = null)
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null)
{
if (developmentId <= 0 || (requestId <= 0 && !cveFraccionamientoEtapa.HasValue) || documentTypeId <= 0)
{
@@ -348,7 +349,8 @@ namespace SIG.Web.AppCode.Services.Documentos
documentTypeId,
executingUser,
domainName,
cveFraccionamientoEtapa);
cveFraccionamientoEtapa,
cveTipoTramite);
if (!resultado.Success || resultado.Data == null)
{
return resultado;
@@ -373,7 +375,8 @@ namespace SIG.Web.AppCode.Services.Documentos
string domainName,
DateTime? fechaDocumento = null,
DateTime? fechaVencimiento = null,
int? cveFraccionamientoEtapa = null)
int? cveFraccionamientoEtapa = null,
int? cveTipoTramite = null)
{
if (content == null || contentLength <= 0)
{
@@ -388,7 +391,8 @@ namespace SIG.Web.AppCode.Services.Documentos
documentTypeId,
executingUser,
domainName,
cveFraccionamientoEtapa);
cveFraccionamientoEtapa,
cveTipoTramite);
if (!contextResult.Success || contextResult.Data == null)
{
@@ -441,7 +445,7 @@ namespace SIG.Web.AppCode.Services.Documentos
{
DbResult<TramiteDocumentoUploadContextModel> contextoActual =
GetUploadContext(
developmentId, requestId, documentTypeId, executingUser, domainName, cveFraccionamientoEtapa);
developmentId, requestId, documentTypeId, executingUser, domainName, cveFraccionamientoEtapa, cveTipoTramite);
if (!contextoActual.Success || contextoActual.Data == null)
{
_fileStore.Rollback(preparedFile);
@@ -463,7 +467,8 @@ namespace SIG.Web.AppCode.Services.Documentos
fechaDocumento,
fechaVencimiento,
true,
uploadContext.CveFraccionamientoEtapa);
uploadContext.CveFraccionamientoEtapa,
uploadContext.CveTipoTramite);
if (!saveResult.Success || saveResult.Data == null)
{
@@ -960,7 +965,7 @@ namespace SIG.Web.AppCode.Services.Documentos
DbResult<TramiteDocumentoUploadContextModel> contextResult =
_repository.GetStageUploadContext(
stageId,
procedureTypeId,
0,
documentTypeId,
executingUser,
domainName);
@@ -969,7 +974,7 @@ namespace SIG.Web.AppCode.Services.Documentos
{
return CopyFailure<TramiteDocumentoUploadContextModel, TramiteDocumentoSaveResultModel>(
contextResult,
"No fue posible obtener la solicitud asociada a la etapa.");
"No fue posible obtener el contexto de documentos de la etapa.");
}
string mensajeValidacion = ValidarCarga(contextResult.Data, executingUser);
@@ -981,6 +986,14 @@ namespace SIG.Web.AppCode.Services.Documentos
TramiteDocumentoUploadContextModel uploadContext =
contextResult.Data;
if (documentTypeId == GisDocumentTypeId &&
uploadContext.CveDocumentoSolicitud > 0 &&
uploadContext.EsAprobadoAnterior == true)
{
return Fail<TramiteDocumentoSaveResultModel>(
"El archivo GIS de la etapa ya fue aprobado y no puede reemplazarse.");
}
using (var transaction = new TransactionLogic())
{
DbResult<TramiteDocumentoSaveResultModel> result =
@@ -996,7 +1009,8 @@ namespace SIG.Web.AppCode.Services.Documentos
null,
executingUser,
domainName,
cveFraccionamientoEtapa: stageId);
cveFraccionamientoEtapa: stageId,
cveTipoTramite: null);
if (!result.Success || result.Data == null)
{
@@ -1049,7 +1063,7 @@ namespace SIG.Web.AppCode.Services.Documentos
DbResult<TramiteDocumentoUploadContextModel> contextResult =
_repository.GetStageUploadContext(
stageId,
procedureTypeId,
0,
documentTypeId,
executingUser,
domainName);
@@ -1058,7 +1072,7 @@ namespace SIG.Web.AppCode.Services.Documentos
{
return CopyFailure<TramiteDocumentoUploadContextModel, bool>(
contextResult,
"No fue posible obtener la solicitud asociada a la etapa.");
"No fue posible obtener el contexto de documentos de la etapa.");
}
string mensajeValidacion = ValidarCarga(contextResult.Data, executingUser);
@@ -1067,6 +1081,14 @@ namespace SIG.Web.AppCode.Services.Documentos
return Fail<bool>(mensajeValidacion);
}
if (documentTypeId == GisDocumentTypeId &&
contextResult.Data.CveDocumentoSolicitud > 0 &&
contextResult.Data.EsAprobadoAnterior == true)
{
return Fail<bool>(
"El archivo GIS de la etapa ya fue aprobado y no puede eliminarse.");
}
if (contextResult.Data.CveDocumentoSolicitud <= 0)
{
return DbResult<bool>.Ok(true);

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,9 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Linq;
using SIG.Web.AppCode.Contracts.Bitacora;
using SIG.Web.AppCode.Contracts.Documentos;
using SIG.Web.AppCode.Contracts.Fraccionamientos;
@@ -16,6 +18,8 @@ namespace SIG.Web.AppCode.Services.Fraccionamientos
public sealed class ServicioGisFraccionamiento : IServicioGisFraccionamiento
{
private const string ExtensionGis = ".gis";
private const string ExtensionGeoJson = ".geojson";
private const string ExtensionZip = ".zip";
private const string TipoContenidoGis = "application/json";
private const long TamanoMaximoArchivo = 30L * 1024L * 1024L;
@@ -56,6 +60,317 @@ namespace SIG.Web.AppCode.Services.Fraccionamientos
_servicioDocumentoTramite = tramiteDocumentoServicio;
}
public DbResult<ResultadoGuardadoGisFraccionamiento> VincularLote(
int cveFraccionamientoEtapa,
int cveFraccionamientoLote,
string clavePoligono,
int cveUsuarioEjecuta,
string nombreDominio)
{
if (cveFraccionamientoLote <= 0 || string.IsNullOrWhiteSpace(clavePoligono) ||
clavePoligono.Length > 100)
{
return CrearFallo<ResultadoGuardadoGisFraccionamiento>("Seleccione un lote y un polígono válidos.");
}
DbResult<ArchivoGisFraccionamiento> archivo = AbrirArchivo(
cveFraccionamientoEtapa, cveUsuarioEjecuta, nombreDominio);
if (!archivo.Success)
{
return CopiarFallo<ArchivoGisFraccionamiento, ResultadoGuardadoGisFraccionamiento>(
archivo, "No fue posible consultar el GIS de la etapa.");
}
try
{
JObject geometria;
using (StreamReader lector = new StreamReader(archivo.Data.Contenido))
{
geometria = JObject.Parse(lector.ReadToEnd());
}
List<JToken> coincidencias = (geometria["features"] ?? new JArray())
.Where(figura => figura is JObject && figura["id"] != null &&
"id:" + (((string)figura["id"]) ?? string.Empty).Trim() == clavePoligono)
.ToList();
if (coincidencias.Count != 1)
{
return CrearFallo<ResultadoGuardadoGisFraccionamiento>(
"El polígono no tiene una clave única en el GIS actual. Actualice el visor.");
}
JToken seleccion = coincidencias[0];
string tipo = (string)seleccion.SelectToken("geometry.type");
if (tipo != "Polygon" && tipo != "MultiPolygon")
{
return CrearFallo<ResultadoGuardadoGisFraccionamiento>("Sólo puede vincular polígonos con lotes.");
}
DbResult<List<CapaGisFraccionamiento>> capas = ListarCapas(
cveFraccionamientoEtapa, cveUsuarioEjecuta, nombreDominio);
if (!capas.Success)
{
return CopiarFallo<List<CapaGisFraccionamiento>, ResultadoGuardadoGisFraccionamiento>(
capas, "No fue posible consultar el tipo de capa.");
}
JToken propiedades = seleccion["properties"];
string nombreCapa = (string)(propiedades == null ? null :
propiedades["_sigCapa"] ?? propiedades["Capa"] ?? propiedades["capa"]);
nombreCapa = string.IsNullOrWhiteSpace(nombreCapa) ? "GIS" : nombreCapa.Trim();
if (!capas.Data.Any(capa => capa.NombreCapa == nombreCapa && capa.TipoCapa == "Lotificacion"))
{
return CrearFallo<ResultadoGuardadoGisFraccionamiento>(
"Configure la capa como Lotificación antes de vincular sus polígonos.");
}
// La lectura y combinación se protegen juntas para no sobrescribir otros vínculos.
using (var transaccion = new TransactionLogic(System.Transactions.IsolationLevel.Serializable))
{
DbResult<VistaGisFraccionamiento> contexto = Obtener(
cveFraccionamientoEtapa, cveUsuarioEjecuta, nombreDominio);
if (!contexto.Success)
{
return CopiarFallo<VistaGisFraccionamiento, ResultadoGuardadoGisFraccionamiento>(
contexto, "No fue posible consultar los lotes de la etapa.");
}
List<VinculoLoteGisFraccionamiento> lotes = contexto.Data.Lotes;
VinculoLoteGisFraccionamiento lote = lotes.FirstOrDefault(
elemento => elemento.CveFraccionamientoLote == cveFraccionamientoLote && elemento.EsActivo);
if (lote == null)
{
return CrearFallo<ResultadoGuardadoGisFraccionamiento>(
"Seleccione un lote activo de esta etapa.");
}
if ((!string.IsNullOrWhiteSpace(lote.GISPoligonoClave) && lote.GISPoligonoClave != clavePoligono) ||
lotes.Any(elemento => elemento.GISPoligonoClave == clavePoligono &&
elemento.CveFraccionamientoLote != cveFraccionamientoLote))
{
return CrearFallo<ResultadoGuardadoGisFraccionamiento>(
"El lote o el polígono ya está vinculado. Actualice la selección.");
}
lote.GISPoligonoClave = clavePoligono;
List<VinculoLoteGisFraccionamiento> vinculos = lotes
.Where(elemento => !string.IsNullOrWhiteSpace(elemento.GISPoligonoClave)).ToList();
DbResult<ResultadoGuardadoGisFraccionamiento> resultado = Guardar(
cveFraccionamientoEtapa, null, null, 0, vinculos, cveUsuarioEjecuta, nombreDominio);
if (resultado.Success)
{
transaccion.Commit();
}
return resultado;
}
}
catch (Exception ex)
{
const string mensaje = "No fue posible vincular el lote. Actualice el visor e inténtelo nuevamente.";
ExceptionLogger.Log(ex, "ServicioGisFraccionamiento.VincularLote", mensaje);
return DbResult<ResultadoGuardadoGisFraccionamiento>.Fail(mensaje, ex.Message, ex);
}
}
public DbResult<ResultadoGuardadoGisFraccionamiento> DesvincularLote(
int cveFraccionamientoEtapa,
int cveFraccionamientoLote,
string clavePoligono,
int cveUsuarioEjecuta,
string nombreDominio)
{
if (cveFraccionamientoLote <= 0 || string.IsNullOrWhiteSpace(clavePoligono) ||
clavePoligono.Length > 100)
{
return CrearFallo<ResultadoGuardadoGisFraccionamiento>("Seleccione un vínculo válido.");
}
try
{
using (var transaccion = new TransactionLogic(System.Transactions.IsolationLevel.Serializable))
{
var contexto = Obtener(cveFraccionamientoEtapa, cveUsuarioEjecuta, nombreDominio);
if (!contexto.Success)
{
return CopiarFallo<VistaGisFraccionamiento, ResultadoGuardadoGisFraccionamiento>(
contexto, "No fue posible consultar los lotes de la etapa.");
}
var lote = contexto.Data.Lotes.FirstOrDefault(elemento =>
elemento.CveFraccionamientoLote == cveFraccionamientoLote && elemento.EsActivo);
if (lote == null || lote.GISPoligonoClave != clavePoligono)
{
return CrearFallo<ResultadoGuardadoGisFraccionamiento>(
"El vínculo cambió. Actualice el visor antes de desvincular.");
}
var restantes = contexto.Data.Lotes.Where(elemento =>
elemento.CveFraccionamientoLote != cveFraccionamientoLote &&
!string.IsNullOrWhiteSpace(elemento.GISPoligonoClave)).ToList();
var resultado = Guardar(cveFraccionamientoEtapa, null, null, 0,
restantes, cveUsuarioEjecuta, nombreDominio);
if (resultado.Success)
{
transaccion.Commit();
}
return resultado;
}
}
catch (Exception excepcion)
{
const string mensaje = "No fue posible desvincular el lote. Actualice el visor e inténtelo nuevamente.";
ExceptionLogger.Log(excepcion, "ServicioGisFraccionamiento.DesvincularLote", mensaje);
return DbResult<ResultadoGuardadoGisFraccionamiento>.Fail(mensaje, excepcion.Message, excepcion);
}
}
public DbResult<List<CapaGisFraccionamiento>> ListarCapas(
int cveFraccionamientoEtapa,
int cveUsuarioEjecuta,
string nombreDominio)
{
DbResult<List<CapaGisFraccionamiento>> inventario = LeerCapasArchivo(
cveFraccionamientoEtapa, cveUsuarioEjecuta, nombreDominio);
if (!inventario.Success)
{
return inventario;
}
DbResult<List<CapaGisFraccionamiento>> configuracion = _repositorio.ListarCapas(
cveFraccionamientoEtapa, cveUsuarioEjecuta, nombreDominio);
if (!configuracion.Success)
{
return configuracion;
}
foreach (CapaGisFraccionamiento capa in inventario.Data)
{
CapaGisFraccionamiento guardada = configuracion.Data.FirstOrDefault(
elemento => string.Equals(elemento.NombreCapa, capa.NombreCapa, StringComparison.Ordinal));
if (guardada != null)
{
capa.TipoCapa = guardada.TipoCapa;
capa.Color = guardada.Color;
capa.EsVisible = guardada.EsVisible;
}
}
return inventario;
}
public DbResult<bool> GuardarCapa(
int cveFraccionamientoEtapa,
CapaGisFraccionamiento capa,
int cveUsuarioEjecuta,
string nombreDominio)
{
string[] tipos = { "Agua", "Drenaje", "Lotificacion", "Pozos", "Otros" };
if (capa == null || string.IsNullOrWhiteSpace(capa.NombreCapa) ||
capa.NombreCapa.Length > 250 || !tipos.Contains(capa.TipoCapa) ||
!Regex.IsMatch(capa.Color ?? string.Empty, @"\A#[0-9a-fA-F]{6}\z"))
{
return CrearFallo<bool>("Indique una capa, tipo y color válidos.");
}
DbResult<List<CapaGisFraccionamiento>> inventario = LeerCapasArchivo(
cveFraccionamientoEtapa, cveUsuarioEjecuta, nombreDominio);
if (!inventario.Success)
{
return CopiarFallo<List<CapaGisFraccionamiento>, bool>(
inventario, "No fue posible consultar las capas de la etapa.");
}
if (!inventario.Data.Any(elemento =>
string.Equals(elemento.NombreCapa, capa.NombreCapa, StringComparison.Ordinal)))
{
return CrearFallo<bool>("La capa ya no existe en el GIS de esta etapa. Actualice el visor.");
}
using (TransactionLogic transaccion = new TransactionLogic())
{
DbResult<bool> resultado = _repositorio.GuardarCapa(
cveFraccionamientoEtapa, capa, cveUsuarioEjecuta, nombreDominio);
if (resultado.Success)
{
transaccion.Commit();
}
return resultado;
}
}
private DbResult<List<CapaGisFraccionamiento>> LeerCapasArchivo(
int cveFraccionamientoEtapa,
int cveUsuarioEjecuta,
string nombreDominio)
{
DbResult<ArchivoGisFraccionamiento> archivo = AbrirArchivo(
cveFraccionamientoEtapa, cveUsuarioEjecuta, nombreDominio);
if (!archivo.Success || archivo.Data == null)
{
return CopiarFallo<ArchivoGisFraccionamiento, List<CapaGisFraccionamiento>>(
archivo, "No fue posible leer las capas del GIS.");
}
try
{
JObject contenido;
using (StreamReader lector = new StreamReader(archivo.Data.Contenido))
{
contenido = JObject.Parse(lector.ReadToEnd());
}
string[] colores =
{
"#1976D2", "#D84315", "#388E3C", "#8E24AA", "#00838F",
"#C2185B", "#827717", "#5D4037", "#455A64", "#F9A825"
};
List<CapaGisFraccionamiento> capas = new List<CapaGisFraccionamiento>();
foreach (JToken figura in contenido["features"] ?? new JArray())
{
JToken propiedades = figura["properties"];
string nombre = (string)(propiedades == null ? null :
propiedades["_sigCapa"] ?? propiedades["Capa"] ?? propiedades["capa"]);
nombre = string.IsNullOrWhiteSpace(nombre) ? "GIS" : nombre.Trim();
string geometria = (string)figura.SelectToken("geometry.type") ?? string.Empty;
CapaGisFraccionamiento capa = capas.FirstOrDefault(
elemento => string.Equals(elemento.NombreCapa, nombre, StringComparison.Ordinal));
if (capa == null)
{
string nombreNormalizado = nombre.ToLowerInvariant();
capa = new CapaGisFraccionamiento
{
NombreCapa = nombre,
TipoCapa = nombreNormalizado.Contains("lotific") ? "Lotificacion" :
nombreNormalizado.Contains("pozo") ? "Pozos" :
nombreNormalizado.Contains("drenaje") ? "Drenaje" :
nombreNormalizado.Contains("agua") ? "Agua" : "Otros",
Color = colores[capas.Count % colores.Length],
EsVisible = true,
Geometria = geometria
};
capas.Add(capa);
}
else if (capa.Geometria != geometria)
{
capa.Geometria = "Mixta";
}
capa.Elementos++;
}
return DbResult<List<CapaGisFraccionamiento>>.Ok(capas);
}
catch (Exception ex)
{
const string mensaje = "No fue posible identificar las capas del archivo GIS.";
ExceptionLogger.Log(ex, "ServicioGisFraccionamiento.LeerCapasArchivo", mensaje);
return DbResult<List<CapaGisFraccionamiento>>.Fail(mensaje, ex.Message, ex);
}
}
public DbResult<VistaGisFraccionamiento> Obtener(
int cveFraccionamientoEtapa,
int cveUsuarioEjecuta,
@@ -160,18 +475,23 @@ namespace SIG.Web.AppCode.Services.Fraccionamientos
if (!tieneArchivoCargado && !guardarVinculos)
{
return CrearFallo<ResultadoGuardadoGisFraccionamiento>(
"Seleccione un archivo .gis antes de guardar.");
"Seleccione un archivo GIS antes de guardar.");
}
ProcesadorArchivoGisFraccionamiento.Resultado archivoProcesado = null;
if (tieneArchivoCargado)
{
if (!string.Equals(
Path.GetExtension(nombreArchivoOriginal),
ExtensionGis,
StringComparison.OrdinalIgnoreCase))
string extension = Path.GetExtension(nombreArchivoOriginal) ?? string.Empty;
bool extensionValida =
string.Equals(extension, ExtensionGis, StringComparison.OrdinalIgnoreCase) ||
string.Equals(extension, ExtensionGeoJson, StringComparison.OrdinalIgnoreCase) ||
string.Equals(extension, ExtensionZip, StringComparison.OrdinalIgnoreCase);
if (!extensionValida)
{
return CrearFallo<ResultadoGuardadoGisFraccionamiento>(
"El archivo seleccionado debe tener extensión .gis.");
"El archivo seleccionado debe tener extensión .gis, .geojson o .zip.");
}
if (longitudContenido > TamanoMaximoArchivo)
@@ -179,6 +499,27 @@ namespace SIG.Web.AppCode.Services.Fraccionamientos
return CrearFallo<ResultadoGuardadoGisFraccionamiento>(
"El archivo GIS no puede exceder 30 MB.");
}
try
{
archivoProcesado = ProcesadorArchivoGisFraccionamiento.Procesar(
nombreArchivoOriginal,
contenido,
longitudContenido);
}
catch (InvalidDataException ex)
{
return DbResult<ResultadoGuardadoGisFraccionamiento>.Fail(
ex.Message,
ex.Message,
ex);
}
catch (Exception ex)
{
return CrearFalloArchivo<ResultadoGuardadoGisFraccionamiento>(
ex,
"ServicioGisFraccionamiento.Guardar.Procesar");
}
}
DbResult<ContextoGisFraccionamiento> resultadoContexto =
@@ -229,7 +570,7 @@ namespace SIG.Web.AppCode.Services.Fraccionamientos
if (!tieneArchivoCargado && !teniaArchivo)
{
return CrearFallo<ResultadoGuardadoGisFraccionamiento>(
"Seleccione un archivo .gis antes de guardar.");
"Seleccione un archivo GIS antes de guardar.");
}
byte[] anteriorArchivo = null;
@@ -262,7 +603,10 @@ namespace SIG.Web.AppCode.Services.Fraccionamientos
try
{
using (var transaccion = new TransactionLogic())
using (var transaccion = new TransactionLogic(
System.Transactions.Transaction.Current == null
? System.Transactions.IsolationLevel.ReadCommitted
: System.Transactions.Transaction.Current.IsolationLevel))
{
ModeloOperacionBitacora operacionBitacora = ModeloOperacionBitacora.Crear(
"GuardarGisEtapa",
@@ -297,7 +641,20 @@ namespace SIG.Web.AppCode.Services.Fraccionamientos
if (tieneArchivoCargado)
{
_almacenArchivos.Guardar(contextoGis, contenido);
if (archivoProcesado == null ||
archivoProcesado.ContenidoGis == null ||
archivoProcesado.ContenidoGis.Length == 0)
{
return CrearFallo<ResultadoGuardadoGisFraccionamiento>(
"No fue posible preparar el archivo GIS para guardarlo.");
}
using (var contenidoNormalizado = new MemoryStream(
archivoProcesado.ContenidoGis,
false))
{
_almacenArchivos.Guardar(contextoGis, contenidoNormalizado);
}
archivoFueEscrito = true;
string nombreArchivoFisico = Path.GetFileName(
@@ -311,13 +668,13 @@ namespace SIG.Web.AppCode.Services.Fraccionamientos
DbResult<SIG.Web.AppCode.Models.Documentos.TramiteDocumentoSaveResultModel> resultadoDocumento =
_servicioDocumentoTramite.RegisterExternalStageFile(
cveFraccionamientoEtapa,
1,
2,
nombreArchivoOriginal,
0,
1016,
archivoProcesado.NombreArchivoGis,
nombreArchivoFisico,
rutaRelativa,
TipoContenidoGis,
longitudContenido,
archivoProcesado.TipoContenido ?? TipoContenidoGis,
archivoProcesado.ContenidoGis.LongLength,
cveUsuarioEjecuta,
nombreDominio,
operacionBitacora);
@@ -503,8 +860,8 @@ namespace SIG.Web.AppCode.Services.Fraccionamientos
DbResult<bool> resultadoEliminacionDocumento =
_servicioDocumentoTramite.RemoveExternalStageFile(
cveFraccionamientoEtapa,
1,
2,
0,
1016,
cveUsuarioEjecuta,
nombreDominio,
operacionBitacora);

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Transactions;
using System.Linq;
@@ -644,9 +644,8 @@ namespace SIG.Web.AppCode.Services.Tramites
: null,
Estatus = estatus,
Condiciones = condiciones,
Documentos = resultadoDocumentos.Data
.Where(documento => documento.CveSolicitud == cveSolicitud)
.ToList(),
Documentos = resultadoDocumentos.Data ??
new List<TramiteDocumentoSolicitudModel>(),
Pagos = resultadoPagos.Data ?? new List<ModeloPagoSolicitud>()
});
}
@@ -760,10 +759,16 @@ namespace SIG.Web.AppCode.Services.Tramites
}
}
if (contexto.Documentos.Any(documento => documento.EstaPendiente))
bool requiereDocumentosAprobados =
(destino.EsCliente && destino.EsOK) ||
string.Equals(destino.Codigo, "Autorizado", StringComparison.OrdinalIgnoreCase);
if (requiereDocumentosAprobados &&
contexto.Documentos.Any(documento => documento.ImpideAvanzar))
{
return RequisitosPendientes(
"Documentos", "Existen documentos requeridos pendientes de cargar.");
"Documentos",
"Existen documentos requeridos pendientes de cargar, aprobar o renovar para este trámite.");
}
if (validarPagosRequeridos &&

File diff suppressed because one or more lines are too long

View File

@@ -2,6 +2,7 @@ using System;
using System.Globalization;
using System.Web.UI.WebControls;
using SIG.Web.AppCode.Configuration;
using SIG.Web.AppCode.Infrastructure.WebForms;
using SIG.Web.AppCode.Security;
namespace SIG.Web.Pages.Clientes

View File

@@ -1842,14 +1842,16 @@
class="ADSdropzoneLocal"
data-maxFile="1"
data-maxfilesize="30"
data-acceptedfiles=".gis"
data-message="Arrastra aquí un archivo .gis o haz clic para seleccionarlo." />
data-acceptedfiles=".gis,.geojson,.zip"
data-message="Arrastra aquí un GIS (.gis/.geojson) o un ZIP Shapefile y haz clic para seleccionarlo." />
<span class="help-block">
Guarde el archivo sin necesidad de vincular lotes.
Puede guardar los vínculos por separado y continuar con los pendientes después.
</span>
</div>
<div id="GisCapas" class="sig-gis-layers"></div>
<div id="EstatusVinculosGis"
class="sig-gis-link-status"></div>
@@ -2180,7 +2182,7 @@
<asp:Content ID="ContenidoScripts" ContentPlaceHolderID="J" runat="server">
<script src='<%= ResolveUrl("~/Scripts/CatalogosTramites.js") %>'
type="text/javascript"></script>
<script src='<%= ResolveUrl("~/Scripts/fraccionamiento-gis.js?v=20260918-1") %>'
<script src='<%= ResolveUrl("~/Scripts/fraccionamiento-gis.js?v=20261002-1") %>'
type="text/javascript"></script>
<script>
window.OpcionesGisFraccionamiento = {
@@ -2190,11 +2192,14 @@
idMapa: 'MapaGis',
idTablaVinculos: 'GisVinculos',
idEstatus: 'EstatusVinculosGis',
idCapas: 'GisCapas',
idBotonGuardar: 'BtnGuardarEtapaGis',
idBotonGuardarVinculos: 'BtnGuardarVinculosEtapaGis',
idBotonEliminar: 'BtnEliminarEtapaGis',
idBotonActualizar: 'BtnActualizarEtapaGis',
urlManejador: '<%= ResolveUrl("~/Pages/Fraccionamientos/FraccionamientoGis.ashx") %>'
urlManejador: '<%= ResolveUrl("~/Pages/Fraccionamientos/FraccionamientoGis.ashx") %>',
googleMapsEnabled: <%= string.Equals(System.Configuration.ConfigurationManager.AppSettings["GoogleMapsEnabled"], "true", System.StringComparison.OrdinalIgnoreCase) ? "true" : "false" %>,
googleMapsApiKey: '<%= System.Web.HttpUtility.JavaScriptStringEncode(System.Configuration.ConfigurationManager.AppSettings["GoogleMapsApiKey"] ?? string.Empty) %>'
};
window.SIGDetalle = window.SIGDetalle || {};

View File

@@ -1,11 +0,0 @@
--- ANTES/App_Code/Contracts/Convenios/IRepositorioConvenios.cs
+++ DESPUES/App_Code/Contracts/Convenios/IRepositorioConvenios.cs
@@ -10,6 +10,8 @@
DbResult<ConvenioDetalleCompleto> Obtener(int cveConvenio, int usuario, string dominio);
DbResult<List<ConvenioConceptoCatalogo>> ListarConceptos(int usuario, string dominio);
DbResult<int> Agregar(SolicitudAltaConvenio solicitud, int usuario, string dominio);
+ DbResult<ConvenioLotesConvenio> ObtenerLotesConvenio(int cveConvenio, int usuario, string dominio);
+ DbResult<bool> GuardarLotesConvenio(int cveConvenio, int lotesConvenio, int usuario, string dominio);
DbResult<bool> Eliminar(int cveConvenio, int usuario, string dominio);
}
}

View File

@@ -1,27 +0,0 @@
--- ANTES/App_Code/Models/Convenios/ModelosConvenios.cs
+++ DESPUES/App_Code/Models/Convenios/ModelosConvenios.cs
@@ -49,6 +49,7 @@
public int ViviendasEnConvenio { get; set; }
public int? ViviendasPendientes { get; set; }
public int? ViviendasContratadas { get; set; }
+ public int LotesConvenio { get; set; }
public string Observaciones { get; set; }
public decimal ImporteConvenio { get; set; }
public decimal ImportePagado { get; set; }
@@ -102,9 +103,16 @@
public int ViviendasEnConvenio { get; set; }
public int? ViviendasPendientes { get; set; }
public int? ViviendasContratadas { get; set; }
+ public int LotesConvenio { get; set; }
public DateTime FechaConvenio { get; set; }
public string Observaciones { get; set; }
public List<ConvenioConceptoCaptura> Conceptos { get; set; }
+ }
+
+ public sealed class ConvenioLotesConvenio
+ {
+ public int CveConvenio { get; set; }
+ public int LotesConvenio { get; set; }
}
[Serializable]

View File

@@ -1,10 +0,0 @@
--- ANTES/App_Code/Models/Fraccionamientos/ModelosFraccionamiento.cs
+++ DESPUES/App_Code/Models/Fraccionamientos/ModelosFraccionamiento.cs
@@ -14,6 +14,7 @@
public bool EsFraccionamiento { get; set; }
public string Etapa { get; set; }
public decimal? Hectareas { get; set; }
+ public decimal Avance { get; set; }
public bool Fideicomiso { get; set; }
public bool EsActivo { get; set; }
}

View File

@@ -1,31 +0,0 @@
--- ANTES/App_Code/Models/Tramites/TramiteSolicitudModels.cs
+++ DESPUES/App_Code/Models/Tramites/TramiteSolicitudModels.cs
@@ -49,6 +49,28 @@
public DateTime? FechaAutorizacion { get; set; }
public bool PuedeCambiarEstatus { get; set; }
public bool EsAutorizada { get; set; }
+ public int DocumentosPendientes { get; set; }
+ public int PagosPendientes { get; set; }
+
+ public string TextoDocumentos
+ {
+ get
+ {
+ return DocumentosPendientes == 0
+ ? "Completo"
+ : DocumentosPendientes + " pendiente(s)";
+ }
+ }
+
+ public string TextoPagos
+ {
+ get
+ {
+ return PagosPendientes == 0
+ ? "Sin pendientes"
+ : PagosPendientes + " pendiente(s)";
+ }
+ }
}
[Serializable]

View File

@@ -1,59 +0,0 @@
--- ANTES/App_Code/Repositories/Convenios/RepositorioConvenios.cs
+++ DESPUES/App_Code/Repositories/Convenios/RepositorioConvenios.cs
@@ -19,6 +19,8 @@
private const string ProcedimientoObtener = "dbo.PA_Tra_ConvenioGet";
private const string ProcedimientoListarConceptos = "dbo.PA_Tra_ConvenioConceptoList";
private const string ProcedimientoAgregar = "dbo.PA_Tra_ConvenioAdd";
+ private const string ProcedimientoObtenerLotes = "dbo.PA_Tra_ConvenioLotesGet";
+ private const string ProcedimientoGuardarLotes = "dbo.PA_Tra_ConvenioLotesUpdate";
private const string ProcedimientoEliminar = "dbo.PA_Tra_ConvenioDelete";
public RepositorioConvenios(IDbExecutor ejecutor)
@@ -193,6 +195,47 @@
"@ConceptosXml",
conceptosXml,
DbType.Xml);
+ });
+ }
+
+ public DbResult<ConvenioLotesConvenio> ObtenerLotesConvenio(
+ int cveConvenio,
+ int usuario,
+ string dominio)
+ {
+ return QueryOne<ConvenioLotesConvenio>(
+ ProcedimientoObtenerLotes,
+ usuario,
+ dominio,
+ comando => StoredProcedureCommand.AddInput(
+ comando,
+ "@CveConvenio",
+ cveConvenio,
+ DbType.Int32));
+ }
+
+ public DbResult<bool> GuardarLotesConvenio(
+ int cveConvenio,
+ int lotesConvenio,
+ int usuario,
+ string dominio)
+ {
+ return Execute(
+ ProcedimientoGuardarLotes,
+ usuario,
+ dominio,
+ comando =>
+ {
+ StoredProcedureCommand.AddInput(
+ comando,
+ "@CveConvenio",
+ cveConvenio,
+ DbType.Int32);
+ StoredProcedureCommand.AddInput(
+ comando,
+ "@LotesConvenio",
+ lotesConvenio,
+ DbType.Int32);
});
}

View File

@@ -1,70 +0,0 @@
--- ANTES/App_Code/Services/Convenios/ServicioConvenios.cs
+++ DESPUES/App_Code/Services/Convenios/ServicioConvenios.cs
@@ -69,6 +69,23 @@
null);
}
+ DbResult<ConvenioLotesConvenio> lotes =
+ _repositorio.ObtenerLotesConvenio(
+ cveConvenio,
+ usuario,
+ dominio);
+
+ if (!lotes.Success)
+ {
+ return DbResult<ConvenioDetalleCompleto>.Fail(
+ lotes.UserMessage,
+ lotes.TechnicalMessage,
+ lotes.Exception);
+ }
+
+ resultado.Data.Encabezado.LotesConvenio =
+ lotes.Data == null ? 0 : lotes.Data.LotesConvenio;
+
return resultado;
}
@@ -112,11 +129,26 @@
usuario,
dominio);
- if (resultado.Success)
- {
- transaccion.Commit();
- }
-
+ if (!resultado.Success)
+ {
+ return resultado;
+ }
+
+ DbResult<bool> lotes = _repositorio.GuardarLotesConvenio(
+ resultado.Data,
+ solicitud.LotesConvenio,
+ usuario,
+ dominio);
+
+ if (!lotes.Success)
+ {
+ return DbResult<int>.Fail(
+ lotes.UserMessage,
+ lotes.TechnicalMessage,
+ lotes.Exception);
+ }
+
+ transaccion.Commit();
return resultado;
}
}
@@ -191,6 +223,11 @@
return "La cantidad de viviendas en convenio no es válida.";
}
+ if (solicitud.LotesConvenio < 0)
+ {
+ return "La cantidad de lotes del convenio no es válida.";
+ }
+
if (solicitud.Conceptos == null || solicitud.Conceptos.Count == 0)
{
return "Agregue al menos un concepto al convenio.";

View File

@@ -1,90 +0,0 @@
--- ANTES/App_Code/Services/Fraccionamientos/ServicioFraccionamiento.cs
+++ DESPUES/App_Code/Services/Fraccionamientos/ServicioFraccionamiento.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using SIG.Web.AppCode.Contracts.Bitacora;
using SIG.Web.AppCode.Contracts.Fraccionamientos;
using SIG.Web.AppCode.Contracts.Tramites;
@@ -34,7 +35,79 @@
return CrearFallo<List<ModeloFilaDesarrollos>>("Seleccione un desarrollador válido.");
}
- return _repositorio.ListarDesarrollos(cveCliente, cveUsuarioEjecuta, nombreDominio);
+ DbResult<List<ModeloFilaDesarrollos>> resultado =
+ _repositorio.ListarDesarrollos(
+ cveCliente,
+ cveUsuarioEjecuta,
+ nombreDominio);
+
+ if (!resultado.Success || resultado.Data == null)
+ {
+ return resultado;
+ }
+
+ List<ModeloFilaDesarrollos> filas = resultado.Data;
+
+ /*
+ * PA_Fraccionamientos_DesarrolladorEtapasList es el listado
+ * agrupado existente. No se cambia su contrato. El avance ya
+ * existe en PA_Fraccionamientos_EtapaList, por lo que se
+ * complementa aquí para que admin y cliente usen el mismo dato.
+ */
+ foreach (int cveFraccionamiento in filas
+ .Select(x => x.CveFraccionamiento)
+ .Distinct())
+ {
+ DbResult<List<ModeloEtapaFraccionamiento>> etapasResultado =
+ _repositorio.ListarEtapas(
+ cveFraccionamiento,
+ cveUsuarioEjecuta,
+ nombreDominio);
+
+ if (!etapasResultado.Success)
+ {
+ return DbResult<List<ModeloFilaDesarrollos>>.Fail(
+ etapasResultado.UserMessage,
+ etapasResultado.TechnicalMessage,
+ etapasResultado.Exception);
+ }
+
+ List<ModeloEtapaFraccionamiento> etapas =
+ etapasResultado.Data ?? new List<ModeloEtapaFraccionamiento>();
+
+ Dictionary<int, decimal> avances = etapas
+ .ToDictionary(x => x.CveFraccionamientoEtapa, x => x.Avance);
+
+ foreach (ModeloFilaDesarrollos fila in filas.Where(x =>
+ x.CveFraccionamiento == cveFraccionamiento &&
+ !x.EsFraccionamiento &&
+ x.CveFraccionamientoEtapa.HasValue))
+ {
+ decimal avance;
+ if (avances.TryGetValue(
+ fila.CveFraccionamientoEtapa.Value,
+ out avance))
+ {
+ fila.Avance = avance;
+ }
+ }
+
+ ModeloFilaDesarrollos cabecera = filas.FirstOrDefault(x =>
+ x.CveFraccionamiento == cveFraccionamiento &&
+ x.EsFraccionamiento);
+
+ if (cabecera != null)
+ {
+ cabecera.Avance = etapas.Count == 0
+ ? 0m
+ : decimal.Round(
+ etapas.Average(x => x.Avance),
+ 2,
+ MidpointRounding.AwayFromZero);
+ }
+ }
+
+ return resultado;
}
public DbResult<List<OpcionClienteFraccionamiento>> ListarClientes(int cveUsuarioEjecuta, string nombreDominio)

View File

@@ -1,38 +0,0 @@
--- ANTES/Pages/Clientes/Desarrollos.aspx
+++ DESPUES/Pages/Clientes/Desarrollos.aspx
@@ -80,7 +80,7 @@
OnRowDataBound="EnlazarFila"
OnRowCommand="Desarrollos_Comando">
<Columns>
- <asp:TemplateField HeaderText="Fraccionamiento">
+ <asp:TemplateField HeaderText="Fraccionamiento / Etapa">
<ItemTemplate>
<asp:Panel runat="server"
Visible='<%# Convert.ToBoolean(Eval("EsFraccionamiento")) %>'>
@@ -97,11 +97,7 @@
<%#: ResumenFraccionamiento(Container.DataItem) %>
</span>
</asp:Panel>
- </ItemTemplate>
- </asp:TemplateField>
-
- <asp:TemplateField HeaderText="Etapa">
- <ItemTemplate>
+
<asp:HyperLink runat="server"
CssClass="sig-cliente-etapa-enlace"
Visible='<%# !Convert.ToBoolean(Eval("EsFraccionamiento")) %>'
@@ -114,6 +110,13 @@
<ItemTemplate>
<asp:Literal runat="server" Mode="Encode"
Text='<%# FormatearHectareas(Container.DataItem) %>' />
+ </ItemTemplate>
+ </asp:TemplateField>
+
+ <asp:TemplateField HeaderText="Avance">
+ <ItemTemplate>
+ <asp:Literal runat="server" Mode="Encode"
+ Text='<%# FormatearAvance(Container.DataItem) %>' />
</ItemTemplate>
</asp:TemplateField>

View File

@@ -1,18 +0,0 @@
--- ANTES/Pages/Clientes/Desarrollos.aspx.cs
+++ DESPUES/Pages/Clientes/Desarrollos.aspx.cs
@@ -329,6 +329,15 @@
fila.NumeroEtapas);
}
+ protected string FormatearAvance(object objeto)
+ {
+ var fila = objeto as ModeloFilaDesarrollos;
+
+ return fila == null
+ ? string.Empty
+ : fila.Avance.ToString("N2", CultureInfo.CurrentCulture) + " %";
+ }
+
protected string FormatearHectareas(object objeto)
{
var fila = objeto as ModeloFilaDesarrollos;

View File

@@ -1,20 +0,0 @@
--- ANTES/Pages/Clientes/EtapaDetalle.aspx
+++ DESPUES/Pages/Clientes/EtapaDetalle.aspx
@@ -2,7 +2,7 @@
AutoEventWireup="true" CodeFile="EtapaDetalle.aspx.cs"
Inherits="SIG.Web.Pages.Clientes.EtapaDetalle" %>
<%@ Register TagPrefix="cliente" TagName="Tramites" Src="~/UserControl/Clientes/TramitesCliente.ascx" %>
-<%@ Register TagPrefix="cliente" TagName="Documentos" Src="~/UserControl/Clientes/DocumentosCliente.ascx" %>
+<%@ Register TagPrefix="etapa" TagName="DocumentosEtapa" Src="~/UserControl/DocumentosEtapa.ascx" %>
<%@ Register TagPrefix="cliente" TagName="Pagos" Src="~/UserControl/Clientes/PagosCliente.ascx" %>
<asp:Content ID="ContenidoEncabezado" ContentPlaceHolderID="H" runat="server">
@@ -75,7 +75,7 @@
<ajax:TabPanel ID="PestanaDocumentos" runat="server" HeaderText="Documentos">
<ContentTemplate>
- <cliente:Documentos ID="UcDocumentos" runat="server" />
+ <etapa:DocumentosEtapa ID="UcDocumentos" runat="server" OnCambiado="Documentos_Cambiados" />
</ContentTemplate>
</ajax:TabPanel>

View File

@@ -1,53 +0,0 @@
--- ANTES/Pages/Clientes/EtapaDetalle.aspx.cs
+++ DESPUES/Pages/Clientes/EtapaDetalle.aspx.cs
@@ -16,6 +16,12 @@
{
get { return (int?)ViewState["CveFraccionamientoEtapaActual"] ?? 0; }
set { ViewState["CveFraccionamientoEtapaActual"] = value; }
+ }
+
+ private int CveFraccionamientoActual
+ {
+ get { return (int?)ViewState["CveFraccionamientoActual"] ?? 0; }
+ set { ViewState["CveFraccionamientoActual"] = value; }
}
#endregion
@@ -45,6 +51,19 @@
CveFraccionamientoEtapaActual = cveFraccionamientoEtapa;
Cargar();
+ }
+
+ protected void Documentos_Cambiados(object origen, EventArgs argumentos)
+ {
+ if (CveFraccionamientoActual <= 0 ||
+ CveFraccionamientoEtapaActual <= 0)
+ {
+ return;
+ }
+
+ UcTramites.Cargar(
+ CveFraccionamientoActual,
+ CveFraccionamientoEtapaActual);
}
private void Cargar()
@@ -85,6 +104,7 @@
ModeloEtapaFraccionamiento datosEtapa = etapa.Data;
ModeloFraccionamiento datosFraccionamiento = fraccionamiento.Data;
+ CveFraccionamientoActual = datosFraccionamiento.CveFraccionamiento;
LitEtapa.Text = datosEtapa.Etapa;
LitHectareas.Text = datosEtapa.Hectareas.HasValue
@@ -112,8 +132,7 @@
datosEtapa.CveFraccionamientoEtapa);
UcDocumentos.Cargar(
datosFraccionamiento.CveFraccionamiento,
- datosEtapa.CveFraccionamientoEtapa,
- false);
+ datosEtapa.CveFraccionamientoEtapa);
UcPagos.Cargar(
datosFraccionamiento.CveFraccionamiento,
datosEtapa.CveFraccionamientoEtapa,

View File

@@ -1,218 +0,0 @@
--- ANTES/Pages/Desarrolladores/DesarrolladorDetalle.aspx
+++ DESPUES/Pages/Desarrolladores/DesarrolladorDetalle.aspx
@@ -20,27 +20,33 @@
margin-bottom: 15px;
}
- .desarrollador-listado > tbody > tr.desarrollador-grupo > td {
- background: #edf4f8;
- padding: 10px 12px;
- }
-
- .desarrollador-cabecera {
- display: flex;
+ .desarrollador-fila-fraccionamiento > td {
+ background: #eef6fb;
+ vertical-align: middle !important;
+ }
+
+ .desarrollador-fila-etapa > td:first-child {
+ padding-left: 30px;
+ }
+
+ .desarrollador-fraccionamiento-resumen {
+ color: #7f8c8d;
+ font-size: 12px;
+ margin-left: 8px;
+ }
+
+ .desarrollador-etapa-enlace {
+ font-weight: 600;
+ }
+
+ .desarrollador-accion-icono {
align-items: center;
- gap: 12px;
- }
-
- .desarrollador-descripcion {
- flex: 1;
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- gap: 8px 20px;
- }
-
- .desarrollador-alternar {
- background: transparent;
+ display: inline-flex;
+ height: 28px;
+ justify-content: center;
+ margin: 0 2px;
+ padding: 0;
+ width: 28px;
}
.desarrollador-credenciales {
@@ -162,55 +168,88 @@
<ContentTemplate>
<div class="table-responsive">
<asp:GridView ID="GvFraccionamientos" runat="server" AutoGenerateColumns="false"
- GridLines="None" CssClass="table table-hover Widthall desarrollador-listado"
- DataKeyNames="CveFraccionamiento,CveFraccionamientoEtapa"
+ GridLines="None" CssClass="table table-hover Widthall sig-grid-agrupado"
+ DataKeyNames="CveFraccionamiento,CveFraccionamientoEtapa,EsFraccionamiento"
OnRowCommand="Fraccionamientos_Comando"
OnRowDataBound="Fraccionamientos_FilaEnlazada"
EmptyDataText="Este desarrollador no tiene fraccionamientos activos.">
<Columns>
- <asp:TemplateField HeaderText="Etapa">
- <ItemTemplate>
- <asp:Panel runat="server" CssClass="desarrollador-cabecera"
+ <asp:TemplateField HeaderText="Fraccionamiento / Etapa">
+ <ItemTemplate>
+ <asp:Panel runat="server"
Visible='<%# Convert.ToBoolean(Eval("EsFraccionamiento")) %>'>
- <div class="desarrollador-descripcion">
- <asp:HyperLink runat="server"
- Text='<%# Server.HtmlEncode(Convert.ToString(Eval("Fraccionamiento"))) %>'
- NavigateUrl='<%# ObtenerUrlFraccionamiento(Eval("CveFraccionamiento")) %>' />
- <span>
- <asp:Literal runat="server" Mode="Encode"
- Text='<%# DescribirFraccionamiento(Container.DataItem) %>' />
- </span>
- </div>
- <asp:LinkButton runat="server" CommandName="AgregarEtapa"
- CausesValidation="false" CssClass="btn btn-primary btn-circle btn-sm"
- ToolTip="Agregar etapa" aria-label="Agregar etapa">
- <i class="fa fa-plus" aria-hidden="true"></i>
- </asp:LinkButton>
- <button type="button" class="btn default desarrollador-alternar"
- title="Mostrar u ocultar etapas" aria-label="Mostrar u ocultar etapas"
+ <button type="button"
+ class="btn btn-circle btn-xs default sig-grid-alternar-grupo-accion desarrollador-accion-icono"
+ title="Mostrar u ocultar etapas"
+ aria-label="Mostrar u ocultar etapas"
aria-expanded="true">
- <i class="fa fa-chevron-up" aria-hidden="true"></i>
+ <i class="fa fa-chevron-up sig-grid-icono-agrupacion" aria-hidden="true"></i>
</button>
+ <asp:HyperLink runat="server"
+ Text='<%# Server.HtmlEncode(Convert.ToString(Eval("Fraccionamiento"))) %>'
+ NavigateUrl='<%# ObtenerUrlFraccionamiento(Eval("CveFraccionamiento")) %>' />
+ <span class="desarrollador-fraccionamiento-resumen">
+ <%#: DescribirFraccionamiento(Container.DataItem) %>
+ </span>
</asp:Panel>
- <asp:Literal runat="server" Mode="Encode" Text='<%# Eval("Etapa") %>'
- Visible='<%# !Convert.ToBoolean(Eval("EsFraccionamiento")) %>' />
- </ItemTemplate>
- </asp:TemplateField>
- <asp:BoundField DataField="Hectareas" HeaderText="Hectáreas de la etapa" DataFormatString="{0:N2}" />
- <asp:CheckBoxField DataField="Fideicomiso" HeaderText="Fideicomiso" />
- <asp:CheckBoxField DataField="EsActivo" HeaderText="Activa" />
+
+ <asp:HyperLink runat="server"
+ CssClass="desarrollador-etapa-enlace"
+ Visible='<%# !Convert.ToBoolean(Eval("EsFraccionamiento")) %>'
+ Text='<%# Server.HtmlEncode(Convert.ToString(Eval("Etapa"))) %>'
+ NavigateUrl='<%# ObtenerUrlEtapa(Eval("CveFraccionamientoEtapa")) %>' />
+ </ItemTemplate>
+ </asp:TemplateField>
+
+ <asp:TemplateField HeaderText="Hectáreas">
+ <ItemTemplate>
+ <asp:Literal runat="server" Mode="Encode"
+ Text='<%# FormatearHectareas(Container.DataItem) %>' />
+ </ItemTemplate>
+ </asp:TemplateField>
+
+ <asp:TemplateField HeaderText="Avance">
+ <ItemTemplate>
+ <asp:Literal runat="server" Mode="Encode"
+ Text='<%# FormatearAvance(Container.DataItem) %>' />
+ </ItemTemplate>
+ </asp:TemplateField>
+
+ <asp:TemplateField HeaderText="Fideicomiso">
+ <ItemTemplate>
+ <asp:CheckBox runat="server" Enabled="false"
+ Visible='<%# !Convert.ToBoolean(Eval("EsFraccionamiento")) %>'
+ Checked='<%# Convert.ToBoolean(Eval("Fideicomiso")) %>' />
+ </ItemTemplate>
+ </asp:TemplateField>
+
+ <asp:TemplateField HeaderText="Activa">
+ <ItemTemplate>
+ <asp:CheckBox runat="server" Enabled="false"
+ Checked='<%# Convert.ToBoolean(Eval("EsActivo")) %>' />
+ </ItemTemplate>
+ </asp:TemplateField>
+
<asp:TemplateField HeaderText="Acciones"
HeaderStyle-CssClass="sig-columna-acciones"
ItemStyle-CssClass="sig-columna-acciones">
<ItemTemplate>
+ <asp:LinkButton runat="server" CommandName="AgregarEtapa"
+ Visible='<%# Convert.ToBoolean(Eval("EsFraccionamiento")) %>'
+ CausesValidation="false"
+ CssClass="btn btn-circle btn-xs blue desarrollador-accion-icono"
+ ToolTip="Agregar etapa" aria-label="Agregar etapa">
+ <i class="fa fa-plus" aria-hidden="true"></i>
+ </asp:LinkButton>
+
<asp:HyperLink runat="server"
- CssClass="btn btn-circle btn-sm btn-primary sig-accion-icono"
+ CssClass="btn btn-circle btn-xs blue desarrollador-accion-icono"
ToolTip="Ver etapa"
aria-label="Ver etapa"
NavigateUrl='<%# ObtenerUrlEtapa(Eval("CveFraccionamientoEtapa")) %>'
Visible='<%# !Convert.ToBoolean(Eval("EsFraccionamiento")) %>'>
- <i class="fa fa-eye" aria-hidden="true"></i>
- </asp:HyperLink>
+ <i class="fa fa-eye" aria-hidden="true"></i>
+ </asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>
</Columns>
@@ -312,40 +351,4 @@
</div>
</asp:Content>
<asp:Content ID="ContenidoScripts" ContentPlaceHolderID="J" runat="server">
- <script>
- (function () {
- var gruposContraidos = {};
- function aplicarGrupo(tabla, boton, contraido) {
- var clave = boton.closest("tr").getAttribute("data-fraccionamiento");
- boton.setAttribute("aria-expanded", contraido ? "false" : "true");
- boton.querySelector("i").className = contraido ? "fa fa-chevron-down" : "fa fa-chevron-up";
- tabla.querySelectorAll('tr[data-cabecera="0"]').forEach(function (fila) {
- if (fila.getAttribute("data-fraccionamiento") === clave) {
- fila.style.display = contraido ? "none" : "";
- }
- });
- }
- function iniciarDesarrollos() {
- document.querySelectorAll(".desarrollador-listado").forEach(function (tabla) {
- if (tabla.getAttribute("data-desarrollos-inicializado") === "1") {
- return;
- }
- tabla.setAttribute("data-desarrollos-inicializado", "1");
- tabla.querySelectorAll(".desarrollador-alternar").forEach(function (boton) {
- var clave = boton.closest("tr").getAttribute("data-fraccionamiento");
- aplicarGrupo(tabla, boton, gruposContraidos[clave] === true);
- boton.addEventListener("click", function () {
- gruposContraidos[clave] = boton.getAttribute("aria-expanded") === "true";
- aplicarGrupo(tabla, boton, gruposContraidos[clave]);
- });
- });
- });
- }
- if (window.Sys && Sys.Application) {
- Sys.Application.add_load(iniciarDesarrollos);
- } else {
- document.addEventListener("DOMContentLoaded", iniciarDesarrollos);
- }
- }());
- </script>
</asp:Content>

View File

@@ -1,85 +0,0 @@
--- ANTES/Pages/Desarrolladores/DesarrolladorDetalle.aspx.cs
+++ DESPUES/Pages/Desarrolladores/DesarrolladorDetalle.aspx.cs
@@ -24,27 +24,69 @@
return;
}
- var desarrollo = (ModeloFilaDesarrollos)argumentos.Row.DataItem;
- argumentos.Row.Attributes["data-fraccionamiento"] =
+ var desarrollo = argumentos.Row.DataItem as ModeloFilaDesarrollos;
+ if (desarrollo == null)
+ {
+ return;
+ }
+
+ string grupo = "desarrollo-" +
desarrollo.CveFraccionamiento.ToString(CultureInfo.InvariantCulture);
- argumentos.Row.Attributes["data-cabecera"] = desarrollo.EsFraccionamiento ? "1" : "0";
+
if (desarrollo.EsFraccionamiento)
{
- argumentos.Row.CssClass = "desarrollador-grupo";
- argumentos.Row.Cells[0].ColumnSpan = GvFraccionamientos.Columns.Count;
- for (int indice = 1; indice < argumentos.Row.Cells.Count; indice++)
- {
- argumentos.Row.Cells[indice].Visible = false;
- }
- }
+ argumentos.Row.CssClass =
+ (argumentos.Row.CssClass +
+ " sig-grid-grupo desarrollador-fila-fraccionamiento").Trim();
+ argumentos.Row.Attributes["data-sig-group-row"] = "1";
+ argumentos.Row.Attributes["data-sig-group-id"] = grupo;
+ argumentos.Row.Attributes["data-sig-level"] = "2";
+ argumentos.Row.Attributes["data-sig-expanded-default"] = "true";
+ return;
+ }
+
+ argumentos.Row.CssClass =
+ (argumentos.Row.CssClass +
+ " sig-grid-fila-dato desarrollador-fila-etapa").Trim();
+ argumentos.Row.Attributes["data-sig-item-row"] = "1";
+ argumentos.Row.Attributes["data-sig-parent-group"] = grupo;
+ argumentos.Row.Attributes["data-sig-level"] = "1";
}
protected string DescribirFraccionamiento(object objeto)
{
var fila = (ModeloFilaDesarrollos)objeto;
- return string.Format(CultureInfo.CurrentCulture,
- "{0} · {1:N2} ha · {2} etapas · {3}",
- fila.Ubicacion, fila.HectareasFraccionamiento, fila.NumeroEtapas, fila.Estatus);
+ return string.Format(
+ CultureInfo.CurrentCulture,
+ "{0} · {1} etapa(s)",
+ fila.Estatus,
+ fila.NumeroEtapas);
+ }
+
+ protected string FormatearHectareas(object objeto)
+ {
+ var fila = objeto as ModeloFilaDesarrollos;
+ if (fila == null)
+ {
+ return string.Empty;
+ }
+
+ decimal? hectareas = fila.EsFraccionamiento
+ ? fila.HectareasFraccionamiento
+ : fila.Hectareas;
+
+ return hectareas.HasValue
+ ? hectareas.Value.ToString("N2", CultureInfo.CurrentCulture)
+ : string.Empty;
+ }
+
+ protected string FormatearAvance(object objeto)
+ {
+ var fila = objeto as ModeloFilaDesarrollos;
+
+ return fila == null
+ ? string.Empty
+ : fila.Avance.ToString("N2", CultureInfo.CurrentCulture) + " %";
}
protected void Etapa_Cambiada(object origen, EventArgs argumentos)

View File

@@ -1,79 +0,0 @@
--- ANTES/UserControl/ConveniosListado.ascx
+++ DESPUES/UserControl/ConveniosListado.ascx
@@ -133,7 +133,7 @@
</div>
</div>
- <div class="sig-convenio-seccion-titulo">Viviendas en desarrollo</div>
+ <div class="sig-convenio-seccion-titulo">Viviendas en desarrollo <span class="text-muted">· Calculados</span></div>
<div class="row">
<div class="col-md-3">
@@ -146,6 +146,8 @@
ID="TxtViviendasAutorizadas"
runat="server"
CssClass="form-control"
+ ReadOnly="true"
+ Text="0"
MaxLength="9" />
</div>
</div>
@@ -160,6 +162,8 @@
ID="TxtViviendasEnConvenio"
runat="server"
CssClass="form-control"
+ ReadOnly="true"
+ Text="0"
MaxLength="9" />
</div>
</div>
@@ -174,6 +178,8 @@
ID="TxtViviendasPendientes"
runat="server"
CssClass="form-control"
+ ReadOnly="true"
+ Text="0"
MaxLength="9" />
</div>
</div>
@@ -188,6 +194,8 @@
ID="TxtViviendasContratadas"
runat="server"
CssClass="form-control"
+ ReadOnly="true"
+ Text="0"
MaxLength="9" />
</div>
</div>
@@ -240,12 +248,31 @@
<div class="form-group">
<asp:Label
runat="server"
+ AssociatedControlID="TxtLotesConvenio"
+ Text="Lotes convenio" />
+ <asp:TextBox
+ ID="TxtLotesConvenio"
+ runat="server"
+ CssClass="form-control"
+ Text="0"
+ MaxLength="9" />
+ </div>
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="col-md-12">
+ <div class="form-group">
+ <asp:Label
+ runat="server"
AssociatedControlID="TxtObservacionesConvenio"
Text="Observaciones" />
<asp:TextBox
ID="TxtObservacionesConvenio"
runat="server"
CssClass="form-control"
+ TextMode="MultiLine"
+ Rows="2"
MaxLength="1000" />
</div>
</div>

View File

@@ -1,80 +0,0 @@
--- ANTES/UserControl/ConveniosListado.ascx.cs
+++ DESPUES/UserControl/ConveniosListado.ascx.cs
@@ -136,7 +136,7 @@
return;
}
- DdlClienteCaptura.Enabled = !cveCliente.HasValue;
+ DdlClienteCaptura.Enabled = true;
if (cveCliente.HasValue && cveCliente.Value > 0)
{
@@ -150,7 +150,7 @@
LimpiarEtapasCaptura();
}
- DdlEtapaCaptura.Enabled = !cveEtapa.HasValue;
+ DdlEtapaCaptura.Enabled = true;
if (!CargarConceptosCatalogo())
{
@@ -430,18 +430,14 @@
CveFraccionamientoEtapa = cveEtapa,
NumeroConvenio = numeroConvenio,
NumeroOficio = TextoNulo(TxtNumeroOficio.Text),
- ViviendasAutorizadas = LeerEnteroOpcional(
- TxtViviendasAutorizadas.Text,
- "Capture una cantidad válida de viviendas autorizadas."),
- ViviendasEnConvenio = LeerEntero(
- TxtViviendasEnConvenio.Text,
- "Capture una cantidad válida de viviendas en convenio."),
- ViviendasPendientes = LeerEnteroOpcional(
- TxtViviendasPendientes.Text,
- "Capture una cantidad válida de viviendas pendientes."),
- ViviendasContratadas = LeerEnteroOpcional(
- TxtViviendasContratadas.Text,
- "Capture una cantidad válida de viviendas contratadas."),
+ // Estos cuatro valores quedan reservados para el cálculo posterior.
+ ViviendasAutorizadas = 0,
+ ViviendasEnConvenio = 0,
+ ViviendasPendientes = 0,
+ ViviendasContratadas = 0,
+ LotesConvenio = LeerEntero(
+ TxtLotesConvenio.Text,
+ "Capture una cantidad válida de lotes del convenio."),
FechaConvenio = LeerFecha(
TxtFechaConvenio.Text,
"Capture una fecha válida para el convenio."),
@@ -579,7 +575,7 @@
"<div class=\"col-md-4\"><strong>Oficio:</strong> {3}</div>" +
"</div>" +
"<div class=\"row\">" +
- "<div class=\"col-md-4\"><strong>Viviendas:</strong> {4}</div>" +
+ "<div class=\"col-md-4\"><strong>Lotes convenio:</strong> {4}</div>" +
"<div class=\"col-md-4\"><strong>Importe:</strong> {5:N2}</div>" +
"<div class=\"col-md-4\"><strong>Saldo pendiente:</strong> {6:N2}</div>" +
"</div>",
@@ -587,7 +583,7 @@
HttpUtility.HtmlEncode(encabezado.Fraccionamiento),
HttpUtility.HtmlEncode(encabezado.Etapa),
HttpUtility.HtmlEncode(encabezado.NumeroOficio),
- encabezado.ViviendasEnConvenio,
+ encabezado.LotesConvenio,
encabezado.ImporteConvenio,
encabezado.SaldoPendiente);
@@ -761,10 +757,11 @@
private void ReiniciarCaptura()
{
ConceptosCaptura = new List<ConvenioConceptoCaptura>();
- TxtViviendasAutorizadas.Text = string.Empty;
+ TxtViviendasAutorizadas.Text = "0";
TxtViviendasEnConvenio.Text = "0";
- TxtViviendasPendientes.Text = string.Empty;
- TxtViviendasContratadas.Text = string.Empty;
+ TxtViviendasPendientes.Text = "0";
+ TxtViviendasContratadas.Text = "0";
+ TxtLotesConvenio.Text = "0";
TxtNumeroConvenio.Text = string.Empty;
TxtNumeroOficio.Text = string.Empty;
TxtFechaConvenio.Text = DateTime.Today.ToString(

View File

@@ -1,23 +0,0 @@
--- ANTES/UserControl/DetalleEtapa.ascx
+++ DESPUES/UserControl/DetalleEtapa.ascx
@@ -58,6 +58,20 @@
<asp:BoundField DataField="Folio" HeaderText="Folio" />
<asp:BoundField DataField="TipoTramite" HeaderText="Trámite" />
<asp:BoundField DataField="EstatusSolicitud" HeaderText="Estatus" />
+ <asp:TemplateField HeaderText="Documentos">
+ <ItemTemplate>
+ <span class='<%# Convert.ToInt32(Eval("DocumentosPendientes")) > 0 ? "text-danger" : "text-success" %>'>
+ <%#: Eval("TextoDocumentos") %>
+ </span>
+ </ItemTemplate>
+ </asp:TemplateField>
+ <asp:TemplateField HeaderText="Pagos">
+ <ItemTemplate>
+ <span class='<%# Convert.ToInt32(Eval("PagosPendientes")) > 0 ? "text-danger" : "text-success" %>'>
+ <%#: Eval("TextoPagos") %>
+ </span>
+ </ItemTemplate>
+ </asp:TemplateField>
<asp:BoundField DataField="FechaInicio" HeaderText="Fecha de inicio" />
<asp:TemplateField HeaderText="Acciones"
HeaderStyle-CssClass="sig-columna-acciones"

View File

@@ -1,43 +0,0 @@
--- ANTES/UserControl/DetalleEtapa.ascx.cs
+++ DESPUES/UserControl/DetalleEtapa.ascx.cs
@@ -328,7 +328,39 @@
return;
}
- GvTramites.DataSource = consulta.Data;
+ List<TramiteSolicitudModel> tramites =
+ consulta.Data ?? new List<TramiteSolicitudModel>();
+
+ foreach (TramiteSolicitudModel tramite in tramites)
+ {
+ var contexto = AppServices.TramiteSolicitudService
+ .ObtenerContextoCambioEstatus(
+ tramite.CveSolicitud,
+ CurrentUser.CveUsuario,
+ CurrentUser.NombreDominio);
+
+ if (!contexto.Success || contexto.Data == null)
+ {
+ Avisar(
+ contexto.Success
+ ? "No fue posible consultar los pendientes del trámite."
+ : contexto.UserMessage);
+ return;
+ }
+
+ tramite.DocumentosPendientes =
+ (contexto.Data.Documentos ??
+ new List<SIG.Web.AppCode.Models.Documentos.TramiteDocumentoSolicitudModel>())
+ .Count(documento =>
+ documento.EsRequerido &&
+ (!documento.TieneArchivo || documento.FechaExpirada));
+
+ tramite.PagosPendientes =
+ (contexto.Data.Pagos ?? new List<ModeloPagoSolicitud>())
+ .Count(pago => pago.EstaPendiente);
+ }
+
+ GvTramites.DataSource = tramites;
GvTramites.DataBind();
}

View File

@@ -1,43 +0,0 @@
--- ANTES/UserControl/DocumentosEtapa.ascx.cs
+++ DESPUES/UserControl/DocumentosEtapa.ascx.cs
@@ -152,9 +152,13 @@
bool hayDocumentosParaCargar = DocumentosActuales.Any(documento =>
documento.PuedeActualizarArchivo && !documento.EsGis);
- DescargarTodos.Visible = hayArchivos;
- DescargarTodos.NavigateUrl = hayArchivos ? UrlDescargaTodos() : string.Empty;
+ bool esDesarrollador = Usuario != null && Usuario.EsDesarrollador;
+ DescargarTodos.Visible = hayArchivos && !esDesarrollador;
+ DescargarTodos.NavigateUrl = DescargarTodos.Visible
+ ? UrlDescargaTodos()
+ : string.Empty;
CargarArchivos.Visible = hayDocumentosParaCargar;
+ VisualizadorDocumento.PermitirDescarga = !esDesarrollador;
MensajeVacio.Text = etapasVisibles.Count == 0 ? "No hay etapas para mostrar." : string.Empty;
Listado.Update();
@@ -452,7 +456,10 @@
case "Descargar":
return documento.TieneArchivo;
case "AdministrarGis":
- return documento.EsGis;
+ return Usuario != null &&
+ !Usuario.EsDesarrollador &&
+ documento.EsGis &&
+ documento.PuedeAdministrarGis;
case "Cargar":
return documento.PuedeActualizarArchivo;
case "Aprobar":
@@ -479,7 +486,11 @@
return Usuario != null && !Usuario.EsDesarrollador &&
documento.TieneVigencia && documento.TieneArchivo;
case "Eliminar":
- return documento.TieneArchivo && documento.PuedeActualizarArchivo;
+ return documento.TieneArchivo &&
+ documento.PuedeActualizarArchivo &&
+ (Usuario == null ||
+ !Usuario.EsDesarrollador ||
+ documento.EsAprobado != true);
default:
return false;
}

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
@@ -49,6 +49,7 @@
<Reference Include="System.Data" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.EnterpriseServices" />
<Reference Include="System.Transactions" />
<Reference Include="System.Web" />

Binary file not shown.

View File

@@ -1,4 +1,4 @@
(function (window, document) {
(function (window, document) {
'use strict';
if (window.SIGDocumentosEtapaCargaMasiva) {
@@ -773,8 +773,6 @@
var destino =
opcion.CveFraccionamientoEtapa +
'|' +
opcion.CveSolicitud +
'|' +
opcion.CveTipoDocumento;
if (destinos[destino]) {
@@ -793,8 +791,6 @@
Incluir: true,
CveFraccionamientoEtapa:
opcion.CveFraccionamientoEtapa,
CveSolicitud:
opcion.CveSolicitud,
CveTipoDocumento:
opcion.CveTipoDocumento,
FechaDocumento:

View File

@@ -1,69 +1,327 @@
(function (window, document, $) {
(function (ventana, documento, $) {
'use strict';
if (window.SIGLotesEtapa) {
if (ventana.SIGLotesEtapa) {
return;
}
function init(context) {
var $ctx = $(context || document);
var instancias = Object.create(null);
var resguardando = false;
$ctx.find('.sig-lotes-etapa .select2me').each(function () {
var $el = $(this);
if (typeof $el.select2 !== 'function') {
return;
}
/*
* Compatible con el Select2 que ya usa la plataforma.
* No reinicializa controles que ya tienen Select2.
*/
if ($el.data('select2') ||
$el.hasClass('select2-hidden-accessible')) {
return;
}
$el.select2({
width: '100%'
});
});
$ctx.find('.sig-lotes-etapa .btn-group.open')
.removeClass('open');
function buscarPropietario(selector, clave) {
return $(selector).filter(function () {
return $(this).attr('data-lotes-propietario') === clave;
}).first();
}
$(function () {
init(document);
});
/*
* WebForms / UpdatePanel
*
* REGLA DEL PROYECTO:
* No inspeccionar paneles actualizados; usar endRequest.
*
* Después de cualquier postback parcial simplemente revisamos
* los controles de Lotes. init() ya evita reinicializar Select2.
*/
if (window.Sys &&
Sys.WebForms &&
Sys.WebForms.PageRequestManager) {
var prm = Sys.WebForms.PageRequestManager.getInstance();
if (!prm._sigLotesEtapaRegistrado) {
prm.add_endRequest(function () {
init(document);
});
prm._sigLotesEtapaRegistrado = true;
function redimensionar(estado) {
if (estado.mapa && ventana.SIGVisorGis) {
ventana.SIGVisorGis.redimensionar(estado.mapa);
}
}
window.SIGLotesEtapa = {
inicializar: init
};
function devolverMapa(estado) {
if (estado.mapa && estado.origen.length) {
estado.mapa.detach().appendTo(estado.origen);
estado.origen.removeClass('sig-lotes-mapa-reservado').css('height', '');
redimensionar(estado);
}
}
function moverAlPanel(estado) {
if (!estado.mapa || !estado.mapa.length) {
return;
}
if (!estado.origen.hasClass('sig-lotes-mapa-reservado')) {
estado.altoOrigen = estado.origen.outerHeight();
}
estado.origen.height(estado.altoOrigen).addClass('sig-lotes-mapa-reservado');
estado.mapa.detach().appendTo(estado.panel.find('[data-lotes-mapa-panel]'));
redimensionar(estado);
}
function actualizarSeleccion(estado) {
var raiz = buscarPropietario('.sig-lotes-etapa', estado.clave);
raiz.find('[data-lotes-fila]').each(function () {
var seleccionada = String($(this).attr('data-lotes-fila')) === String(estado.lote || '');
$(this).toggleClass('sig-lotes-fila-seleccionada', seleccionada)
.attr('aria-selected', seleccionada ? 'true' : 'false');
});
var fila = raiz.find('[data-lotes-fila]').filter(function () {
return String($(this).attr('data-lotes-fila')) === String(estado.lote || '');
}).first();
var contenedor = estado.panel.find('[data-lotes-menu-panel]').empty();
var acciones = fila.find('.sig-menu-acciones').clone(false);
// Los enlaces conservan el destino de postback del grid y sus permisos de servidor.
acciones.find('[id]').removeAttr('id');
acciones.find('.sig-menu-acciones-boton').attr('aria-expanded', 'false');
acciones.find('.sig-lotes-ver-mapa').closest('li').remove();
acciones.appendTo(contenedor);
}
function consultarDetalle(estado) {
if (!estado.panel.hasClass('sig_panel_open') || !estado.pendiente) {
return;
}
var gestor = ventana.Sys && Sys.WebForms && Sys.WebForms.PageRequestManager.getInstance();
if (gestor && gestor.get_isInAsyncPostBack()) {
return;
}
var boton = documento.getElementById(estado.panel.attr('data-lotes-consultar'));
var campo = documento.getElementById(estado.panel.attr('data-lotes-campo'));
if (!boton || !campo) {
return;
}
campo.value = estado.pendiente;
estado.pendiente = null;
boton.click();
}
function abrirDetalle(estado, lote) {
estado.panel[0].click();
estado.lote = lote.CveFraccionamientoLote;
estado.vinculo = lote.GISPoligonoClave;
estado.panel.find('[data-lotes-titulo]').text(lote.Nombre || ('Lote ' + estado.lote));
estado.panel.find('[data-lotes-estado]').text('Consultando información del lote...');
estado.panel.find('[data-lotes-detalle]').hide();
estado.panel.find('[data-lotes-desvincular]').toggle(!!estado.vinculo);
actualizarSeleccion(estado);
ventana.SIGPanelLateral.abrir(estado.panel);
moverAlPanel(estado);
estado.pendiente = estado.lote;
consultarDetalle(estado);
}
function conectarMapa(estado) {
if (!estado.mapa || estado.mapa.is('[data-sig-lotes-mapa-inicializado]')) {
return;
}
estado.mapa.on('sig:loteSeleccionado', function (evento, lote) {
abrirDetalle(estado, lote);
});
estado.mapa.attr('data-sig-lotes-mapa-inicializado', '1');
}
function conectarPanel(estado) {
var panel = estado.panel;
if (panel.is('[data-sig-lotes-panel-inicializado]')) {
return;
}
estado.anclaPanel = $('<span class="sig-lotes-ancla-panel" hidden></span>').insertBefore(panel);
// El origen del panel también queda fuera de los UpdatePanel.
panel.detach().appendTo($('form').first());
panel.on('cerrado.sig.panel', function () {
estado.pendiente = null;
if (!resguardando) {
devolverMapa(estado);
}
});
panel.on('click.sigLotes', '[data-lotes-desvincular]', function () {
var boton = $(this);
if (!estado.vinculo || boton.prop('disabled')) {
return;
}
boton.prop('disabled', true);
var lote = estado.lote;
var clave = estado.vinculo;
panel.find('[data-lotes-estado]').text('Desvinculando lote...');
$.ajax({
url: estado.mapa.attr('data-gis-url'),
type: 'POST',
dataType: 'json',
timeout: 30000,
data: {
metodo: 'DesvincularLote',
CveFraccionamientoEtapa: estado.etapa,
CveFraccionamientoLote: lote,
ClavePoligono: clave
}
}).done(function (respuesta) {
if (!respuesta.success) {
panel.find('[data-lotes-estado]').text(respuesta.message || 'No fue posible desvincular.');
return;
}
if (estado.lote === lote && estado.vinculo === clave) {
estado.vinculo = '';
boton.hide();
panel.find('[data-lotes-estado]').text('Lote desvinculado. Puede seleccionar el polígono para vincular otro lote.');
estado.lote = null;
actualizarSeleccion(estado);
}
ventana.SIGVisorGis.limpiarSeleccion(estado.mapa, lote);
}).fail(function (respuesta) {
panel.find('[data-lotes-estado]').text(
respuesta.responseJSON && respuesta.responseJSON.message ||
'No se pudo confirmar la desvinculación. Seleccione nuevamente el polígono.');
}).always(function () {
boton.prop('disabled', false);
});
});
panel.attr('data-sig-lotes-panel-inicializado', '1');
}
function restaurarMapas() {
if (resguardando) {
return;
}
$('.sig-lotes-mapa-origen').each(function () {
var origen = $(this);
var clave = origen.attr('data-lotes-propietario');
var etapa = origen.attr('data-lotes-etapa');
var estado = instancias[clave];
var paneles = $('.sig-lotes-panel').filter(function () {
return $(this).attr('data-lotes-propietario') === clave;
});
if (!estado) {
estado = instancias[clave] = { clave: clave, etapa: etapa, panel: paneles.first(), origen: origen };
}
var nuevoPanel = paneles.filter(function () {
return this !== estado.panel[0];
}).first();
if (nuevoPanel.length) {
ventana.SIGPanelLateral.cerrar(estado.panel);
estado.panel.remove();
estado.panel = nuevoPanel;
}
var reemplazoOrigen = estado.origen[0] !== origen[0];
estado.origen = origen;
var nuevoMapa = origen.find('.sig-visor-gis').first();
if (estado.etapa !== etapa || (reemplazoOrigen && !nuevoMapa.length)) {
ventana.SIGPanelLateral.cerrar(estado.panel);
if (estado.mapa) {
estado.mapa.remove();
}
estado.mapa = null;
estado.lote = null;
estado.pendiente = null;
estado.reabrirPanel = false;
estado.etapa = etapa;
origen.removeClass('sig-lotes-mapa-reservado').css('height', '');
}
if (estado.mapa && nuevoMapa.length && nuevoMapa[0] !== estado.mapa[0]) {
nuevoMapa.remove();
}
if (!estado.mapa || !estado.mapa.length) {
estado.mapa = nuevoMapa;
}
conectarPanel(estado);
conectarMapa(estado);
if (estado.reabrirPanel) {
estado.reabrirPanel = false;
ventana.SIGPanelLateral.abrir(estado.panel);
}
if (estado.mapa) {
estado.mapa.removeClass('sig-lotes-mapa-resguardado');
}
if (estado.panel.hasClass('sig_panel_open')) {
moverAlPanel(estado);
} else {
devolverMapa(estado);
}
actualizarSeleccion(estado);
});
$.each(instancias, function (clave, estado) {
if (buscarPropietario('.sig-lotes-mapa-origen', clave).length) {
return;
}
ventana.SIGPanelLateral.cerrar(estado.panel);
if (estado.mapa) {
estado.mapa.remove();
}
estado.panel.remove();
delete instancias[clave];
});
}
function resguardarMapas(emisor, argumentos) {
// pageLoading ocurre después de recibir la respuesta y antes de reemplazar el DOM.
resguardando = true;
$.each(instancias, function (clave, estado) {
if (!estado.mapa || !estado.mapa.length) {
return;
}
estado.altoOrigen = estado.origen.hasClass('sig-lotes-mapa-reservado') ?
estado.altoOrigen : estado.origen.outerHeight();
estado.origen.height(estado.altoOrigen).addClass('sig-lotes-mapa-reservado');
estado.mapa.detach().appendTo($('form').first()).addClass('sig-lotes-mapa-resguardado');
});
var reemplazos = argumentos && argumentos.get_panelsUpdating ? argumentos.get_panelsUpdating() : [];
var eliminados = argumentos && argumentos.get_panelsDeleting ? argumentos.get_panelsDeleting() : [];
$.each(instancias, function (clave, estado) {
var ancla = estado.anclaPanel && estado.anclaPanel[0];
var reemplazaPanel = $.grep([].concat(reemplazos, eliminados), function (panel) {
return ancla && (panel === ancla || $.contains(panel, ancla));
}).length > 0;
if (reemplazaPanel) {
// El mapa ya está a salvo. WebForms debe disponer las pestañas y controles
// del panel que el servidor va a reemplazar para no duplicar componentes AJAX.
estado.reabrirPanel = estado.panel.hasClass('sig_panel_open');
ventana.SIGPanelLateral.cerrar(estado.panel);
estado.panel.detach().insertAfter(estado.anclaPanel);
}
});
resguardando = false;
}
function inicializar() {
restaurarMapas();
$.each(instancias, function (clave, estado) {
if (estado.mapa) {
estado.mapa.removeClass('sig-lotes-mapa-resguardado');
}
var contenido = estado.panel.find('[data-lotes-detalle]');
var coincide = !estado.pendiente &&
String(contenido.attr('data-lotes-detalle')) === String(estado.lote);
contenido.toggle(coincide);
if (coincide) {
estado.panel.find('[data-lotes-estado]').text('');
} else if (estado.lote && !estado.pendiente && estado.panel.hasClass('sig_panel_open')) {
estado.panel.find('[data-lotes-estado]').text('No fue posible mostrar el lote. Selecciónelo nuevamente.');
}
ventana.setTimeout(function () { consultarDetalle(estado); }, 0);
});
$('.sig-lotes-etapa .select2me:not([data-sig-lotes-select-inicializado])').each(function () {
var elemento = $(this);
if (typeof elemento.select2 !== 'function') {
return;
}
if (!elemento.data('select2') && !elemento.hasClass('select2-hidden-accessible')) {
elemento.select2({ width: '100%' });
}
elemento.attr('data-sig-lotes-select-inicializado', '1');
});
}
$(documento).on('click.sigLotes', '.sig-lotes-ver-mapa', function (evento) {
evento.preventDefault();
var boton = $(this);
var lote = boton.attr('data-lote');
// El menú puede estar temporalmente en el formulario, fuera del grid.
var estado;
$.each(instancias, function (clave, candidata) {
if (buscarPropietario('.sig-lotes-etapa', clave)
.find('[data-lotes-fila="' + lote + '"]').length) {
estado = candidata;
return false;
}
});
if (!estado || !estado.mapa || !estado.mapa.length) {
if (ventana.SIGAlerts) {
ventana.SIGAlerts.enqueue({ type: 4, message: 'La etapa no tiene un mapa disponible.' });
}
return;
}
ventana.SIGVisorGis.verLote(estado.mapa, lote);
});
ventana.SIGLotesEtapa = {
inicializar: inicializar,
restaurarMapas: restaurarMapas
};
$(inicializar);
if (ventana.Sys && Sys.WebForms && Sys.WebForms.PageRequestManager) {
var gestor = Sys.WebForms.PageRequestManager.getInstance();
gestor.add_pageLoading(resguardarMapas);
gestor.add_endRequest(inicializar);
}
}(window, document, jQuery));

775
SIG.Web/Scripts/VisorGis.js Normal file
View File

@@ -0,0 +1,775 @@
(function (window, document, $) {
'use strict';
if (window.SIGVisorGis) { return; }
var api = window.SIGVisorGis = {};
var googlePromise = null;
function esc(value) {
return $('<div/>').text(value == null ? '' : String(value)).html();
}
function layerOf(feature) {
var p = feature && feature.properties || {};
return $.trim(String(p._sigCapa || p.Capa || p.capa || 'GIS')) || 'GIS';
}
function isSupported(g) {
return g && $.inArray(g.type, [
'Point', 'MultiPoint', 'LineString', 'MultiLineString', 'Polygon', 'MultiPolygon'
]) >= 0;
}
function loadGoogle(key) {
if (window.google && window.google.maps && window.google.maps.Data) {
return $.Deferred().resolve().promise();
}
if (googlePromise) { return googlePromise; }
var d = $.Deferred();
googlePromise = d.promise();
var callback = '__sigVisorGisMapsReady';
window[callback] = function () {
d.resolve();
try { delete window[callback]; } catch (_) { window[callback] = null; }
};
var s = document.createElement('script');
s.async = true;
s.defer = true;
s.src = 'https://maps.googleapis.com/maps/api/js?key=' + encodeURIComponent(key) + '&callback=' + callback;
var temporizador = window.setTimeout(function () {
googlePromise = null;
d.reject();
}, 30000);
d.always(function () {
window.clearTimeout(temporizador);
});
s.onerror = function () {
googlePromise = null;
d.reject();
};
document.head.appendChild(s);
return googlePromise;
}
function boundsOf(geo) {
var b = null;
function visit(v) {
if (!$.isArray(v)) { return; }
if (v.length >= 2 && typeof v[0] === 'number' && typeof v[1] === 'number') {
if (!b) { b = { minX:v[0], maxX:v[0], minY:v[1], maxY:v[1] }; }
else {
b.minX=Math.min(b.minX,v[0]); b.maxX=Math.max(b.maxX,v[0]);
b.minY=Math.min(b.minY,v[1]); b.maxY=Math.max(b.maxY,v[1]);
}
return;
}
$.each(v, function (_, x) { visit(x); });
}
$.each(geo.features || [], function (_, f) { if (isSupported(f.geometry)) { visit(f.geometry.coordinates); } });
return b;
}
function pathForLine(coords, project, close) {
if (!coords || !coords.length) { return ''; }
var p = project(coords[0]), r = ['M'+p[0]+','+p[1]];
for (var i=1;i<coords.length;i++) { p=project(coords[i]); r.push('L'+p[0]+','+p[1]); }
if (close) { r.push('Z'); }
return r.join(' ');
}
function pathsFor(g, project) {
var out=[];
if (g.type === 'LineString') { out.push(pathForLine(g.coordinates, project, false)); }
else if (g.type === 'MultiLineString') { $.each(g.coordinates, function(_,x){out.push(pathForLine(x,project,false));}); }
else if (g.type === 'Polygon') { $.each(g.coordinates,function(_,x){out.push(pathForLine(x,project,true));}); }
else if (g.type === 'MultiPolygon') {
$.each(g.coordinates,function(_,p){$.each(p,function(_,x){out.push(pathForLine(x,project,true));});});
}
return out.join(' ');
}
function limitesEncuadre(estado) {
var visibles = $.grep(estado.geo.features || [], function (figura) {
return isSupported(figura.geometry) && estado.visible[layerOf(figura)] !== false;
});
var lotificacion = $.grep(visibles, function (figura) {
var capa = estado.capas[layerOf(figura)];
return capa && capa.TipoCapa === 'Lotificacion';
});
var poligonos = $.grep(lotificacion, function (figura) {
return figura.geometry.type === 'Polygon' || figura.geometry.type === 'MultiPolygon';
});
// Los polígonos de lotes tienen prioridad sobre líneas auxiliares de la misma capa.
return boundsOf({ features: poligonos.length ? poligonos :
(lotificacion.length ? lotificacion : visibles) });
}
function encuadrarGoogle(estado) {
var limites = limitesEncuadre(estado);
if (!limites) {
// Sin capas visibles se conserva la última posición, sin incluir capas ocultas.
return;
}
var margenLongitud = limites.maxX === limites.minX ? 0.00005 : 0;
var margenLatitud = limites.maxY === limites.minY ? 0.00005 : 0;
var encuadre = new google.maps.LatLngBounds(
{ lat: limites.minY - margenLatitud, lng: limites.minX - margenLongitud },
{ lat: limites.maxY + margenLatitud, lng: limites.maxX + margenLongitud });
var ancho = estado.$root.find('[data-gis-map]').width();
var panelAbierto = estado.$root.find('[data-gis-alternar-capas]').attr('aria-expanded') === 'true';
estado.map.fitBounds(encuadre, {
top: 35,
bottom: 35,
left: 35,
right: panelAbierto && ancho > 700 ? 310 : 35
});
}
function actualizarDibujo(estado, recalcularEncuadre) {
if (estado.dataLayer) {
applyGoogleStyle(estado);
if (recalcularEncuadre) {
encuadrarGoogle(estado);
}
} else {
renderSvg(estado);
}
}
function guardarCapa(estado, capa, fila) {
var aviso = fila.find('[data-gis-estado-capa]');
fila.find('input, select, button').prop('disabled', true);
aviso.text('Guardando...');
$.ajax({
url: estado.$root.attr('data-gis-url'),
type: 'POST',
dataType: 'json',
timeout: 30000,
data: {
metodo: 'GuardarCapa',
CveFraccionamientoEtapa: estado.$root.attr('data-gis-stage'),
NombreCapa: capa.NombreCapa,
TipoCapa: capa.TipoCapa,
Color: capa.Color,
EsVisible: capa.EsVisible
}
}).done(function (respuesta) {
aviso.text(respuesta.success ? 'Guardado' : 'No se guardó. Pulse Reintentar.');
fila.find('[data-gis-reintentar]').toggle(!respuesta.success);
}).fail(function () {
aviso.text('No se guardó. El cambio sólo se muestra en esta vista.');
fila.find('[data-gis-reintentar]').show();
}).always(function () {
fila.find('input, select, button').prop('disabled', false);
});
}
function renderLayers(estado) {
var contenedor = estado.$root.find('[data-gis-layers]').empty();
var boton = estado.$root.find('[data-gis-alternar-capas]');
var panel = estado.$root.find('[data-gis-panel-capas]');
panel.attr('id', 'gis-panel-' + estado.uid);
boton.attr('aria-controls', panel.attr('id'));
if (!boton.is('[data-sig-menu-capas-inicializado]')) {
boton.on('click.sigVisor', function () {
var abierto = boton.attr('aria-expanded') !== 'true';
panel.toggle(abierto);
boton.attr('aria-expanded', String(abierto));
});
boton.attr('data-sig-menu-capas-inicializado', '1');
}
$.each(estado.layers, function (indice, nombre) {
var capa = estado.capas[nombre];
var fila = $('<div class="sig-visor-gis__fila-capa"></div>').appendTo(contenedor);
var etiqueta = $('<label></label>').appendTo(fila);
var casilla = $('<input type="checkbox" />').prop('checked', capa.EsVisible).appendTo(etiqueta);
$('<span></span>').text(nombre).appendTo(etiqueta);
$('<span class="sig-visor-gis__cantidad"></span>').text(estado.layerCounts[nombre]).appendTo(etiqueta);
var geometria = capa.Geometria || '';
var descripcion = geometria.indexOf('Polygon') >= 0 ? 'Polígonos' :
geometria.indexOf('LineString') >= 0 ? 'Líneas' :
geometria.indexOf('Point') >= 0 ? 'Puntos' : 'Geometría mixta';
$('<span class="sig-visor-gis__geometria"></span>').text(descripcion).appendTo(fila);
var opciones = $('<div class="sig-visor-gis__opciones-capa"></div>').appendTo(fila);
var selector = $('<select class="form-control input-sm"></select>')
.attr('aria-label', 'Tipo de ' + nombre).appendTo(opciones);
$.each({ Agua: 'Línea de agua', Drenaje: 'Línea de drenaje',
Lotificacion: 'Lotificación', Pozos: 'Pozos', Otros: 'Otros' }, function (valor, texto) {
$('<option></option>').val(valor).text(texto).appendTo(selector);
});
selector.val(capa.TipoCapa);
var color = $('<input type="color" />').val(capa.Color)
.attr('aria-label', 'Color de ' + nombre).appendTo(opciones);
$('<p class="sig-visor-gis__aviso" data-gis-estado-capa role="status"></p>').appendTo(fila);
var reintentar = $('<button type="button" class="btn btn-xs btn-default" data-gis-reintentar>Reintentar</button>')
.hide().appendTo(fila);
fila.find('input, select').on('change.sigVisor', function () {
var recalcularEncuadre = capa.EsVisible !== casilla.prop('checked') ||
capa.TipoCapa !== selector.val();
capa.EsVisible = casilla.prop('checked');
capa.TipoCapa = selector.val();
capa.Color = color.val();
estado.visible[nombre] = capa.EsVisible;
actualizarDibujo(estado, recalcularEncuadre);
guardarCapa(estado, capa, fila);
});
reintentar.on('click.sigVisor', function () {
guardarCapa(estado, capa, fila);
});
fila.attr('data-sig-capa-inicializada', '1');
});
}
function claveFigura(figura) {
return figura && figura.id != null && $.trim(String(figura.id)) !== ''
? 'id:' + $.trim(String(figura.id)) : '';
}
function nombreLote(lote) {
return lote.Nombre || ('Lote ' + (lote.Numero || lote.CveFraccionamientoLote));
}
function loteVinculado(estado, clave) {
return $.grep(estado.lotes || [], function (lote) {
return lote.GISPoligonoClave === clave;
})[0];
}
function mostrarFichaLote(contenedor, lote) {
contenedor.empty();
var ficha = $('<dl class="sig-visor-gis__ficha-lote"></dl>').appendTo(contenedor);
$.each([
['Lote', nombreLote(lote)], ['Etapa', lote.Etapa], ['Tipo', lote.Tipo],
['Calle', lote.Calle], ['Catastro', lote.Catastro],
['Superficie', lote.MetrosCuadrados == null ? 'Sin registrar' :
Number(lote.MetrosCuadrados).toLocaleString('es-MX') + ' m²']
], function (indice, dato) {
$('<dt></dt>').text(dato[0]).appendTo(ficha);
$('<dd></dd>').text(dato[1] || 'Sin registrar')
.toggleClass('sig-visor-gis__superficie-lote', dato[0] === 'Superficie').appendTo(ficha);
});
}
function cargarLotes(estado) {
return $.ajax({
url: estado.$root.attr('data-gis-url'),
dataType: 'json',
cache: false,
timeout: 30000,
data: {
metodo: 'Context',
CveFraccionamientoEtapa: estado.$root.attr('data-gis-stage')
}
}).then(function (respuesta) {
if (!respuesta.success || !respuesta.data || !$.isArray(respuesta.data.Lotes)) {
return $.Deferred().reject().promise();
}
return respuesta;
});
}
function abrirLote(estado, figura) {
var clave = claveFigura(figura);
var modal = estado.$root.find('[data-gis-modal-lote]');
var mensaje = modal.find('[data-gis-mensaje-lote]');
estado.consultaLotesActual = (estado.consultaLotesActual || 0) + 1;
var consultaActual = estado.consultaLotesActual;
if (!modal.is('[data-sig-consulta-lotes-inicializada]')) {
modal.on('hide.bs.modal.sigVisorLotes', function () {
estado.consultaLotesActual++;
});
modal.attr('data-sig-consulta-lotes-inicializada', '1');
}
estado.figuraSeleccionada = figura;
estado.claveSeleccionada = clave;
actualizarDibujo(estado);
modal.find('[data-gis-clave-lote]').text('Polígono: ' + clave);
modal.find('[data-gis-datos-lote]').empty();
modal.find('[data-gis-seleccion-lote], [data-gis-vincular-lote]').hide();
mensaje.text('Consultando lotes de la etapa...');
if (document.fullscreenElement && document.exitFullscreen) {
document.exitFullscreen().catch(function () {});
}
var usaPanel = estado.$root.is('[data-sig-lotes-mapa-inicializado]');
if (usaPanel) {
estado.$root.find('[data-gis-info]').text('Consultando lote...').show();
} else {
modal.modal('show');
}
cargarLotes(estado).done(function (respuesta) {
if (estado.consultaLotesActual !== consultaActual || estado.claveSeleccionada !== clave ||
!$.contains(document, estado.$root[0])) {
return;
}
estado.lotes = respuesta.data.Lotes;
var lote = loteVinculado(estado, clave);
modal.find('[data-gis-titulo-lote]').text(lote ? nombreLote(lote) : 'Vincular polígono con lote');
mensaje.text('');
if (lote) {
mostrarVinculo(estado, figura, lote);
if (usaPanel) {
estado.$root.trigger('sig:loteSeleccionado', [lote]);
} else {
mostrarFichaLote(modal.find('[data-gis-datos-lote]'), lote);
}
return;
}
estado.$root.find('[data-gis-info]').text('Polígono sin lote vinculado.');
modal.modal('show');
var selector = modal.find('[data-gis-selector-lote]').empty();
$('<option></option>').val('').text('Seleccione un lote').appendTo(selector);
$.each(estado.lotes, function (indice, disponible) {
if (disponible.EsActivo && !disponible.GISPoligonoClave) {
$('<option></option>').val(disponible.CveFraccionamientoLote)
.text(nombreLote(disponible)).appendTo(selector);
}
});
modal.find('[data-gis-seleccion-lote], [data-gis-vincular-lote]').show();
if (selector.find('option').length === 1) {
mensaje.text('No hay lotes activos disponibles en esta etapa.');
}
}).fail(function () {
if (estado.consultaLotesActual !== consultaActual || estado.claveSeleccionada !== clave ||
!$.contains(document, estado.$root[0])) {
return;
}
mensaje.text('No fue posible consultar los lotes. Cierre y vuelva a seleccionar el polígono.');
estado.$root.find('[data-gis-info]').text(mensaje.text()).show();
});
var boton = modal.find('[data-gis-vincular-lote]');
if (!boton.is('[data-sig-vincular-lote-inicializado]')) {
boton.on('click.sigVisorLote', function () {
var lote = parseInt(modal.find('[data-gis-selector-lote]').val(), 10) || 0;
if (!lote) {
mensaje.text('Seleccione un lote disponible.');
return;
}
var figuraActual = estado.figuraSeleccionada;
modal.find('button, select').prop('disabled', true);
mensaje.text('Guardando vínculo...');
$.ajax({
url: estado.$root.attr('data-gis-url'),
type: 'POST',
dataType: 'json',
timeout: 30000,
data: {
metodo: 'VincularLote',
CveFraccionamientoEtapa: estado.$root.attr('data-gis-stage'),
CveFraccionamientoLote: lote,
ClavePoligono: claveFigura(figuraActual)
}
}).done(function (respuesta) {
if (!respuesta.success) {
mensaje.text(respuesta.message || 'No fue posible vincular el lote.');
return;
}
var vinculado = $.grep(estado.lotes, function (elemento) {
return elemento.CveFraccionamientoLote === lote;
})[0];
vinculado.GISPoligonoClave = claveFigura(figuraActual);
mostrarVinculo(estado, figuraActual, vinculado);
mostrarFichaLote(modal.find('[data-gis-datos-lote]'), vinculado);
modal.find('[data-gis-seleccion-lote], [data-gis-vincular-lote]').hide();
mensaje.text('Lote vinculado correctamente.');
actualizarDibujo(estado);
if (estado.$root.is('[data-sig-lotes-mapa-inicializado]')) {
modal.modal('hide');
estado.$root.trigger('sig:loteSeleccionado', [vinculado]);
}
}).fail(function (respuesta) {
mensaje.text(respuesta.responseJSON && respuesta.responseJSON.message ||
'No se pudo confirmar el guardado. Cierre y vuelva a seleccionar el polígono.');
}).always(function () {
modal.find('button, select').prop('disabled', false);
});
});
boton.attr('data-sig-vincular-lote-inicializado', '1');
}
}
function mostrarVinculo(estado, figura, lote) {
var informacion = estado.$root.find('[data-gis-info]').empty().show();
$('<strong></strong>').text(layerOf(figura)).appendTo(informacion);
$('<br />').appendTo(informacion);
$('<button type="button" class="sig-visor-gis__enlace-lote"></button>')
.text(nombreLote(lote)).on('click.sigVisorLote', function () {
abrirLote(estado, figura);
}).appendTo(informacion);
}
function featureInfo(estado, figura) {
var propiedades = figura.properties || {};
var informacion = estado.$root.find('[data-gis-info]').empty().show();
$('<strong></strong>').text(layerOf(figura)).appendTo(informacion);
var capa = estado.capas[layerOf(figura)];
var tipo = figura.geometry && figura.geometry.type;
estado.claveSeleccionada = claveFigura(figura);
actualizarDibujo(estado);
if (capa && capa.TipoCapa === 'Lotificacion' &&
(tipo === 'Polygon' || tipo === 'MultiPolygon')) {
if (!estado.claveSeleccionada || estado.claveSeleccionada.length > 100) {
$('<p></p>').text('Este polígono necesita una clave GIS válida y única.').appendTo(informacion);
return;
}
abrirLote(estado, figura);
return;
}
$.each(propiedades, function (nombre, valor) {
if (nombre.indexOf('_sig') !== 0 && valor != null && valor !== '') {
$('<span></span>').text(nombre + ': ' + valor).appendTo(informacion);
}
});
}
function applyGoogleStyle(state) {
state.dataLayer.setStyle(function (f) {
var layer = String(f.getProperty('_sigCapa') || 'GIS');
var type = f.getGeometry() && f.getGeometry().getType();
var visible = state.visible[layer] !== false;
var color = state.capas[layer] ? state.capas[layer].Color : '#1976D2';
var seleccionado = state.claveSeleccionada && state.claveSeleccionada === 'id:' + String(f.getId()).trim();
return {
visible: visible,
clickable: visible,
fillOpacity: type === 'Polygon' || type === 'MultiPolygon' ? 0.22 : 0,
strokeWeight: seleccionado ? 5 : (type === 'LineString' || type === 'MultiLineString' ? 3 : 2),
strokeColor: seleccionado ? '#FF8F00' : color,
fillColor: color,
icon: {
path: google.maps.SymbolPath.CIRCLE,
scale: 5,
fillColor: color,
fillOpacity: 1,
strokeColor: '#FFFFFF',
strokeWeight: 1
}
};
});
}
function renderGoogle(state) {
var el = state.$root.find('[data-gis-map]')[0];
$(el).empty();
state.map = new google.maps.Map(el, {
center: { lat: 29.072967, lng: -110.955919 },
zoom: 16,
maxZoom: 21,
zoomControl: true,
zoomControlOptions: { position: google.maps.ControlPosition.LEFT_BOTTOM },
mapTypeId: 'roadmap'
});
var controlCapas = state.$root.find('[data-gis-control-capas]')[0];
controlCapas.style.position = 'relative';
controlCapas.style.top = '0';
controlCapas.style.right = '0';
controlCapas.style.margin = '10px';
state.map.controls[google.maps.ControlPosition.RIGHT_TOP].push(controlCapas);
state.dataLayer = new google.maps.Data({map:state.map});
state.dataLayer.addGeoJson(state.geo);
applyGoogleStyle(state);
state.dataLayer.addListener('click', function(e){
var props={}; e.feature.forEachProperty(function(v,k){props[k]=v;});
featureInfo(state, { id: e.feature.getId(), properties: props,
geometry: { type: e.feature.getGeometry().getType() } });
});
encuadrarGoogle(state);
}
function renderSvg(state) {
state.dataLayer = null;
var controlCapas = state.$root.find('[data-gis-control-capas]');
controlCapas.appendTo(state.$root.find('.sig-visor-gis__contenedor'));
controlCapas.css({ position: '', top: '', right: '', margin: '' });
var $map=state.$root.find('[data-gis-map]').empty(), el=$map[0];
var b = limitesEncuadre(state) || state.ultimoEncuadre;
state.ultimoEncuadre = b;
if(!b){$map.html('<div class="alert alert-warning">El GIS no contiene geometrías visibles.</div>');return;}
var w=Math.max($map.width()||800,300), h=Math.max($map.height()||430,300), m=18;
var rx=b.maxX-b.minX||1, ry=b.maxY-b.minY||1, scale=Math.min((w-m*2)/rx,(h-m*2)/ry);
var ox=(w-rx*scale)/2, oy=(h-ry*scale)/2;
function project(p){return [ox+(p[0]-b.minX)*scale,h-(oy+(p[1]-b.minY)*scale)];}
var svg=document.createElementNS('http://www.w3.org/2000/svg','svg');
svg.setAttribute('viewBox','0 0 '+w+' '+h); svg.setAttribute('class','sig-visor-gis__svg');
$.each(state.geo.features||[],function(_,f){
if(!isSupported(f.geometry) || state.visible[layerOf(f)]===false){return;}
var type=f.geometry.type, node;
var colorCapa = state.capas[layerOf(f)].Color;
if(type==='Point'||type==='MultiPoint'){
var pts=type==='Point'?[f.geometry.coordinates]:f.geometry.coordinates;
$.each(pts,function(_,pt){var q=project(pt);node=document.createElementNS('http://www.w3.org/2000/svg','circle');node.setAttribute('cx',q[0]);node.setAttribute('cy',q[1]);node.setAttribute('r','4');node.setAttribute('class','sig-visor-gis__point');node.style.fill=colorCapa;node.addEventListener('click',function(){featureInfo(state,f);});svg.appendChild(node);});
} else {
var d=pathsFor(f.geometry,project); if(!d){return;}
node=document.createElementNS('http://www.w3.org/2000/svg','path');node.setAttribute('d',d);
node.setAttribute('class',(type.indexOf('Polygon')>=0?'sig-visor-gis__polygon':'sig-visor-gis__line'));
node.style.stroke = state.claveSeleccionada === claveFigura(f) ? '#FF8F00' : colorCapa;
node.style.strokeWidth = state.claveSeleccionada === claveFigura(f) ? '5' : '2';
if (type.indexOf('Polygon') >= 0) {
node.style.fill = colorCapa;
node.style.fillOpacity = '0.22';
}
node.setAttribute('fill-rule','evenodd'); node.addEventListener('click',function(){featureInfo(state,f);}); svg.appendChild(node);
}
});
el.appendChild(svg);
$('<div class="sig-visor-gis__note">Vista GIS · Active Google Maps en configuración para usar mapa base.</div>').appendTo($map);
}
function init(raiz) {
var elemento = $(raiz);
if (elemento.attr('data-sig-visor-gis-inicializado') === '1' ||
elemento.attr('data-sig-visor-gis-cargando') === '1') {
return;
}
var etapa = parseInt(elemento.attr('data-gis-stage'), 10) || 0;
var direccion = elemento.attr('data-gis-url');
if (!etapa || !direccion) {
return;
}
var estado = {
$root: elemento,
uid: Math.random().toString(36).slice(2),
geo: null,
layers: [],
layerCounts: Object.create(null),
visible: Object.create(null),
capas: Object.create(null),
dataLayer: null
};
elemento.data('sigVisorGis', estado);
elemento.find('[data-gis-file]').text(elemento.attr('data-gis-file-name') || '');
elemento.attr('data-sig-visor-gis-cargando', '1');
function terminar() {
elemento.attr('data-sig-visor-gis-inicializado', '1');
elemento.removeAttr('data-sig-visor-gis-cargando');
}
function mostrarError(mensaje) {
elemento.removeAttr('data-sig-visor-gis-cargando');
elemento.find('[data-gis-map]').empty().append(
$('<div class="alert alert-danger"></div>').text(mensaje));
}
function mostrarAlternativa() {
if (!$.contains(document, elemento[0])) {
return;
}
try {
renderSvg(estado);
terminar();
} catch (error) {
mostrarError('No fue posible dibujar el GIS de la etapa.');
}
}
$.ajax({
url: direccion,
type: 'GET',
dataType: 'text',
cache: false,
timeout: 30000,
data: {
metodo: 'File',
CveFraccionamientoEtapa: etapa
}
}).done(function (texto) {
if (!$.contains(document, elemento[0])) {
return;
}
try {
var geometria = JSON.parse(String(texto || '').replace(/^\uFEFF/, ''));
if (!geometria || geometria.type !== 'FeatureCollection' ||
!$.isArray(geometria.features)) {
throw new Error();
}
geometria.features = $.grep(geometria.features, function (figura) {
return figura && isSupported(figura.geometry);
});
if (!geometria.features.length) {
throw new Error();
}
estado.geo = geometria;
var colores = ['#1976D2', '#D84315', '#388E3C', '#8E24AA', '#00838F',
'#C2185B', '#827717', '#5D4037', '#455A64', '#F9A825'];
$.each(geometria.features, function (indice, figura) {
var capa = layerOf(figura);
figura.properties = figura.properties || {};
figura.properties._sigCapa = capa;
if (!estado.layerCounts[capa]) {
var nombre = capa.toLowerCase();
estado.capas[capa] = {
NombreCapa: capa,
TipoCapa: nombre.indexOf('lotific') >= 0 ? 'Lotificacion' :
nombre.indexOf('pozo') >= 0 ? 'Pozos' :
nombre.indexOf('drenaje') >= 0 ? 'Drenaje' :
nombre.indexOf('agua') >= 0 ? 'Agua' : 'Otros',
Color: colores[estado.layers.length % colores.length],
EsVisible: true,
Geometria: figura.geometry.type
};
estado.layers.push(capa);
estado.layerCounts[capa] = 0;
estado.visible[capa] = true;
} else if (estado.capas[capa].Geometria !== figura.geometry.type) {
estado.capas[capa].Geometria = 'Mixta';
}
estado.layerCounts[capa]++;
});
$.ajax({
url: direccion,
type: 'GET',
dataType: 'json',
cache: false,
timeout: 30000,
data: { metodo: 'Capas', CveFraccionamientoEtapa: etapa }
}).done(function (respuesta) {
if (!respuesta.success || !$.isArray(respuesta.data)) {
elemento.find('[data-gis-estado-capas]').text('No se pudo leer la configuración guardada.');
return;
}
$.each(respuesta.data, function (indice, capa) {
if (estado.capas[capa.NombreCapa]) {
estado.capas[capa.NombreCapa] = capa;
estado.visible[capa.NombreCapa] = capa.EsVisible;
}
});
}).fail(function () {
elemento.find('[data-gis-estado-capas]').text(
'No se pudo leer la configuración guardada. Se muestran valores iniciales.');
}).always(function () {
if (!$.contains(document, elemento[0])) {
return;
}
renderLayers(estado);
var habilitado = elemento.attr('data-gis-google-enabled') === '1';
var clave = elemento.attr('data-gis-google-key') || '';
if (habilitado && clave) {
loadGoogle(clave).done(function () {
if (!$.contains(document, elemento[0])) {
return;
}
try {
renderGoogle(estado);
terminar();
} catch (error) {
mostrarAlternativa();
}
}).fail(mostrarAlternativa);
} else {
mostrarAlternativa();
}
});
} catch (error) {
mostrarError('El archivo GIS guardado no tiene un formato compatible.');
}
}).fail(function () {
mostrarError('No fue posible cargar el GIS de la etapa.');
});
}
api.redimensionar = function (raiz) {
var estado = $(raiz).data('sigVisorGis');
if (!estado || !estado.geo) {
return;
}
if (estado.map) {
var centro = estado.map.getCenter();
var zoom = estado.map.getZoom();
google.maps.event.trigger(estado.map, 'resize');
if (centro) {
estado.map.setCenter(centro);
}
if (zoom != null) {
estado.map.setZoom(zoom);
}
} else if (estado.$root.is('[data-sig-visor-gis-inicializado]')) {
renderSvg(estado);
}
};
api.limpiarSeleccion = function (raiz, claveLote) {
var estado = $(raiz).data('sigVisorGis');
if (!estado) {
return;
}
var seleccionAfectada = false;
$.each(estado.lotes || [], function (indice, lote) {
if (String(lote.CveFraccionamientoLote) === String(claveLote)) {
seleccionAfectada = estado.claveSeleccionada === lote.GISPoligonoClave;
lote.GISPoligonoClave = '';
}
});
if (seleccionAfectada) {
estado.claveSeleccionada = null;
estado.$root.find('[data-gis-info]').empty();
}
actualizarDibujo(estado);
};
api.verLote = function (raiz, claveLote) {
var estado = $(raiz).data('sigVisorGis');
if (!estado || !estado.geo) {
return;
}
estado.consultaLotesActual = (estado.consultaLotesActual || 0) + 1;
var consulta = estado.consultaLotesActual;
var informacion = estado.$root.find('[data-gis-info]').text('Consultando lote...').show();
cargarLotes(estado).done(function (respuesta) {
if (consulta !== estado.consultaLotesActual || !$.contains(document, estado.$root[0])) {
return;
}
estado.lotes = respuesta.data.Lotes;
var lote = $.grep(estado.lotes, function (elemento) {
return String(elemento.CveFraccionamientoLote) === String(claveLote) && elemento.EsActivo;
})[0];
var figura = lote && $.grep(estado.geo.features, function (elemento) {
return claveFigura(elemento) === lote.GISPoligonoClave;
})[0];
if (!figura) {
informacion.text('Este lote no tiene un polígono vinculado en el archivo actual. Seleccione un polígono libre para vincularlo.');
estado.$root[0].scrollIntoView({ block: 'center' });
return;
}
var capa = layerOf(figura);
estado.visible[capa] = true;
estado.capas[capa].EsVisible = true;
renderLayers(estado);
estado.claveSeleccionada = claveFigura(figura);
estado.figuraSeleccionada = figura;
actualizarDibujo(estado);
mostrarVinculo(estado, figura, lote);
estado.$root.trigger('sig:loteSeleccionado', [lote]);
if (estado.map) {
var limites = boundsOf({ features: [figura] });
if (limites) {
estado.map.fitBounds(new google.maps.LatLngBounds(
{ lat: limites.minY, lng: limites.minX },
{ lat: limites.maxY, lng: limites.maxX }), 70);
}
}
}).fail(function () {
if (consulta === estado.consultaLotesActual) {
informacion.text('No fue posible consultar el vínculo del lote. Inténtelo nuevamente.');
}
});
};
function scan() {
if (window.SIGLotesEtapa) {
window.SIGLotesEtapa.restaurarMapas();
}
$('.sig-visor-gis[data-gis-stage]').each(function () {
init(this);
});
}
api.init=scan;
api.ensureGoogleMaps=loadGoogle;
$(scan);
if(window.Sys&&Sys.WebForms&&Sys.WebForms.PageRequestManager){
try{Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function(){scan();});}catch(_){ }
}
})(window, document, window.jQuery);

View File

@@ -7,6 +7,81 @@
return;
}
var menuFlotante = null;
function cerrarMenuFlotante() {
if (!menuFlotante) {
return;
}
var actual = menuFlotante;
menuFlotante = null;
actual.control.removeClass('menu-open');
actual.flecha.attr('aria-expanded', 'false');
actual.menu.removeClass('filtrosig-menu-flotante').removeAttr('style');
if ($.contains(document, actual.control[0])) {
actual.menu.detach().appendTo(actual.control);
} else {
actual.menu.remove();
}
}
function posicionarMenuFlotante() {
if (!menuFlotante) {
return;
}
var actual = menuFlotante;
if (!$.contains(document, actual.control[0])) {
cerrarMenuFlotante();
return;
}
var borde = actual.flecha[0].getBoundingClientRect();
var ancho = window.innerWidth;
var alto = window.innerHeight;
actual.menu.css({
width: Math.min(240, ancho - 12),
minWidth: Math.min(210, ancho - 12),
maxHeight: Math.max(50, alto - 12),
left: 0,
top: 0,
right: 'auto',
bottom: 'auto'
});
var altura = actual.menu.outerHeight();
var arriba = borde.bottom + 4;
if (arriba + altura > alto - 6) {
arriba = Math.max(6, borde.top - altura - 4);
}
actual.menu.css({
left: Math.max(6, Math.min(borde.right - actual.menu.outerWidth(), ancho - actual.menu.outerWidth() - 6)),
top: Math.min(arriba, Math.max(6, alto - altura - 6))
});
}
function alternarMenuFlotante(control, menu, flecha) {
var cerrar = menuFlotante && menuFlotante.control[0] === control[0];
cerrarMenuFlotante();
if (cerrar) {
return;
}
menuFlotante = { control: control, menu: menu, flecha: flecha };
control.addClass('menu-open');
flecha.attr('aria-expanded', 'true');
menu.detach().appendTo(control.closest('form')).addClass('filtrosig-menu-flotante');
posicionarMenuFlotante();
}
window.addEventListener('resize', posicionarMenuFlotante);
document.addEventListener('scroll', function (evento) {
if (menuFlotante && !menuFlotante.menu[0].contains(evento.target)) {
posicionarMenuFlotante();
}
}, true);
$(document).on('keydown.sigFiltroMenu', function (evento) {
if (evento.key === 'Escape') {
cerrarMenuFlotante();
}
});
var FILTRO_RENDERED = 'filtrosigrendered';
var FILTRO_HIDDEN = 'filtrosig-hidden';
var FILTRO_IGNORE = 'filtrosig-ignore';
@@ -33,7 +108,7 @@
crearControl($grid, campos);
$grid.addClass(FILTRO_RENDERED);
$grid.addClass(FILTRO_RENDERED).attr('data-sig-filtro-inicializado', '1');
});
};
@@ -586,16 +661,8 @@
e.stopPropagation();
$('.filtrosig-control')
.not($control)
.removeClass(
'menu-open'
);
alternarMenuFlotante($control, $menu, $flecha);
$control.toggleClass(
'menu-open'
);
});
@@ -697,9 +764,7 @@
/*
* Cerrar menú.
*/
$control.removeClass(
'menu-open'
);
cerrarMenuFlotante();
/*
@@ -1146,10 +1211,7 @@
'click.filtrosig',
function () {
$('.filtrosig-control')
.removeClass(
'menu-open'
);
cerrarMenuFlotante();
}
);
@@ -1205,6 +1267,8 @@
Sys.WebForms.PageRequestManager
) {
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(cerrarMenuFlotante);
Sys.WebForms.PageRequestManager
.getInstance()
.add_endRequest(function () {
@@ -1214,4 +1278,4 @@
}
})(window, window.jQuery);
})(window, window.jQuery);

View File

@@ -1,4 +1,4 @@
(function (window, $, undefined) {
(function (window, $, undefined) {
'use strict';
var interfaz = window.GisFraccionamiento = window.GisFraccionamiento || {};
@@ -12,13 +12,16 @@
idMapa: 'MapaGis',
idTablaVinculos: 'GisVinculos',
idEstatus: 'EstatusVinculosGis',
idCapas: 'GisCapas',
idBotonGuardar: 'BtnGuardarEtapaGis',
idBotonGuardarVinculos: 'BtnGuardarVinculosEtapaGis',
idBotonEliminar: 'BtnEliminarEtapaGis',
idBotonActualizar: 'BtnActualizarEtapaGis',
urlManejador: '/Pages/Fraccionamientos/FraccionamientoGis.ashx',
zoomInicial: 16,
centro: { lat: 29.072967, lng: -110.955919 }
centro: { lat: 29.072967, lng: -110.955919 },
googleMapsEnabled: false,
googleMapsApiKey: ''
}, window.OpcionesGisFraccionamiento || {});
}
@@ -32,10 +35,14 @@
vinculosPorClavePoligono: {},
poligonoPorCveLote: {},
clavesPoligono: [],
capas: [],
cantidadPorCapa: {},
capasVisibles: {},
clavePoligonoSeleccionado: null,
nombrePoligonoPorClave: {},
geoJson: null,
archivo: null,
archivoEsZip: false,
tieneArchivoServidor: false,
tieneCambios: false,
requiereActualizarDetalle: false,
@@ -79,52 +86,31 @@
}
function validarGeoJson(valor) {
if (!valor ||
valor.type !== 'FeatureCollection' ||
!$.isArray(valor.features)) {
throw new Error(
'El archivo .gis debe contener un GeoJSON FeatureCollection válido.');
if (!valor || valor.type !== 'FeatureCollection' || !$.isArray(valor.features)) {
throw new Error('El archivo GIS debe contener un GeoJSON FeatureCollection válido.');
}
if (valor.features.length === 0) {
throw new Error('El archivo .gis no contiene geometrías.');
throw new Error('El archivo GIS no contiene geometrías.');
}
var claves = {};
var cantidadPoligonos = 0;
$.each(valor.features, function (_, elementoGeografico) {
if (!elementoGeografico || !elementoGeografico.geometry) {
return;
}
var tipoGeometria = elementoGeografico.geometry.type;
if (tipoGeometria !== 'Polygon' && tipoGeometria !== 'MultiPolygon') {
return;
}
var clave = obtenerClavePoligono(elementoGeografico);
if (claves[clave]) {
throw new Error(
'El archivo contiene dos polígonos con la misma clave GIS.');
}
if (clave.length > 100) {
throw new Error(
'Una clave de polígono GIS excede 100 caracteres.');
}
var cantidadUtil = 0;
var tipos = ['Point','MultiPoint','LineString','MultiLineString','Polygon','MultiPolygon'];
$.each(valor.features, function (_, feature) {
if (!feature || !feature.geometry || $.inArray(feature.geometry.type, tipos) < 0) { return; }
feature.properties = feature.properties || {};
feature.properties._sigCapa = $.trim(String(feature.properties._sigCapa || 'GIS')) || 'GIS';
cantidadUtil++;
if (feature.geometry.type !== 'Polygon' && feature.geometry.type !== 'MultiPolygon') { return; }
if (feature.properties._sigVinculableLote === false) { return; }
var clave = obtenerClavePoligono(feature);
if (claves[clave]) { throw new Error('El archivo contiene dos polígonos con la misma clave GIS.'); }
if (clave.length > 100) { throw new Error('Una clave de polígono GIS excede 100 caracteres.'); }
claves[clave] = true;
elementoGeografico.properties = elementoGeografico.properties || {};
elementoGeografico.properties._sigClavePoligono = clave;
cantidadPoligonos++;
feature.properties._sigClavePoligono = clave;
});
if (cantidadPoligonos === 0) {
throw new Error(
'El archivo .gis no contiene geometrías Polygon o MultiPolygon.');
if (cantidadUtil === 0) {
throw new Error('El archivo GIS no contiene puntos, líneas o polígonos compatibles.');
}
return valor;
}
@@ -217,6 +203,7 @@
}).done(function (texto) {
try {
estado.archivo = null;
estado.archivoEsZip = false;
cargarGeoJson(estado, convertirTextoJson(texto));
} catch (excepcion) {
limpiarVisor(estado);
@@ -234,17 +221,15 @@
estado.geoJson = null;
estado.clavesPoligono = [];
estado.nombrePoligonoPorClave = {};
estado.capas = [];
estado.cantidadPorCapa = {};
estado.capasVisibles = {};
$('#' + estado.opciones.idCapas).empty();
if (estado.capaDatos) {
var elementos = [];
estado.capaDatos.forEach(function (elementoGeografico) {
elementos.push(elementoGeografico);
});
$.each(elementos, function (_, elementoGeografico) {
estado.capaDatos.remove(elementoGeografico);
});
estado.capaDatos.forEach(function (feature) { elementos.push(feature); });
$.each(elementos, function (_, feature) { estado.capaDatos.remove(feature); });
}
$('#' + estado.opciones.idMapa).empty();
estado.mapa = null;
estado.capaDatos = null;
@@ -256,26 +241,48 @@
estado.geoJson = valor;
estado.clavesPoligono = [];
estado.nombrePoligonoPorClave = {};
$.each(valor.features, function (_, elementoGeografico) {
if (!elementoGeografico || !elementoGeografico.geometry) {
return;
estado.capas = [];
estado.cantidadPorCapa = {};
estado.capasVisibles = {};
$.each(valor.features, function (_, feature) {
if (!feature || !feature.geometry) { return; }
var capa = $.trim(String((feature.properties || {})._sigCapa || 'GIS')) || 'GIS';
if (!estado.cantidadPorCapa[capa]) {
estado.capas.push(capa);
estado.cantidadPorCapa[capa] = 0;
estado.capasVisibles[capa] = true;
}
if (elementoGeografico.geometry.type !== 'Polygon' &&
elementoGeografico.geometry.type !== 'MultiPolygon') {
return;
}
var clave = elementoGeografico.properties._sigClavePoligono;
estado.cantidadPorCapa[capa]++;
if (feature.geometry.type !== 'Polygon' && feature.geometry.type !== 'MultiPolygon') { return; }
var clave = feature.properties._sigClavePoligono;
estado.clavesPoligono.push(clave);
estado.nombrePoligonoPorClave[clave] = obtenerNombreElemento(elementoGeografico, clave);
estado.nombrePoligonoPorClave[clave] = obtenerNombreElemento(feature, clave);
});
dibujarCapas(estado);
dibujarMapa(estado);
dibujarVinculos(estado);
}
function dibujarCapas(estado) {
var $c = $('#' + estado.opciones.idCapas).empty();
if (!$c.length) { return; }
$.each(estado.capas, function (indice, capa) {
var id = 'GisCapa_' + indice;
var $label = $('<label class="sig-gis-layer-item"></label>').attr('for', id);
$('<input type="checkbox" checked />').attr('id', id).attr('data-gis-capa', capa).appendTo($label);
$('<span></span>').text(capa + ' (' + estado.cantidadPorCapa[capa] + ')').appendTo($label);
$c.append($label);
});
$c.find('input[data-gis-capa]:not([data-sig-capa-inicializada])').each(function () {
var casilla = $(this);
casilla.on('change.sigGisLayers', function () {
estado.capasVisibles[casilla.attr('data-gis-capa')] = this.checked;
actualizarEstilosMapa(estado);
});
casilla.attr('data-sig-capa-inicializada', '1');
});
}
function dibujarMapa(estado) {
var elemento = document.getElementById(estado.opciones.idMapa);
if (!elemento) {
@@ -291,6 +298,24 @@
return;
}
var usarGoogle = estado.opciones.googleMapsEnabled === true &&
estado.opciones.googleMapsApiKey &&
estado.opciones.googleMapsApiKey !== 'TU_API_KEY' &&
window.SIGVisorGis &&
typeof window.SIGVisorGis.ensureGoogleMaps === 'function';
if (usarGoogle) {
dibujarMapaSvg(estado, elemento);
window.SIGVisorGis.ensureGoogleMaps(estado.opciones.googleMapsApiKey)
.done(function () {
if (actual === estado && estado.geoJson) {
$(elemento).empty();
dibujarMapaGoogle(estado, elemento);
}
});
return;
}
dibujarMapaSvg(estado, elemento);
}
@@ -308,7 +333,7 @@
estado.capaDatos.addListener('click', function (evento) {
var clave = evento.feature.getProperty('_sigClavePoligono');
abrirModalAsignacion(estado, clave);
if (clave) { abrirModalAsignacion(estado, clave); }
});
var limites = new google.maps.LatLngBounds();
@@ -327,18 +352,20 @@
}
function aplicarEstiloGoogle(estado) {
if (!estado.capaDatos) {
return;
}
estado.capaDatos.setStyle(function (elementoGeografico) {
var clave = elementoGeografico.getProperty('_sigClavePoligono');
var vinculado = !!estado.vinculosPorClavePoligono[clave];
if (!estado.capaDatos) { return; }
estado.capaDatos.setStyle(function (feature) {
var clave = feature.getProperty('_sigClavePoligono');
var capa = String(feature.getProperty('_sigCapa') || 'GIS');
var vinculado = !!(clave && estado.vinculosPorClavePoligono[clave]);
var geometry = feature.getGeometry();
var tipo = geometry ? geometry.getType() : '';
var visible = estado.capasVisibles[capa] !== false;
return {
fillOpacity: vinculado ? 0.42 : 0.18,
strokeWeight: vinculado ? 3 : 2,
clickable: true
visible: visible,
fillOpacity: tipo === 'Polygon' || tipo === 'MultiPolygon' ? (vinculado ? 0.42 : 0.18) : 0,
strokeWeight: tipo === 'LineString' || tipo === 'MultiLineString' ? 3 : (vinculado ? 3 : 2),
clickable: visible && !!clave,
pointRadius: 5
};
});
}
@@ -346,84 +373,40 @@
function dibujarMapaSvg(estado, elemento) {
estado.modoMapa = 'svg';
$(elemento).empty();
var limites = obtenerLimitesGeo(estado.geoJson);
if (!limites) {
$(elemento).html(
'<div class="alert alert-warning">No fue posible calcular la extensión de los polígonos.</div>');
$(elemento).html('<div class="alert alert-warning">No fue posible calcular la extensión del GIS.</div>');
return;
}
var ancho = Math.max($(elemento).width() || 700, 300);
var alto = Math.max($(elemento).height() || 480, 300);
var margen = 24;
var rangoX = limites.maximoX - limites.minimoX || 1;
var rangoY = limites.maximoY - limites.minimoY || 1;
var escala = Math.min(
(ancho - margen * 2) / rangoX,
(alto - margen * 2) / rangoY);
var anchoDibujo = rangoX * escala;
var altoDibujo = rangoY * escala;
var desplazamientoX = (ancho - anchoDibujo) / 2;
var desplazamientoY = (alto - altoDibujo) / 2;
function proyectar(punto) {
return [
desplazamientoX + (punto[0] - limites.minimoX) * escala,
alto - (desplazamientoY + (punto[1] - limites.minimoY) * escala)
];
}
var elementoSvg = document.createElementNS(
'http://www.w3.org/2000/svg',
'svg');
elementoSvg.setAttribute('viewBox', '0 0 ' + ancho + ' ' + alto);
elementoSvg.setAttribute('class', 'sig-gis-svg');
elementoSvg.setAttribute('role', 'img');
elementoSvg.setAttribute('aria-label', 'Polígonos del archivo GIS');
$.each(estado.geoJson.features, function (_, elementoGeografico) {
if (!elementoGeografico || !elementoGeografico.geometry) {
var ancho=Math.max($(elemento).width()||700,300), alto=Math.max($(elemento).height()||480,300), margen=24;
var rangoX=limites.maximoX-limites.minimoX||1, rangoY=limites.maximoY-limites.minimoY||1;
var escala=Math.min((ancho-margen*2)/rangoX,(alto-margen*2)/rangoY);
var dx=(ancho-rangoX*escala)/2, dy=(alto-rangoY*escala)/2;
function proyectar(p){return [dx+(p[0]-limites.minimoX)*escala,alto-(dy+(p[1]-limites.minimoY)*escala)];}
var svg=document.createElementNS('http://www.w3.org/2000/svg','svg');
svg.setAttribute('viewBox','0 0 '+ancho+' '+alto); svg.setAttribute('class','sig-gis-svg');
svg.setAttribute('role','img'); svg.setAttribute('aria-label','Capas del archivo GIS');
$.each(estado.geoJson.features,function(_,feature){
if(!feature||!feature.geometry){return;}
var capa=$.trim(String((feature.properties||{})._sigCapa||'GIS'))||'GIS';
if(estado.capasVisibles[capa]===false){return;}
var tipo=feature.geometry.type, clave=feature.properties&&feature.properties._sigClavePoligono;
if(tipo==='Point'||tipo==='MultiPoint'){
var puntos=tipo==='Point'?[feature.geometry.coordinates]:feature.geometry.coordinates;
$.each(puntos,function(_,pt){var q=proyectar(pt),circulo=document.createElementNS('http://www.w3.org/2000/svg','circle');circulo.setAttribute('cx',q[0]);circulo.setAttribute('cy',q[1]);circulo.setAttribute('r','4');circulo.setAttribute('class','sig-gis-point');svg.appendChild(circulo);});
return;
}
var clave = elementoGeografico.properties &&
elementoGeografico.properties._sigClavePoligono;
if (!clave) {
return;
}
var datosRuta = crearRutaGeometria(elementoGeografico.geometry, proyectar);
if (!datosRuta) {
return;
}
var rutaElemento = document.createElementNS(
'http://www.w3.org/2000/svg',
'path');
rutaElemento.setAttribute('d', datosRuta);
rutaElemento.setAttribute(
'class',
'sig-gis-polygon ' +
(estado.vinculosPorClavePoligono[clave]
? 'is-vinculado'
: 'is-pending'));
rutaElemento.setAttribute('fill-rule', 'evenodd');
rutaElemento.setAttribute('data-clave-poligono', clave);
rutaElemento.addEventListener('click', function () {
abrirModalAsignacion(estado, clave);
});
elementoSvg.appendChild(rutaElemento);
var ruta=crearRutaGeometria(feature.geometry,proyectar); if(!ruta){return;}
var path=document.createElementNS('http://www.w3.org/2000/svg','path'); path.setAttribute('d',ruta);
if(tipo==='Polygon'||tipo==='MultiPolygon'){
path.setAttribute('class','sig-gis-polygon '+(clave&&estado.vinculosPorClavePoligono[clave]?'is-linked':'is-pending'));
path.setAttribute('fill-rule','evenodd');
if(clave){path.setAttribute('data-clave-poligono',clave);path.addEventListener('click',function(){abrirModalAsignacion(estado,clave);});}
} else { path.setAttribute('class','sig-gis-line'); }
svg.appendChild(path);
});
elemento.appendChild(elementoSvg);
$('<div class="sig-gis-map-note"></div>')
.text('Vista de geometría. Google Maps no está cargado en esta página.')
.appendTo(elemento);
elemento.appendChild(svg);
$('<div class="sig-gis-map-note"></div>').text('Vista GIS. Active Google Maps para mostrar mapa base.').appendTo(elemento);
}
function obtenerLimitesGeo(datosGeoJson) {
@@ -468,36 +451,17 @@
}
function crearRutaGeometria(geometria, proyectar) {
var poligonos;
if (geometria.type === 'Polygon') {
poligonos = [geometria.coordinates];
} else if (geometria.type === 'MultiPolygon') {
poligonos = geometria.coordinates;
} else {
return '';
function linea(coordenadas, cerrar) {
if (!coordenadas || !coordenadas.length) { return ''; }
var p=proyectar(coordenadas[0]), r=['M'+p[0]+','+p[1]];
for(var i=1;i<coordenadas.length;i++){p=proyectar(coordenadas[i]);r.push('L'+p[0]+','+p[1]);}
if(cerrar){r.push('Z');} return r.join(' ');
}
var resultado = [];
$.each(poligonos, function (_, poligono) {
$.each(poligono, function (_, anillo) {
if (!anillo || anillo.length === 0) {
return;
}
var primero = proyectar(anillo[0]);
resultado.push('M' + primero[0] + ',' + primero[1]);
for (var indice = 1; indice < anillo.length; indice++) {
var punto = proyectar(anillo[indice]);
resultado.push('L' + punto[0] + ',' + punto[1]);
}
resultado.push('Z');
});
});
var resultado=[];
if(geometria.type==='LineString'){resultado.push(linea(geometria.coordinates,false));}
else if(geometria.type==='MultiLineString'){$.each(geometria.coordinates,function(_,x){resultado.push(linea(x,false));});}
else if(geometria.type==='Polygon'){$.each(geometria.coordinates,function(_,x){resultado.push(linea(x,true));});}
else if(geometria.type==='MultiPolygon'){$.each(geometria.coordinates,function(_,p){$.each(p,function(_,x){resultado.push(linea(x,true));});});}
return resultado.join(' ');
}
@@ -733,7 +697,7 @@
function validarAntesDeGuardar(estado, soloArchivo) {
if (soloArchivo && !estado.archivo) {
return 'Seleccione un archivo .gis para guardar.';
return 'Seleccione un GIS (.gis/.geojson) o un ZIP Shapefile para guardar.';
}
if (!soloArchivo && (estado.archivo || !estado.tieneArchivoServidor)) {
@@ -744,12 +708,12 @@
return 'No hay cambios de vínculos para guardar.';
}
if (!estado.geoJson) {
return 'Seleccione un archivo .gis válido.';
if (!estado.geoJson && !(soloArchivo && estado.archivoEsZip)) {
return 'Seleccione un archivo GIS válido.';
}
if (estado.clavesPoligono.length === 0) {
return 'El archivo GIS no contiene polígonos para guardar.';
if (!soloArchivo && estado.clavesPoligono.length === 0) {
return 'El archivo GIS no contiene polígonos para vincular lotes.';
}
return null;
@@ -792,9 +756,11 @@
if (soloArchivo) {
estado.tieneArchivoServidor = true;
estado.archivo = null;
estado.archivoEsZip = false;
if (window.ADSLocalDropzone) {
window.ADSLocalDropzone.clear(estado.opciones.idEntradaArchivo);
}
cargarArchivoServidor(estado);
} else {
$.each(estado.lotes, function (_, lote) {
var cveLote = parseInt(
@@ -841,8 +807,17 @@
try {
estado.archivo = archivo;
var nombre = archivo && archivo.name ? archivo.name : '';
estado.archivoEsZip = /\.zip$/i.test(nombre);
// Cargar un archivo no modifica los vínculos guardados ni los pendientes.
if (estado.archivoEsZip) {
actualizarBotonesAccion(estado);
limpiarMensaje();
mostrarMensaje('ZIP Shapefile seleccionado. Al guardar se procesará en servidor y se generará el GIS por capas.', false);
return;
}
// Cargar .gis/.geojson no modifica los vínculos guardados ni los pendientes.
cargarGeoJson(estado, convertirTextoJson(texto));
actualizarBotonesAccion(estado);
limpiarMensaje();
@@ -883,6 +858,7 @@
}
estado.archivo = null;
estado.archivoEsZip = false;
if (estado.tieneArchivoServidor) {
cargarArchivoServidor(estado);

View File

@@ -1,4 +1,4 @@
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="Site.master.cs" Inherits="SIG.Web.Site" %>
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="Site.master.cs" Inherits="SIG.Web.Site" %>
<%@ Import Namespace="System.Web.Optimization" %>
<!DOCTYPE html>
@@ -245,7 +245,7 @@
</div>
</div>
<div class="page-footer">
<div class="page-footer" style="display:none;" >
<div class="page-footer-inner">SIG WebForms Starter</div>
<div class="scroll-to-top"><i class="icon-arrow-up"></i></div>
</div>

View File

@@ -1,4 +1,4 @@
.sig-lotes-etapa .sig-lotes-bloque { margin-bottom: 24px; }
.sig-lotes-etapa .sig-lotes-bloque { margin-bottom: 24px; }
.sig-lotes-etapa .sig-lotes-titulo {
display:flex; align-items:flex-end; justify-content:space-between;
gap:15px; margin-bottom:10px;
@@ -31,3 +31,68 @@
}
.sig-lotes-etapa .sig-lotes-excel { grid-template-columns:1fr; }
}
.sig_panel_lateral.sig-lotes-panel {
width: 65vw;
max-width: 100vw;
}
.sig-lotes-mapa-reservado {
background: #e5e7e9;
border: 1px solid #d4d8dc;
box-sizing: border-box;
}
.sig-lotes-mapa-resguardado {
position: fixed;
left: -100000px;
top: 0;
width: 1000px;
visibility: hidden;
pointer-events: none;
}
.sig-lotes-etapa .table > tbody > tr.sig-lotes-fila-seleccionada > td {
background: #fff0c2;
box-shadow: inset 0 1px #e5a82c, inset 0 -1px #e5a82c;
}
.sig-lotes-ver-mapa {
display: block;
width: 100%;
border: 0;
background: transparent;
text-align: left;
padding: 8px 14px;
color: #555;
}
.sig-lotes-ver-mapa:hover,
.sig-lotes-ver-mapa:focus {
background: #eee;
}
.sig-lotes-detalle-acciones {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 10px;
margin: 12px 0;
}
.sig-lotes-ficha th {
width: 40%;
}
.sig-lotes-panel .sig_panel_cuerpo {
padding: 12px 16px;
}
.sig-lotes-panel [data-lotes-mapa-panel] .sig-visor-gis__map {
height: 42vh;
min-height: 280px;
}
.sig-lotes-panel [data-lotes-mapa-panel] .sig-visor-gis {
margin-top: 0;
}

229
SIG.Web/Styles/VisorGis.css Normal file
View File

@@ -0,0 +1,229 @@
.sig-visor-gis {
margin:12px 0 18px;
border:1px solid #dfe4e8;
background:#fff;
}
.sig-visor-gis__header {
display:flex;
justify-content:space-between;
align-items:flex-start;
gap:12px;
padding:10px 12px;
border-bottom:1px solid #e7eaed;
}
.sig-visor-gis__title {
margin:0 0 2px;
font-weight:600;
}
.sig-visor-gis__file {
font-size:11px;
color:#7a8591;
}
.sig-visor-gis__layers {
display:flex;
flex-wrap:wrap;
justify-content:flex-end;
gap:6px;
max-width:65%;
}
.sig-visor-gis__layer {
margin:0;
padding:4px 7px;
border:1px solid #d9dee4;
border-radius:3px;
background:#fafbfc;
font-size:11px;
font-weight:400;
cursor:pointer;
}
.sig-visor-gis__layer input {
margin:0 5px 0 0;
vertical-align:-1px;
}
.sig-visor-gis__map {
position:relative;
min-height:430px;
background:#f7f9fb;
overflow:hidden;
}
.sig-visor-gis__loading {
padding:30px;
text-align:center;
color:#7a8591;
}
.sig-visor-gis__svg {
display:block;
width:100%;
height:430px;
}
.sig-visor-gis__polygon {
fill:rgba(51,122,183,.13);
stroke:#337ab7;
stroke-width:1.5;
vector-effect:non-scaling-stroke;
cursor:pointer;
}
.sig-visor-gis__line {
fill:none;
stroke:#337ab7;
stroke-width:2;
vector-effect:non-scaling-stroke;
cursor:pointer;
}
.sig-visor-gis__point {
fill:#337ab7;
stroke:#fff;
stroke-width:1.5;
vector-effect:non-scaling-stroke;
cursor:pointer;
}
.sig-visor-gis__polygon:hover,.sig-visor-gis__line:hover,.sig-visor-gis__point:hover {
opacity:.68;
}
.sig-visor-gis__note {
position:absolute;
right:7px;
bottom:7px;
padding:3px 6px;
border:1px solid #d9dee4;
background:rgba(255,255,255,.9);
font-size:10px;
color:#6b7683;
}
.sig-visor-gis__info {
padding:8px 12px;
border-top:1px solid #e7eaed;
font-size:11px;
}
.sig-visor-gis__info span {
display:inline-block;
margin-right:12px;
}
@media(max-width:991px) {
.sig-visor-gis__header {
display:block;
}
.sig-visor-gis__layers {
max-width:none;
justify-content:flex-start;
margin-top:8px;
}
.sig-visor-gis__map,.sig-visor-gis__svg {
min-height:330px;
height:330px;
}
}
.sig-visor-gis__contenedor {
position: relative;
}
.sig-visor-gis__control-capas {
position: absolute;
z-index: 2;
top: 60px;
right: 10px;
width: 280px;
max-width: calc(100% - 20px);
text-align: right;
}
.sig-visor-gis__panel-capas {
margin-top: 6px;
padding: 12px;
max-height: 295px;
overflow-y: auto;
background: rgba(255, 255, 255, .97);
border: 1px solid #d9dee4;
box-shadow: 0 2px 6px rgba(0, 0, 0, .18);
text-align: left;
}
.sig-visor-gis__fila-capa {
padding: 10px 0;
border-bottom: 1px solid #e7eaed;
}
.sig-visor-gis__fila-capa label {
display: block;
font-weight: normal;
margin-bottom: 5px;
}
.sig-visor-gis__fila-capa input[type=checkbox] {
margin-right: 6px;
}
.sig-visor-gis__opciones-capa {
display: flex;
align-items: center;
gap: 8px;
}
.sig-visor-gis__opciones-capa select {
flex: 1;
min-width: 0;
}
.sig-visor-gis__opciones-capa input[type=color] {
width: 36px;
height: 30px;
padding: 2px;
}
.sig-visor-gis__aviso {
margin: 5px 0;
font-size: 11px;
white-space: normal;
}
.sig-visor-gis__cantidad {
float: right;
text-align: right;
}
.sig-visor-gis__geometria {
display: block;
color: #687582;
font-size: 11px;
margin-bottom: 5px;
}
.sig-visor-gis__enlace-lote {
border: 0;
background: transparent;
color: #1764a0;
padding: 4px 0;
text-decoration: underline;
font-weight: 600;
}
.sig-visor-gis__ficha-lote {
display: grid;
grid-template-columns: 120px 1fr;
gap: 8px;
}
.sig-visor-gis__ficha-lote dd {
margin: 0;
}
.sig-visor-gis__superficie-lote {
text-align: right;
}

View File

@@ -384,3 +384,13 @@ tr.filtrosig-ignore {
max-width: 120px;
}
}
.filtrosig-menu.filtrosig-menu-flotante {
display: block;
position: fixed;
z-index: 10060;
margin: 0;
overflow-y: auto;
overflow-x: hidden;
box-sizing: border-box;
}

View File

@@ -1,4 +1,4 @@
#ModalStageGis .modal-dialog {
#ModalStageGis .modal-dialog {
width: 94%;
max-width: 1280px;
}
@@ -164,3 +164,25 @@
font-weight: 600;
word-break: break-all;
}
.sig-gis-layers {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin: 10px 0;
}
.sig-gis-layer-item {
margin: 0;
padding: 4px 7px;
border: 1px solid #d9dee4;
border-radius: 3px;
background: #fafbfc;
font-size: 11px;
font-weight: 400;
cursor: pointer;
}
.sig-gis-layer-item input { margin: 0 5px 0 0; vertical-align: -1px; }
.sig-gis-line { fill: none; stroke: #337ab7; stroke-width: 2; vector-effect: non-scaling-stroke; }
.sig-gis-point { fill: #337ab7; stroke: #fff; stroke-width: 1.5; vector-effect: non-scaling-stroke; }

View File

@@ -1,4 +1,4 @@
<%@ Control Language="C#" AutoEventWireup="false" CodeFile="ConveniosListado.ascx.cs" Inherits="SIG.Web.UserControl.ConveniosListado" %>
<%@ Control Language="C#" AutoEventWireup="false" CodeFile="ConveniosListado.ascx.cs" Inherits="SIG.Web.UserControl.ConveniosListado" %>
<asp:UpdatePanel ID="UpConvenios" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="true">
<ContentTemplate>
@@ -36,6 +36,7 @@
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="TipoTramite" HeaderText="Tipo de trámite" />
<asp:BoundField DataField="Estatus" HeaderText="Estado" />
<asp:BoundField
@@ -101,6 +102,14 @@
</div>
<div class="modal-body">
<div class="form-group">
<asp:Label runat="server"
AssociatedControlID="DdlTipoTramiteCaptura"
Text="Tipo de trámite" />
<asp:DropDownList ID="DdlTipoTramiteCaptura"
runat="server"
CssClass="form-control select2me" />
</div>
<div class="row sig-convenio-contexto-captura">
<div class="col-md-6">
<div class="form-group">
@@ -145,7 +154,7 @@
<asp:TextBox
ID="TxtViviendasAutorizadas"
runat="server"
CssClass="form-control"
CssClass="form-control text-right"
ReadOnly="true"
Text="0"
MaxLength="9" />
@@ -161,7 +170,7 @@
<asp:TextBox
ID="TxtViviendasEnConvenio"
runat="server"
CssClass="form-control"
CssClass="form-control text-right"
ReadOnly="true"
Text="0"
MaxLength="9" />
@@ -177,7 +186,7 @@
<asp:TextBox
ID="TxtViviendasPendientes"
runat="server"
CssClass="form-control"
CssClass="form-control text-right"
ReadOnly="true"
Text="0"
MaxLength="9" />
@@ -193,7 +202,7 @@
<asp:TextBox
ID="TxtViviendasContratadas"
runat="server"
CssClass="form-control"
CssClass="form-control text-right"
ReadOnly="true"
Text="0"
MaxLength="9" />
@@ -253,7 +262,7 @@
<asp:TextBox
ID="TxtLotesConvenio"
runat="server"
CssClass="form-control"
CssClass="form-control text-right"
Text="0"
MaxLength="9" />
</div>
@@ -305,7 +314,7 @@
<asp:TextBox
ID="TxtImporteConcepto"
runat="server"
CssClass="form-control"
CssClass="form-control text-right"
MaxLength="30" />
</div>
</div>
@@ -337,7 +346,7 @@
<asp:TextBox
ID="TxtNumeroPagosConcepto"
runat="server"
CssClass="form-control"
CssClass="form-control text-right"
Text="1"
MaxLength="2" />
</div>
@@ -392,7 +401,8 @@
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Importe">
<asp:TemplateField HeaderText="Importe"
ItemStyle-HorizontalAlign="Right">
<ItemTemplate>
<asp:Label
ID="LblImporteConceptoFila"
@@ -404,7 +414,7 @@
ID="TxtImporteParcialidad"
runat="server"
Visible='<%# !Convert.ToBoolean(Eval("EsConcepto")) %>'
CssClass="form-control input-sm"
CssClass="form-control input-sm text-right"
Text='<%# Eval("ImporteTexto") %>' />
</ItemTemplate>
</asp:TemplateField>
@@ -578,7 +588,8 @@
<asp:BoundField DataField="ImportePagado" HeaderText="Pagado" DataFormatString="{0:N2}" ItemStyle-HorizontalAlign="Right" />
<asp:BoundField DataField="SaldoPendiente" HeaderText="Saldo" DataFormatString="{0:N2}" ItemStyle-HorizontalAlign="Right" />
<asp:BoundField DataField="FechaVencimiento" HeaderText="Vencimiento" DataFormatString="{0:dd/MM/yyyy}" />
<asp:BoundField DataField="Estatus" HeaderText="Estado" />
<asp:BoundField DataField="TipoTramite" HeaderText="Tipo de trámite" />
<asp:BoundField DataField="Estatus" HeaderText="Estado" />
</Columns>
</asp:GridView>
</div>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@@ -157,6 +157,27 @@ namespace SIG.Web.UserControl
return;
}
var tiposTramite = AppServices.TramiteCatalogService.ListTiposTramite(
null, false, CurrentUser.CveUsuario, CurrentUser.NombreDominio);
if (!tiposTramite.Success)
{
PageAlertManager.Alert(Page, tiposTramite.UserMessage, TipoMensaje.MsgAdvertencia);
return;
}
DdlTipoTramiteCaptura.DataSource = tiposTramite.Data;
DdlTipoTramiteCaptura.DataValueField = "CveTipoTramite";
DdlTipoTramiteCaptura.DataTextField = "TipoTramite";
DdlTipoTramiteCaptura.DataBind();
DdlTipoTramiteCaptura.Items.Insert(0, new ListItem("Seleccione el tipo de trámite", ""));
if (FiltroActual.CveTipoTramite.HasValue)
{
ListItem opcionTramite = DdlTipoTramiteCaptura.Items.FindByValue(
FiltroActual.CveTipoTramite.Value.ToString(CultureInfo.InvariantCulture));
if (opcionTramite != null)
{
DdlTipoTramiteCaptura.SelectedValue = opcionTramite.Value;
}
}
EnlazarCaptura();
AbrirCaptura();
}
@@ -357,6 +378,7 @@ namespace SIG.Web.UserControl
int cveCliente;
int cveEtapa;
int cveTipoTramite;
if (!int.TryParse(DdlClienteCaptura.SelectedValue, out cveCliente) ||
cveCliente <= 0)
@@ -371,6 +393,12 @@ namespace SIG.Web.UserControl
"Seleccione el fraccionamiento y etapa del convenio.");
}
if (!int.TryParse(DdlTipoTramiteCaptura.SelectedValue, out cveTipoTramite) ||
cveTipoTramite <= 0)
{
throw new FormatException("Seleccione el tipo de trámite del convenio.");
}
string numeroConvenio = (TxtNumeroConvenio.Text ?? string.Empty).Trim();
if (string.IsNullOrWhiteSpace(numeroConvenio))
@@ -428,6 +456,7 @@ namespace SIG.Web.UserControl
{
CveCliente = cveCliente,
CveFraccionamientoEtapa = cveEtapa,
CveTipoTramite = cveTipoTramite,
NumeroConvenio = numeroConvenio,
NumeroOficio = TextoNulo(TxtNumeroOficio.Text),
// Estos cuatro valores quedan reservados para el cálculo posterior.
@@ -575,17 +604,19 @@ namespace SIG.Web.UserControl
"<div class=\"col-md-4\"><strong>Oficio:</strong> {3}</div>" +
"</div>" +
"<div class=\"row\">" +
"<div class=\"col-md-4\"><strong>Lotes convenio:</strong> {4}</div>" +
"<div class=\"col-md-4\"><strong>Importe:</strong> {5:N2}</div>" +
"<div class=\"col-md-4\"><strong>Saldo pendiente:</strong> {6:N2}</div>" +
"</div>",
"<div class=\"col-md-4 text-right\"><strong>Lotes convenio:</strong> {4}</div>" +
"<div class=\"col-md-4 text-right\"><strong>Importe:</strong> {5:N2}</div>" +
"<div class=\"col-md-4 text-right\"><strong>Saldo pendiente:</strong> {6:N2}</div>" +
"</div>" +
"<div><strong>Tipo de trámite:</strong> {7}</div>",
HttpUtility.HtmlEncode(encabezado.Cliente),
HttpUtility.HtmlEncode(encabezado.Fraccionamiento),
HttpUtility.HtmlEncode(encabezado.Etapa),
HttpUtility.HtmlEncode(encabezado.NumeroOficio),
encabezado.LotesConvenio,
encabezado.ImporteConvenio,
encabezado.SaldoPendiente);
encabezado.SaldoPendiente,
HttpUtility.HtmlEncode(encabezado.TipoTramite));
GvDetalle.DataSource = ConstruirDetalle(resultado.Data);
GvDetalle.DataBind();

View File

@@ -1,4 +1,4 @@
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="DetalleEtapa.ascx.cs"
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="DetalleEtapa.ascx.cs"
Inherits="SIG.Web.UserControl.DetalleEtapa" %>
<%@ Register TagPrefix="etapa" TagName="DocumentosEtapa" Src="~/UserControl/DocumentosEtapa.ascx" %>
<%@ Register TagPrefix="etapa" TagName="SupervisionesEtapa" Src="~/UserControl/SupervisionesEtapa.ascx" %>
@@ -34,7 +34,7 @@
</div>
<div class="form-group col-md-4">
<asp:Label runat="server" AssociatedControlID="TxtHectareas" Text="Hectáreas" />
<asp:TextBox ID="TxtHectareas" runat="server" MaxLength="15" CssClass="form-control" />
<asp:TextBox ID="TxtHectareas" runat="server" MaxLength="15" CssClass="form-control text-right" />
</div>
</div>
<div class="form-group">

View File

@@ -1,4 +1,4 @@
<%@ Control Language="C#" AutoEventWireup="false" CodeFile="DocumentosEtapa.ascx.cs"
<%@ Control Language="C#" AutoEventWireup="false" CodeFile="DocumentosEtapa.ascx.cs"
Inherits="SIG.Web.UserControl.DocumentosEtapa" %>
<asp:UpdatePanel ID="Listado" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="true">
@@ -275,11 +275,6 @@
<asp:DropDownList ID="EtapaSolicitud" runat="server" CssClass="form-control select2me"
AutoPostBack="true" OnSelectedIndexChanged="CambiarEtapaSolicitud" />
</div>
<div class="form-group">
<asp:Label runat="server" AssociatedControlID="TramiteSolicitud" Text="Trámite asociado (opcional)" />
<asp:DropDownList ID="TramiteSolicitud" runat="server" CssClass="form-control select2me"
AutoPostBack="true" OnSelectedIndexChanged="CambiarTramiteSolicitud" />
</div>
<div class="form-group">
<asp:Label runat="server" AssociatedControlID="TipoDocumentoSolicitud" Text="Tipo de documento" />
<asp:DropDownList ID="TipoDocumentoSolicitud" runat="server" CssClass="form-control select2me" />

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@@ -76,6 +76,11 @@ namespace SIG.Web.UserControl
protected override void OnInit(EventArgs argumentos)
{
base.OnInit(argumentos);
Documentos.DataKeyNames = new[]
{
"CveFraccionamientoEtapa",
"CveTipoDocumento", "CveDocumentoSolicitud", "EsGrupo"
};
ScriptManager administrador = ScriptManager.GetCurrent(Page);
if (administrador != null)
{
@@ -299,6 +304,11 @@ namespace SIG.Web.UserControl
get { return Documento == null ? 0 : Documento.CveFraccionamientoEtapa; }
}
public int CveTipoTramite
{
get { return Documento == null ? 0 : Documento.CveTipoTramite; }
}
public int CveTipoDocumento
{
get { return Documento == null ? 0 : Documento.CveTipoDocumento; }
@@ -815,6 +825,10 @@ namespace SIG.Web.UserControl
protected void AbrirCargaMasiva(object origen, EventArgs argumentos)
{
List<OpcionCargaMasivaDocumento> opciones = ObtenerOpcionesCargaMasiva();
if (opciones == null)
{
return;
}
if (opciones.Count == 0)
{
Avisar("No hay documentos disponibles para cargar en el contexto actual.");
@@ -863,6 +877,10 @@ namespace SIG.Web.UserControl
}
List<OpcionCargaMasivaDocumento> opciones = ObtenerOpcionesCargaMasiva();
if (opciones == null)
{
return;
}
var destinosUtilizados = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
var errores = new List<string>();
int seleccionados = 0;
@@ -892,7 +910,6 @@ namespace SIG.Web.UserControl
OpcionCargaMasivaDocumento opcion = opciones.FirstOrDefault(item =>
item.CveFraccionamientoEtapa == dato.CveFraccionamientoEtapa &&
item.CveSolicitud == dato.CveSolicitud &&
item.CveTipoDocumento == dato.CveTipoDocumento);
if (opcion == null)
@@ -902,7 +919,6 @@ namespace SIG.Web.UserControl
}
string destino = opcion.CveFraccionamientoEtapa.ToString(CultureInfo.InvariantCulture) + "|" +
opcion.CveSolicitud.ToString(CultureInfo.InvariantCulture) + "|" +
opcion.CveTipoDocumento.ToString(CultureInfo.InvariantCulture);
if (!destinosUtilizados.Add(destino))
@@ -955,7 +971,7 @@ namespace SIG.Web.UserControl
var resultado = AppServices.TramiteDocumentoService.Upload(
CveFraccionamientoActual,
opcion.CveSolicitud,
0,
opcion.CveTipoDocumento,
archivo.FileName,
archivo.ContentType,
@@ -1019,18 +1035,36 @@ namespace SIG.Web.UserControl
private List<OpcionCargaMasivaDocumento> ObtenerOpcionesCargaMasiva()
{
List<TramiteDocumentoSolicitudModel> documentos = DocumentosActuales
if (Usuario == null)
{
Avisar("La sesión del usuario no está disponible.");
return null;
}
var resultado = AppServices.TramiteDocumentoService.ListarRequisitos(
CveFraccionamientoActual,
CveEtapaActual,
CveTipoTramiteFiltro,
Usuario.CveUsuario,
Usuario.NombreDominio);
if (!resultado.Success)
{
Avisar(resultado.UserMessage);
return null;
}
// La carga anticipada incluye opciones que todavía no son pendientes.
List<TramiteDocumentoSolicitudModel> documentos =
(resultado.Data ?? new List<TramiteDocumentoSolicitudModel>())
.Where(documento => documento.PuedeActualizarArchivo && !documento.EsGis)
.GroupBy(documento => new
{
documento.CveFraccionamientoEtapa,
documento.CveSolicitud,
documento.CveTipoDocumento
})
.Select(grupo => grupo.First())
.OrderBy(documento => documento.TipoDocumento)
.ThenBy(documento => documento.Etapa)
.ThenBy(documento => documento.TipoTramite)
.ToList();
Dictionary<int, int> repeticionesTipo = documentos
@@ -1040,18 +1074,13 @@ namespace SIG.Web.UserControl
return documentos.Select(documento => new OpcionCargaMasivaDocumento
{
CveFraccionamientoEtapa = documento.CveFraccionamientoEtapa,
CveSolicitud = documento.CveSolicitud,
CveTipoDocumento = documento.CveTipoDocumento,
TipoDocumento = documento.TipoDocumento,
TieneVigencia = documento.TieneVigencia,
Etapa = documento.Etapa,
TipoTramite = documento.TipoTramite,
Etiqueta = repeticionesTipo[documento.CveTipoDocumento] > 1
? documento.TipoDocumento + " — " +
(documento.Etapa ?? "Etapa") +
(string.IsNullOrWhiteSpace(documento.TipoTramite)
? string.Empty
: " / " + documento.TipoTramite)
(documento.Etapa ?? "Etapa")
: documento.TipoDocumento
}).ToList();
}
@@ -1059,12 +1088,10 @@ namespace SIG.Web.UserControl
private sealed class OpcionCargaMasivaDocumento
{
public int CveFraccionamientoEtapa { get; set; }
public int CveSolicitud { get; set; }
public int CveTipoDocumento { get; set; }
public string TipoDocumento { get; set; }
public string Etiqueta { get; set; }
public string Etapa { get; set; }
public string TipoTramite { get; set; }
public bool TieneVigencia { get; set; }
}
@@ -1080,7 +1107,6 @@ namespace SIG.Web.UserControl
public bool? Incluir { get; set; }
public int CveFraccionamientoEtapa { get; set; }
public int CveSolicitud { get; set; }
public int CveTipoDocumento { get; set; }
public string FechaDocumento { get; set; }
public string FechaVencimiento { get; set; }
@@ -1107,55 +1133,25 @@ namespace SIG.Web.UserControl
EtapaSolicitud.DataBind();
ConfigurarFormulario("Solicitar", "Solicitar documento adicional");
TieneVigenciaSolicitud.Checked = false;
CargarTramitesSolicitud();
CargarTiposDocumento();
MostrarFormulario();
}
protected void CambiarEtapaSolicitud(object origen, EventArgs argumentos)
{
CargarTramitesSolicitud();
}
private void CargarTramitesSolicitud()
{
int etapa;
if (!int.TryParse(EtapaSolicitud.SelectedValue, out etapa))
{
return;
}
var tramites = AppServices.TramiteSolicitudService.ListForDevelopment(
CveFraccionamientoActual, etapa, null, null, Usuario.CveUsuario, Usuario.NombreDominio);
TramiteSolicitud.Items.Clear();
TramiteSolicitud.Items.Add(new ListItem("Sin trámite asociado", "0"));
if (!tramites.Success)
{
Avisar(tramites.UserMessage);
return;
}
foreach (var tramite in tramites.Data)
{
TramiteSolicitud.Items.Add(new ListItem(tramite.Folio + " / " + tramite.TipoTramite,
tramite.CveSolicitud.ToString(CultureInfo.InvariantCulture)));
}
CargarTiposDocumento();
}
protected void CambiarTramiteSolicitud(object origen, EventArgs argumentos)
{
CargarTiposDocumento();
}
private void CargarTiposDocumento()
{
TipoDocumentoSolicitud.Items.Clear();
int etapa;
int tramite;
if (!int.TryParse(EtapaSolicitud.SelectedValue, out etapa) ||
!int.TryParse(TramiteSolicitud.SelectedValue, out tramite))
if (!int.TryParse(EtapaSolicitud.SelectedValue, out etapa))
{
return;
}
var tipos = AppServices.TramiteDocumentoService.ListarConfiguracionSolicitud(
CveFraccionamientoActual, tramite, Usuario.CveUsuario, Usuario.NombreDominio, etapa);
CveFraccionamientoActual, 0, Usuario.CveUsuario, Usuario.NombreDominio, etapa);
if (!tipos.Success)
{
Avisar(tipos.UserMessage);
@@ -1170,10 +1166,8 @@ namespace SIG.Web.UserControl
protected void GuardarRequerimiento(object origen, EventArgs argumentos)
{
int etapa;
int tramite;
int tipo;
if (!int.TryParse(EtapaSolicitud.SelectedValue, out etapa) ||
!int.TryParse(TramiteSolicitud.SelectedValue, out tramite) ||
!int.TryParse(TipoDocumentoSolicitud.SelectedValue, out tipo))
{
Avisar("Seleccione etapa y tipo de documento.");
@@ -1183,7 +1177,6 @@ namespace SIG.Web.UserControl
{
CveFraccionamiento = CveFraccionamientoActual,
CveFraccionamientoEtapa = etapa,
CveSolicitud = tramite,
CveTipoDocumento = tipo,
EsRequerido = true,
EsCliente = true,
@@ -1211,7 +1204,7 @@ namespace SIG.Web.UserControl
var configuraciones = AppServices.TramiteDocumentoService.ListarConfiguracionSolicitud(
CveFraccionamientoActual,
DocumentoSeleccionado.CveSolicitud,
0,
Usuario.CveUsuario,
Usuario.NombreDominio,
DocumentoSeleccionado.CveFraccionamientoEtapa);

View File

@@ -23,6 +23,27 @@ namespace SIG.Web.UserControl
#region Propiedades
private List<TramiteDocumentoSolicitudModel> DocumentosDisponibles
{
get
{
return ViewState["DocumentosDisponibles"] as List<TramiteDocumentoSolicitudModel>
?? new List<TramiteDocumentoSolicitudModel>();
}
set { ViewState["DocumentosDisponibles"] = value; }
}
private TramiteDocumentoSolicitudModel ObtenerDocumentoSeleccionado()
{
int cveTipoDocumento;
if (!int.TryParse(TipoDocumento.SelectedValue, out cveTipoDocumento))
{
return null;
}
return DocumentosDisponibles.FirstOrDefault(
documento => documento.CveTipoDocumento == cveTipoDocumento);
}
private int CveSolicitudActual
{
get { return (int?)ViewState["CveSolicitudActual"] ?? 0; }
@@ -85,7 +106,8 @@ namespace SIG.Web.UserControl
private void EnlazarDocumentos(List<TramiteDocumentoSolicitudModel> documentos)
{
Documentos.DataSource = documentos;
DocumentosDisponibles = documentos ?? new List<TramiteDocumentoSolicitudModel>();
Documentos.DataSource = DocumentosDisponibles;
Documentos.DataBind();
}
@@ -166,6 +188,7 @@ namespace SIG.Web.UserControl
Avisar("No hay documentos disponibles para cargar con su usuario.");
return;
}
DocumentosDisponibles = disponibles;
TipoDocumento.DataSource = disponibles;
TipoDocumento.DataTextField = "TipoDocumento";
TipoDocumento.DataValueField = "CveTipoDocumento";
@@ -183,11 +206,18 @@ namespace SIG.Web.UserControl
private bool CargarContextoArchivo()
{
TramiteDocumentoSolicitudModel documento = ObtenerDocumentoSeleccionado();
if (documento == null)
{
Avisar("Seleccione un documento disponible.");
return false;
}
DbResult<TramiteDocumentoUploadContextModel> resultado =
AppServices.TramiteDocumentoService.GetUploadContext(
CveFraccionamientoActual, CveSolicitudActual,
Convert.ToInt32(TipoDocumento.SelectedValue, CultureInfo.InvariantCulture),
Usuario.CveUsuario, Usuario.NombreDominio);
CveFraccionamientoActual, 0,
documento.CveTipoDocumento,
Usuario.CveUsuario, Usuario.NombreDominio,
documento.CveFraccionamientoEtapa);
if (!resultado.Success || resultado.Data == null)
{
Avisar(resultado.UserMessage);
@@ -233,14 +263,21 @@ namespace SIG.Web.UserControl
return;
}
TramiteDocumentoSolicitudModel documento = ObtenerDocumentoSeleccionado();
if (documento == null)
{
MostrarDocumento();
Avisar("Seleccione un documento disponible.");
return;
}
DbResult<TramiteDocumentoSaveResultModel> resultado =
AppServices.TramiteDocumentoService.Upload(
CveFraccionamientoActual, CveSolicitudActual,
Convert.ToInt32(TipoDocumento.SelectedValue, CultureInfo.InvariantCulture),
CveFraccionamientoActual, 0, documento.CveTipoDocumento,
archivo.FileName, archivo.ContentType,
archivo.InputStream, archivo.ContentLength,
ComentarioDocumento.Text, Usuario.CveUsuario, Usuario.NombreDominio,
fecha, vencimiento);
fecha, vencimiento, documento.CveFraccionamientoEtapa);
if (!resultado.Success)
{
MostrarDocumento();
@@ -253,7 +290,7 @@ namespace SIG.Web.UserControl
RefrescarRequisitos();
SolicitarVista();
NotificarCambio();
Avisar("Documento de etapa guardado; disponible para los trámites que lo requieren.", TipoMensaje.ToastExito);
Avisar("Documento guardado para la etapa y el tipo de trámite seleccionados.", TipoMensaje.ToastExito);
}
private static bool LeerFecha(string texto, out DateTime? fecha)

View File

@@ -1,11 +1,13 @@
<%@ Control Language="C#" AutoEventWireup="true"
<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="LotesEtapa.ascx.cs"
Inherits="SIG.Web.UserControl.LotesEtapa" %>
<%@ Register Src="~/UserControl/VisorGis.ascx" TagPrefix="sig" TagName="VisorGis" %>
<asp:UpdatePanel ID="UpLotes" runat="server"
UpdateMode="Conditional" ChildrenAsTriggers="true">
<ContentTemplate>
<div class="sig-lotes-etapa">
<div id="RaizLotes" runat="server" class="sig-lotes-etapa">
<asp:Panel ID="PnlTiposVivienda" runat="server" CssClass="sig-lotes-bloque">
<div class="sig-lotes-titulo">
@@ -32,8 +34,10 @@
EmptyDataText="No hay tipos de vivienda capturados.">
<Columns>
<asp:BoundField DataField="TipoVivienda" HeaderText="Tipo de vivienda" />
<asp:BoundField DataField="Cantidad" HeaderText="Cantidad capturada" />
<asp:BoundField DataField="LotesVinculados" HeaderText="Lotes registrados" />
<asp:BoundField DataField="Cantidad" HeaderText="Cantidad capturada"
ItemStyle-HorizontalAlign="Right" />
<asp:BoundField DataField="LotesVinculados" HeaderText="Lotes registrados"
ItemStyle-HorizontalAlign="Right" />
<asp:TemplateField HeaderText="Acciones"
HeaderStyle-CssClass="sig-lotes-col-acciones"
ItemStyle-CssClass="sig-lotes-col-acciones">
@@ -89,6 +93,10 @@
</div>
</div>
<asp:Panel ID="ContenedorMapaLotes" runat="server" CssClass="sig-lotes-mapa-origen">
<sig:VisorGis ID="UcVisorGis" runat="server" />
</asp:Panel>
<div class="table-responsive">
<asp:GridView ID="GvLotes" runat="server"
AutoGenerateColumns="false"
@@ -96,17 +104,22 @@
CssClass="table table-striped table-hover Widthall filtrosig scrollsig"
DataKeyNames="CveFraccionamientoLote"
OnRowCommand="Lotes_RowCommand"
OnRowDataBound="Lotes_RowDataBound"
EmptyDataText="No hay lotes registrados en esta etapa.">
<Columns>
<asp:BoundField DataField="Nombre" HeaderText="Lote" />
<asp:BoundField DataField="TipoVivienda" HeaderText="Tipo de vivienda" />
<asp:BoundField DataField="Calle" HeaderText="Calle" />
<asp:BoundField DataField="Catastro" HeaderText="Catastro" />
<asp:BoundField DataField="MetrosCuadrados" HeaderText="m²" DataFormatString="{0:N2}" />
<asp:BoundField DataField="Latitud" HeaderText="Latitud" DataFormatString="{0:0.0000000}" />
<asp:BoundField DataField="Longitud" HeaderText="Longitud" DataFormatString="{0:0.0000000}" />
<asp:BoundField DataField="MetrosCuadrados" HeaderText="m²" DataFormatString="{0:N2}"
ItemStyle-HorizontalAlign="Right" />
<asp:BoundField DataField="Latitud" HeaderText="Latitud" DataFormatString="{0:0.0000000}"
ItemStyle-HorizontalAlign="Right" />
<asp:BoundField DataField="Longitud" HeaderText="Longitud" DataFormatString="{0:0.0000000}"
ItemStyle-HorizontalAlign="Right" />
<asp:TemplateField HeaderText="Agua potable">
<asp:TemplateField HeaderText="Agua potable"
ItemStyle-HorizontalAlign="Right">
<ItemTemplate>
<%# Eval("AvanceAguaPotable", "{0:0.##}") %>%
<span class='<%# Convert.ToBoolean(Eval("AguaPotableAutorizada")) ? "label label-success" : "label label-default" %>'>
@@ -115,7 +128,8 @@
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Drenaje">
<asp:TemplateField HeaderText="Drenaje"
ItemStyle-HorizontalAlign="Right">
<ItemTemplate>
<%# Eval("AvanceDrenaje", "{0:0.##}") %>%
<span class='<%# Convert.ToBoolean(Eval("DrenajeAutorizado")) ? "label label-success" : "label label-default" %>'>
@@ -136,14 +150,20 @@
HeaderStyle-CssClass="sig-lotes-col-menu"
ItemStyle-CssClass="sig-lotes-col-menu">
<ItemTemplate>
<div class="btn-group">
<div class="sig-menu-acciones">
<button type="button"
class="btn btn-default btn-sm dropdown-toggle sig-lotes-menu-boton"
data-toggle="dropdown"
class="btn btn-default btn-sm sig-menu-acciones-boton sig-lotes-menu-boton"
aria-haspopup="true" aria-expanded="false"
title="Acciones">
<i class="fa fa-ellipsis-v"></i>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<ul class="dropdown-menu sig-menu-acciones-lista">
<li>
<button type="button" class="sig-lotes-ver-mapa"
data-lote="<%# Eval("CveFraccionamientoLote") %>">
<i class="fa fa-map-marker"></i> Ver en mapa
</button>
</li>
<li runat="server" visible='<%# PuedeEditar(Container.DataItem) %>'>
<asp:LinkButton runat="server"
CommandName="Editar"
@@ -238,7 +258,7 @@
<div class="form-group">
<label>Cantidad</label>
<asp:TextBox ID="TxtCantidadTipoVivienda" runat="server"
CssClass="form-control" MaxLength="10" />
CssClass="form-control text-right" MaxLength="10" />
</div>
</div>
<div class="modal-footer">
@@ -264,7 +284,7 @@
<div class="form-group col-md-3">
<label>Cantidad de lotes</label>
<asp:TextBox ID="TxtCantidadLotes" runat="server"
CssClass="form-control" Text="1" />
CssClass="form-control text-right" Text="1" />
</div>
<div class="form-group col-md-4">
<label>Nombre base</label>
@@ -349,7 +369,7 @@
</div>
<div class="form-group col-md-3">
<label>Metros cuadrados</label>
<asp:TextBox ID="TxtLoteM2" runat="server" CssClass="form-control" />
<asp:TextBox ID="TxtLoteM2" runat="server" CssClass="form-control text-right" />
</div>
<div class="form-group col-md-4">
<label>Duplicador</label>
@@ -358,11 +378,11 @@
</div>
<div class="form-group col-md-4">
<label>Latitud</label>
<asp:TextBox ID="TxtLoteLatitud" runat="server" CssClass="form-control" />
<asp:TextBox ID="TxtLoteLatitud" runat="server" CssClass="form-control text-right" />
</div>
<div class="form-group col-md-4">
<label>Longitud</label>
<asp:TextBox ID="TxtLoteLongitud" runat="server" CssClass="form-control" />
<asp:TextBox ID="TxtLoteLongitud" runat="server" CssClass="form-control text-right" />
</div>
</div>
</div>
@@ -386,11 +406,11 @@
<div class="modal-body">
<div class="form-group">
<label>Avance agua potable (%)</label>
<asp:TextBox ID="TxtAvanceAgua" runat="server" CssClass="form-control" />
<asp:TextBox ID="TxtAvanceAgua" runat="server" CssClass="form-control text-right" />
</div>
<div class="form-group">
<label>Avance drenaje (%)</label>
<asp:TextBox ID="TxtAvanceDrenaje" runat="server" CssClass="form-control" />
<asp:TextBox ID="TxtAvanceDrenaje" runat="server" CssClass="form-control text-right" />
</div>
</div>
<div class="modal-footer">
@@ -412,7 +432,7 @@
</div>
<div class="modal-body">
<p class="help-block">
Se registra también en Documentos de la etapa. Si está aprobado no debe poder reemplazarse.
Acepta .gis/.geojson o ZIP Shapefile. Se procesa y registra también en Documentos de la etapa. Si está aprobado no puede reemplazarse.
</p>
<div class="form-group">
<input id="ArchivoGis"
@@ -420,11 +440,6 @@
type="hidden"
class="ADSdropzoneLocal" />
</div>
<div class="form-group">
<label>Nota</label>
<asp:TextBox ID="TxtNotaGis" runat="server"
TextMode="MultiLine" Rows="3" CssClass="form-control" />
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn default" data-dismiss="modal">Cancelar</button>
@@ -439,3 +454,61 @@
</div>
</ContentTemplate>
</asp:UpdatePanel>
<asp:Panel ID="PanelDetalleLote" runat="server"
CssClass="sig_panel_lateral sig-lotes-panel" aria-hidden="true" role="dialog" aria-label="Detalle del lote">
<div class="sig_panel_contenido">
<div class="sig_panel_cabecera">
<h4 data-lotes-titulo>Detalle del lote</h4>
<button type="button" class="btn default" data-sig-panel-cerrar>Cerrar</button>
</div>
<div class="sig_panel_cuerpo">
<div data-lotes-mapa-panel></div>
<div class="sig-lotes-detalle-acciones">
<div data-lotes-menu-panel></div>
<button type="button" class="btn default" data-lotes-desvincular>
<i class="fa fa-chain-broken"></i> Desvincular lote
</button>
</div>
<p data-lotes-estado role="status" aria-live="polite"></p>
<asp:UpdatePanel ID="UpDetalleLote" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="true">
<ContentTemplate>
<asp:HiddenField ID="LoteSeleccionado" runat="server" />
<asp:LinkButton ID="BtnConsultarDetalleLote" runat="server" CssClass="hidden"
CausesValidation="false" OnClick="ConsultarDetalleLote_Click">Consultar lote</asp:LinkButton>
<asp:Panel ID="ContenidoDetalleLote" runat="server" Visible="false">
<ajax:TabContainer ID="PestanasDetalleLote" runat="server" ActiveTabIndex="0">
<Tabs>
<ajax:TabPanel ID="PestanaGeneralLote" runat="server" HeaderText="Información general">
<ContentTemplate>
<asp:Literal ID="InformacionLote" runat="server" />
<%-- BitacoraGrid administra sus paneles de paginación; el contenedor se actualiza al seleccionar otro lote. --%>
<sig:BitacoraGrid ID="BitacoraLote" runat="server" Titulo="Bitácora del lote" />
</ContentTemplate>
</ajax:TabPanel>
<ajax:TabPanel ID="PestanaSupervisionesLote" runat="server" HeaderText="Supervisiones">
<ContentTemplate>
<asp:Label ID="MensajeSupervisionesLote" runat="server" />
<asp:GridView ID="GvSupervisionesLote" runat="server" AutoGenerateColumns="false"
GridLines="None" CssClass="table table-striped table-hover Widthall"
EmptyDataText="No hay supervisiones registradas para este lote.">
<Columns>
<asp:BoundField DataField="FechaVisita" HeaderText="Fecha" DataFormatString="{0:dd/MM/yyyy}" />
<asp:BoundField DataField="Supervisor" HeaderText="Supervisor" />
<asp:CheckBoxField DataField="SeRealizo" HeaderText="Realizada" />
<asp:TemplateField HeaderText="Aprobación">
<ItemTemplate><%#: Eval("Aprobado") == null ? "Pendiente" : (Convert.ToBoolean(Eval("Aprobado")) ? "Aprobado" : "No aprobado") %></ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Observaciones" HeaderText="Observaciones" />
</Columns>
</asp:GridView>
</ContentTemplate>
</ajax:TabPanel>
</Tabs>
</ajax:TabContainer>
</asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</div>
</asp:Panel>

View File

@@ -1,8 +1,9 @@
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
@@ -10,6 +11,7 @@ using ClosedXML.Excel;
using SIG.Web.AppCode.Configuration;
using SIG.Web.AppCode.Infrastructure.WebForms;
using SIG.Web.AppCode.Models.Common;
using SIG.Web.AppCode.Models.Bitacora;
using SIG.Web.AppCode.Models.Fraccionamientos;
using SIG.Web.AppCode.Session;
@@ -17,8 +19,6 @@ namespace SIG.Web.UserControl
{
public partial class LotesEtapa : System.Web.UI.UserControl
{
private const int CveTipoDocumentoGis = 1016;
private UserSessionModel Usuario
{
get { return AppServices.UserContext.GetCurrentUser(); }
@@ -81,10 +81,10 @@ namespace SIG.Web.UserControl
CargaArchivoWebHelper.Configurar(
ArchivoGis,
".gis",
".gis,.geojson,.zip",
30,
1,
"Arrastra aquí el archivo .gis o haz clic para seleccionarlo.");
"Arrastra aquí un GIS (.gis/.geojson) o un ZIP Shapefile y haz clic para seleccionarlo.");
}
@@ -139,6 +139,11 @@ namespace SIG.Web.UserControl
public void Cargar(int cveFraccionamiento, int cveEtapa)
{
if (CveEtapaActual != cveEtapa)
{
ViewState["CveLoteDetalleActual"] = 0;
ContenidoDetalleLote.Visible = false;
}
CveFraccionamientoActual = cveFraccionamiento;
CveEtapaActual = cveEtapa;
Refrescar();
@@ -181,7 +186,128 @@ namespace SIG.Web.UserControl
GvLotes.DataSource = listadoLotes;
GvLotes.DataBind();
UcVisorGis.Cargar(CveEtapaActual);
UpLotes.Update();
int detalle = (int?)ViewState["CveLoteDetalleActual"] ?? 0;
if (detalle > 0)
{
ConsultarDetalleLote(detalle);
}
}
protected override void OnPreRender(EventArgs e)
{
RaizLotes.Attributes["data-lotes-propietario"] = ClientID;
ContenedorMapaLotes.Attributes["data-lotes-propietario"] = ClientID;
ContenedorMapaLotes.Attributes["data-lotes-etapa"] = CveEtapaActual.ToString();
PanelDetalleLote.Attributes["data-lotes-propietario"] = ClientID;
PanelDetalleLote.Attributes["data-lotes-campo"] = LoteSeleccionado.ClientID;
PanelDetalleLote.Attributes["data-lotes-consultar"] = BtnConsultarDetalleLote.ClientID;
ContenidoDetalleLote.Attributes["data-lotes-detalle"] =
Convert.ToString(ViewState["CveLoteDetalleActual"]);
base.OnPreRender(e);
}
protected void Lotes_RowDataBound(object sender, GridViewRowEventArgs e)
{
var lote = e.Row.DataItem as ModeloLoteFraccionamiento;
if (lote == null)
{
return;
}
e.Row.Attributes["data-lotes-fila"] = lote.CveFraccionamientoLote.ToString();
}
protected void ConsultarDetalleLote_Click(object sender, EventArgs e)
{
int lote;
if (int.TryParse(LoteSeleccionado.Value, out lote))
{
ConsultarDetalleLote(lote);
}
}
private void ConsultarDetalleLote(int claveLote)
{
ContenidoDetalleLote.Visible = false;
if (Usuario == null || CveEtapaActual <= 0)
{
return;
}
var contexto = AppServices.ServicioGisFraccionamiento.Obtener(
CveEtapaActual, Usuario.CveUsuario, Usuario.NombreDominio);
if (!contexto.Success || contexto.Data == null ||
!contexto.Data.Lotes.Any(lote => lote.CveFraccionamientoLote == claveLote && lote.EsActivo))
{
ViewState["CveLoteDetalleActual"] = 0;
UpDetalleLote.Update();
Alertar("El lote ya no está disponible en esta etapa.");
return;
}
var resultado = AppServices.ServicioFraccionamiento.ObtenerLote(
CveFraccionamientoActual, claveLote, Usuario.CveUsuario, Usuario.NombreDominio);
if (!resultado.Success || resultado.Data == null ||
resultado.Data.CveFraccionamientoEtapa != CveEtapaActual)
{
ViewState["CveLoteDetalleActual"] = 0;
UpDetalleLote.Update();
Alertar(resultado.UserMessage);
return;
}
if (((int?)ViewState["CveLoteDetalleActual"] ?? 0) != claveLote)
{
PestanasDetalleLote.ActiveTabIndex = 0;
}
ViewState["CveLoteDetalleActual"] = claveLote;
var actual = resultado.Data;
var ficha = new StringBuilder("<table class='table sig-lotes-ficha'><tbody>");
AgregarDatoLote(ficha, "Lote", actual.Nombre, false);
AgregarDatoLote(ficha, "Etapa", actual.Etapa, false);
AgregarDatoLote(ficha, "Tipo de vivienda", actual.TipoVivienda, false);
AgregarDatoLote(ficha, "Tipo", actual.Tipo, false);
AgregarDatoLote(ficha, "Calle", actual.Calle, false);
AgregarDatoLote(ficha, "Catastro", actual.Catastro, false);
AgregarDatoLote(ficha, "Duplicador", actual.Duplicador, false);
AgregarDatoLote(ficha, "m²", actual.MetrosCuadrados.HasValue ? actual.MetrosCuadrados.Value.ToString("N2") : "", true);
AgregarDatoLote(ficha, "Latitud", Formato(actual.Latitud), true);
AgregarDatoLote(ficha, "Longitud", Formato(actual.Longitud), true);
AgregarDatoLote(ficha, "Avance agua potable", actual.AvanceAguaPotable.ToString("0.##") + "%", true);
AgregarDatoLote(ficha, "Agua potable", actual.AguaPotableAutorizada ? "Autorizada" : "Pendiente", false);
AgregarDatoLote(ficha, "Avance drenaje", actual.AvanceDrenaje.ToString("0.##") + "%", true);
AgregarDatoLote(ficha, "Drenaje", actual.DrenajeAutorizado ? "Autorizado" : "Pendiente", false);
AgregarDatoLote(ficha, "Estado", TextoEstado(actual), false);
ficha.Append("</tbody></table>");
InformacionLote.Text = ficha.ToString();
ContenidoDetalleLote.Visible = true;
BitacoraLote.ConfigurarConsulta(new List<BitacoraCampoFiltroModel>
{
new BitacoraCampoFiltroModel
{
NombreTablaSQL = "FraccionamientosLotes",
NombreCampoSQL = "CveFraccionamientoLote",
Valor = claveLote.ToString()
}
}, new List<BitacoraRelacionMostrarModel>());
BitacoraLote.Consultar(true);
var historial = AppServices.ServicioVisitas.ListarHistorialLote(
claveLote, Usuario.CveUsuario, Usuario.NombreDominio);
MensajeSupervisionesLote.Text = historial.Success ? "" : HttpUtility.HtmlEncode(historial.UserMessage);
GvSupervisionesLote.DataSource = historial.Success ? historial.Data : null;
GvSupervisionesLote.DataBind();
UpDetalleLote.Update();
}
private static void AgregarDatoLote(StringBuilder ficha, string etiqueta, string valor, bool numerico)
{
ficha.Append("<tr><th scope='row'>").Append(HttpUtility.HtmlEncode(etiqueta));
ficha.Append(numerico ? "</th><td class='text-right'>" : "</th><td>");
ficha.Append(HttpUtility.HtmlEncode(string.IsNullOrWhiteSpace(valor) ? "—" : valor));
ficha.Append("</td></tr>");
}
private static void CargarComboTipos(
@@ -727,8 +853,6 @@ namespace SIG.Web.UserControl
protected void AbrirGis_Click(object sender, EventArgs e)
{
TxtNotaGis.Text = string.Empty;
/*
* Se conserva el mismo control genérico ADSdropzoneLocal.
* La configuración se vuelve a aplicar al abrir el modal
@@ -736,10 +860,10 @@ namespace SIG.Web.UserControl
*/
CargaArchivoWebHelper.Configurar(
ArchivoGis,
".gis",
".gis,.geojson,.zip",
30,
1,
"Arrastra aquí el archivo .gis o haz clic para seleccionarlo.");
"Arrastra aquí un GIS (.gis/.geojson) o un ZIP Shapefile y haz clic para seleccionarlo.");
MostrarModal("ModalGisEtapa");
}
@@ -752,17 +876,20 @@ namespace SIG.Web.UserControl
if (archivoGis == null)
{
MostrarModal("ModalGisEtapa");
Alertar("Seleccione el Archivo GIS de la Etapa.");
Alertar("Seleccione el archivo GIS de la etapa.");
return;
}
if (!string.Equals(
Path.GetExtension(archivoGis.FileName),
".gis",
StringComparison.OrdinalIgnoreCase))
string extension = Path.GetExtension(archivoGis.FileName) ?? string.Empty;
bool extensionValida =
string.Equals(extension, ".gis", StringComparison.OrdinalIgnoreCase) ||
string.Equals(extension, ".geojson", StringComparison.OrdinalIgnoreCase) ||
string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase);
if (!extensionValida)
{
MostrarModal("ModalGisEtapa");
Alertar("El archivo seleccionado debe tener extensión .gis.");
Alertar("El archivo GIS debe ser .gis, .geojson o un ZIP Shapefile.");
return;
}
@@ -774,45 +901,25 @@ namespace SIG.Web.UserControl
return;
}
var ctx = AppServices.TramiteDocumentoService.GetUploadContext(
CveFraccionamientoActual, 0, CveTipoDocumentoGis,
Usuario.CveUsuario, Usuario.NombreDominio, CveEtapaActual);
if (!ctx.Success || ctx.Data == null)
{
MostrarModal("ModalGisEtapa");
Alertar(ctx.UserMessage);
return;
}
if (ctx.Data.CveDocumentoSolicitud > 0 &&
ctx.Data.EsAprobadoAnterior == true)
{
MostrarModal("ModalGisEtapa");
Alertar("El Archivo GIS de la Etapa ya fue aprobado y no puede reemplazarse.");
return;
}
var r = AppServices.TramiteDocumentoService.Upload(
CveFraccionamientoActual, 0, CveTipoDocumentoGis,
var resultado = AppServices.ServicioGisFraccionamiento.Guardar(
CveEtapaActual,
archivoGis.FileName,
archivoGis.ContentType,
archivoGis.InputStream,
archivoGis.ContentLength,
TxtNotaGis.Text,
null,
Usuario.CveUsuario,
Usuario.NombreDominio,
DateTime.Today, null, CveEtapaActual);
Usuario.NombreDominio);
if (!r.Success)
if (!resultado.Success)
{
MostrarModal("ModalGisEtapa");
Alertar(r.UserMessage);
Alertar(resultado.UserMessage);
return;
}
CerrarModal("ModalGisEtapa");
Toast("Archivo GIS guardado y agregado a Documentos.");
Refrescar();
Toast("GIS procesado, guardado y agregado a Documentos.");
}
protected bool PuedeEditar(object data)

View File

@@ -0,0 +1,55 @@
<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="VisorGis.ascx.cs"
Inherits="SIG.Web.UserControl.VisorGis" %>
<asp:Panel ID="PnlVisor" runat="server" CssClass="sig-visor-gis" Visible="false">
<div class="sig-visor-gis__header">
<div>
<h5 class="sig-visor-gis__title"><i class="fa fa-map"></i> GIS de la etapa</h5>
<span class="sig-visor-gis__file" data-gis-file></span>
</div>
</div>
<div class="sig-visor-gis__contenedor">
<div class="sig-visor-gis__map" data-gis-map>
<div class="sig-visor-gis__loading"><i class="fa fa-spinner fa-spin"></i> Cargando GIS...</div>
</div>
<div class="sig-visor-gis__control-capas" data-gis-control-capas>
<button type="button" class="btn btn-default" data-gis-alternar-capas
aria-expanded="true" title="Mostrar u ocultar capas">
<i class="fa fa-bars" aria-hidden="true"></i> Capas
</button>
<div class="sig-visor-gis__panel-capas" data-gis-panel-capas>
<strong>Capas del archivo</strong>
<p class="sig-visor-gis__aviso" data-gis-estado-capas role="status"></p>
<div data-gis-layers></div>
</div>
</div>
</div>
<div class="sig-visor-gis__info" data-gis-info style="display:none;"></div>
<div class="modal fade" data-gis-modal-lote tabindex="-1" role="dialog" aria-label="Lote del polígono">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Cerrar">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" data-gis-titulo-lote>Lote del polígono</h4>
</div>
<div class="modal-body">
<p data-gis-clave-lote></p>
<div data-gis-datos-lote></div>
<div data-gis-seleccion-lote>
<label>Lote disponible de la etapa
<select class="form-control" data-gis-selector-lote aria-label="Lote disponible de la etapa"></select>
</label>
</div>
<p data-gis-mensaje-lote role="status"></p>
</div>
<div class="modal-footer">
<button type="button" class="btn default" data-dismiss="modal">Cerrar</button>
<button type="button" class="btn blue" data-gis-vincular-lote>Vincular lote</button>
</div>
</div>
</div>
</div>
</asp:Panel>

View File

@@ -0,0 +1,59 @@
using System;
using System.Configuration;
using System.Globalization;
using System.Web;
using System.Web.UI;
using SIG.Web.AppCode.Configuration;
using SIG.Web.AppCode.Models.Common;
using SIG.Web.AppCode.Models.Fraccionamientos;
using SIG.Web.AppCode.Session;
namespace SIG.Web.UserControl
{
public partial class VisorGis : System.Web.UI.UserControl
{
private UserSessionModel Usuario
{
get { return AppServices.UserContext.GetCurrentUser(); }
}
public void Cargar(int cveFraccionamientoEtapa)
{
PnlVisor.Visible = false;
if (cveFraccionamientoEtapa <= 0 || Usuario == null)
{
return;
}
DbResult<VistaGisFraccionamiento> resultado =
AppServices.ServicioGisFraccionamiento.Obtener(
cveFraccionamientoEtapa,
Usuario.CveUsuario,
Usuario.NombreDominio);
if (!resultado.Success || resultado.Data == null || !resultado.Data.TieneArchivo)
{
return;
}
string key = ConfigurationManager.AppSettings["GoogleMapsApiKey"] ?? string.Empty;
bool mapsEnabled = string.Equals(
ConfigurationManager.AppSettings["GoogleMapsEnabled"],
"true",
StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrWhiteSpace(key) &&
!string.Equals(key, "TU_API_KEY", StringComparison.OrdinalIgnoreCase);
PnlVisor.Visible = true;
PnlVisor.Attributes["data-gis-stage"] =
cveFraccionamientoEtapa.ToString(CultureInfo.InvariantCulture);
PnlVisor.Attributes["data-gis-url"] =
ResolveUrl("~/Pages/Fraccionamientos/FraccionamientoGis.ashx");
PnlVisor.Attributes["data-gis-google-enabled"] = mapsEnabled ? "1" : "0";
PnlVisor.Attributes["data-gis-google-key"] =
HttpUtility.HtmlAttributeEncode(mapsEnabled ? key : string.Empty);
PnlVisor.Attributes["data-gis-file-name"] =
HttpUtility.HtmlAttributeEncode(resultado.Data.NombreArchivo ?? string.Empty);
}
}
}

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="domainConnections" type="System.Configuration.NameValueSectionHandler" />
@@ -31,8 +31,8 @@
<add key="CredencialPacProfactPruebas" value="mvpNUXmQfK8=" />
<add key="SigVisualizadorArchivoLibreOfficePath" value="C:\Program Files\LibreOffice\program\soffice.exe" />
<add key="SigVisualizadorArchivoOfficeTimeoutSeconds" value="90" />
<add key="GoogleMapsApiKey" value="TU_API_KEY" />
<add key="GoogleMapsEnabled" value="false" />
<add key="GoogleMapsApiKey" value="AIzaSyAnQe1o8Odw69LBXOb6G-8Acei0OSTk1Hc" />
<add key="GoogleMapsEnabled" value="true" />
<!-- reCAPTCHA v2: al desactivarlo no se muestra ni se valida. La clave secreta nunca se envía al navegador. -->
<add key="RecaptchaEnabled" value="true" />
<add key="RecaptchaSiteKey" value="6LeVOFQtAAAAAOxZKnBiKFlnMnd90aR1PwJmUGgJ" />
@@ -42,6 +42,7 @@
<compilation debug="true" targetFramework="4.8.1">
<assemblies>
<add assembly="System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<add assembly="System.IO.Compression, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
<add assembly="netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" />
</assemblies>
</compilation>