ADM-009: Tablas Fiscales (IVA + IIBB) — append-only versioned ref data #22

Merged
dmolinari merged 36 commits from feature/ADM-009 into main 2026-04-18 11:45:13 +00:00
Showing only changes of commit 3eda59f5aa - Show all commits

View File

@@ -231,6 +231,91 @@ public sealed class ExceptionFilter : IExceptionFilter
context.ExceptionHandled = true; context.ExceptionHandled = true;
break; break;
// ADM-009: TipoDeIva fiscal exceptions
case PorcentajeInmutableException:
context.Result = new ObjectResult(new
{
error = "inmutable_usar_nueva_version",
message = "El porcentaje de un TipoDeIva es inmutable. Creá una nueva versión vía POST /iva/{id}/nueva-version."
})
{
StatusCode = StatusCodes.Status409Conflict
};
context.ExceptionHandled = true;
break;
case AlicuotaInmutableException:
context.Result = new ObjectResult(new
{
error = "inmutable_usar_nueva_version",
message = "La alícuota de IngresosBrutos es inmutable. Creá una nueva versión vía POST /iibb/{id}/nueva-version."
})
{
StatusCode = StatusCodes.Status409Conflict
};
context.ExceptionHandled = true;
break;
case PredecesorYaCerradoException predecesorYaCerradoEx:
context.Result = new ObjectResult(new
{
error = "predecesora_ya_cerrada",
message = predecesorYaCerradoEx.Message
})
{
StatusCode = StatusCodes.Status409Conflict
};
context.ExceptionHandled = true;
break;
case DuplicateCodigoException duplicateCodigoEx:
context.Result = new ObjectResult(new
{
error = "duplicate_codigo",
message = duplicateCodigoEx.Message
})
{
StatusCode = StatusCodes.Status409Conflict
};
context.ExceptionHandled = true;
break;
case DuplicateProvinciaException duplicateProvinciaEx:
context.Result = new ObjectResult(new
{
error = "duplicate_provincia",
message = duplicateProvinciaEx.Message
})
{
StatusCode = StatusCodes.Status409Conflict
};
context.ExceptionHandled = true;
break;
case TipoDeIvaNotFoundException tipoDeIvaNotFoundEx:
context.Result = new ObjectResult(new
{
error = "tipo_iva_not_found",
message = tipoDeIvaNotFoundEx.Message
})
{
StatusCode = StatusCodes.Status404NotFound
};
context.ExceptionHandled = true;
break;
case IngresosBrutosNotFoundException ingresosBrutosNotFoundEx:
context.Result = new ObjectResult(new
{
error = "ingresos_brutos_not_found",
message = ingresosBrutosNotFoundEx.Message
})
{
StatusCode = StatusCodes.Status404NotFound
};
context.ExceptionHandled = true;
break;
// ADM-008: PuntoDeVenta exceptions // ADM-008: PuntoDeVenta exceptions
case PuntoDeVentaNotFoundException puntoDeVentaNotFoundEx: case PuntoDeVentaNotFoundException puntoDeVentaNotFoundEx:
context.Result = new ObjectResult(new context.Result = new ObjectResult(new
@@ -285,6 +370,21 @@ public sealed class ExceptionFilter : IExceptionFilter
context.ExceptionHandled = true; context.ExceptionHandled = true;
break; break;
// ADM-009: vigencia_desde_invalida — domain throws ArgumentException for invalid vigencia range
case ArgumentException argEx when argEx.Message.Contains("vigencia_desde_invalida") ||
argEx.ParamName == "vigenciaDesde" ||
argEx.Message.Contains("debe ser posterior"):
context.Result = new ObjectResult(new
{
error = "vigencia_desde_invalida",
message = argEx.Message
})
{
StatusCode = StatusCodes.Status400BadRequest
};
context.ExceptionHandled = true;
break;
case ValidationException validationEx: case ValidationException validationEx:
var errors = validationEx.Errors var errors = validationEx.Errors
.GroupBy(e => e.PropertyName) .GroupBy(e => e.PropertyName)