# Plan de Mejoras UX — Módulo Importaciones

**Fecha**: 2026-04-27
**Principio guía**: ¿Esto hace la vida del usuario más fácil y rápida?
**Alcance**: Mejoras sobre la UI existente (sin cambios de backend ni nuevas funcionalidades)

---

## Diagnóstico por pantalla

### Problemas transversales
- Campos obligatorios del backend no marcados con `*` ni color diferente en el frontend
- Sin texto de ayuda (`helperText`) en campos técnicos (NCM, CBM, FOB, ISC...)
- Sin agrupación visual de campos relacionados (todas las cajas en una grilla plana)
- Botones de estado con nombres internos (`→ EN_TRANSITO`) en vez de lenguaje de negocio
- Sin feedback preventivo — el usuario solo descubre errores al hacer click en Guardar
- Sin indicación de "qué debo completar primero" para avanzar en el flujo

---

## Mejoras por componente

---

### 1. `EmbarqueFormDialog` — "Nuevo / Editar embarque"

#### Problemas actuales
- Modalidad es texto libre — el usuario no sabe qué valores son válidos
- Campos no agrupados: logística (puertos, modalidad), documentos (BL, booking), fechas, y financiero (cotización) todos mezclados
- "Cotización cierre" visible al crear, pero solo aplica al cerrar el despacho
- "ETA" sin explicación — un usuario nuevo no sabe que es la fecha estimada de arribo
- Moneda no marcada como obligatoria aunque el backend la requiere para calcular costos

#### Cambios a implementar

**a) Agrupar campos con secciones visuales (`Divider` + `Typography` caption):**

```
[Proveedor y origen]       → Proveedor*, Moneda*, País origen*
[Ruta y logística]         → Puerto origen, Puerto destino, Modalidad (select), Booking, Bill of Lading
[Fechas]                   → Fecha embarque, ETA (con tooltip "Estimated Time of Arrival"), Arribo real
[Notas]                    → Notas (solo en edición, o colapsable al crear)
```

**b) Convertir `Modalidad` en `TextField select`** con opciones:
```
RoRo | FCL 20' | FCL 40' | FCL 40' HC | LCL
```

**c) Marcar campos requeridos** (`required` en TextField + asterisco):
- Proveedor: ya tiene lógica en `disabled={!proveedor?.id}` pero no comunica por qué
- Moneda: agregar `required` visual

**d) Ocultar "Cotización cierre"** del formulario de creación. Solo mostrarlo en edición cuando el embarque ya tiene despacho.

**e) Agregar `helperText` a campos técnicos:**
```
Bill of Lading → "Número del documento de transporte marítimo"
Booking        → "Número de reserva con la naviera"
ETA            → "Fecha estimada de arribo al puerto destino"
```

**f) Tooltip en el campo `Proveedor`**: "Seleccioná al proveedor extranjero del embarque"

**g) Alert de contexto al abrir (solo en creación):**
```
ℹ️ Campos marcados con * son obligatorios. Podrás agregar ítems y costos después de guardar.
```

---

### 2. `ItemFormDialog` — "Agregar / Editar ítem" (perfil AUTOS)

#### Problemas actuales
- "CC" como label — debería decir "Cilindrada (cc)"
- "FOB unitario USD*" es el campo más importante pero aparece al final
- "Lote subasta", "Inland origen USD", "Cantidad de dueños" sin ninguna descripción
- "Orden" — nadie sabe para qué sirve en este contexto
- Todos los campos del mismo peso visual — no se distingue cuáles son esenciales vs. opcionales

#### Cambios a implementar

**a) Reorganizar por secciones:**
```
[Identificación]   → Chasis* (con validación 17 chars VIN), Motor, Marca*, Modelo*, Año*
[Especificaciones] → Versión, Cilindrada (cc)*, Color, Kilometraje, Cantidad dueños
[Origen y precio]  → FOB unitario USD*, Inland origen USD, Lote subasta
```

**b) Mejorar labels y helperText:**
```
Chasis           → label: "Chasis (VIN)*"     helperText: "17 caracteres — se convierte en código de producto"
CC               → label: "Cilindrada (cc)*"
Lote subasta     → helperText: "Número de lote en la subasta de origen (opcional)"
Inland origen    → label: "Inland origen USD" helperText: "Flete interno desde subasta hasta puerto de embarque (opcional)"
Cantidad dueños  → label: "N° de dueños anteriores" helperText: "0 = vehículo 0 km"
Orden            → mover al final, helperText: "Número de orden dentro del embarque (opcional)"
```

