This commit is contained in:
Jorge Luis caudillo esparza
2026-08-18 11:45:00 -07:00
parent da4af4cb2a
commit 4e80ecca77
25 changed files with 1371 additions and 258 deletions

View File

@@ -494,6 +494,7 @@ Rules:
- Mandatory: read and follow `AGENTS_WEBFORMS_PARTIAL_POSTBACKS.md` for the single master form, ScriptManager ownership, UpdatePanel usage, and partial-postback rules.
- Mandatory: read and follow `AGENTS_JAVASCRIPT_INITIALIZATION.md` for per-element initialization flags, global event guards, and idempotent control setup after partial postbacks.
- Mandatory: read and follow `AGENTS_CATALOG_STRUCTURE.md` for catalog titles, breadcrumbs, actions, filters, indicators, grids, quick-create modals, and detail pages.
- Mandatory: read and follow `AGENTS_DOCUMENT_STORAGE.md` for document folders, client access validation, protected file retrieval, and GIS file naming.
- Keep stored procedure names centralized.
- Repositories must use `CommandType.StoredProcedure` and parameterized inputs/outputs.
- Never concatenate raw user input into SQL.

View File

@@ -0,0 +1,44 @@
# Reglas obligatorias para almacenamiento de documentos
Estas reglas complementan `AGENTS.md` y aplican a todo archivo persistido por la aplicación.
## Estructura física
La raíz de documentos de la aplicación es:
```text
Documentos/
Generales/
Clientes/
{CveCliente}/
```
- `Generales` contiene documentos que no pertenecen a un cliente específico.
- `Clientes` contiene una carpeta por `CveCliente`.
- Antes de guardar un archivo, el servicio debe asegurar la existencia de `Documentos`, `Documentos/Generales`, `Documentos/Clientes` y de la carpeta específica del cliente cuando aplique.
- No asumir que las carpetas ya existen. Usar una operación idempotente como `Directory.CreateDirectory` para crearlas cuando falten.
- La misma regla aplica a futuras subcarpetas de documentos.
## Acceso y seguridad
- Las páginas WebForms y handlers no deben construir rutas físicas ni abrir archivos de cliente por su cuenta.
- Todo guardado y obtención de archivos debe pasar por un servicio dedicado de documentos. Un handler de descarga sólo puede transmitir el archivo previamente autorizado y resuelto por ese servicio.
- Antes de construir o abrir una ruta física, el servicio debe resolver en servidor el cliente propietario a partir de la entidad de negocio y validar el acceso del usuario.
- No confiar para autorización en `CveCliente`, rutas físicas, rutas relativas ni nombres de archivo recibidos desde el navegador.
- El rol `Empresa` se considera desarrollador y sólo puede acceder a documentos de clientes activos que tenga asignados en `Sis_UsuariosClientes`.
- Los demás roles activos, incluidos `Administrador` y `SuperUsuario`, tienen acceso global a documentos, salvo que una regla funcional más restrictiva se defina explícitamente para un módulo.
- Las rutas físicas bajo `Documentos` no deben exponerse como URLs públicas. Las descargas deben pasar por un endpoint autenticado que vuelva a validar el acceso mediante el servicio.
## GIS de etapas de fraccionamiento
- El botón `Agregar GIS` carga un archivo físico con extensión `.gis`; no solicita nombre ni URL de visualización al usuario.
- El archivo se guarda en `Documentos/Clientes/{CveCliente}/`.
- El nombre se genera exclusivamente en servidor con el formato:
```text
gis-{CveFraccionamiento}-{CveFraccionamientoEtapa}.gis
```
- El usuario no puede elegir ni modificar el nombre final del archivo.
- Al reemplazar el GIS de una etapa se conserva el mismo nombre físico y se sobrescribe el archivo correspondiente.
- La obtención del GIS debe usar el servicio de documentos y nunca una URL directa al folder `Documentos`.

View File

@@ -2,6 +2,7 @@ using System;
using System.Configuration;
using SIG.Web.AppCode.Contracts.Bitacora;
using SIG.Web.AppCode.Contracts.Database;
using SIG.Web.AppCode.Contracts.Documentos;
using SIG.Web.AppCode.Contracts.Facturacion;
using SIG.Web.AppCode.Contracts.Fraccionamientos;
using SIG.Web.AppCode.Contracts.General;
@@ -13,6 +14,7 @@ using SIG.Web.AppCode.Notifications.Contracts;
using SIG.Web.AppCode.Notifications.Services;
using SIG.Web.AppCode.Repositories.Bitacora;
using SIG.Web.AppCode.Repositories.Database;
using SIG.Web.AppCode.Repositories.Documentos;
using SIG.Web.AppCode.Repositories.Facturacion;
using SIG.Web.AppCode.Repositories.General;
using SIG.Web.AppCode.Repositories.Menu;
@@ -20,6 +22,7 @@ using SIG.Web.AppCode.Repositories.Fraccionamientos;
using SIG.Web.AppCode.Repositories.Security;
using SIG.Web.AppCode.Repositories.Tramites;
using SIG.Web.AppCode.Services.Bitacora;
using SIG.Web.AppCode.Services.Documentos;
using SIG.Web.AppCode.Services.Facturacion;
using SIG.Web.AppCode.Services.Fraccionamientos;
using SIG.Web.AppCode.Services.Menu;
@@ -41,6 +44,7 @@ namespace SIG.Web.AppCode.Configuration
private static IUserAdministrationRepository UserAdministrationRepository { get; set; }
public static IUserAdministrationService UserAdministrationService { get; private set; }
public static IGeneralCatalogRepository GeneralCatalogRepository { get; private set; }
public static IClienteDocumentoService ClienteDocumentoService { get; private set; }
public static IFraccionamientoService FraccionamientoService { get; private set; }
public static ITramiteCatalogService TramiteCatalogService { get; private set; }
public static ICfdiTimbradoService CfdiTimbradoService { get; private set; }
@@ -83,6 +87,8 @@ namespace SIG.Web.AppCode.Configuration
PasswordHasher,
BitacoraService);
GeneralCatalogRepository = new GeneralCatalogRepository(DbExecutor);
ClienteDocumentoService = new ClienteDocumentoService(
new ClienteDocumentoRepository(DbExecutor));
FraccionamientoService = new FraccionamientoService(
new FraccionamientoRepository(DbExecutor),
BitacoraService);

View File

@@ -0,0 +1,13 @@
using SIG.Web.AppCode.Models.Common;
using SIG.Web.AppCode.Models.Documentos;
namespace SIG.Web.AppCode.Contracts.Documentos
{
public interface IClienteDocumentoRepository
{
DbResult<ClienteDocumentoEtapaContextoModel> GetStageContext(
int stageId,
int executingUser,
string domainName);
}
}

View File

