Saltar a contenido

RF-005 — Entrega: retiro en sucursal, envío a domicilio y promesa de plazo

Estado Implementado
Tipo Lógica propia en el paso de entrega del checkout
Ubicación src/modules/checkout/components/shipping/index.tsx · src/lib/data/fulfillment.ts · src/modules/shipping/components/free-shipping-price-nudge/
Depende de RF-000 · RF-004 · cotización de flete del backend

Requisito

Presentar por separado el retiro en sucursal y el envío a domicilio; informar al cliente, antes de elegir, cuánto va a demorar el retiro en cada sucursal según los artículos de su carrito; cotizar en vivo el precio de cada opción de envío; e incentivar el envío gratuito informando cuánto falta para alcanzar el umbral.

Solución adoptada

Separar las opciones por el tipo de su conjunto de fulfillment (pickup frente al resto) y presentarlas como dos grupos excluyentes. La promesa de plazo se calcula en el navegador a partir de la metadata de las variantes del carrito, tomando el máximo por sucursal.

flowchart TD
    C[Carrito] --> IT[Ítems]
    IT --> S{supplier_id de la variante}
    S -->|1 · interno| A[t_entrega_aviadores · t_entrega_multi]
    S -->|otro · externo| B[t_entrega para ambas sucursales]
    A --> MAX[Máximo por sucursal]
    B --> MAX
    MAX --> P[Promesa por sucursal]
    OPT[Opciones de envío] --> T{service_zone.fulfillment_set.type}
    T -->|pickup| G1[Retiro en sucursal + promesa]
    T -->|otro| G2[Envío a domicilio + precio cotizado]

Funciones

Función Detalle
Separación de modalidades Dos grupos excluyentes: retiro en sucursal y envío a domicilio
Promesa de plazo por sucursal calculateMaxDeliveryTimes() recorre los ítems y toma el mayor plazo de cada sucursal
Redacción de la promesa Distingue «retiro inmediato en horas hábiles» de una cantidad de horas, con singular y plural
Cotización en vivo calculatePriceForShippingOption() por opción, resuelto en paralelo y tolerante a fallas individuales
Incentivo de envío gratuito Informa el monto restante y el avance hacia el umbral, en línea o como aviso emergente

Reglas de negocio

  • Tomar el plazo mayor del carrito: el pedido se retira completo, no por artículo.
  • Leer los plazos por sucursal solo para el proveedor interno (supplier_id = 1); para el resto, aplicar el plazo general a ambas sucursales.
  • Asociar cada opción de retiro con su sucursal por coincidencia de texto en el nombre (aviadores o central, y multiplaza).
  • Expresar el plazo en horas hábiles, no en días corridos.
  • Cotizar cada opción de envío por separado y no descartar el resto cuando una falla.
  • Excluir mutuamente las dos modalidades: elegir retiro descarta la opción de envío y viceversa.
  • Ofrecer envío a domicilio solo cuando la dirección del carrito tiene ciudad: las zonas se resuelven por ciudad, así que sin ella no hay cobertura ni precio que mostrar. En ese caso se explica la situación y se ofrece volver a cargar la dirección, y el retiro sigue disponible.

Criterios de aceptación

# Criterio
1 Presentar retiro y envío como grupos separados, y solo cuando existen opciones de cada tipo
2 Exhibir el plazo de retiro por sucursal según el artículo de mayor demora del carrito
3 Enunciar «retiro inmediato» cuando el plazo es cero para el proveedor interno
4 Cotizar el precio de cada opción de envío para la dirección cargada
5 Informar el monto restante para alcanzar el envío gratuito
6 Explicar la ausencia de envío a domicilio y distinguir la falta de dirección de la falta de cobertura

Limitaciones conocidas

  • Quedar la promesa en cero cuando la metadata de la variante no viene cargada desde Medusa (supplier_id, t_entrega, t_entrega_aviadores, t_entrega_multi), sin distinguir «sin demora» de «sin dato».
  • Fijar las dos sucursales en el código y resolverlas por texto de su nombre.
  • Calcular la promesa en el navegador a partir de metadata del carrito, sin validación del backend.