Proyecto: NEBULA ERP
Módulo: Presupuesto
Submódulo: Parámetros
Historia de Usuario: HU-PRE-001
Versión: 1
Fecha: 30/09/2026
Estado: Aceptado
Autor: Equipo Frontend · Centrica
El módulo de Presupuesto requiere que el usuario administrador configure, en una única pantalla, los parámetros generales que gobiernan el comportamiento del sistema: información de la entidad, tipo de presupuesto (público/privado), código CUPIO, vigencia presupuestal, fecha del sistema, regalías, PAC, vigencias futuras, anticipos a contrato y documentos por centros de costos. Adicionalmente, cada modificación debe quedar registrada en una tabla de auditoría.
La HU-PRE-001 define 9 funcionalidades (FN-ALC1-01 a FN-ALC1-09), 14 reglas de negocio (RN-ALC1-01 a RN-ALC1-14) y 11 criterios de aceptación (CA-ALC1-01 a CA-ALC1-11). La complejidad es Media y la prioridad Alta.
El reto técnico no es la captura de datos —es un formulario único que se guarda entero— sino:
version) y auditoría.SystemSyncTopbarDateService.Se implementa la pantalla Parámetros del Sistema como un formulario reactivo único, controlado por un store dedicado, con la lógica condicional repartida entre el store (reglas de negocio puras) y el componente (reglas que dependen del estado del formulario). La persistencia es un PUT completo con control de versión. La fecha del sistema se sincroniza con la topbar. Cada guardado exitoso genera un registro de auditoría en backend.
| Capa | Responsabilidad |
|---|---|
Componente (BudgetParametersComponent) |
FormGroup, validadores condicionales, sincronización form ⇄ store, permisos, toasts, confirmaciones. |
Store (BudgetParametersStore) |
Estado reactivo (signals), reglas de negocio independientes del form, persistencia, manejo de errores, sessionStorage. |
Layout (budget-parameters.layout.ts) |
Distribución visual declarativa con secciones condicionales. |
Servicio (ServiceBudgetParameters) |
HTTP: getParametros, getCupioOptions, updateParametros. |
i18n (BUDGET_PARAMETERS) |
Claves centralizadas, sin literales sueltos. |
La decisión clave fue no duplicar validaciones entre store y componente. Cada regla vive en un solo lugar:
| Tipo de regla | Dónde vive | Por qué |
|---|---|---|
| Reglas puras (no dependen de tocar un control): CUPIO obligatorio si es pública, fecha contra último cierre, cambio detectado. | Store | Se pueden probar aisladas y no requieren el FormGroup. |
| Reglas condicionales (dependen del estado de un control): porcentaje de anticipo, vigencia inicial de regalía, CUPIO si el usuario acaba de cambiar el toggle. | Componente (FormControl) | Necesitan la interacción del usuario y el ciclo de vida del form. |
| Reglas de formato (patrón, rango, required básico) | Componente (Validators) |
Viven en el FormControl. |
Esta separación se refleja en los tests: el store no valida presupuestoRegalia, afectaPac, vigenciaInicialRegalia ni porcentajeAnticipo; el componente sí. Duplicarlas bloqueaba el botón Guardar antes de que el usuario pudiera diligenciar el campo.
El store expone signals de solo lectura (loading, saving, currentValues, hasChanges, cupioOptions, vigenciaFinalCalculada, fechaSistemaError, minDate, canSave) y el componente añade signals propios para el layout (esEntidadPublica, tieneRegalia, realizaAnticipos, tipoProcesoReserva, fechaAutomatica).
La sincronización store → form se hace con un effect() que escribe solo si el valor cambió (setIfChanged) y respeta isUpdatingFromStore para evitar bucles. La sincronización form → store se hace con una suscripción a valueChanges que despacha cada campo a su regla.
PUT completo con UpdateBudgetParametersPayload.version: el payload incluye la versión original.sessionStorage:
BUDGET_PARAMETERS_STORAGE_KEY: borrador del formulario para no perder cambios al recargar.BUDGET_PARAMETERS_PENDING_SAVE_KEY: payload pendiente por si la petición se interrumpe.fechaSistema devuelto se propaga vía SystemSyncTopbarDateService.updateSystemDate().afectaPresupuestoPublico = 'S'.presupuestoRegalia = 'S'; debe ser ≥ vigencia configurada de la entidad.inicial + 1 y bloqueada.realizaAnticipos = 'S'.tipoEntidad y version son siempre de solo lectura.hasChanges).canDeactivate) pide confirmación al salir con cambios.PageContainer, DialogService, NebulaToastService.| ID | Requisito | Estado |
|---|---|---|
| FN-ALC1-01 | Carga inicial de datos fijos (NIT, DV, Nombre) en solo lectura | ✅ |
| FN-ALC1-02 | Toggle "Afecta Presupuesto Público" controla CUPIO, PAC y Regalías | ✅ |
| FN-ALC1-03 | Selección de Código CUPIO con autocompletado de Tipo de Entidad | ✅ |
| FN-ALC1-04 | Control de vigencia (4 dígitos, positivos) | ✅ |
| FN-ALC1-05 | Fecha del sistema editable o automática, validada contra último cierre | ✅ |
| FN-ALC1-06 | Regalías: vigencias inicial/final condicionales (final = inicial + 1) | ✅ |
| FN-ALC1-07 | Procesos presupuestales: PAC, Vigencia Futura, Centros de Costos, tipo de reserva | ✅ |
| FN-ALC1-08 | Anticipos a contrato: porcentaje condicional | ✅ |
| FN-ALC1-09 | Guardar y Cancelar con confirmación, validaciones, persistencia y auditoría | ✅ |
| RN-ALC1-01 a RN-ALC1-14 | Reglas de negocio | ✅ |
| CA-ALC1-01 a CA-ALC1-11 | Criterios de aceptación | ✅ |
budget-parameters.store.tsbudget-parameters.component.tsbudget-parameters.layout.tsbudget-parameters.constants.ts (claves i18n BUDGET_PARAMETERS).ServiceBudgetParameters (data-access).SystemSyncTopbarDateService (shared/data-access).vigencia inicial + 1, siempre bloqueada.isUpdatingFromStore: bandera que evita que los efectos reaccionen a escrituras provenientes del propio store.