@@ -0,0 +1,28 @@
using System.IO;
using SIG.Web.AppCode.Models.Common;
using SIG.Web.AppCode.Models.Documentos;
namespace SIG.Web.AppCode.Contracts.Documentos
{
public interface IClienteDocumentoService
{
DbResult<ClienteDocumentoEtapaContextoModel> GetStageContext(
int stageId,
int executingUser,
string domainName);
DbResult<ClienteDocumentoArchivoModel> SaveStageGis(
int developmentId,
int stageId,
string originalFileName,
Stream content,
long contentLength,
int executingUser,
string domainName);
DbResult<ClienteDocumentoArchivoModel> GetStageGis(
int stageId,
int executingUser,
string domainName);
}
}

View File

@@ -24,7 +24,7 @@ namespace SIG.Web.AppCode.Contracts.Fraccionamientos
int executingUser,
string domainName);
DbResult<FraccionamientoEtapaGisModel> SaveStageGis(
FraccionamientoEtapaGisModel gis,
int stageId,
int executingUser,
string domainName);
DbResult<List<FraccionamientoEtapaTramiteModel>> ListStageProcedures(int developmentId, int executingUser, string domainName);

View File

@@ -27,7 +27,7 @@ namespace SIG.Web.AppCode.Contracts.Fraccionamientos
int executingUser,
string domainName);
DbResult<FraccionamientoEtapaGisModel> SaveStageGis(
FraccionamientoEtapaGisModel gis,
int stageId,
int executingUser,
string domainName);
DbResult<List<FraccionamientoEtapaTramiteModel>> ListStageProcedures(int developmentId, int executingUser, string domainName);

View File

@@ -0,0 +1,78 @@
using System;
using System.IO;
using System.Web;
using System.Web.SessionState;
using SIG.Web.AppCode.Configuration;
using SIG.Web.AppCode.Models.Common;
using SIG.Web.AppCode.Models.Documentos;
using SIG.Web.AppCode.Session;
namespace SIG.Web.Pages.Fraccionamientos
{
public sealed class FraccionamientoGisHandler : IHttpHandler, IRequiresSessionState
{
public bool IsReusable
{
get
{
return false;
}
}
public void ProcessRequest(HttpContext context)
{
if (!AppServices.UserContext.IsAuthenticated())
{
context.Response.StatusCode = 401;
return;
}
int stageId;
if (!int.TryParse(
context.Request.QueryString["etapa"],
out stageId) ||
stageId <= 0)
{
context.Response.StatusCode = 400;
return;
}
UserSessionModel currentUser =
AppServices.UserContext.GetCurrentUser();
if (currentUser == null)
{
context.Response.StatusCode = 401;
return;
}
DbResult<ClienteDocumentoArchivoModel> result =
AppServices.ClienteDocumentoService.GetStageGis(
stageId,
currentUser.CveUsuario,
currentUser.NombreDominio);
if (!result.Success ||
result.Data == null ||
string.IsNullOrWhiteSpace(result.Data.RutaFisica) ||
!File.Exists(result.Data.RutaFisica))
{
context.Response.StatusCode = 404;
return;
}
ClienteDocumentoArchivoModel file = result.Data;
context.Response.Clear();
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.Cache.SetNoStore();
context.Response.ContentType = file.ContentType;
context.Response.AddHeader(
"Content-Disposition",
"attachment; filename=\"" + file.NombreArchivo + "\"");
context.Response.TransmitFile(file.RutaFisica);
context.ApplicationInstance.CompleteRequest();
}
}
}

View File

@@ -0,0 +1,20 @@
namespace SIG.Web.AppCode.Models.Documentos
{
public sealed class ClienteDocumentoEtapaContextoModel
{
public int CveFraccionamientoEtapa { get; set; }
public int CveFraccionamiento { get; set; }
public int CveCliente { get; set; }
public string Etapa { get; set; }
}
public sealed class ClienteDocumentoArchivoModel
{
public int CveCliente { get; set; }
public int CveFraccionamiento { get; set; }
public int CveFraccionamientoEtapa { get; set; }
public string NombreArchivo { get; set; }
public string RutaFisica { get; set; }
public string ContentType { get; set; }
}
}

View File

@@ -0,0 +1,52 @@
using System.Data;
using SIG.Web.AppCode.Contracts.Database;
using SIG.Web.AppCode.Contracts.Documentos;
using SIG.Web.AppCode.Models.Common;
using SIG.Web.AppCode.Models.Documentos;
using SIG.Web.AppCode.Repositories.Database;
using SIG.Web.AppCode.Utilities;
namespace SIG.Web.AppCode.Repositories.Documentos
{
public sealed class ClienteDocumentoRepository : IClienteDocumentoRepository
{
private readonly IDbExecutor _db;
public ClienteDocumentoRepository(IDbExecutor db)
{
_db = db;
}
public DbResult<ClienteDocumentoEtapaContextoModel> GetStageContext(
int stageId,
int executingUser,
string domainName)
{
return _db.Execute(domainName, connection =>
{
using (IDbCommand command = connection.CreateCommand())
{
StoredProcedureCommand.Configure(
command,
"dbo.PA_Fraccionamientos_EtapaDocumentoGet",
executingUser);
StoredProcedureCommand.AddInput(
command,
"@CveFraccionamientoEtapa",
stageId,
DbType.Int32);
ClienteDocumentoEtapaContextoModel value;
using (IDataReader reader = command.ExecuteReader())
{
value = reader.ToObject<ClienteDocumentoEtapaContextoModel>();
}
StoredProcedureCommand.EnsureSuccess(command);
return value;
}
});
}
}
}

View File