**c) Mover `FOB unitario USD` al inicio de la sección de precios** — es el campo más crítico

**d) Validación visual del chasis**: mostrar contador de caracteres `(X/17)` en tiempo real y color rojo si no tiene 17

**e) Preview de "FOB total" más prominente** — actualmente es una caja gris al costado, darle más peso visual con color de acento

---

### 3. `ItemFormDialog` — "Agregar / Editar ítem" (perfil CONSUMO_MASIVO)

#### Problemas actuales
- "SKU interno (mapeo)" sin explicación — ¿qué es mapeo?
- "NCM" sin ninguna ayuda — código arancelario que el usuario debe saber de antemano
- "CBM unit." — unidad volumétrica desconocida para muchos
- "Arancel %" e "ISC %" sin explicación de de dónde vienen ni cómo afectan

#### Cambios a implementar

**a) `helperText` por campo:**
```
SKU interno (mapeo) → "Producto en el catálogo interno al que se mapea este ítem del proveedor"
SKU proveedor       → "Código del artículo en la factura del proveedor extranjero"
NCM                 → "Nomenclatura Común del Mercosur — código arancelario (ej: 8703.23.10)"
CBM unit.           → "Volumen en metros cúbicos por unidad"
Arancel %           → "Porcentaje de arancel de importación"
ISC %               → "Impuesto Selectivo al Consumo aplicable al artículo"
```

**b) Tooltip de información** en los campos NCM, Arancel %, ISC % con ícono `?` que explique cómo obtener el valor

---

### 4. `CostoFormDialog` — "Agregar / Editar costo"

#### Problemas actuales
- "Costo directo a un ítem" sin contexto — ¿por qué importa? ¿cuándo usarlo?
- "Prorrateo" con opciones FOB/PESO/CBM/CANTIDAD/IGUAL sin ninguna explicación
- "Fecha devengo" vs "Fecha pago" — diferencia no obvia para un no-contador
- "Gasto extra de gestión" — ¿qué califica como gasto extra?
- El importe no muestra la moneda de forma dinámica al cambiar el selector
- Cotización hardcodeada en `1` — no sugerida automáticamente desde `cont_tipo_cambio`

#### Cambios a implementar

**a) Secciones claras:**
```
[¿Qué costo es?]           → Concepto*, Moneda, Descripción libre
[¿De quién?]               → Proveedor (opcional), N° factura
[¿Cómo se aplica?]         → Toggle "Costo directo a un ítem" + ítem / Criterio prorrateo
[Fechas]                   → Fecha devengo, Fecha pago
[Importe]                  → Importe*, Cotización*, = Importe Gs (calculado)
[Extras]                   → Toggle "Gasto extra de gestión" + Motivo / Observaciones
```

**b) `helperText` en toggles:**
```
"Costo directo a un ítem"  → helperText: "Activar si este costo aplica solo a un vehículo/SKU específico. Si es de todo el embarque, dejarlo desactivado."
"Gasto extra de gestión"   → helperText: "Para costos no previstos (demoras, almacenaje extendido). Queda auditado en la bitácora."
```

**c) `helperText` en Prorrateo:**
```
FOB          → "Se distribuye según el valor FOB de cada ítem"
PESO         → "Se distribuye según el peso de cada ítem"
CBM          → "Se distribuye según el volumen en m³"
CANTIDAD     → "Se distribuye según la cantidad de unidades"
Partes iguales → "El mismo monto para cada ítem"
```
Implementar como Tooltip en cada MenuItem o como `helperText` debajo del select.

**d) Mostrar moneda activa en el label de Importe:**
```jsx
label={`Importe${form.moneda_id ? ` (${monedaSeleccionada?.codigo})` : ''}`}
```

**e) Aclarar fechas:**
```
Fecha devengo → helperText: "Cuándo se generó la obligación (ej: fecha de la factura)"
Fecha pago    → helperText: "Cuándo se pagó o se pagará al proveedor"
```

---

