Alta manual de devoluciones (/returns/create)
Permite a un empleado crear una devolución en nombre del cliente — el caso típico de una devolución en tienda o gestionada por ATC por teléfono. Es el equivalente interno del wizard del portal del cliente, con tres diferencias de fondo: se piden los datos logísticos (origen, mercancía reclamada, almacén), el email de confirmación es opcional y la devolución queda asociada al empleado que la crea.
La UI es un acordeón de 4 pasos más una pantalla de éxito (accordionValue 1 → 5). Solo el paso activo está desplegado; los ya completados muestran un check verde y un botón Editar para volver.
flowchart LR
S1[1 · Recuperar pedido<br/>nº pedido + email] --> S2[2 · Artículos<br/>origen · mercancía · almacén]
S2 --> S3[3 · Método de<br/>devolución]
S3 --> S4[4 · Revisar<br/>y confirmar]
S4 -->|POST /api/set-return| S5[5 · Éxito<br/>HWRET… + email opcional]
Estado del proceso (RefundContext)
Todo el wizard se apoya en context/RefundContext.tsx, que guarda { refund, order, accordionValue } y lo persiste en localStorage bajo la clave refundProcess:
- Se rehidrata al montar (
isMountedevita parpadeos: hasta entonces se muestran skeletons). - Se reescribe en cada cambio del proceso.
- Se borra al llegar al paso 5, para que la siguiente devolución empiece limpia.
El botón Iniciar nueva devolución (visible desde el paso 2) pide confirmación y llama a destroyRefund().
El portal del cliente usa sessionStorage y este usa localStorage: aquí el proceso sobrevive al cierre de la pestaña, lo que resulta práctico en tienda pero deja datos de pedido en el equipo hasta completar o reiniciar el alta.
Paso 1 — Recuperar el pedido
form-get-order.tsx: número de pedido y email, validados con zod (ambos obligatorios, email con formato válido; placeholder HWXX999999). Llama a POST /api/get-order, guarda el pedido en el contexto y avanza al paso 2.
A diferencia del portal del cliente, este handler no envía is_customer: true a robo-api, por lo que la respuesta no está restringida a la vista de cliente.
Paso 2 — Artículos y datos logísticos
form-return-items.tsx es el paso con más reglas. Por cada artículo seleccionado hay que fijar tres campos:
| Campo | Valor por defecto |
|---|---|
| Origen | El origen WITHDRAWAL del catálogo (/return-origin/info) |
| Mercancía reclamada | Sí (CLAIMED_GOODS.yes) |
| Almacén | El almacén del pedido (order.id_return_store), salvo Grecia (ver abajo) |
Almacén por defecto y caso Grecia
const userDefaultWarehouse =
order?.country === GREECE_COUNTRY_CODE // "GR"
? GREECE_WAREHOUSE_ID // 61
: order?.id_return_store || -1;
Los pedidos de Grecia se asignan al almacén 61 de forma incondicional, ignorando el almacén del pedido (commit 27594a3). Ambos valores están codificados en constants/warehouses.ts.
Validaciones (zod + superRefine)
- Al menos un artículo seleccionado.
- Mercancía reclamada obligatoria en cada artículo.
- Si la mercancía reclamada es Sí, el almacén es obligatorio y debe ser mayor que 0.
Gastos de envío y cancelaciones
- La línea de gastos de envío (SKU
S00233) se muestra con un icono de camión en lugar de imagen y no permite editar los datos logísticos. - Si todos los productos quedan con origen
CANCELLED, la línea de gastos de envío se marca también como cancelada automáticamente. Se avisa por diálogo antes de continuar.
Paso 3 — Método de devolución
form-return-method.tsx ofrece los métodos habilitados para el país del pedido (POST /api/methods/getSearchMethods, que en robo-api es /return-method/search). El precio del método se resta del total.
Paso 4 — Revisar y confirmar
resume.tsx muestra el resumen completo: artículos con su origen, mercancía reclamada y almacén (solo si la mercancía es Sí), gastos de envío, método elegido y total.
Incluye un checkbox opt-in para enviar el email de confirmación al cliente. Sin marcarlo, la devolución se crea sin notificar — comportamiento deliberado para altas internas o correcciones.
Al confirmar (diálogo de confirmación mediante):
- Si todos los productos están cancelados, propaga la cancelación a la línea de gastos de envío.
POST /api/set-return, que añadecustomer: <sub de Auth0>— la devolución queda vinculada al empleado que la crea.- Con el
return_name_iddevuelto, firma la URL del PDF en el idioma del pedido (order.localerecortado a dos letras). - Si el checkbox estaba marcado, dispara el journey
CREATEDde Marketing Cloud (una sola vez,journeyTriggered). - Avanza al paso 5 y limpia
localStorage.
Paso 5 — Éxito
success-message.tsx confirma el alta con el número de devolución generado y permite iniciar otra.
Diferencias con el wizard del portal del cliente
| Aspecto | Portal del cliente | Back-office |
|---|---|---|
| Navegación | 4 pasos con Stepper e historial | Acordeón de 4 pasos con botón Editar por paso |
| Persistencia | sessionStorage | localStorage |
| Motivo de devolución | Obligatorio por artículo | No se pide |
| Origen / mercancía / almacén | No se piden | Obligatorios por artículo |
| Email de confirmación | Siempre se envía | Opcional (checkbox) |
| Identidad | Cliente (pedido + email) | Empleado autenticado (customer: sub) |