@@ -156,7 +156,7 @@ namespace SIG.Web.AppCode.Repositories.Fraccionamientos
}
public DbResult<FraccionamientoEtapaGisModel> SaveStageGis(
FraccionamientoEtapaGisModel gis,
int stageId,
int executingUser,
string domainName)
{
@@ -164,24 +164,11 @@ namespace SIG.Web.AppCode.Repositories.Fraccionamientos
"dbo.PA_Fraccionamientos_EtapaGISSave",
executingUser,
domainName,
command =>
{
StoredProcedureCommand.AddInput(
command,
"@CveFraccionamientoEtapa",
gis.CveFraccionamientoEtapa,
DbType.Int32);
StoredProcedureCommand.AddInput(
command,
"@Nombre",
gis.Nombre,
DbType.String);
StoredProcedureCommand.AddInput(
command,
"@UrlVisualizacion",
gis.UrlVisualizacion,
DbType.String);
});
command => StoredProcedureCommand.AddInput(
command,
"@CveFraccionamientoEtapa",
stageId,
DbType.Int32));
}
public DbResult<List<FraccionamientoEtapaTramiteModel>> ListStageProcedures(

View File

@@ -0,0 +1,283 @@
using System;
using System.Globalization;
using System.IO;
using System.Web;
using SIG.Web.AppCode.Contracts.Documentos;
using SIG.Web.AppCode.Models.Common;
using SIG.Web.AppCode.Models.Documentos;
using SIG.Web.AppCode.Services.Logging;
namespace SIG.Web.AppCode.Services.Documentos
{
public sealed class ClienteDocumentoService : IClienteDocumentoService
{
private const string GisExtension = ".gis";
private const string GisContentType = "application/octet-stream";
private readonly IClienteDocumentoRepository _repository;
public ClienteDocumentoService(IClienteDocumentoRepository repository)
{
_repository = repository;
}
public DbResult<ClienteDocumentoEtapaContextoModel> GetStageContext(
int stageId,
int executingUser,
string domainName)
{
if (stageId <= 0)
{
return Fail<ClienteDocumentoEtapaContextoModel>(
"Seleccione una etapa válida.");
}
return _repository.GetStageContext(
stageId,
executingUser,
domainName);
}
public DbResult<ClienteDocumentoArchivoModel> SaveStageGis(
int developmentId,
int stageId,
string originalFileName,
Stream content,
long contentLength,
int executingUser,
string domainName)
{
if (developmentId <= 0 || stageId <= 0)
{
return Fail<ClienteDocumentoArchivoModel>(
"Seleccione un fraccionamiento y una etapa válidos.");
}
if (content == null || contentLength <= 0)
{
return Fail<ClienteDocumentoArchivoModel>(
"Seleccione un archivo GIS válido.");
}
if (!string.Equals(
Path.GetExtension(originalFileName),
GisExtension,
StringComparison.OrdinalIgnoreCase))
{
return Fail<ClienteDocumentoArchivoModel>(
"El archivo seleccionado debe tener extensión .gis.");
}
DbResult<ClienteDocumentoEtapaContextoModel> contextResult =
_repository.GetStageContext(
stageId,
executingUser,
domainName);
if (!contextResult.Success)
{
return DbResult<ClienteDocumentoArchivoModel>.Fail(
contextResult.UserMessage,
contextResult.TechnicalMessage,
contextResult.Exception);
}
ClienteDocumentoEtapaContextoModel stageContext =
contextResult.Data;
if (stageContext == null ||
stageContext.CveCliente <= 0 ||
stageContext.CveFraccionamiento != developmentId ||
stageContext.CveFraccionamientoEtapa != stageId)
{
return Fail<ClienteDocumentoArchivoModel>(
"La etapa no pertenece al fraccionamiento actual o no está disponible para el usuario.");
}
try
{
string clientDirectory = EnsureClientDirectory(
stageContext.CveCliente);
string fileName = BuildStageGisFileName(stageContext);
string physicalPath = Path.Combine(
clientDirectory,
fileName);
using (var fileStream = new FileStream(
physicalPath,
FileMode.Create,
FileAccess.Write,
FileShare.None))
{
content.CopyTo(fileStream);
}
return DbResult<ClienteDocumentoArchivoModel>.Ok(
BuildFileModel(
stageContext,
fileName,
physicalPath));
}
catch (Exception ex)
{
const string userMessage =
"No fue posible guardar el archivo GIS; favor de contactar a Sistemas.";
ExceptionLogger.Log(
ex,
"ClienteDocumentoService.SaveStageGis",
userMessage);
return DbResult<ClienteDocumentoArchivoModel>.Fail(
userMessage,
ex.Message,
ex);
}
}
public DbResult<ClienteDocumentoArchivoModel> GetStageGis(
int stageId,
int executingUser,
string domainName)
{
if (stageId <= 0)
{
return Fail<ClienteDocumentoArchivoModel>(
"Seleccione una etapa válida.");
}
DbResult<ClienteDocumentoEtapaContextoModel> contextResult =
_repository.GetStageContext(
stageId,
executingUser,
domainName);
if (!contextResult.Success)
{
return DbResult<ClienteDocumentoArchivoModel>.Fail(
contextResult.UserMessage,
contextResult.TechnicalMessage,
contextResult.Exception);
}
ClienteDocumentoEtapaContextoModel stageContext =
contextResult.Data;
if (stageContext == null ||
stageContext.CveCliente <= 0 ||
stageContext.CveFraccionamiento <= 0 ||
stageContext.CveFraccionamientoEtapa != stageId)
{
return Fail<ClienteDocumentoArchivoModel>(
"La etapa no está disponible para el usuario actual.");
}
try
{
string clientDirectory = BuildClientDirectory(
stageContext.CveCliente);
string fileName = BuildStageGisFileName(stageContext);
string physicalPath = Path.Combine(
clientDirectory,
fileName);
if (!File.Exists(physicalPath))
{
return Fail<ClienteDocumentoArchivoModel>(
"No se encontró el archivo GIS de la etapa.");
}
return DbResult<ClienteDocumentoArchivoModel>.Ok(
BuildFileModel(
stageContext,
fileName,
physicalPath));
}
catch (Exception ex)
{
const string userMessage =
"No fue posible obtener el archivo GIS; favor de contactar a Sistemas.";
ExceptionLogger.Log(
ex,
"ClienteDocumentoService.GetStageGis",
userMessage);
return DbResult<ClienteDocumentoArchivoModel>.Fail(
userMessage,
ex.Message,
ex);
}
}
private static ClienteDocumentoArchivoModel BuildFileModel(
ClienteDocumentoEtapaContextoModel stageContext,
string fileName,
string physicalPath)
{
return new ClienteDocumentoArchivoModel
{
CveCliente = stageContext.CveCliente,
CveFraccionamiento = stageContext.CveFraccionamiento,
CveFraccionamientoEtapa =
stageContext.CveFraccionamientoEtapa,
NombreArchivo = fileName,
RutaFisica = physicalPath,
ContentType = GisContentType
};
}
private static string BuildStageGisFileName(
ClienteDocumentoEtapaContextoModel stageContext)
{
return string.Format(
CultureInfo.InvariantCulture,
"gis-{0}-{1}.gis",
stageContext.CveFraccionamiento,
stageContext.CveFraccionamientoEtapa);
}
private static string EnsureClientDirectory(int clientId)
{
string applicationRoot = GetApplicationRoot();
string documentsDirectory = Path.Combine(
applicationRoot,
"Documentos");
string generalDirectory = Path.Combine(
documentsDirectory,
"Generales");
string clientsDirectory = Path.Combine(
documentsDirectory,
"Clientes");
string clientDirectory = Path.Combine(
clientsDirectory,
clientId.ToString(CultureInfo.InvariantCulture));
Directory.CreateDirectory(documentsDirectory);
Directory.CreateDirectory(generalDirectory);
Directory.CreateDirectory(clientsDirectory);
Directory.CreateDirectory(clientDirectory);
return clientDirectory;
}
private static string BuildClientDirectory(int clientId)
{
return Path.Combine(
GetApplicationRoot(),
"Documentos",
"Clientes",
clientId.ToString(CultureInfo.InvariantCulture));
}
private static string GetApplicationRoot()
{
string applicationRoot = HttpRuntime.AppDomainAppPath;
return string.IsNullOrWhiteSpace(applicationRoot)
? AppDomain.CurrentDomain.BaseDirectory
: applicationRoot;
}
private static DbResult<T> Fail<T>(string message)
{
return DbResult<T>.Fail(message, message, null);
}
}
}

View File

@@ -411,9 +411,16 @@ namespace SIG.Web.AppCode.Services.Fraccionamientos
Uri uri;
return Uri.TryCreate(value, UriKind.Absolute, out uri)
? uri.GetLeftPart(UriPartial.Path)
: "[URL no válida]";
if (Uri.TryCreate(value, UriKind.Absolute, out uri))
{
return uri.GetLeftPart(UriPartial.Path);
}
int queryIndex = value.IndexOf('?');
return queryIndex >= 0
? value.Substring(0, queryIndex)
: value;
}
private static IList<BitacoraCampoEventoModel> LotFields(

View File

@@ -224,42 +224,19 @@ namespace SIG.Web.AppCode.Services.Fraccionamientos
}
public DbResult<FraccionamientoEtapaGisModel> SaveStageGis(
FraccionamientoEtapaGisModel gis,
int stageId,
int executingUser,
string domainName)
{
if (gis == null || gis.CveFraccionamientoEtapa <= 0)
if (stageId <= 0)
{
return Fail<FraccionamientoEtapaGisModel>(
"Seleccione una etapa válida.");
}
gis.Nombre = TrimOrNull(gis.Nombre);
gis.UrlVisualizacion = TrimOrNull(gis.UrlVisualizacion);
if (string.IsNullOrWhiteSpace(gis.Nombre))
{
return Fail<FraccionamientoEtapaGisModel>(
"Capture el nombre del GIS.");
}
if (gis.Nombre.Length > 200)
{
return Fail<FraccionamientoEtapaGisModel>(
"El nombre del GIS no puede exceder 200 caracteres.");
}
if (string.IsNullOrWhiteSpace(gis.UrlVisualizacion) ||
gis.UrlVisualizacion.Length > 2000 ||
!IsValidHttpUrl(gis.UrlVisualizacion))
{
return Fail<FraccionamientoEtapaGisModel>(
"Capture una URL absoluta http o https válida para el GIS.");
}
return ExecuteInTransaction(
() => _repository.SaveStageGis(
gis,
stageId,
executingUser,
domainName),
result => result.HuboCambio
@@ -884,17 +861,6 @@ namespace SIG.Web.AppCode.Services.Fraccionamientos
return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
}
private static bool IsValidHttpUrl(string value)
{
Uri uri;
return Uri.TryCreate(value, UriKind.Absolute, out uri) &&
string.IsNullOrEmpty(uri.UserInfo) &&
!string.IsNullOrWhiteSpace(uri.Host) &&
(uri.Scheme == Uri.UriSchemeHttp ||
uri.Scheme == Uri.UriSchemeHttps);
}
private static DbResult<T> Fail<T>(string message)
{
return DbResult<T>.Fail(message, message, new ArgumentException(message));

View File

@@ -0,0 +1,412 @@
{
"type": "FeatureCollection",
"name": "Etapa1_10_lotes",
"crs": {
"type": "name",
"properties": {
"name": "EPSG:4326"
}
},
"features": [
{
"type": "Feature",
"properties": {
"Etapa": "Etapa 1",
"Nombre": "Umbrella-1",
"Tipo": "Lote",
"Calle": "Calle Demo 1",
"Catastro": "CAT-001",
"MetrosCuadrados": 200.0,
"Duplicador": 1,
"Estatus": "Activa"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-110.9555,
29.09
],
[
-110.95532,
29.09
],
[
-110.95532,
29.090139999999998
],
[
-110.9555,
29.090139999999998
],
[
-110.9555,
29.09
]
]
]
}
},
{
"type": "Feature",
"properties": {
"Etapa": "Etapa 1",
"Nombre": "Umbrella-2",
"Tipo": "Lote",
"Calle": "Calle Demo 1",
"Catastro": "CAT-002",
"MetrosCuadrados": 200.0,
"Duplicador": 1,
"Estatus": "Activa"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-110.9553,
29.09
],
[
-110.95512,
29.09
],
[
-110.95512,
29.090139999999998
],
[
-110.9553,
29.090139999999998
],
[
-110.9553,
29.09
]
]
]
}
},
{
"type": "Feature",
"properties": {
"Etapa": "Etapa 1",
"Nombre": "Umbrella-3",
"Tipo": "Lote",
"Calle": "Calle Demo 1",
"Catastro": "CAT-003",
"MetrosCuadrados": 200.0,
"Duplicador": 1,
"Estatus": "Activa"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-110.9551,
29.09
],
[
-110.95492,
29.09
],
[
-110.95492,
29.090139999999998
],
[
-110.9551,
29.090139999999998
],
[
-110.9551,
29.09
]
]
]
}
},
{
"type": "Feature",
"properties": {
"Etapa": "Etapa 1",
"Nombre": "Umbrella-4",
"Tipo": "Lote",
"Calle": "Calle Demo 1",
"Catastro": "CAT-004",
"MetrosCuadrados": 200.0,
"Duplicador": 1,
"Estatus": "Activa"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-110.9549,
29.09
],
[
-110.95472,
29.09
],
[
-110.95472,
29.090139999999998
],
[
-110.9549,
29.090139999999998
],
[
-110.9549,
29.09
]
]
]
}
},
{
"type": "Feature",
"properties": {
"Etapa": "Etapa 1",
"Nombre": "Umbrella-5",
"Tipo": "Lote",
"Calle": "Calle Demo 1",
"Catastro": "CAT-005",
"MetrosCuadrados": 200.0,
"Duplicador": 1,
"Estatus": "Activa"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-110.9547,
29.09
],
[
-110.95452,
29.09
],
[
-110.95452,
29.090139999999998
],
[
-110.9547,
29.090139999999998
],
[
-110.9547,
29.09
]
]
]
}
},
{
"type": "Feature",
"properties": {
"Etapa": "Etapa 1",
"Nombre": "Umbrella-6",
"Tipo": "Lote",
"Calle": "Calle Demo 2",
"Catastro": "CAT-006",
"MetrosCuadrados": 200.0,
"Duplicador": 1,
"Estatus": "Activa"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-110.9555,
29.09016
],
[
-110.95532,
29.09016
],
[
-110.95532,
29.0903
],
[
-110.9555,
29.0903
],
[
-110.9555,
29.09016
]
]
]
}
},
{
"type": "Feature",
"properties": {
"Etapa": "Etapa 1",
"Nombre": "Umbrella-7",
"Tipo": "Lote",
"Calle": "Calle Demo 2",
"Catastro": "CAT-007",
"MetrosCuadrados": 200.0,
"Duplicador": 1,
"Estatus": "Activa"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-110.9553,
29.09016
],
[
-110.95512,
29.09016
],
[
-110.95512,
29.0903
],
[
-110.9553,
29.0903
],
[
-110.9553,
29.09016
]
]
]
}
},
{
"type": "Feature",
"properties": {
"Etapa": "Etapa 1",
"Nombre": "Umbrella-8",
"Tipo": "Lote",
"Calle": "Calle Demo 2",
"Catastro": "CAT-008",
"MetrosCuadrados": 200.0,
"Duplicador": 1,
"Estatus": "Activa"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-110.9551,
29.09016
],
[
-110.95492,
29.09016
],
[
-110.95492,
29.0903
],
[
-110.9551,
29.0903
],
[
-110.9551,
29.09016
]
]
]
}
},
{
"type": "Feature",
"properties": {
"Etapa": "Etapa 1",
"Nombre": "Umbrella-9",
"Tipo": "Lote",
"Calle": "Calle Demo 2",
"Catastro": "CAT-009",
"MetrosCuadrados": 200.0,
"Duplicador": 1,
"Estatus": "Activa"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-110.9549,
29.09016
],
[
-110.95472,
29.09016
],
[
-110.95472,
29.0903
],
[
-110.9549,
29.0903
],
[
-110.9549,
29.09016
]
]
]
}
},
{
"type": "Feature",
"properties": {
"Etapa": "Etapa 1",
"Nombre": "Umbrella-10",
"Tipo": "Lote",
"Calle": "Calle Demo 2",
"Catastro": "CAT-010",
"MetrosCuadrados": 200.0,
"Duplicador": 1,
"Estatus": "Activa"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-110.9547,
29.09016
],
[
-110.95452,
29.09016
],
[
-110.95452,
29.0903
],
[
-110.9547,
29.0903
],
[
-110.9547,
29.09016
]
]
]
}
}
]
}

