From 7ddb71c24c5e7299f0b0eafbc6b304bfeb993c5e Mon Sep 17 00:00:00 2001 From: dmolinari Date: Wed, 15 Apr 2026 15:31:20 -0300 Subject: [PATCH] feat(domain): BATCH 2 - Permiso entity + catalogo const [UDT-005] --- src/api/SIGCM2.Domain/Entities/Permiso.cs | 49 +++++++++++++++++ .../Exceptions/PermisoNotFoundException.cs | 12 +++++ src/api/SIGCM2.Domain/Permissions/Permiso.cs | 53 +++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 src/api/SIGCM2.Domain/Entities/Permiso.cs create mode 100644 src/api/SIGCM2.Domain/Exceptions/PermisoNotFoundException.cs create mode 100644 src/api/SIGCM2.Domain/Permissions/Permiso.cs diff --git a/src/api/SIGCM2.Domain/Entities/Permiso.cs b/src/api/SIGCM2.Domain/Entities/Permiso.cs new file mode 100644 index 0000000..ee08070 --- /dev/null +++ b/src/api/SIGCM2.Domain/Entities/Permiso.cs @@ -0,0 +1,49 @@ +namespace SIGCM2.Domain.Entities; + +/// +/// Entidad de dominio que representa un permiso atómico del catálogo RBAC. +/// Inmutable — solo se puede leer desde BD (sin creación por API). +/// +public sealed class Permiso +{ + public int Id { get; } + public string Codigo { get; } + public string Nombre { get; } + public string? Descripcion { get; } + public string Modulo { get; } + public bool Activo { get; } + public DateTime FechaCreacion { get; } + + private Permiso( + int id, + string codigo, + string nombre, + string? descripcion, + string modulo, + bool activo, + DateTime fechaCreacion) + { + Id = id; + Codigo = codigo; + Nombre = nombre; + Descripcion = descripcion; + Modulo = modulo; + Activo = activo; + FechaCreacion = fechaCreacion; + } + + /// + /// Factory para hidratación desde BD (read-only — el catálogo solo se modifica vía migraciones). + /// + public static Permiso ForRead( + int id, + string codigo, + string nombre, + string? descripcion, + string modulo, + bool activo, + DateTime fechaCreacion) + { + return new Permiso(id, codigo, nombre, descripcion, modulo, activo, fechaCreacion); + } +} diff --git a/src/api/SIGCM2.Domain/Exceptions/PermisoNotFoundException.cs b/src/api/SIGCM2.Domain/Exceptions/PermisoNotFoundException.cs new file mode 100644 index 0000000..c9f95cb --- /dev/null +++ b/src/api/SIGCM2.Domain/Exceptions/PermisoNotFoundException.cs @@ -0,0 +1,12 @@ +namespace SIGCM2.Domain.Exceptions; + +public sealed class PermisoNotFoundException : Exception +{ + public string Codigo { get; } + + public PermisoNotFoundException(string codigo) + : base($"El permiso '{codigo}' no existe.") + { + Codigo = codigo; + } +} diff --git a/src/api/SIGCM2.Domain/Permissions/Permiso.cs b/src/api/SIGCM2.Domain/Permissions/Permiso.cs new file mode 100644 index 0000000..e07dadf --- /dev/null +++ b/src/api/SIGCM2.Domain/Permissions/Permiso.cs @@ -0,0 +1,53 @@ +namespace SIGCM2.Domain.Permissions; + +/// +/// Catálogo canónico de permisos RBAC del sistema. +/// Source of truth: cada código aquí debe tener su fila en dbo.Permiso vía migración. +/// Convención: al agregar un permiso nuevo → también asignarlo al rol admin en la misma migración. +/// +public static class Permiso +{ + // ── Ventas: contado ────────────────────────────────────────────────────── + public const string VentasContadoCrear = "ventas:contado:crear"; + public const string VentasContadoModificar = "ventas:contado:modificar"; + public const string VentasContadoCobrar = "ventas:contado:cobrar"; + public const string VentasContadoFacturar = "ventas:contado:facturar"; + + // ── Ventas: cuenta corriente ───────────────────────────────────────────── + public const string VentasCtacteCrear = "ventas:ctacte:crear"; + public const string VentasCtacteFacturar = "ventas:ctacte:facturar"; + + // ── Textos ─────────────────────────────────────────────────────────────── + public const string TextosEditar = "textos:editar"; + public const string TextosReclamosVer = "textos:reclamos:ver"; + + // ── Pauta ──────────────────────────────────────────────────────────────── + public const string PautaAzanuVer = "pauta:azanu:ver"; + public const string PautaLimpiar = "pauta:limpiar"; + public const string PautaRecursosFueraDeHora = "pauta:recursos:fueradehora"; + + // ── Productores ────────────────────────────────────────────────────────── + public const string ProductoresDeudaVer = "productores:deuda:ver"; + public const string ProductoresPendientesCrear = "productores:pendientes:crear"; + public const string ProductoresDeudaBypass = "productores:deuda:bypass"; + + // ── Administración ─────────────────────────────────────────────────────── + public const string AdministracionUsuariosGestionar = "administracion:usuarios:gestionar"; + public const string AdministracionTarifariosGestionar = "administracion:tarifarios:gestionar"; + public const string AdministracionMediosGestionar = "administracion:medios:gestionar"; + public const string AdministracionAuditoriaVer = "administracion:auditoria:ver"; + + /// + /// Set completo de todos los códigos canónicos (útil para validación y seeds). + /// + public static readonly IReadOnlySet Todos = new HashSet + { + VentasContadoCrear, VentasContadoModificar, VentasContadoCobrar, VentasContadoFacturar, + VentasCtacteCrear, VentasCtacteFacturar, + TextosEditar, TextosReclamosVer, + PautaAzanuVer, PautaLimpiar, PautaRecursosFueraDeHora, + ProductoresDeudaVer, ProductoresPendientesCrear, ProductoresDeudaBypass, + AdministracionUsuariosGestionar, AdministracionTarifariosGestionar, + AdministracionMediosGestionar, AdministracionAuditoriaVer, + }; +}