feat(domain): Medio + Seccion entities + 4 exceptions — ADM-001 B2
Entities sealed immutable con factory ForCreation + copy-with methods WithUpdatedProfile/WithActivo (Codigo inmutable en Medio; MedioId y Codigo inmutables en Seccion — enforzado en Validators en B4). Exceptions: MedioCodigoDuplicado (UQ global), SeccionCodigoDuplicadoEnMedio (UQ compuesto), MedioNotFound, SeccionNotFound. Todas heredan de DomainException.
This commit is contained in:
75
src/api/SIGCM2.Domain/Entities/Medio.cs
Normal file
75
src/api/SIGCM2.Domain/Entities/Medio.cs
Normal 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);
|
||||||
|
}
|
||||||
72
src/api/SIGCM2.Domain/Entities/Seccion.cs
Normal file
72
src/api/SIGCM2.Domain/Entities/Seccion.cs
Normal 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);
|
||||||
|
}
|
||||||
9
src/api/SIGCM2.Domain/Entities/TipoMedio.cs
Normal file
9
src/api/SIGCM2.Domain/Entities/TipoMedio.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace SIGCM2.Domain.Entities;
|
||||||
|
|
||||||
|
public enum TipoMedio
|
||||||
|
{
|
||||||
|
Diario = 1,
|
||||||
|
Radio = 2,
|
||||||
|
Web = 3,
|
||||||
|
Poster = 4,
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/api/SIGCM2.Domain/Exceptions/MedioNotFoundException.cs
Normal file
15
src/api/SIGCM2.Domain/Exceptions/MedioNotFoundException.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/api/SIGCM2.Domain/Exceptions/SeccionNotFoundException.cs
Normal file
15
src/api/SIGCM2.Domain/Exceptions/SeccionNotFoundException.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user