View File

@@ -498,33 +498,11 @@
<asp:HyperLink ID="LnkStageGisOpen"
runat="server"
CssClass="btn btn-default btn-sm"
Target="_blank"
rel="noopener noreferrer">
<i class="fa fa-external-link"></i>
Abrir en otra pestaña
CssClass="btn btn-default btn-sm">
<i class="fa fa-download"></i>
Descargar GIS
</asp:HyperLink>
</div>
<div class="fraction-gis-frame-wrap">
<iframe id="IframeStageGis"
runat="server"
class="fraction-gis-frame js-sig-stage-gis-frame"
title="GIS de la etapa seleccionada"
loading="lazy"
referrerpolicy="no-referrer"
sandbox="allow-scripts allow-same-origin allow-forms allow-popups">
</iframe>
</div>
</asp:Panel>
<asp:Panel ID="PnlStageGisInvalidUrl"
runat="server"
CssClass="alert alert-warning fraction-gis-warning"
role="alert"
Visible="false">
El GIS guardado no tiene una URL HTTP/HTTPS válida.
Use <strong>Administrar GIS</strong> para corregirla.
</asp:Panel>
<div class="fraction-table-scroll fraction-lots-table">
@@ -985,25 +963,15 @@
</div>
<div class="form-group">
<label for="TxtStageGisName">Nombre del GIS *</label>
<asp:TextBox ID="TxtStageGisName"
<label for="FileStageGis">Archivo GIS *</label>
<asp:FileUpload ID="FileStageGis"
runat="server"
ClientIDMode="Static"
CssClass="form-control"
MaxLength="200" />
</div>
<div class="form-group">
<label for="TxtStageGisUrl">URL de visualización *</label>
<asp:TextBox ID="TxtStageGisUrl"
runat="server"
ClientIDMode="Static"
CssClass="form-control"
TextMode="Url"
MaxLength="2000"
placeholder="https://..." />
accept=".gis" />
<span class="help-block">
Utilice una dirección HTTP o HTTPS que permita mostrarse dentro de la plataforma.
Seleccione un archivo con extensión .gis.
El nombre se asignará automáticamente al guardar.
</span>
</div>
</div>
@@ -1025,9 +993,8 @@
</div>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger
ControlID="BtnSaveStageGis"
EventName="Click" />
<asp:PostBackTrigger
ControlID="BtnSaveStageGis" />
</Triggers>
</asp:UpdatePanel>
</div>
@@ -1314,35 +1281,7 @@
<script>
window.SIGDetail = window.SIGDetail || {};
window.SIGDetail.initializeStageGisFrames = function (root) {
var context = root || document;
var frames = $(context)
.find('.js-sig-stage-gis-frame:not([data-sig-stage-gis-initialized="1"])')
.addBack('.js-sig-stage-gis-frame:not([data-sig-stage-gis-initialized="1"])');
frames.each(function () {
var frame = this;
var source = frame.getAttribute('data-src');
var parser;
if (!source) {
return;
}
parser = document.createElement('a');
parser.href = source;
if (parser.protocol !== 'http:' && parser.protocol !== 'https:') {
return;
}
frame.setAttribute('src', source);
frame.setAttribute('data-sig-stage-gis-initialized', '1');
});
};
window.SIGDetail.initialize = function (root) {
window.SIGDetail.initializeStageGisFrames(root || document);
};
window.SIGDetail.initializeModal = function (modalSelector) {

View File

@@ -8,6 +8,7 @@ using SIG.Web.AppCode.Configuration;
using SIG.Web.AppCode.Infrastructure.WebForms;
using SIG.Web.AppCode.Models.Bitacora;
using SIG.Web.AppCode.Models.Common;
using SIG.Web.AppCode.Models.Documentos;
using SIG.Web.AppCode.Models.Fraccionamientos;
using SIG.Web.AppCode.Security;
using SIG.Web.AppCode.Session;
@@ -132,20 +133,6 @@ namespace SIG.Web.Pages.Fraccionamientos
}
}
private int CveFraccionamientoEtapaGisRegistroActual
{
get
{
return ViewState["CveFraccionamientoEtapaGisRegistroActual"] == null
? 0
: (int)ViewState["CveFraccionamientoEtapaGisRegistroActual"];
}
set
{
ViewState["CveFraccionamientoEtapaGisRegistroActual"] = value;
}
}
#endregion
protected void Page_Load(object sender, EventArgs e)
{
@@ -467,8 +454,6 @@ namespace SIG.Web.Pages.Fraccionamientos
object sender,
EventArgs e)
{
string safeUrl;
if (CveFraccionamientoEtapaGisActual <= 0)
{
ShowStageGisValidation(
@@ -476,58 +461,35 @@ namespace SIG.Web.Pages.Fraccionamientos
return;
}
string gisName = (TxtStageGisName.Text ?? string.Empty).Trim();
if (string.IsNullOrWhiteSpace(gisName))
{
ShowStageGisValidation("Capture el nombre del GIS.");
return;
}
if (gisName.Length > 200)
if (!FileStageGis.HasFile ||
FileStageGis.PostedFile == null ||
FileStageGis.PostedFile.ContentLength <= 0)
{
ShowStageGisValidation(
"El nombre del GIS no puede exceder 200 caracteres.");
"Seleccione un archivo GIS válido.");
return;
}
if (!TryGetSafeVisualizationUrl(
TxtStageGisUrl.Text,
out safeUrl))
{
ShowStageGisValidation(
"Capture una URL de visualización HTTP o HTTPS válida.");
return;
}
DbResult<FraccionamientoEtapaModel> stageResult =
AppServices.FraccionamientoService.GetStage(
DbResult<ClienteDocumentoArchivoModel> fileResult =
AppServices.ClienteDocumentoService.SaveStageGis(
CveFraccionamientoActual,
CveFraccionamientoEtapaGisActual,
FileStageGis.PostedFile.FileName,
FileStageGis.PostedFile.InputStream,
FileStageGis.PostedFile.ContentLength,
CurrentUser.CveUsuario,
CurrentUser.NombreDominio);
if (!StageBelongsToCurrentDevelopment(stageResult))
if (!fileResult.Success)
{
ShowStageGisModal();
Alert(
GetStageValidationMessage(stageResult),
GetStageValidationMessageType(stageResult));
Alert(fileResult.UserMessage, TipoMensaje.MsgError);
return;
}
var gis = new FraccionamientoEtapaGisModel
{
CveFraccionamientoEtapaGIS =
CveFraccionamientoEtapaGisRegistroActual,
CveFraccionamientoEtapa =
CveFraccionamientoEtapaGisActual,
Nombre = gisName,
UrlVisualizacion = safeUrl
};
DbResult<FraccionamientoEtapaGisModel> result =
AppServices.FraccionamientoService.SaveStageGis(
gis,
CveFraccionamientoEtapaGisActual,
CurrentUser.CveUsuario,
CurrentUser.NombreDominio);
@@ -1005,17 +967,23 @@ namespace SIG.Web.Pages.Fraccionamientos
return;
}
DbResult<FraccionamientoEtapaModel> stageResult =
AppServices.FraccionamientoService.GetStage(
DbResult<ClienteDocumentoEtapaContextoModel> stageResult =
AppServices.ClienteDocumentoService.GetStageContext(
stageId,
CurrentUser.CveUsuario,
CurrentUser.NombreDominio);
if (!StageBelongsToCurrentDevelopment(stageResult))
if (!stageResult.Success ||
stageResult.Data == null ||
stageResult.Data.CveFraccionamiento != CveFraccionamientoActual)
{
Alert(
GetStageValidationMessage(stageResult),
GetStageValidationMessageType(stageResult));
stageResult.Success
? "La etapa no pertenece al fraccionamiento actual."
: stageResult.UserMessage,
stageResult.Success
? TipoMensaje.MsgAdvertencia
: TipoMensaje.MsgError);
return;
}
@@ -1045,21 +1013,11 @@ namespace SIG.Web.Pages.Fraccionamientos
HideStageGisMessage();
CveFraccionamientoEtapaGisActual = stageId;
CveFraccionamientoEtapaGisRegistroActual = gis == null
? 0
: gis.CveFraccionamientoEtapaGIS;
LitStageGisModalTitle.Text = gis == null
? "Agregar GIS"
: "Administrar GIS";
LitStageGisStageName.Text = EncodeDisplayValue(
stageResult.Data.Etapa);
TxtStageGisName.Text = gis == null
? string.Empty
: gis.Nombre;
TxtStageGisUrl.Text = gis == null
? string.Empty
: gis.UrlVisualizacion;
UpStageGisModal.Update();
ShowStageGisModal();
}
@@ -1180,25 +1138,6 @@ namespace SIG.Web.Pages.Fraccionamientos
: TipoMensaje.MsgAdvertencia;
}
private static bool TryGetSafeVisualizationUrl(
string url,
out string safeUrl)
{
safeUrl = null;
Uri parsedUrl;
if (string.IsNullOrWhiteSpace(url) ||
!Uri.TryCreate(url.Trim(), UriKind.Absolute, out parsedUrl) ||
(parsedUrl.Scheme != Uri.UriSchemeHttp &&
parsedUrl.Scheme != Uri.UriSchemeHttps))
{
return false;
}
safeUrl = parsedUrl.AbsoluteUri;
return true;
}
private void BindClients()
{
DbResult<List<FraccionamientoClienteOptionModel>> result =
@@ -1507,14 +1446,9 @@ namespace SIG.Web.Pages.Fraccionamientos
PhStageGisMissing.Visible = false;
PhStageGisExistingActions.Visible = false;
PnlStageGisExisting.Visible = false;
PnlStageGisInvalidUrl.Visible = false;
LitStageGisName.Text = string.Empty;
LitStageGisUpdatedAt.Text = string.Empty;
LnkStageGisOpen.NavigateUrl = string.Empty;
IframeStageGis.Attributes.Remove("src");
IframeStageGis.Attributes.Remove("data-src");
IframeStageGis.Attributes.Remove(
"data-sig-stage-gis-initialized");
GvLots.DataSource = new List<FraccionamientoLoteModel>();
GvLots.DataBind();
}
@@ -1524,14 +1458,9 @@ namespace SIG.Web.Pages.Fraccionamientos
PhStageGisMissing.Visible = false;
PhStageGisExistingActions.Visible = false;
PnlStageGisExisting.Visible = false;
PnlStageGisInvalidUrl.Visible = false;
LitStageGisName.Text = string.Empty;
LitStageGisUpdatedAt.Text = string.Empty;
LnkStageGisOpen.NavigateUrl = string.Empty;
IframeStageGis.Attributes.Remove("src");
IframeStageGis.Attributes.Remove("data-src");
IframeStageGis.Attributes.Remove(
"data-sig-stage-gis-initialized");
DbResult<FraccionamientoEtapaGisModel> result =
AppServices.FraccionamientoService.GetStageGis(
@@ -1562,8 +1491,27 @@ namespace SIG.Web.Pages.Fraccionamientos
return;
}
DbResult<ClienteDocumentoArchivoModel> fileResult =
AppServices.ClienteDocumentoService.GetStageGis(
stageId,
CurrentUser.CveUsuario,
CurrentUser.NombreDominio);
if (!fileResult.Success || fileResult.Data == null)
{
PhStageGisMissing.Visible = true;
if (fileResult.Exception != null)
{
Alert(fileResult.UserMessage, TipoMensaje.MsgError);
}
return;
}
PhStageGisExistingActions.Visible = true;
LitStageGisName.Text = EncodeDisplayValue(gis.Nombre);
LitStageGisName.Text = EncodeDisplayValue(
fileResult.Data.NombreArchivo);
DateTime updatedAt = gis.FechaModificacion ?? gis.FechaAlta;
LitStageGisUpdatedAt.Text = Server.HtmlEncode(
@@ -1571,19 +1519,10 @@ namespace SIG.Web.Pages.Fraccionamientos
"dd/MM/yyyy HH:mm",
CultureInfo.CurrentCulture));
string safeUrl;
if (!TryGetSafeVisualizationUrl(
gis.UrlVisualizacion,
out safeUrl))
{
PnlStageGisInvalidUrl.Visible = true;
return;
}
PnlStageGisExisting.Visible = true;
LnkStageGisOpen.NavigateUrl = safeUrl;
IframeStageGis.Attributes["data-src"] = safeUrl;
LnkStageGisOpen.NavigateUrl = ResolveUrl(
"~/Pages/Fraccionamientos/FraccionamientoGis.ashx?etapa=" +
stageId.ToString(CultureInfo.InvariantCulture));
}
private void EditLot(int lotId)

