2026-04-13 21:36:01 -03:00
|
|
|
using FluentValidation;
|
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
|
using SIGCM2.Application.Abstractions;
|
|
|
|
|
using SIGCM2.Application.Auth.Login;
|
2026-04-14 13:28:36 -03:00
|
|
|
using SIGCM2.Application.Auth.Logout;
|
|
|
|
|
using SIGCM2.Application.Auth.Refresh;
|
2026-04-15 17:46:23 -03:00
|
|
|
using SIGCM2.Application.Common;
|
2026-04-16 18:53:57 -03:00
|
|
|
using SIGCM2.Application.Medios.Create;
|
|
|
|
|
using SIGCM2.Application.Medios.Deactivate;
|
|
|
|
|
using SIGCM2.Application.Medios.GetById;
|
|
|
|
|
using SIGCM2.Application.Medios.List;
|
|
|
|
|
using SIGCM2.Application.Medios.Reactivate;
|
|
|
|
|
using SIGCM2.Application.Medios.Update;
|
2026-04-15 15:31:26 -03:00
|
|
|
using SIGCM2.Application.Permisos.Assign;
|
|
|
|
|
using SIGCM2.Application.Permisos.Dtos;
|
|
|
|
|
using SIGCM2.Application.Permisos.GetByRol;
|
|
|
|
|
using SIGCM2.Application.Permisos.List;
|
2026-04-15 12:50:24 -03:00
|
|
|
using SIGCM2.Application.Roles.Create;
|
|
|
|
|
using SIGCM2.Application.Roles.Deactivate;
|
|
|
|
|
using SIGCM2.Application.Roles.Dtos;
|
|
|
|
|
using SIGCM2.Application.Roles.Get;
|
|
|
|
|
using SIGCM2.Application.Roles.List;
|
|
|
|
|
using SIGCM2.Application.Roles.Update;
|
fix(adm-008): correcciones del verify loop
Seis ajustes post-verify detectados durante la corrida full de tests:
1. PuntoDeVentaRepository: UQ_PuntoDeVenta_Medio_AFIP (no _MedioId_NumeroAFIP)
— el catch de unique violation no disparaba → 500 en race duplicado.
2. Application.DependencyInjection: registro de 8 handlers PuntosDeVenta
— sin esto, dispatcher arrojaba "No service registered" → 500.
3. ReservarNumeroCommandHandler: backoff ampliado a 5 retries
[25, 75, 200, 500, 1200]ms para soportar 50 threads concurrentes.
4. SecuenciaComprobante: SYSTEM_VERSIONING = OFF (AD8 revisitado).
Under UPDATE concurrente sobre misma fila, el engine arroja
"transaction time earlier than period start time" — limitación
conocida de Temporal Tables con alta contención de UPDATEs.
Decisión: secuencia es operacional, no configuración → sin history.
V013 y SqlTestFixture actualizados para ser idempotentes.
5. SqlTestFixture: EnsureV013SchemaAsync idempotente + PuntoDeVenta_History
en TablesToIgnore + permiso administracion:puntos_de_venta:gestionar
en seed canónico + asignación a rol admin.
6. Tests: conteos 22→23 permisos (V013 agrega uno); repository fixtures
ignoran PuntoDeVenta_History; test UpdatePdv_WhenPdvInactive eliminado
(over-specified — spec no bloquea update en PdV inactivo, solo en Medio
padre inactivo; alineado con frontend que permite editar PdV inactivo).
Resultado: 190/190 Api.Tests y tests específicos ADM-008 verdes
(Domain 13, Application 42, Api 21 = 76 tests nuevos). El único failure
residual (AuditEventRepositoryTests.QueryAsync_Limit_EmitsCursor) es
pre-existente y no relacionado a ADM-008.
Covers: verify report CRITICAL (UQ name mismatch) + WARNINGs descubiertos
durante la ejecución (DI registro, temporal tables concurrency, permiso
fixture, counts de tests pre-existentes).
2026-04-17 13:02:35 -03:00
|
|
|
using SIGCM2.Application.PuntosDeVenta.Create;
|
|
|
|
|
using SIGCM2.Application.PuntosDeVenta.Deactivate;
|
|
|
|
|
using SIGCM2.Application.PuntosDeVenta.GetById;
|
|
|
|
|
using SIGCM2.Application.PuntosDeVenta.List;
|
|
|
|
|
using SIGCM2.Application.PuntosDeVenta.Reactivate;
|
|
|
|
|
using SIGCM2.Application.PuntosDeVenta.Update;
|
2026-04-17 18:09:52 -03:00
|
|
|
using SIGCM2.Application.TiposDeIva.Create;
|
|
|
|
|
using SIGCM2.Application.TiposDeIva.Deactivate;
|
|
|
|
|
using SIGCM2.Application.TiposDeIva.Dtos;
|
|
|
|
|
using SIGCM2.Application.TiposDeIva.GetById;
|
|
|
|
|
using SIGCM2.Application.TiposDeIva.GetHistorial;
|
|
|
|
|
using SIGCM2.Application.TiposDeIva.List;
|
|
|
|
|
using SIGCM2.Application.TiposDeIva.NuevaVersion;
|
|
|
|
|
using SIGCM2.Application.TiposDeIva.Reactivate;
|
|
|
|
|
using SIGCM2.Application.TiposDeIva.Update;
|
|
|
|
|
using SIGCM2.Application.IngresosBrutos.Create;
|
|
|
|
|
using SIGCM2.Application.IngresosBrutos.Deactivate;
|
|
|
|
|
using SIGCM2.Application.IngresosBrutos.Dtos;
|
|
|
|
|
using SIGCM2.Application.IngresosBrutos.GetById;
|
|
|
|
|
using SIGCM2.Application.IngresosBrutos.GetHistorial;
|
|
|
|
|
using SIGCM2.Application.IngresosBrutos.List;
|
|
|
|
|
using SIGCM2.Application.IngresosBrutos.NuevaVersion;
|
|
|
|
|
using SIGCM2.Application.IngresosBrutos.Reactivate;
|
|
|
|
|
using SIGCM2.Application.IngresosBrutos.Update;
|
2026-04-16 18:53:57 -03:00
|
|
|
using SIGCM2.Application.Secciones.Create;
|
|
|
|
|
using SIGCM2.Application.Secciones.Deactivate;
|
|
|
|
|
using SIGCM2.Application.Secciones.GetById;
|
|
|
|
|
using SIGCM2.Application.Secciones.List;
|
|
|
|
|
using SIGCM2.Application.Secciones.Reactivate;
|
|
|
|
|
using SIGCM2.Application.Secciones.Update;
|
2026-04-15 17:46:23 -03:00
|
|
|
using SIGCM2.Application.Usuarios.ChangeMyPassword;
|
2026-04-15 10:47:48 -03:00
|
|
|
using SIGCM2.Application.Usuarios.Create;
|
2026-04-15 17:46:23 -03:00
|
|
|
using SIGCM2.Application.Usuarios.Deactivate;
|
|
|
|
|
using SIGCM2.Application.Usuarios.GetById;
|
|
|
|
|
using SIGCM2.Application.Usuarios.List;
|
|
|
|
|
using SIGCM2.Application.Usuarios.Reactivate;
|
|
|
|
|
using SIGCM2.Application.Usuarios.ResetPassword;
|
2026-04-15 21:43:08 -03:00
|
|
|
using SIGCM2.Application.Usuarios.Permisos;
|
2026-04-15 17:46:23 -03:00
|
|
|
using SIGCM2.Application.Usuarios.Update;
|
2026-04-13 21:36:01 -03:00
|
|
|
|
|
|
|
|
namespace SIGCM2.Application;
|
|
|
|
|
|
|
|
|
|
public static class DependencyInjection
|
|
|
|
|
{
|
|
|
|
|
public static IServiceCollection AddApplication(this IServiceCollection services)
|
|
|
|
|
{
|
2026-04-18 09:44:21 -03:00
|
|
|
// UDT-011: TimeProvider singleton — available to all handlers for Cat2 date computation
|
|
|
|
|
services.AddSingleton(TimeProvider.System);
|
|
|
|
|
|
2026-04-14 13:28:36 -03:00
|
|
|
// Command handlers
|
2026-04-13 21:36:01 -03:00
|
|
|
services.AddScoped<ICommandHandler<LoginCommand, LoginResponseDto>, LoginCommandHandler>();
|
2026-04-14 13:28:36 -03:00
|
|
|
services.AddScoped<ICommandHandler<RefreshCommand, RefreshResponseDto>, RefreshCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<LogoutCommand, LogoutResponseDto>, LogoutCommandHandler>();
|
2026-04-15 10:47:48 -03:00
|
|
|
services.AddScoped<ICommandHandler<CreateUsuarioCommand, UsuarioCreatedDto>, CreateUsuarioCommandHandler>();
|
2026-04-13 21:36:01 -03:00
|
|
|
|
2026-04-15 12:50:24 -03:00
|
|
|
// Roles (UDT-004)
|
|
|
|
|
services.AddScoped<ICommandHandler<ListRolesQuery, IReadOnlyList<RolDto>>, ListRolesQueryHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<GetRolByCodigoQuery, RolDto>, GetRolByCodigoQueryHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<CreateRolCommand, RolCreatedDto>, CreateRolCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<UpdateRolCommand, RolDto>, UpdateRolCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<DeactivateRolCommand, RolDto>, DeactivateRolCommandHandler>();
|
|
|
|
|
|
2026-04-15 15:31:26 -03:00
|
|
|
// Permisos (UDT-005)
|
|
|
|
|
services.AddScoped<ICommandHandler<ListPermisosQuery, IReadOnlyList<PermisoDto>>, ListPermisosQueryHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<GetRolPermisosQuery, IReadOnlyList<PermisoDto>>, GetRolPermisosQueryHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<AssignPermisosToRolCommand, IReadOnlyList<PermisoDto>>, AssignPermisosToRolCommandHandler>();
|
|
|
|
|
|
2026-04-15 17:46:23 -03:00
|
|
|
// Usuarios (UDT-008)
|
|
|
|
|
services.AddScoped<ICommandHandler<ListUsuariosQuery, PagedResult<UsuarioListItemDto>>, ListUsuariosQueryHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<GetUsuarioByIdQuery, UsuarioDetailDto>, GetUsuarioByIdQueryHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<UpdateUsuarioCommand, UsuarioDetailDto>, UpdateUsuarioCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<DeactivateUsuarioCommand, UsuarioDetailDto>, DeactivateUsuarioCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<ReactivateUsuarioCommand, UsuarioDetailDto>, ReactivateUsuarioCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<ChangeMyPasswordCommand, Unit>, ChangeMyPasswordCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<ResetUsuarioPasswordCommand, ResetUsuarioPasswordResponse>, ResetUsuarioPasswordCommandHandler>();
|
|
|
|
|
|
2026-04-15 21:43:08 -03:00
|
|
|
// Usuarios/Permisos (UDT-009)
|
|
|
|
|
services.AddScoped<ICommandHandler<GetUsuarioPermisosQuery, UsuarioPermisosDto>, GetUsuarioPermisosQueryHandler>();
|
2026-04-15 21:43:38 -03:00
|
|
|
services.AddScoped<ICommandHandler<UpdateUsuarioPermisosOverridesCommand, UsuarioPermisosDto>, UpdateUsuarioPermisosOverridesCommandHandler>();
|
2026-04-15 21:43:08 -03:00
|
|
|
|
2026-04-16 18:53:57 -03:00
|
|
|
// Medios (ADM-001)
|
|
|
|
|
services.AddScoped<ICommandHandler<CreateMedioCommand, MedioCreatedDto>, CreateMedioCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<UpdateMedioCommand, MedioUpdatedDto>, UpdateMedioCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<DeactivateMedioCommand, MedioStatusDto>, DeactivateMedioCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<ReactivateMedioCommand, MedioStatusDto>, ReactivateMedioCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<ListMediosQuery, PagedResult<MedioListItemDto>>, ListMediosQueryHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<GetMedioByIdQuery, MedioDetailDto>, GetMedioByIdQueryHandler>();
|
|
|
|
|
|
|
|
|
|
// Secciones (ADM-001)
|
|
|
|
|
services.AddScoped<ICommandHandler<CreateSeccionCommand, SeccionCreatedDto>, CreateSeccionCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<UpdateSeccionCommand, SeccionUpdatedDto>, UpdateSeccionCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<DeactivateSeccionCommand, SeccionStatusDto>, DeactivateSeccionCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<ReactivateSeccionCommand, SeccionStatusDto>, ReactivateSeccionCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<ListSeccionesQuery, PagedResult<SeccionListItemDto>>, ListSeccionesQueryHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<GetSeccionByIdQuery, SeccionDetailDto>, GetSeccionByIdQueryHandler>();
|
|
|
|
|
|
fix(adm-008): correcciones del verify loop
Seis ajustes post-verify detectados durante la corrida full de tests:
1. PuntoDeVentaRepository: UQ_PuntoDeVenta_Medio_AFIP (no _MedioId_NumeroAFIP)
— el catch de unique violation no disparaba → 500 en race duplicado.
2. Application.DependencyInjection: registro de 8 handlers PuntosDeVenta
— sin esto, dispatcher arrojaba "No service registered" → 500.
3. ReservarNumeroCommandHandler: backoff ampliado a 5 retries
[25, 75, 200, 500, 1200]ms para soportar 50 threads concurrentes.
4. SecuenciaComprobante: SYSTEM_VERSIONING = OFF (AD8 revisitado).
Under UPDATE concurrente sobre misma fila, el engine arroja
"transaction time earlier than period start time" — limitación
conocida de Temporal Tables con alta contención de UPDATEs.
Decisión: secuencia es operacional, no configuración → sin history.
V013 y SqlTestFixture actualizados para ser idempotentes.
5. SqlTestFixture: EnsureV013SchemaAsync idempotente + PuntoDeVenta_History
en TablesToIgnore + permiso administracion:puntos_de_venta:gestionar
en seed canónico + asignación a rol admin.
6. Tests: conteos 22→23 permisos (V013 agrega uno); repository fixtures
ignoran PuntoDeVenta_History; test UpdatePdv_WhenPdvInactive eliminado
(over-specified — spec no bloquea update en PdV inactivo, solo en Medio
padre inactivo; alineado con frontend que permite editar PdV inactivo).
Resultado: 190/190 Api.Tests y tests específicos ADM-008 verdes
(Domain 13, Application 42, Api 21 = 76 tests nuevos). El único failure
residual (AuditEventRepositoryTests.QueryAsync_Limit_EmitsCursor) es
pre-existente y no relacionado a ADM-008.
Covers: verify report CRITICAL (UQ name mismatch) + WARNINGs descubiertos
durante la ejecución (DI registro, temporal tables concurrency, permiso
fixture, counts de tests pre-existentes).
2026-04-17 13:02:35 -03:00
|
|
|
// Puntos de Venta (ADM-008)
|
|
|
|
|
services.AddScoped<ICommandHandler<CreatePuntoDeVentaCommand, PuntoDeVentaCreatedDto>, CreatePuntoDeVentaCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<UpdatePuntoDeVentaCommand, PuntoDeVentaUpdatedDto>, UpdatePuntoDeVentaCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<DeactivatePuntoDeVentaCommand, PuntoDeVentaStatusDto>, DeactivatePuntoDeVentaCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<ReactivatePuntoDeVentaCommand, PuntoDeVentaStatusDto>, ReactivatePuntoDeVentaCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<ListPuntosDeVentaQuery, PagedResult<PuntoDeVentaListItemDto>>, ListPuntosDeVentaQueryHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<GetPuntoDeVentaByIdQuery, PuntoDeVentaDetailDto>, GetPuntoDeVentaByIdQueryHandler>();
|
|
|
|
|
|
2026-04-17 18:09:52 -03:00
|
|
|
// Tipos de IVA (ADM-009)
|
|
|
|
|
services.AddScoped<ICommandHandler<CreateTipoDeIvaCommand, TipoDeIvaDto>, CreateTipoDeIvaCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<UpdateTipoDeIvaCommand, TipoDeIvaDto>, UpdateTipoDeIvaCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<NuevaVersionTipoDeIvaCommand, NuevaVersionResultDto>, NuevaVersionTipoDeIvaCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<DeactivateTipoDeIvaCommand, TipoDeIvaDto>, DeactivateTipoDeIvaCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<ReactivateTipoDeIvaCommand, TipoDeIvaDto>, ReactivateTipoDeIvaCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<GetTipoDeIvaByIdQuery, TipoDeIvaDto>, GetTipoDeIvaByIdQueryHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<ListTiposDeIvaQuery, PagedResult<TipoDeIvaDto>>, ListTiposDeIvaQueryHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<GetHistorialTipoDeIvaQuery, IReadOnlyList<HistorialCadenaDto>>, GetHistorialTipoDeIvaQueryHandler>();
|
|
|
|
|
|
|
|
|
|
// Ingresos Brutos (ADM-009)
|
|
|
|
|
services.AddScoped<ICommandHandler<CreateIngresosBrutosCommand, IngresosBrutosDto>, CreateIngresosBrutosCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<UpdateIngresosBrutosCommand, IngresosBrutosDto>, UpdateIngresosBrutosCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<NuevaVersionIngresosBrutosCommand, NuevaVersionIibbResultDto>, NuevaVersionIngresosBrutosCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<DeactivateIngresosBrutosCommand, IngresosBrutosDto>, DeactivateIngresosBrutosCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<ReactivateIngresosBrutosCommand, IngresosBrutosDto>, ReactivateIngresosBrutosCommandHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<GetIngresosBrutosByIdQuery, IngresosBrutosDto>, GetIngresosBrutosByIdQueryHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<ListIngresosBrutosQuery, PagedResult<IngresosBrutosDto>>, ListIngresosBrutosQueryHandler>();
|
|
|
|
|
services.AddScoped<ICommandHandler<GetHistorialIngresosBrutosQuery, IReadOnlyList<HistorialCadenaIibbDto>>, GetHistorialIngresosBrutosQueryHandler>();
|
|
|
|
|
|
2026-04-14 13:28:36 -03:00
|
|
|
// FluentValidation validators (scans entire Application assembly)
|
2026-04-13 21:36:01 -03:00
|
|
|
services.AddValidatorsFromAssemblyContaining<LoginCommandValidator>();
|
|
|
|
|
|
|
|
|
|
return services;
|
|
|
|
|
}
|
|
|
|
|
}
|