ADM-001: Medios y Secciones (fundacional) #15

Merged
dmolinari merged 9 commits from feature/ADM-001 into main 2026-04-17 14:37:15 +00:00
7 changed files with 219 additions and 0 deletions
Showing only changes of commit bb98dbf217 - Show all commits

View File

@@ -0,0 +1,75 @@
namespace SIGCM2.Domain.Entities;
public sealed class Medio
{
public int Id { get; }
public string Codigo { get; }
public string Nombre { get; }
public TipoMedio Tipo { get; }
public int? PlataformaEmpresaId { get; }
public bool Activo { get; }
public DateTime FechaCreacion { get; }
public DateTime? FechaModificacion { get; }
public Medio(
int id,
string codigo,
string nombre,
TipoMedio tipo,
int? plataformaEmpresaId,
bool activo,
DateTime fechaCreacion,
DateTime? fechaModificacion)
{
Id = id;
Codigo = codigo;
Nombre = nombre;
Tipo = tipo;
PlataformaEmpresaId = plataformaEmpresaId;
Activo = activo;
FechaCreacion = fechaCreacion;
FechaModificacion = fechaModificacion;
}
/// <summary>
/// Factory for creating a new Medio (Id=0 — DB assigns via IDENTITY; Activo=true; FechaCreacion set by DB default).
/// </summary>
public static Medio ForCreation(string codigo, string nombre, TipoMedio tipo, int? plataformaEmpresaId)
{
return new Medio(
id: 0,
codigo: codigo,
nombre: nombre,
tipo: tipo,
plataformaEmpresaId: plataformaEmpresaId,
activo: true,
fechaCreacion: default,
fechaModificacion: null);
}
/// <summary>
/// Returns a new instance with updated fields. Codigo is immutable (use BD UQ to enforce).
/// Sets FechaModificacion = UtcNow.
/// </summary>
public Medio WithUpdatedProfile(string nombre, TipoMedio tipo, int? plataformaEmpresaId)
=> new(
id: Id,
codigo: Codigo,
nombre: nombre,
tipo: tipo,
plataformaEmpresaId: plataformaEmpresaId,
activo: Activo,
fechaCreacion: FechaCreacion,
fechaModificacion: DateTime.UtcNow);
public Medio WithActivo(bool activo)
=> new(
id: Id,
codigo: Codigo,
nombre: Nombre,
tipo: Tipo,
plataformaEmpresaId: PlataformaEmpresaId,
activo: activo,
fechaCreacion: FechaCreacion,
fechaModificacion: DateTime.UtcNow);
}

View File

@@ -0,0 +1,72 @@
namespace SIGCM2.Domain.Entities;
public sealed class Seccion
{
public int Id { get; }
public int MedioId { get; }
public string Codigo { get; }
public string Nombre { get; }
public string Tipo { get; } // 'clasificados' | 'notables' | 'suplementos' — enforzado por CHECK en BD
public bool Activo { get; }
public DateTime FechaCreacion { get; }
public DateTime? FechaModificacion { get; }
public Seccion(
int id,
int medioId,
string codigo,
string nombre,
string tipo,
bool activo,
DateTime fechaCreacion,
DateTime? fechaModificacion)
{
Id = id;
MedioId = medioId;
Codigo = codigo;
Nombre = nombre;
Tipo = tipo;
Activo = activo;
FechaCreacion = fechaCreacion;
FechaModificacion = fechaModificacion;
}
public static Seccion ForCreation(int medioId, string codigo, string nombre, string tipo)
{
return new Seccion(
id: 0,
medioId: medioId,
codigo: codigo,
nombre: nombre,
tipo: tipo,
activo: true,
fechaCreacion: default,
fechaModificacion: null);
}
/// <summary>
/// Returns a new instance with updated fields. MedioId and Codigo are immutable.
/// Sets FechaModificacion = UtcNow.
/// </summary>
public Seccion WithUpdatedProfile(string nombre, string tipo)
=> new(
id: Id,
medioId: MedioId,
codigo: Codigo,
nombre: nombre,
tipo: tipo,
activo: Activo,
fechaCreacion: FechaCreacion,
fechaModificacion: DateTime.UtcNow);
public Seccion WithActivo(bool activo)
=> new(
id: Id,
medioId: MedioId,
codigo: Codigo,
nombre: Nombre,
tipo: Tipo,
activo: activo,
fechaCreacion: FechaCreacion,
fechaModificacion: DateTime.UtcNow);
}

View File

@@ -0,0 +1,9 @@
namespace SIGCM2.Domain.Entities;
public enum TipoMedio
{
Diario = 1,
Radio = 2,
Web = 3,
Poster = 4,
}

View File

@@ -0,0 +1,15 @@
namespace SIGCM2.Domain.Exceptions;
/// <summary>
/// Thrown when attempting to create a Medio with a Codigo that already exists (global UQ).
/// </summary>
public sealed class MedioCodigoDuplicadoException : DomainException
{
public string Codigo { get; }
public MedioCodigoDuplicadoException(string codigo)
: base($"El medio con código '{codigo}' ya existe.")
{
Codigo = codigo;
}
}

View File

@@ -0,0 +1,15 @@
namespace SIGCM2.Domain.Exceptions;
/// <summary>
/// Thrown when a requested Medio does not exist in the system.
/// </summary>
public sealed class MedioNotFoundException : DomainException
{
public int Id { get; }
public MedioNotFoundException(int id)
: base($"El medio con id '{id}' no existe.")
{
Id = id;
}
}

View File

@@ -0,0 +1,18 @@
namespace SIGCM2.Domain.Exceptions;
/// <summary>
/// Thrown when attempting to create a Seccion with a Codigo that already exists within the same Medio
/// (composite UQ on MedioId + Codigo).
/// </summary>
public sealed class SeccionCodigoDuplicadoEnMedioException : DomainException
{
public int MedioId { get; }
public string Codigo { get; }
public SeccionCodigoDuplicadoEnMedioException(int medioId, string codigo)
: base($"La sección con código '{codigo}' ya existe para el medio {medioId}.")
{
MedioId = medioId;
Codigo = codigo;
}
}

View File

@@ -0,0 +1,15 @@
namespace SIGCM2.Domain.Exceptions;
/// <summary>
/// Thrown when a requested Seccion does not exist in the system.
/// </summary>
public sealed class SeccionNotFoundException : DomainException
{
public int Id { get; }
public SeccionNotFoundException(int id)
: base($"La sección con id '{id}' no existe.")
{
Id = id;
}
}