View File

@@ -310,16 +310,6 @@ namespace SIG.Web.Pages.Fraccionamientos
/// </summary>
protected global::System.Web.UI.WebControls.HyperLink LnkStageGisOpen;
/// <summary>
/// IframeStageGis control.
/// </summary>
protected global::System.Web.UI.HtmlControls.HtmlGenericControl IframeStageGis;
/// <summary>
/// PnlStageGisInvalidUrl control.
/// </summary>
protected global::System.Web.UI.WebControls.Panel PnlStageGisInvalidUrl;
/// <summary>
/// GvLots control.
/// </summary>
@@ -569,14 +559,9 @@ namespace SIG.Web.Pages.Fraccionamientos
protected global::System.Web.UI.WebControls.Literal LitStageGisStageName;
/// <summary>
/// TxtStageGisName control.
/// FileStageGis control.
/// </summary>
protected global::System.Web.UI.WebControls.TextBox TxtStageGisName;
/// <summary>
/// TxtStageGisUrl control.
/// </summary>
protected global::System.Web.UI.WebControls.TextBox TxtStageGisUrl;
protected global::System.Web.UI.WebControls.FileUpload FileStageGis;
/// <summary>
/// BtnSaveStageGis control.

View File

@@ -0,0 +1 @@
<%@ WebHandler Language="C#" Class="SIG.Web.Pages.Fraccionamientos.FraccionamientoGisHandler" %>

