From 7551b4d824918cf925e099bc4b511c591521882c Mon Sep 17 00:00:00 2001 From: "Mariano Z." Date: Mon, 5 May 2025 22:17:03 -0300 Subject: [PATCH] automated dev commit --- .dockerignore | 62 +++++++ .gitignore | 161 +++++++++++++++++ Dockerfile | 0 Models/ErrorCodes.cs | 46 +++++ Models/ImagenDigital.cs | 16 ++ Models/Mensaje.cs | 16 ++ Models/ObjPersona.cs | 49 ++++++ Models/ParamObtDocDigitalizado.cs | 28 +++ Models/ResultObtDocDigitalizado.cs | 19 ++ Program.cs | 43 +++++ Properties/launchSettings.json | 41 +++++ README.md | 90 ++++++++++ Services/IWsServicioDeInformacion.cs | 11 ++ Services/WsServicioDeInformacion.cs | 250 +++++++++++++++++++++++++++ SoapService.csproj | 15 ++ SoapService.http | 6 + appsettings.Development.json | 8 + appsettings.json | 9 + 18 files changed, 870 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 Models/ErrorCodes.cs create mode 100644 Models/ImagenDigital.cs create mode 100644 Models/Mensaje.cs create mode 100644 Models/ObjPersona.cs create mode 100644 Models/ParamObtDocDigitalizado.cs create mode 100644 Models/ResultObtDocDigitalizado.cs create mode 100644 Program.cs create mode 100644 Properties/launchSettings.json create mode 100644 README.md create mode 100644 Services/IWsServicioDeInformacion.cs create mode 100644 Services/WsServicioDeInformacion.cs create mode 100644 SoapService.csproj create mode 100644 SoapService.http create mode 100644 appsettings.Development.json create mode 100644 appsettings.json diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..cb9291a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,62 @@ +# Archivos y carpetas de desarrollo +.vs/ +.vscode/ +.idea/ +*.suo +*.user +*.userosscache +*.sln.docstates + +# Carpetas de build +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Dd]ebug/ +[Rr]elease/ +x64/ +x86/ +build/ +msbuild.log +msbuild.err +msbuild.wrn + +# Archivos temporales +*.log +*.logs +*.tmp +*.swp + +# Archivos de Git y control de versiones +.git/ +.gitignore +.github/ + +# Archivos de Docker +Dockerfile +.dockerignore +docker-compose*.yml + +# Archivos de documentación y ejemplos +README.md +LICENSE +*.md +docs/ +examples/ + +# Archivos específicos de entorno +.env +*.env +appsettings.*.json + +# Archivos de pruebas +[Tt]est*/ +*.Tests/ +TestResults/ + +# Paquetes NuGet +*.nupkg +packages/ + +# Archivos del sistema operativo +.DS_Store +Thumbs.db diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a3707e0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,161 @@ +# Visual Studio files +.vs/ +.vscode/ +*.suo +*.user +*.userosscache +*.sln.docstates +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +msbuild.log +msbuild.err +msbuild.wrn + +# ReSharper +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# Visual Studio cache/options directory +.vs/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# VS Code directories +.vscode/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# JetBrains Rider +.idea/ +*.sln.iml + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# Mono auto generated files +mono_crash.* + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Logs +*.log +*.logs diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..e69de29 diff --git a/Models/ErrorCodes.cs b/Models/ErrorCodes.cs new file mode 100644 index 0000000..dbad723 --- /dev/null +++ b/Models/ErrorCodes.cs @@ -0,0 +1,46 @@ +namespace SoapService.Models; + +public static class ErrorCodes +{ + // Warnings (700-1000) + public static class Warnings + { + public const int DatosPersonaRegularizar = 701; + public const string DatosPersonaRegularizarMensaje = "Datos de Persona a regularizar"; + + public const int DocumentoHurtadoExtraviado = 702; + public const string DocumentoHurtadoExtraviadoMensaje = "Documento Denunciado como Hurtado/Extraviado el ../../...."; + + public const int HojaInteriorHurtada = 703; + public const string HojaInteriorHurtadaMensaje = "La Hoja interior Serie {0}, Número {1}, figura como hurtada"; + + public const int DocumentoNoUltimo = 704; + public const string DocumentoNoUltimoMensaje = "El documento presentado no es el último gestionado"; + + public const int ValoresNoCoinciden = 705; + public const string ValoresNoCoincidenMensaje = "Los valores del material no coinciden con el último documento digitalizado ingresado. Por favor, verifique los datos y digite nuevamente si corresponde."; + } + + // Errores Leves (> 1000) + public static class ErroresLeves + { + public const int PersonaInexistente = 1001; + public const string PersonaInexistenteMensaje = "Persona inexistente"; + + public const int LimiteConsultasExcedido = 1002; + public const string LimiteConsultasExcedidoMensaje = "Límite de consultas excedido"; + + public const int NumeroCedulaAnulado = 1003; + public const string NumeroCedulaAnuladoMensaje = "Número de cédula anulado"; + } + + // Errores Graves (> 10000) + public static class ErroresGraves + { + public const int ParametrosIncorrectos = 10001; + public const string ParametrosIncorrectosMensaje = "Parámetros incorrectos"; + + public const int ConsultaNoCompletada = 10002; + public const string ConsultaNoCompletadaMensaje = "No se pudo completar la consulta"; + } +} diff --git a/Models/ImagenDigital.cs b/Models/ImagenDigital.cs new file mode 100644 index 0000000..9bd0961 --- /dev/null +++ b/Models/ImagenDigital.cs @@ -0,0 +1,16 @@ +using System.Runtime.Serialization; + +namespace SoapService.Models; + +[DataContract(Namespace = "http://dnic.gub.uy/")] +public class ImagenDigital +{ + [DataMember(Order = 0)] + public string Foto { get; set; } + + [DataMember(Order = 1)] + public int LargoBytes { get; set; } + + [DataMember(Order = 2)] + public int TipoImagen { get; set; } +} diff --git a/Models/Mensaje.cs b/Models/Mensaje.cs new file mode 100644 index 0000000..719cf9d --- /dev/null +++ b/Models/Mensaje.cs @@ -0,0 +1,16 @@ +using System.Runtime.Serialization; + +namespace SoapService.Models; + +[DataContract(Namespace = "http://dnic.gub.uy/")] +public class Mensaje +{ + [DataMember(Order = 0)] + public int CodMensaje { get; set; } + + [DataMember(Order = 1)] + public string Descripcion { get; set; } + + [DataMember(Order = 2)] + public string DatoExtra { get; set; } +} diff --git a/Models/ObjPersona.cs b/Models/ObjPersona.cs new file mode 100644 index 0000000..3fbafd8 --- /dev/null +++ b/Models/ObjPersona.cs @@ -0,0 +1,49 @@ +using System.Runtime.Serialization; + +namespace SoapService.Models; + +[DataContract(Namespace = "http://dnic.gub.uy/")] +public class ObjPersona +{ + [DataMember(Order = 0)] + public string CodTipoDocumento { get; set; } + + [DataMember(Order = 1)] + public string NroDocumento { get; set; } + + [DataMember(Order = 2)] + public string Nombre1 { get; set; } + + [DataMember(Order = 3)] + public string Nombre2 { get; set; } + + [DataMember(Order = 4)] + public string PrimerApellido { get; set; } + + [DataMember(Order = 5)] + public string SegundoApellido { get; set; } + + [DataMember(Order = 6)] + public string ApellidoAdoptivo1 { get; set; } + + [DataMember(Order = 7)] + public string ApellidoAdoptivo2 { get; set; } + + [DataMember(Order = 8)] + public int Sexo { get; set; } + + [DataMember(Order = 9)] + public string FechaNacimiento { get; set; } + + [DataMember(Order = 10)] + public int CodNacionalidad { get; set; } + + [DataMember(Order = 11)] + public string NombreEnCedula { get; set; } + + [DataMember(Order = 12)] + public int IdSolicitud { get; set; } + + [DataMember(Order = 13)] + public int IdRespuesta { get; set; } +} diff --git a/Models/ParamObtDocDigitalizado.cs b/Models/ParamObtDocDigitalizado.cs new file mode 100644 index 0000000..44e1520 --- /dev/null +++ b/Models/ParamObtDocDigitalizado.cs @@ -0,0 +1,28 @@ +using System.Runtime.Serialization; + +namespace SoapService.Models; + +[DataContract(Namespace = "http://dnic.gub.uy/")] +public class ParamObtDocDigitalizado +{ + [DataMember(Name = "ClaveAcceso1", Order = 0)] + public string ClaveAcceso1 { get; set; } + + [DataMember(Name = "ClaveAcceso2", Order = 1)] + public string ClaveAcceso2 { get; set; } + + [DataMember(Name = "NroDocumento", Order = 2)] + public string NroDocumento { get; set; } + + [DataMember(Name = "NroIdentificacion", Order = 3)] + public int NroIdentificacion { get; set; } + + [DataMember(Name = "NroSerie", Order = 4)] + public string NroSerie { get; set; } + + [DataMember(Name = "Organismo", Order = 5)] + public string Organismo { get; set; } + + [DataMember(Name = "TipoDocumento", Order = 6)] + public string TipoDocumento { get; set; } = "DO"; +} diff --git a/Models/ResultObtDocDigitalizado.cs b/Models/ResultObtDocDigitalizado.cs new file mode 100644 index 0000000..3a18ac2 --- /dev/null +++ b/Models/ResultObtDocDigitalizado.cs @@ -0,0 +1,19 @@ +using System.Runtime.Serialization; + +namespace SoapService.Models; + +[DataContract(Namespace = "http://dnic.gub.uy/")] +public class ResultObtDocDigitalizado +{ + [DataMember(Order = 0)] + public ObjPersona Persona { get; set; } + + [DataMember(Order = 1)] + public ImagenDigital[] Imagenes { get; set; } + + [DataMember(Order = 2)] + public Mensaje[]? Warnings { get; set; } + + [DataMember(Order = 3)] + public Mensaje[] Errores { get; set; } +} diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..8f17b4a --- /dev/null +++ b/Program.cs @@ -0,0 +1,43 @@ +using Microsoft.Extensions.DependencyInjection.Extensions; +using SoapCore; +using SoapService.Services; + +var builder = WebApplication.CreateBuilder(args); + +// Agregar servicios al contenedor +builder.Services.AddSoapCore(); +builder.Services.TryAddSingleton(); +builder.Services.AddControllers(); +builder.Services.AddEndpointsApiExplorer(); + +// Configurar Logging +builder.Logging.AddConsole(); +builder.Logging.AddDebug(); + +// Configurar URL y Kestrel +builder.WebHost.UseKestrel(options => +{ + options.ListenAnyIP(5050); +}); + +var app = builder.Build(); + +// Configurar el pipeline HTTP +app.UseHttpsRedirection(); +app.UseRouting(); + +// Configurar endpoints SOAP +app.UseEndpoints(endpoints => +{ + endpoints.UseSoapEndpoint( + "/WsServicioDeInformacion.svc", + new SoapEncoderOptions(), + SoapSerializer.DataContractSerializer); + + endpoints.UseSoapEndpoint( + "/WsServicioDeInformacion.asmx", + new SoapEncoderOptions(), + SoapSerializer.XmlSerializer); +}); + +app.Run(); diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json new file mode 100644 index 0000000..2b387f8 --- /dev/null +++ b/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:28336", + "sslPort": 44394 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5032", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7249;http://localhost:5032", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..d4ba701 --- /dev/null +++ b/README.md @@ -0,0 +1,90 @@ +# Servicio de Simulación de Documentos Digitalizados + +Este documento explica cómo utilizar el servicio de simulación de documentos digitalizados para fines educativos. El servicio genera información ficticia de personas basada en números de documentos de identidad (cédulas). + +## Características principales + +- Generación de datos personales ficticios deterministas (siempre los mismos para la misma cédula) +- Simulación de errores y advertencias controladas mediante patrones en los números de cédula +- Generación de edades específicas basadas en los últimos dígitos de la cédula + +## Cómo generar errores y advertencias específicos + +El servicio utiliza los **dos primeros dígitos** de la cédula para determinar si ocurre un error o una advertencia: + +| Dos primeros dígitos | Resultado generado | +| -------------------- | -------------------------------------------- | +| 11 | Error - Persona inexistente | +| 12 | Error - Límite de consultas excedido | +| 13 | Error - Número de cédula anulado | +| 14 | Advertencia - Datos de persona a regularizar | +| 15 | Advertencia - Documento hurtado o extraviado | +| Otros | Sin errores ni advertencias | + +Por ejemplo, si consulta la cédula `11.234.567-8`, el servicio devolverá un error indicando que la persona no existe. + +## Cómo obtener cédulas con edades específicas + +La edad de la persona generada se determina por los **últimos dos dígitos** de la cédula: + +- Para una persona de 25 años: use una cédula que termine en "25" +- Para una persona de 18 años: use una cédula que termine en "18" +- Para una persona de 65 años: use una cédula que termine en "65" + +Por ejemplo, la cédula `4.321.025-9` generará una persona que tiene 25 años. + +## Ejemplos de uso + +### Ejemplos de cédulas que generan errores: + +- `11.234.567-8`: Error - Persona inexistente +- `12.345.678-9`: Error - Límite de consultas excedido +- `13.456.789-0`: Error - Número de cédula anulado + +### Ejemplos de cédulas que generan advertencias: + +- `14.567.890-1`: Sin error, con advertencia - Datos a regularizar +- `15.456.789-0`: Sin error, con advertencia - Documento hurtado/extraviado +- `56.789.123-4`: Sin error, sin advertencia (no comienza con 11-15) + +### Ejemplos de cédulas con edades específicas: + +- `4.321.018-9`: Persona de 18 años +- `5.678.930-3`: Persona de 30 años +- `6.789.045-1`: Persona de 45 años +- `7.890.175-8`: Persona de 75 años + +### Combinando características: + +- `15.467.825-7`: Persona de 25 años con advertencia de documento hurtado +- `14.418.965-3`: Persona de 65 años con advertencia de datos a regularizar + +## Otros datos generados + +Además de la edad, el servicio genera determinísticamente para cada cédula: + +- Nombres y apellidos +- Sexo (basado en el número de cédula) +- Fecha de nacimiento (basada en la edad) +- Nacionalidad +- Nombres completos para la cédula +- Identificadores de solicitud y respuesta + +## Notas importantes + +1. Los datos generados son ficticios y no corresponden a personas reales. +2. El servicio es determinista: la misma cédula siempre generará los mismos datos. +3. Para edades de 0-9, asegúrese de incluir un cero delante (por ejemplo, "05" para 5 años). +4. Para cédulas sin dígitos suficientes, el sistema puede comportarse de manera inesperada. + +## Formato de parámetros requeridos + +Para realizar una consulta válida, debe proporcionar los siguientes parámetros: + +- `NroDocumento`: Número de cédula (requerido) +- `NroSerie`: Número de serie del documento (requerido) +- `Organismo`: Código del organismo solicitante (requerido) +- `ClaveAcceso1`: Clave de acceso (requerida) +- `TipoDocumento`: Tipo de documento (opcional) + +La ausencia de cualquiera de los parámetros requeridos resultará en un error de "Parámetros incorrectos". diff --git a/Services/IWsServicioDeInformacion.cs b/Services/IWsServicioDeInformacion.cs new file mode 100644 index 0000000..6d58b7e --- /dev/null +++ b/Services/IWsServicioDeInformacion.cs @@ -0,0 +1,11 @@ +using SoapService.Models; +using System.ServiceModel; + +namespace SoapService.Services; + +[ServiceContract(Namespace = "http://dnic.gub.uy/")] +public interface IWsServicioDeInformacion +{ + [OperationContract] + ResultObtDocDigitalizado ObtDocDigitalizado(ParamObtDocDigitalizado param); +} diff --git a/Services/WsServicioDeInformacion.cs b/Services/WsServicioDeInformacion.cs new file mode 100644 index 0000000..c602594 --- /dev/null +++ b/Services/WsServicioDeInformacion.cs @@ -0,0 +1,250 @@ +using SoapService.Models; + +namespace SoapService.Services; + +public class WsServicioDeInformacion : IWsServicioDeInformacion +{ + private static readonly Dictionary _personasGeneradas = new(); + private static readonly Random _random = new(); + + // Expanded lists of Uruguayan names and surnames + private static readonly string[] _nombresHombre = { + "Juan", "Carlos", "Martín", "Luis", "Diego", "Marcelo", "Alejandro", "Fernando", + "Matías", "Pablo", "Eduardo", "Federico", "Gonzalo", "Sergio", "Daniel", + "Raúl", "Gabriel", "Andrés", "Nicolás", "Roberto", "Sebastián", "Héctor", + "Gustavo", "Leonardo", "Rodrigo", "Gerardo", "Ricardo", "Santiago", "Ignacio", + "Emiliano", "Dante", "Agustín", "Julio", "Mario", "Alfredo", "Bruno", "Mauricio" + }; + private static readonly string[] _nombresMujer = { + "María", "Ana", "Laura", "Sofía", "Lucía", "Valentina", "Natalia", "Andrea", + "Gabriela", "Carolina", "Verónica", "Claudia", "Patricia", "Alejandra", "Victoria", + "Soledad", "Carmen", "Isabel", "Cecilia", "Paula", "Florencia", "Silvia", "Leticia", + "Jimena", "Romina", "Agustina", "Lorena", "Camila", "Valeria", "Daniela", "Mariana", + "Eugenia", "Rosario", "Pilar", "Adriana", "Carla", "Micaela", "Magdalena", "Inés" + }; + private static readonly string[] _segundosNombres = { + "José", "Pablo", "Elena", "Inés", "Alberto", "Miguel", "Beatriz", "Javier", + "Alejandro", "Antonio", "Teresa", "Francisco", "Manuel", "Mercedes", "Rosario", + "Ernesto", "Juana", "Felipe", "Jaime", "Clara", "Ignacio", "Ángel", "Joaquín", + "Rafael", "Susana", "Héctor", "Alicia", "Marta", "Luciana", "Mateo", "Margarita" + }; + private static readonly string[] _apellidos = { + "Rodríguez", "Fernández", "García", "Martínez", "López", "González", "Pérez", + "Gómez", "Sánchez", "Romero", "Silva", "Castro", "Torres", "Álvarez", "Benítez", + "Ramírez", "Flores", "Herrera", "Gutiérrez", "Suárez", "Rojas", "Vargas", "Acosta", + "Morales", "Giménez", "Cardozo", "Méndez", "Delgado", "Díaz", "Pereyra", "Olivera", + "Ferreira", "Núñez", "Castillo", "Aguirre", "Duarte", "Sosa", "Vázquez", "Techera", + "Medina", "Hernández", "Cabrera", "Machado", "Bentancor", "Moreira", "Fagúndez", "Pintos" + }; + + public ResultObtDocDigitalizado ObtDocDigitalizado(ParamObtDocDigitalizado param) + { + // Validate input parameters + if (string.IsNullOrEmpty(param?.NroDocumento) || + string.IsNullOrEmpty(param?.NroSerie) || + string.IsNullOrEmpty(param?.Organismo) || + string.IsNullOrEmpty(param?.ClaveAcceso1)) + { + return CreateErrorResult(ErrorCodes.ErroresGraves.ParametrosIncorrectos, + ErrorCodes.ErroresGraves.ParametrosIncorrectosMensaje); + } + + try + { + int seed = GetSeedFromCI(param.NroDocumento); + Random randomCI = new(seed); + + var (errors, warnings) = CheckErrorsAndWarnings(param.NroDocumento); + if (errors.Any()) + { + return new ResultObtDocDigitalizado { Errores = errors.ToArray() }; + } + + ObjPersona persona = GeneratePerson(param, randomCI); + var images = GenerateImages(seed); + + return new ResultObtDocDigitalizado + { + Persona = persona, + Imagenes = images, + Warnings = warnings.Any() ? warnings.ToArray() : null + }; + } + catch (Exception ex) + { + return CreateErrorResult(ErrorCodes.ErroresGraves.ConsultaNoCompletada, + $"Error inesperado: {ex.Message}", ex.StackTrace!); + } + } + + private (List Errors, List Warnings) CheckErrorsAndWarnings(string nroDocumento) + { + var errors = new List(); + var warnings = new List(); + + // Extract digits for error/warning checking + string digits = new string(nroDocumento.Where(char.IsDigit).ToArray()); + if (string.IsNullOrEmpty(digits)) + { + errors.Add(CreateMensaje(ErrorCodes.ErroresGraves.ParametrosIncorrectos, + ErrorCodes.ErroresGraves.ParametrosIncorrectosMensaje)); + return (errors, warnings); + } + + string firstTwoDigits = digits.Length >= 2 ? digits.Substring(0, 2) : digits.PadRight(2, '0'); + + switch (firstTwoDigits) + { + case "11": // Persona inexistente + errors.Add(CreateMensaje(ErrorCodes.ErroresLeves.PersonaInexistente, + ErrorCodes.ErroresLeves.PersonaInexistenteMensaje)); + return (errors, warnings); + + case "12": // Límite excedido + errors.Add(CreateMensaje(ErrorCodes.ErroresLeves.LimiteConsultasExcedido, + ErrorCodes.ErroresLeves.LimiteConsultasExcedidoMensaje)); + return (errors, warnings); + + case "13": // Cédula anulada + errors.Add(CreateMensaje(ErrorCodes.ErroresLeves.NumeroCedulaAnulado, + ErrorCodes.ErroresLeves.NumeroCedulaAnuladoMensaje)); + return (errors, warnings); + + case "14": // Regularización needed + warnings.Add(CreateMensaje(ErrorCodes.Warnings.DatosPersonaRegularizar, + ErrorCodes.Warnings.DatosPersonaRegularizarMensaje)); + break; + + case "15": // Documento hurtado + warnings.Add(CreateMensaje(ErrorCodes.Warnings.DocumentoHurtadoExtraviado, + ErrorCodes.Warnings.DocumentoHurtadoExtraviadoMensaje)); + break; + } + + return (errors, warnings); + } + + private ObjPersona GeneratePerson(ParamObtDocDigitalizado param, Random randomCI) + { + // Return cached person if exists + if (_personasGeneradas.TryGetValue(param.NroDocumento, out var existingPerson)) + { + return existingPerson; + } + + // Generate deterministic person data + int sexo = randomCI.Next(1, 3); // 1 = Masculino, 2 = Femenino + string nombre1 = sexo == 1 + ? _nombresHombre[randomCI.Next(_nombresHombre.Length)] + : _nombresMujer[randomCI.Next(_nombresMujer.Length)]; + + string nombre2 = _segundosNombres[randomCI.Next(_segundosNombres.Length)]; + string apellido1 = _apellidos[randomCI.Next(_apellidos.Length)]; + string apellido2 = _apellidos[randomCI.Next(_apellidos.Length)]; + + // Optional adoptive surnames + string? apellidoAdoptivo1 = randomCI.NextDouble() < 0.1 ? _apellidos[randomCI.Next(_apellidos.Length)] : null; + string? apellidoAdoptivo2 = apellidoAdoptivo1 != null && randomCI.NextDouble() < 0.5 ? _apellidos[randomCI.Next(_apellidos.Length)] : null; + + // Extract last two digits of document number for age + string digits = new string(param.NroDocumento.Where(char.IsDigit).ToArray()); + string lastTwoDigits = digits.Length >= 2 ? digits[^2..] : digits.PadLeft(2, '0'); + int edad = int.Parse(lastTwoDigits); + + // Ensure age is reasonable (e.g., 0-99); adjust if needed + edad = Math.Clamp(edad, 0, 99); + + // Generate birth date based on age + DateTime fechaNacimiento = DateTime.Now.AddYears(-edad).AddDays(-randomCI.Next(0, 365)); + string fechaNacimientoStr = fechaNacimiento.ToString("yyyy-MM-dd"); + + // Build full name + string nombreCompleto = $"{nombre1} {nombre2} {apellido1} {apellido2}"; + if (apellidoAdoptivo1 != null) + { + nombreCompleto += $" {apellidoAdoptivo1}"; + if (apellidoAdoptivo2 != null) + nombreCompleto += $" {apellidoAdoptivo2}"; + } + + // Create person + var persona = new ObjPersona + { + CodTipoDocumento = param.TipoDocumento, + NroDocumento = param.NroDocumento, + Nombre1 = nombre1, + Nombre2 = nombre2, + PrimerApellido = apellido1, + SegundoApellido = apellido2, + ApellidoAdoptivo1 = apellidoAdoptivo1!, + ApellidoAdoptivo2 = apellidoAdoptivo2!, + Sexo = sexo, + FechaNacimiento = fechaNacimientoStr, + CodNacionalidad = randomCI.Next(1, 3), // 1 = Oriental, 2 = Extranjero + NombreEnCedula = nombreCompleto, + IdSolicitud = 10000 + (randomCI.Next(0, 90000)), + IdRespuesta = 10000 + (randomCI.Next(0, 90000)) + }; + + // Cache the person + _personasGeneradas[param.NroDocumento] = persona; + return persona; + } + + private ImagenDigital[] GenerateImages(int seed) + { + Random randomImage = new(seed); + int length1 = 100 + (randomImage.Next(0, 300)); // 100-399 bytes + int length2 = 100 + (randomImage.Next(0, 300)); // 100-399 bytes + + return new[] + { + new ImagenDigital + { + Foto = "No Implementado...", + LargoBytes = length1, + TipoImagen = 1 + }, + new ImagenDigital + { + Foto = "No Implementado...", + LargoBytes = length2, + TipoImagen = 2 + } + }; + } + + private int GetSeedFromCI(string nroDocumento) + { + string digits = new string(nroDocumento.Where(char.IsDigit).ToArray()); + if (string.IsNullOrEmpty(digits)) + { + return 12345; + } + + if (digits.Length > 8) + { + digits = digits[^8..]; + } + + return int.TryParse(digits, out int seed) ? seed : 12345; + } + + private ResultObtDocDigitalizado CreateErrorResult(int code, string message, string extraData = "Trace") + { + return new ResultObtDocDigitalizado + { + Errores = new[] { CreateMensaje(code, message, extraData) } + }; + } + + private Mensaje CreateMensaje(int code, string description, string extraData = "Trace") + { + return new Mensaje + { + CodMensaje = code, + Descripcion = description, + DatoExtra = extraData + }; + } +} diff --git a/SoapService.csproj b/SoapService.csproj new file mode 100644 index 0000000..8fc52a5 --- /dev/null +++ b/SoapService.csproj @@ -0,0 +1,15 @@ + + + + net8.0 + enable + enable + + + + + + + + + diff --git a/SoapService.http b/SoapService.http new file mode 100644 index 0000000..aa12801 --- /dev/null +++ b/SoapService.http @@ -0,0 +1,6 @@ +@SoapService_HostAddress = http://localhost:5032 + +GET {{SoapService_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/appsettings.Development.json b/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/appsettings.json b/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +}