Pre-Orden (Beta)
Documentación del proceso de creación de una pre-orden en el sistema
Guía de Operaciones - Pre-Ventas (Pre-Sale)
📋 Índice
- ¿Qué es Pre-Venta?
- ¿Cómo Funciona?
- Configuración de Pre-Venta
- Subida de Stock
- Procesamiento de Pre-Órdenes
- Cancelación Automática de Pre-Órdenes Expiradas
- Monitoreo y Reportes
🎯 ¿Qué es Pre-Venta?
La Pre-Venta es una funcionalidad que permite a los usuarios hacer pedidos antes de que el stock esté disponible. Esto es especialmente útil para tiendas como Krispy Kreme que reciben stock fresco diariamente.
Beneficios
- ✅ Para el Usuario: Asegura su pedido antes de que se agote el stock
- ✅ Para la Tienda: Conoce la demanda antes de preparar el stock
- ✅ Para Cheaf: Mejora la experiencia del usuario y reduce cancelaciones
🔄 ¿Cómo Funciona?
Flujo General
1. Se configura las tiendas con la cantidad de stock que se subirá en preventa
↓
2. Cron job ejecuta comando "upload_presale_stock"
↓
3. Sistema sube stock SOLO a tiendas con configuración de pre-venta
↓
4. Usuario ve tienda con "Pre-Venta Disponible" y stock disponible
↓
5. Usuario hace pedido (stock > 0)
↓
6. Si es dentro de ventana de pre-venta, se crea como "Pre-Orden"
↓
7. Pre-orden queda PENDIENTE (sin cobro, sin delivery, sin Deliverect)
→ Orden con status "Requested" (3)
↓
8. Krispy Kreme sube stock REAL mediante su sistema
↓
9. Sistema procesa pre-órdenes automáticamente (FIFO):
- Cobra al usuario
- Configura delivery (si aplica)
- Envía a Deliverect (si aplica)
→ Orden permanece en status "Requested" (3)
↓
10. Tienda cambia manualmente el status a "Booked" cuando está listaNotas Importantes:
- El cobro NO es inmediato. Se cobra cuando Krispy Kreme sube el stock real.
- El delivery y Deliverect se procesan cuando se sube el stock real, no al crear la pre-orden.
- Los cupones y créditos se aplican de manera normal al crear la pre-orden (no se difieren).
- Las órdenes en pre-venta se marcan con la bandera
is_presale = Truepara identificarlas fácilmente en queries y reportes.
Ventana de Pre-Venta
La ventana de pre-venta se cierra automáticamente cuando la tienda llega a su hora de apertura (collect_after).
-
Ventana Abierta: Los usuarios pueden hacer pre-órdenes
- Desde:
presale_opening_time(ej: 4:00 PM) - Hasta:
collect_after(hora de apertura de la tienda, ej: 10:00 AM del día siguiente)
- Desde:
-
Ventana Cerrada: Los usuarios NO pueden hacer pre-órdenes
- Cuando:
current_time >= collect_after(la tienda ya abrió) - Las órdenes normales siguen procesándose sin problema
- Solo la opción de pre-venta aparece cerrada en el frontend
- Cuando:
Ejemplo de Timeline:
16:00 (4 PM) → Pre-venta ABIERTA ✅
22:00 (10 PM) → Pre-venta ABIERTA ✅
09:59 AM → Pre-venta ABIERTA ✅ (tienda aún no abre)
10:00 AM → Pre-venta CERRADA ❌ (tienda abrió - collect_after)
11:00 AM → Pre-venta CERRADA ❌ (órdenes normales disponibles)⚙️ Configuración de Pre-Venta
Paso 1: Habilitar Pre-Venta en una Tienda
-
Ir al Admin de Django → Restaurants → Stores
-
Buscar y seleccionar la tienda que deseas configurar
-
Dentro de la pantalla de la tienda, ir a la sección "Pre Sale Configurations"
-
Configurar los campos:
- Presale Opening Time: Hora de apertura (formato 24h, ej: 16:00:00)
- Enabled: ✅ Marcar para activar
-
Guardar
Paso 2: Configurar Stock por Menú
-
Ir al Admin de Django → Restaurants → Menus
-
Buscar el menú de la tienda
-
Editar el menú:
- Presale Stock Amount: Cantidad de stock que se subirá (ej: 50)
- Si es 0, ese menú NO participará en pre-venta
-
Guardar
Ejemplo de Configuración
Tienda: Krispy Kreme Centro
- Presale Opening Time: 16:00:00 (4:00 PM)
- Enabled: ✅ Sí
Menús:
- Docena Original Glazed → Presale Stock Amount: 50
- Media Docena Surtida → Presale Stock Amount: 30
- Café Americano → Presale Stock Amount: 0 (no participa)
📦 Subida de Stock
Proceso de Subida de Stock
Importante: Krispy Kreme sube sus paquetes mediante su propio sistema interno. El comando upload_presale_stock NO crea los paquetes, solo:
- ✅ Toma el stock configurado en
presale_stock_amount - ✅ Lo agrega al stock actual del menú
- ✅ Solo afecta tiendas con configuración de pre-venta activa
Opción 1: Subida Automática (Recomendado)
El comando se ejecuta automáticamente cada 15 minutos mediante un cron job. Esto permite detectar la ventana de apertura de pre-venta de cada tienda.
Configuración en Cron:
# Ejecuta cada 15 minutos para detectar ventanas de apertura
*/15 * * * * /path/to/command upload_presale_stock¿Cómo funciona?
- El cron se ejecuta cada 15 minutos
- Verifica qué tiendas tienen su ventana de pre-venta abierta
- Solo procesa tiendas con
PreSaleConfigurationactiva (enabled = True) - Solo afecta menús con
presale_stock_amount > 0
Opción 2: Subida Manual
Usar el comando manual cuando sea necesario:
# Subir stock para todas las tiendas configuradas
make manage cmd="upload_presale_stock --force"
# Subir stock para una tienda específica
make manage cmd="upload_presale_stock --force --store-id 123"
# Modo prueba (no hace cambios reales)
make manage cmd="upload_presale_stock --force --dry-run"
# Sin enviar notificaciones a favoritos
make manage cmd="upload_presale_stock --force --skip-favorites"¿Qué Hace la Subida de Stock?
- ✅ Identifica tiendas elegibles: Solo tiendas con
PreSaleConfigurationactiva - ✅ Agrega stock: Suma el
presale_stock_amountal stock actual de cada menú - ✅ Registra cambios: Crea entrada en historial (RestaurantMenuLog)
- ✅ Actualiza Firestore: Sincroniza con la app móvil
- ✅ Envía notificaciones: Push a usuarios con la tienda en favoritos
Ejemplo:
- Stock actual: 10 unidades
- Presale Stock Amount: 50 unidades
- Resultado: Stock nuevo = 60 unidades
🔄 Procesamiento de Pre-Órdenes
¿Cuándo se Procesan?
Las pre-órdenes se procesan automáticamente cuando Krispy Kreme sube stock real mediante su sistema interno.
¿Qué Sucede al Procesar?
Cuando se procesa una pre-orden, el sistema ejecuta:
- ✅ Cobra al usuario con el token de pago guardado
- ✅ Configura delivery si el pedido es para entrega
- ✅ Envía a Deliverect si la tienda tiene integración activa
Importante:
- El usuario NO recibe notificación cuando se procesa la pre-orden.
- Las órdenes se crean con status "Requested" (3) y permanecen en ese status después de procesarse.
Orden de Procesamiento
Las pre-órdenes se procesan en orden FIFO (First In, First Out):
- La primera pre-orden creada se procesa primero
- La segunda pre-orden se procesa después, y así sucesivamente
- Esto garantiza equidad para todos los usuarios
Estados de Pre-Orden
| Estado Pre-Orden | Status Orden | Descripción | Acción |
|---|---|---|---|
| Pending | Requested (3) | En espera de stock real | Ninguna - Pre-orden en cola |
| Processing | Requested (3) | Siendo procesada | Cobrando y configurando delivery |
| Completed | Requested (3) | Procesada exitosamente | ✅ Orden lista |
| Failed - Payment | Requested (3) | Falló el pago | ❌ Se envía email a soporte |
| Failed - Delivery | Requested (3) | Falló el delivery | ❌ Se envía email a soporte |
| Failed - Processing | Requested (3) | Error general | ❌ Se envía email a soporte |
Nota: Todas las pre-órdenes mantienen el status "Requested" (3) independientemente de su estado de procesamiento. La tienda debe cambiar manualmente el status a "Booked" cuando el pedido esté listo para recoger.
❌ Cancelación Automática de Pre-Órdenes Expiradas
Resumen
El comando cancel_expired_preorders cancela automáticamente las pre-órdenes que permanecen pendientes 30 minutos después de la hora de apertura real de la tienda (collect_after). Se ejecuta cada 15 minutos para garantizar la cancelación oportuna.
Comando: cancel_expired_preorders
Ubicación: app/orders/management/commands/cancel_expired_preorders.py
Frecuencia: Cada 15 minutos vía cron job
¿Cómo Funciona?
1. Selección de Tiendas
- Encuentra todas las tiendas con pre-órdenes pendientes (
PreOrder.status = 'pending') - Obtiene el horario de la tienda para hoy
- Recupera la hora
collect_after(hora de apertura real)
2. Cálculo de Expiración
- Tiempo de Expiración =
collect_after+ 30 minutos (en zona horaria de la tienda) - Lógica de Cancelación = Retroactiva (cancela TODAS las pre-órdenes expiradas)
- Si hora actual > tiempo de expiración → Cancelar
- Sin restricción de ventana de tiempo → Captura cualquier cancelación perdida
3. Cancelación de Pre-Orden
Para cada pre-orden expirada:
- Cambia
PreOrder.statusafailed_processing - Establece
PreOrder.processed_ata la marca de tiempo actual - Cambia
Order.statusa0(Cancelada) - Registra la cancelación para auditoría
4. Lógica de Cancelación Retroactiva
Ejemplo de Timeline:
Tienda abre (collect_after): 10:00 AM (zona horaria de la tienda)
Tiempo de expiración: 10:30 AM (collect_after + 30 min)
El cron se ejecuta a las:
- 10:15 AM ✗ Aún no expirado (15 min después de abrir)
- 10:30 AM ✓ Expirado, cancela pre-órdenes
- 10:45 AM ✓ Aún expirado, cancela las restantes
- 11:00 AM ✓ Aún expirado, cancela las restantes
- 12:00 PM ✓ Aún expirado, cancela las restantes (retroactivo)Punto Clave: El comando es retroactivo - cancela TODAS las pre-órdenes pendientes que pasaron el tiempo de expiración, sin importar cuándo se ejecute el cron.
Argumentos del Comando
--force
Fuerza la cancelación sin importar el tiempo (para pruebas)
make manage cmd="cancel_expired_preorders --force"--store-id <ID>
Procesa solo una tienda específica (para pruebas)
make manage cmd="cancel_expired_preorders --store-id 123"--dry-run
Simula el comando sin hacer cambios reales
make manage cmd="cancel_expired_preorders --dry-run"Argumentos Combinados
# Probar tienda específica sin hacer cambios
make manage cmd="cancel_expired_preorders --store-id 123 --dry-run"
# Forzar cancelación para tienda específica
make manage cmd="cancel_expired_preorders --store-id 123 --force"Configuración del Cron Job
Agregar al crontab para ejecutar cada 15 minutos:
# Editar crontab
crontab -e
# Agregar esta línea (ajustar ruta según sea necesario)
*/15 * * * * cd /path/to/cheaf-admin && /path/to/venv/bin/python manage.py cancel_expired_preorders >> /var/log/cheaf/cancel_expired_preorders.log 2>&1¿Por Qué Cancelar Después de 30 Minutos?
Las pre-órdenes que permanecen pendientes 30 minutos después de que la tienda abre indican:
- ❌ Stock no subido - La tienda no recibió stock
- ❌ Procesamiento fallido - El procesador de pre-órdenes encontró un error
- ❌ Tienda cerrada - La tienda no abrió según lo programado
En todos los casos, es mejor cancelar y permitir el reembolso que dejar a los clientes esperando indefinidamente.
Logs y Monitoreo
Niveles de Log:
- INFO: Operación normal, cancelaciones de pre-órdenes
- WARNING: Tiendas omitidas, sin horario o collect_after
- ERROR: Fallos en el proceso de cancelación
Ejemplos de Logs:
INFO: Cancel expired pre-orders command started. Force: False, Store ID: None, Dry Run: False
INFO: Store 123 (Krispy Kreme Centro) collect_after: 10:00:00, expiration: 10:30:00
INFO: Cancelled expired PreOrder #456 (Order #789) for store 123
INFO: Cancel expired pre-orders command completed. Processed: 1, Cancelled: 3, Errors: 0📊 Monitoreo y Reportes
Ver Pre-Órdenes en el Admin
- Ir al Admin de Django → Orders → Pre orders
- Filtrar por:
- Status: Estado de la pre-orden (Pending, Completed, Failed, etc.)
- Payment provider: Proveedor de pago (Conekta, MercadoPago, Stripe)
- Created at: Fecha de creación
- Buscar por:
- ID de pre-orden
- ID de orden
- ID del usuario
Información Importante
Cada pre-orden muestra:
- Order: Número de orden asociada
- Status: Estado actual
- Created At: Cuándo se creó
- Processed At: Cuándo se procesó (si aplica)
- Payment Provider: Proveedor de pago (Conekta, MercadoPago, etc.)
Documentación del Proceso de Creación de una Orden
Proceso funcional de creación de una orden en el sistema
Modal de Cancelación de Pedidos - CancelOrderModal
Documentación completa del componente [CancelOrderModal] que gestiona la experiencia de usuario al cancelar pedidos en la aplicación móvil. El sistema implementa políticas diferenciadas por país (Chile/Argentina/México con CANCELLATION-2-2 vs otros países con sistema anti-fraude), evalúa condiciones de alto valor (HIGH_BASKET_SIZE), y determina qué mensaje mostrar al usuario basado en su historial de cancelaciones, método de pago, y configuraciones de fraude del backend.