View File

@@ -130,6 +130,7 @@
<Content Include="Pages\Fraccionamientos\Fraccionamientos.aspx" />
<Content Include="Pages\Fraccionamientos\FraccionamientoDetalle.aspx" />
<Content Include="Pages\Fraccionamientos\PlantillaLotes.ashx" />
<Content Include="Pages\Fraccionamientos\FraccionamientoGis.ashx" />
<Content Include="Site.master" />
<Content Include="Web.config" />
<Content Include="adssw.js" Condition="Exists('adssw.js')" />

View File

@@ -69,6 +69,13 @@
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<security>
<requestFiltering>
<hiddenSegments>
<add segment="Documentos" />
</hiddenSegments>
</requestFiltering>
</security>
<handlers>
<add name="PdfViewerHandler" path="SigPdfViewerHandler.ashx" verb="*" type="SIG.Web.AppCode.SigControls.PDFViewer.PdfViewerHandler" resourceType="Unspecified" />
<add name="PdfViewerUploadHandler" path="SigPdfViewerUploadHandler.ashx" verb="POST" type="SIG.Web.AppCode.SigControls.PDFViewer.PdfViewerUploadHandler" resourceType="Unspecified" />

View File

@@ -0,0 +1,81 @@
CREATE OR ALTER PROCEDURE [dbo].[PA_Fraccionamientos_EtapaDocumentoGet]
@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
DECLARE @NombreRol varchar(100);
SELECT @NombreRol = R.NombreRol
FROM dbo.Sis_Usuarios AS U
INNER JOIN dbo.Sis_Roles AS R
ON R.CveRol = U.CveRol
WHERE U.CveUsuario = @CveUsuarioEjecuta
AND U.Activo = 1;
IF @NombreRol IS NULL
BEGIN
SET @ErrorMostrar = 'El usuario no está disponible para consultar documentos.';
SET @ErrorTipo = 2;
RETURN;
END;
SELECT
E.CveFraccionamientoEtapa,
E.CveFraccionamiento,
F.CveCliente,
E.Etapa
FROM dbo.FraccionamientosEtapas AS E
INNER JOIN dbo.Fraccionamientos AS F
ON F.CveFraccionamiento = E.CveFraccionamiento
WHERE E.CveFraccionamientoEtapa = @CveFraccionamientoEtapa
AND
(
@NombreRol <> 'Empresa'
OR EXISTS
(
SELECT 1
FROM dbo.Sis_UsuariosClientes AS UC
WHERE UC.CveUsuario = @CveUsuarioEjecuta
AND UC.CveCliente = F.CveCliente
AND UC.Activo = 1
)
);
IF @@ROWCOUNT = 0
BEGIN
SET @ErrorMostrar = 'La etapa no existe o no está asignada al usuario.';
SET @ErrorTipo = 2;
RETURN;
END;
SET @Return = 1;
END TRY
BEGIN CATCH
SET @ErrorMostrar = 'Ocurrió un error al validar el acceso al documento; 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_Fraccionamientos_EtapaDocumentoGet'),
'; Línea: ', ERROR_LINE(),
'; Detalle: ', ERROR_MESSAGE()
);
RAISERROR(N'%s', 10, 1, @ErrorTecnico);
END CATCH;
END;
GO

