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.
2. Flecha de colapso del sidebar, movida al header (junto al logo)
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
@confirmdel modal ahora manda{ motivo: string | null }en vez de no mandar nada — siConfirmActionModalya está integrado enTransaccionDetalleView.vueconvariant="pay", ese caso no se rompe (el payload siempre se manda,motivoesnullpara pagos). Si ya hay un handler de@confirmsin 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 headerstyle.css— color final de--color-status-infoCancelReasonSelect.vue— componente nuevoConfirmActionModal.vue— integración del selector de motivo + eventoconfirmcon payload
Checklist de integración
- [x] Mergear el array
navdeAppLayout.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 deisVisible()/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.vueafrontend/src/components/. - [x] Integrar el selector en el flujo real de cancelación (
TransaccionDetalleView.vue), actualizando el handler de@confirmpara recibir{ motivo }. - [x] Actualizar
--color-status-infoenstyle.cssal valor final (#3B7DDB/ dark#6FA3E8). - [x] Adicional, no estaba en el checklist original: el motivo también se manda al backend (
TransactionController::cancel()aceptamotivoopcional) y queda en la metadata del audit logTRANSACTION_STATUS_CHANGE— texto libre, mismo patrón JSONB que ya usan todos los demás audit logs. No resuelve la pregunta de mapeo asub_statusde 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
CancelAPI de Soterex — anotada también en el M5 dedoc/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.