### 5. `DespachoFormPanel` — "Despacho aduanero"

#### Problemas actuales
- 8 campos de tributos sin ninguna agrupación ni explicación
- Nombres abreviados: "INC", "IRE", "ANA" — sin tooltips
- No hay advertencia de que "Confirmar despacho" es irreversible hasta que se hace click
- "Total tributos" al final, poca prominencia visual

#### Cambios a implementar

**a) Tooltips obligatorios en cada tributo:**
```
Arancel          → "Derecho aduanero de importación según el NCM del producto"
IVA Importación  → "IVA aplicado en aduana (10% del CIF generalmente)"
ISC              → "Impuesto Selectivo al Consumo — ver tabla ISC en configuración"
INC              → "Impuesto a la No Contribuyente"
Anticipo IRE     → "Anticipo del Impuesto a la Renta Empresarial"
Tasa ANA         → "Tasa de la Administración Nacional de Aduanas"
Otros tributos   → "Cualquier otro tributo no clasificado en las categorías anteriores"
```

**b) Agrupar en dos columnas con `Divider` entre grupos:**
```
[Impuestos principales]  → Arancel, IVA Importación, ISC
[Impuestos adicionales]  → INC, Anticipo IRE, Tasa ANA, Otros tributos
```

**c) `Total tributos` sticky** al fondo del panel con fondo de acento y tamaño prominente

**d) Alert antes del botón "Confirmar despacho":**
```
⚠️ Confirmar el despacho es una acción irreversible. Se generará el asiento contable y el embarque pasará a estado DESPACHADO.
```

**e) Mostrar cotización sugerida** si hay tipo de cambio USD cargado para la fecha del despacho:
```
ℹ️ Cotización vigente al 28/04/2026: Gs. 7.800 / USD
```

---

### 6. Lista de embarques — Botones de estado

#### Problemas actuales
- "→ EN_TRANSITO" usa nombre interno del enum
- "ELIMINAR" en rojo siempre visible, incluso en estados donde no debería destacarse
- Sin indicación del siguiente paso lógico cuando el embarque está en un estado específico

#### Cambios a implementar

**a) Traducir botones de transición al lenguaje del negocio:**

| Estado actual | Botón actual | Botón mejorado |
|---|---|---|
| BORRADOR | → EN_TRANSITO | → Embarcado |
| EN_TRANSITO | → ARRIBADO | → Marcado como llegado |
| ARRIBADO | → EN_DESPACHO | → Iniciar despacho |
| EN_DESPACHO | (confirmar despacho en tab) | — |
| DESPACHADO | (liberar en modal) | → Liberar al depósito |
| LIBERADO | → CERRADO | → Cerrar expediente |
| CERRADO | → SELLADO | → Sellar |

**b) Tooltip en cada botón** con descripción breve de qué implica la transición

**c) Chips de estado con colores semánticos:**
```
BORRADOR      → gris
EN_TRANSITO   → azul
ARRIBADO      → azul oscuro
EN_DESPACHO   → naranja
DESPACHADO    → amarillo
LIBERADO      → verde claro
CERRADO       → verde
SELLADO       → verde oscuro + 🔒
```

**d) Panel de "siguiente paso" en el header del detalle** (solo en estados activos):
```jsx
// Ejemplo cuando estado = DESPACHADO
<Alert severity="info" sx={{ mb: 1 }}>
  Próximo paso: <strong>Liberar al depósito</strong> — se crearán los productos en inventario
</Alert>
```

---

### 7. `IscVehiculosTab` — "Nueva tasa ISC"

#### Problemas actuales
- Sin placeholder ni ejemplos en ningún campo
- Sin explicación de qué es ISC en este contexto
- "Vigente hasta" vacío = sin fecha de fin, pero eso no es obvio

#### Cambios a implementar

**a) Descripción introductoria en el panel** (ya existe, mejorarla):
```
Definí las tasas ISC según cilindrada y año del modelo.
Al cargar el despacho, el sistema sugerirá la tasa correspondiente.
Ejemplo: vehículo año 2022 de 1600cc → tasa 5%
```