View File

@@ -0,0 +1,95 @@
ALTER PROCEDURE [dbo].[PA_Fraccionamientos_EtapaGISGet]
@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
DECLARE @NombreRol varchar(100);
SELECT @NombreRol = R.NombreRol
FROM dbo.Sis_Usuarios AS U
INNER JOIN dbo.Sis_Roles AS R
ON R.CveRol = U.CveRol
WHERE U.CveUsuario = @CveUsuarioEjecuta
AND U.Activo = 1;
IF @NombreRol IS NULL
BEGIN
SET @ErrorMostrar = 'El usuario no está disponible para consultar el GIS.';
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
(
@NombreRol <> 'Empresa'
OR EXISTS
(
SELECT 1
FROM dbo.Sis_UsuariosClientes AS UC
WHERE UC.CveUsuario = @CveUsuarioEjecuta
AND UC.CveCliente = F.CveCliente
AND UC.Activo = 1
)
)
)
BEGIN
SET @ErrorMostrar = 'La etapa no existe o no está asignada al usuario.';
SET @ErrorTipo = 2;
RETURN;
END;
SELECT
G.CveFraccionamientoEtapaGIS,
G.CveFraccionamientoEtapa,
E.CveFraccionamiento,
F.CveCliente,
E.Etapa,
G.Nombre,
G.UrlVisualizacion,
G.FechaAlta,
G.FechaModificacion
FROM dbo.FraccionamientosEtapasGIS AS G
INNER JOIN dbo.FraccionamientosEtapas AS E
ON E.CveFraccionamientoEtapa = G.CveFraccionamientoEtapa
INNER JOIN dbo.Fraccionamientos AS F
ON F.CveFraccionamiento = E.CveFraccionamiento
WHERE G.CveFraccionamientoEtapa = @CveFraccionamientoEtapa;
SET @Return = 1;
END TRY
BEGIN CATCH
SET @ErrorMostrar = 'Ocurrió un error al consultar el GIS de la etapa; 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_Fraccionamientos_EtapaGISGet'),
'; Línea: ', ERROR_LINE(),
'; Detalle: ', ERROR_MESSAGE()
);
RAISERROR(N'%s', 10, 1, @ErrorTecnico);
END CATCH;
END;
GO

