Skip to content

Ajustes de navegación + motivo de cancelación + color de estado

Date: 2026-07-25 Status: ✅ Aprobado, validado visualmente — listo para aplicar

Los 4 cambios

1. Auditoría pasa de Administración a Operación

Es una vista de consulta operativa (quién hizo qué, cuándo), no un ABM de configuración — tiene más sentido agrupada con Transacciones/Prefondeo/Reportes. Ver reference/AppLayout.vue, el array nav.

Antes vivía en un botón al pie del sidebar, poco visible. Ahora está en la esquina superior derecha del sidebar, junto al logo — visible sin tener que mirar hacia abajo. En estado colapsado, queda como una franja angosta debajo del ícono (con la flecha invertida para expandir), en vez de desaparecer.

3. Motivo de cancelación — combo requerido + opción de agregar uno nuevo

Nuevo componente CancelReasonSelect.vue, integrado en ConfirmActionModal.vue cuando variant="cancel":

  • Combo con motivos predefinidos + una opción "+ Agregar nueva razón..." al final.
  • Al elegir "agregar nueva", se abre un input para cargar el texto — al confirmar, el motivo nuevo queda seleccionado y disponible en la lista para la próxima vez (estado local del componente en esta referencia; en la implementación real debería persistir en el backend, ver pregunta abierta abajo).
  • El botón de confirmar cancelación queda deshabilitado hasta elegir un motivo — no se puede cancelar sin uno.
  • El evento @confirm del modal ahora manda { motivo: string | null } en vez de no mandar nada — si ConfirmActionModal ya está integrado en TransaccionDetalleView.vue con variant="pay", ese caso no se rompe (el payload siempre se manda, motivo es null para pagos). Si ya hay un handler de @confirm sin parámetro en el código real, hay que agregarle el parámetro.

⚠️ Pregunta abierta, no bloqueante — a resolver antes de M5 (integración real con Soterex): los 3 motivos "de fábrica" que puse (cancelada_remitente, ajuste_beneficiario, ajuste_monto) son justo los 3 sub_status que ya define la API de Soterex para cancelaciones (códigos 1000/1001/1002 del spec, ver doc/site/public/openapi.yaml). Pero un motivo nuevo cargado por un usuario no tiene ningún código de Soterex asociado, y el Cancel API exige sub_status: {code, message} para poder llamarse. Falta definir con el cliente: ¿los motivos nuevos se mandan a Soterex con un código genérico "otro" (si existe), o quedan como dato interno de auditoría/reporting y la llamada real a Soterex siempre usa uno de los 3 códigos oficiales por detrás? No bloquea nada de lo que se implementa ahora — M5 está bloqueado por otras razones ya documentadas (Pregunta Abierta #2b del funcional).

4. Color de ACCEPTED: de azul apagado a azul más vívido

Historial completo, porque zigzagueamos en vivo hasta llegar acá: se probó primero cambiarlo a amarillo (pedido inicial, buscando más contraste), pero al verlo al lado de la alerta de "saldo insuficiente" (que usa un ámbar) se pisaban visualmente — abandonado. Se volvió a azul, pero un tono más vívido que el original (#3B7DDB en vez de #5B7FA6) para que sí contraste bien contra el resto de la paleta (verde de PAID, gris de CANCELLED, ámbar/rojo de alertas). Este es el valor final, aprobado.

Archivos de referencia adjuntos (reference/)

  • AppLayout.vue — nav reorganizado + colapso en el header
  • style.css — color final de --color-status-info
  • CancelReasonSelect.vue — componente nuevo
  • ConfirmActionModal.vue — integración del selector de motivo + evento confirm con payload

Checklist de integración

  • [x] Mergear el array nav de AppLayout.vue (Auditoría en Operación) — con cuidado si el código real ya tiene lógica de permisos por ítem de nav, preservarla. (La lógica de isVisible()/meStore.canRead() no se tocó — es indiferente a qué grupo del array pertenece cada ítem.)
  • [x] Mergear el layout del header/colapso de AppLayout.vue.
  • [x] Copiar CancelReasonSelect.vue a frontend/src/components/.
  • [x] Integrar el selector en el flujo real de cancelación (TransaccionDetalleView.vue), actualizando el handler de @confirm para recibir { motivo }.
  • [x] Actualizar --color-status-info en style.css al valor final (#3B7DDB / dark #6FA3E8).
  • [x] Adicional, no estaba en el checklist original: el motivo también se manda al backend (TransactionController::cancel() acepta motivo opcional) y queda en la metadata del audit log TRANSACTION_STATUS_CHANGE — texto libre, mismo patrón JSONB que ya usan todos los demás audit logs. No resuelve la pregunta de mapeo a sub_status de Soterex (sigue abierta abajo), solo evita que el dato se capture y se descarte sin dejar rastro. 2 tests nuevos (117 en total).
  • [ ] Decidir (o dejar como TODO explícito en el código) la pregunta abierta del punto 3 antes de que M5 llame de verdad al Cancel API de Soterex — anotada también en el M5 de doc/plans/2026-07-25-plan-desarrollo-modulos.md, para que no se pierda solo en este doc.

Verificado: suite completa de backend (117 tests) + vue-tsc/vite build limpios + round-trip real contra el stack (cancelar una transacción ACCEPTED con motivo vía curl, confirmado en /api/admin/auditoria que la metadata trae motivo). No verificado en navegador real (sin herramienta de browser disponible en la sesión) — ver doc/qa/ si corresponde agregar un ítem de QA manual para el combo de motivo y el nuevo layout del sidebar.

Documentación viva — se actualiza junto con el código, no es un anexo aparte.