**b) Placeholders en todos los campos:**
```
Año desde    → placeholder: "ej: 2020"
Año hasta    → placeholder: "ej: 2030"
cc desde     → placeholder: "ej: 1001"
cc hasta     → placeholder: "ej: 2000"
Tasa ISC %   → placeholder: "ej: 5.00"
Descripción  → placeholder: "ej: Sedanes 1001-2000cc 2020-2030"
```

**c) HelperText en "Vigente hasta":**
```
Dejar vacío si la tasa no tiene fecha de vencimiento prevista
```

**d) Preview de rango** en tiempo real:
```jsx
// Si todos los campos están llenos:
<Typography variant="caption" color="primary">
  Esta tasa aplica a vehículos año 2020–2030, cilindrada 1001–2000cc, con ISC del 5%
</Typography>
```

---

## Orden de implementación

| Prioridad | Componente | Impacto | Esfuerzo |
|---|---|---|---|
| 1 | `CostoFormDialog` — secciones + helperText | Alto (campo más complejo) | Medio |
| 2 | `EmbarqueFormDialog` — secciones + modalidad select | Alto (punto de entrada) | Bajo |
| 3 | `DespachoFormPanel` — tooltips + alert confirmación | Alto (acción irreversible) | Bajo |
| 4 | `ItemFormDialog` (AUTOS) — labels + validación chasis | Medio | Bajo |
| 5 | Lista embarques — chips de color + botones traducidos | Medio | Bajo |
| 6 | `ItemFormDialog` (CONSUMO_MASIVO) — helperText | Medio | Bajo |
| 7 | `IscVehiculosTab` — placeholders + preview | Bajo (uso admin) | Bajo |

---

## Componentes reutilizables a crear

| Nombre | Uso |
|---|---|
| `<SectionDivider label="Texto" />` | Separador visual con label dentro de grids de formulario |
| `<InfoTooltip text="..." />` | Ícono `?` con tooltip — evita sobrecargar el formulario de texto |
| `<StateChip estado="..." />` | Chip de estado con colores semánticos, reutilizable en toda la app |
| `<NextStepAlert embarque={...} />` | Panel de "próximo paso" según estado actual |

---

## Ejemplo de `SectionDivider`

```jsx
// src/components/ui/SectionDivider.jsx
import { Box, Divider, Typography } from "@mui/material";

export function SectionDivider({ label }) {
  return (
    <Box sx={{ gridColumn: "1 / -1", display: "flex", alignItems: "center", gap: 1, mt: 0.5 }}>
      <Typography variant="caption" color="text.secondary" sx={{ whiteSpace: "nowrap" }}>
        {label}
      </Typography>
      <Divider sx={{ flex: 1 }} />
    </Box>
  );
}
```

## Ejemplo de `InfoTooltip`

```jsx
// src/components/ui/InfoTooltip.jsx
import { HelpOutline } from "@mui/icons-material";
import { Tooltip, IconButton } from "@mui/material";

export function InfoTooltip({ text }) {
  return (
    <Tooltip title={text} placement="top" arrow>
      <IconButton size="small" sx={{ color: "text.secondary", p: 0.25 }}>
        <HelpOutline fontSize="inherit" />
      </IconButton>
    </Tooltip>
  );
}
```

---

## Validaciones frontend a agregar (sin cambios de backend)

| Campo | Validación actual | Validación a agregar |
|---|---|---|
| Chasis (VIN) | Obligatorio si AUTOS | Exactamente 17 chars alfanuméricos, contador en tiempo real |
| FOB unitario | No hay | Debe ser > 0, error visual si queda en 0 |
| Importe (costo) | No hay | Debe ser > 0 |
| Cotización (costo) | No hay | Debe ser > 0 |
| Año ítem (AUTOS) | No hay | Entre 1900 y año actual + 1 |
| Cilindrada cc | No hay | Debe ser > 0 si se completa |
| N° Despacho | No hay | No vacío, alertar si no contiene al menos 5 chars |
| Gasto extra | Motivo obligatorio | Check inmediato al escribir (no esperar submit) |

---

## Accesibilidad mínima

- Todos los `Dialog` deben tener `aria-labelledby` apuntando al `DialogTitle`
- Campos con error deben incluir `aria-describedby` apuntando al `helperText`
- Botones de transición de estado deben tener `aria-label` descriptivo: `"Marcar embarque como Embarcado"`
- Chips de estado con color: siempre acompañar el color con texto (nunca solo color)