View File

@@ -0,0 +1,168 @@
ALTER PROCEDURE [dbo].[PA_Fraccionamientos_EtapaGISSave]
@CveFraccionamientoEtapa int,
@Nombre varchar(200) = NULL,
@UrlVisualizacion varchar(2000) = 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
DECLARE @NombreRol varchar(100);
DECLARE @CveFraccionamiento int;
DECLARE @CveCliente int;
DECLARE @Etapa varchar(150);
SELECT @NombreRol = R.NombreRol
FROM dbo.Sis_Usuarios AS U
INNER JOIN dbo.Sis_Roles AS R
ON R.CveRol = U.CveRol
WHERE U.CveUsuario = @CveUsuarioEjecuta
AND U.Activo = 1;
IF @NombreRol IS NULL
BEGIN
SET @ErrorMostrar = 'El usuario no está disponible para guardar el GIS.';
SET @ErrorTipo = 2;
RETURN;
END;
SELECT
@CveFraccionamiento = E.CveFraccionamiento,
@CveCliente = F.CveCliente,
@Etapa = E.Etapa
FROM dbo.FraccionamientosEtapas AS E
INNER JOIN dbo.Fraccionamientos AS F
ON F.CveFraccionamiento = E.CveFraccionamiento
WHERE E.CveFraccionamientoEtapa = @CveFraccionamientoEtapa
AND
(
@NombreRol <> 'Empresa'
OR EXISTS
(
SELECT 1
FROM dbo.Sis_UsuariosClientes AS UC
WHERE UC.CveUsuario = @CveUsuarioEjecuta
AND UC.CveCliente = F.CveCliente
AND UC.Activo = 1
)
);
IF @CveFraccionamiento IS NULL
BEGIN
SET @ErrorMostrar = 'La etapa no existe o no está asignada al usuario.';
SET @ErrorTipo = 2;
RETURN;
END;
SET @Nombre = CONCAT(
'gis-',
@CveFraccionamiento,
'-',
@CveFraccionamientoEtapa,
'.gis');
SET @UrlVisualizacion = CONCAT(
'~/Pages/Fraccionamientos/FraccionamientoGis.ashx?etapa=',
@CveFraccionamientoEtapa);
DECLARE @CveFraccionamientoEtapaGIS int;
DECLARE @NombreAnterior varchar(200);
DECLARE @UrlVisualizacionAnterior varchar(2000);
DECLARE @EsNuevo bit = 0;
DECLARE @HuboCambio bit = 0;
SELECT
@CveFraccionamientoEtapaGIS = G.CveFraccionamientoEtapaGIS,
@NombreAnterior = G.Nombre,
@UrlVisualizacionAnterior = G.UrlVisualizacion
FROM dbo.FraccionamientosEtapasGIS AS G WITH (UPDLOCK, HOLDLOCK)
WHERE G.CveFraccionamientoEtapa = @CveFraccionamientoEtapa;
IF @CveFraccionamientoEtapaGIS IS NULL
BEGIN
INSERT INTO dbo.FraccionamientosEtapasGIS
(
CveFraccionamientoEtapa,
Nombre,
UrlVisualizacion,
CveUsuario
)
VALUES
(
@CveFraccionamientoEtapa,
@Nombre,
@UrlVisualizacion,
@CveUsuarioEjecuta
);
SET @CveFraccionamientoEtapaGIS = CONVERT(
int,
SCOPE_IDENTITY());
SET @EsNuevo = 1;
SET @HuboCambio = 1;
END
ELSE
BEGIN
UPDATE dbo.FraccionamientosEtapasGIS
SET
Nombre = @Nombre,
UrlVisualizacion = @UrlVisualizacion,
FechaModificacion = GETDATE(),
CveUsuario = @CveUsuarioEjecuta
WHERE CveFraccionamientoEtapaGIS =
@CveFraccionamientoEtapaGIS;
SET @HuboCambio = 1;
END;
SELECT
G.CveFraccionamientoEtapaGIS,
G.CveFraccionamientoEtapa,
E.CveFraccionamiento,
F.CveCliente,
E.Etapa,
G.Nombre,
G.UrlVisualizacion,
@NombreAnterior AS NombreAnterior,
@UrlVisualizacionAnterior AS UrlVisualizacionAnterior,
@EsNuevo AS EsNuevo,
@HuboCambio AS HuboCambio,
G.FechaAlta,
G.FechaModificacion
FROM dbo.FraccionamientosEtapasGIS AS G
INNER JOIN dbo.FraccionamientosEtapas AS E
ON E.CveFraccionamientoEtapa = G.CveFraccionamientoEtapa
INNER JOIN dbo.Fraccionamientos AS F
ON F.CveFraccionamiento = E.CveFraccionamiento
WHERE G.CveFraccionamientoEtapaGIS =
@CveFraccionamientoEtapaGIS;
SET @Return = 1;
END TRY
BEGIN CATCH
SET @ErrorMostrar = 'Ocurrió un error al guardar el GIS de la etapa; 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_Fraccionamientos_EtapaGISSave'),
'; Línea: ', ERROR_LINE(),
'; Detalle: ', ERROR_MESSAGE()
);
RAISERROR(N'%s', 10, 1, @ErrorTecnico);
END CATCH;
END;
GO