Cheaf Docs
Orders/Order Unfulfilled

Flujo de Encuesta (Usuario y Partner)

Documentación completa del sistema de encuesta para pedidos no completados que determina la responsabilidad cuando un pedido no es recogido por el usuario.

El sistema de encuesta para pedidos no completados es un mecanismo bilateral que determina la responsabilidad cuando un pedido no es recogido por el usuario. El sistema requiere respuestas tanto del usuario de la app como del restaurante para establecer quién es responsable del incumplimiento y aplicar las acciones correspondientes según el tipo de pago y las respuestas proporcionadas.

¿Cuándo se activa?

Este sistema se activa automáticamente cuando:

  • Un pedido es marcado como STATUS_UNFULFILLED (9)
  • Se crea una entidad UnfulfilledOrder
  • Ambas partes (usuario y restaurante) deben proporcionar feedback
  • El proceso continúa hasta obtener resolución definitiva

Cobertura Geográfica

  • Países: Universal - todos los mercados donde opera Cheaf
  • Excepción: Chile y Argentina tienen procesamiento adicional con cencosud_unfulfilled
  • Particularidad México: Notificaciones de soporte automáticas para conflictos

Funcionalidad Principal

Servicios de la API

ManageUnfulfilledAppUserOrder

  • Endpoint: /api/unfulfilled-app-user/
  • Propósito: Gestiona la perspectiva del usuario de la aplicación

ManageUnfulfilledRestaurantOrder

  • Endpoint: /api/unfulfilled-restaurant/
  • Propósito: Gestiona la perspectiva del restaurante

Lógica de Procesamiento

1. Iniciación del Proceso

Condición de Activación

Trigger: Pedido identificado como no completado
Creación: UnfulfilledOrder entity
Estado inicial: finished=False, user_answer=null, store_answer=null
Campos de control: user_finished_view=False, store_finished_view=False

Estados de Respuesta

user_answer: null | "0" | "1" | "2"
store_answer: null | "0" | "1" | "2"

Códigos de Respuesta:
- "0": Order completed (Pedido sí fue completado)
- "1": Order unfulfilled by user (Culpa del usuario)  
- "2": Order unfulfilled by store (Culpa del restaurante)

2. Matriz de Decisión

Tabla de Resolución

user_answerstore_answerResultadoStatus Finalu_status
nullnullEsperando respuestas1410
"0"nullEsperando tienda1410
null"0"Esperando usuario1410
"0""0"Completado120
"1""1"Culpa Usuario430/31/32
"2""2"Culpa Tienda1240/41
DiferenteDiferenteConflicto-50

3. Consulta de Encuestas (GET)

Para Usuarios de App (ManageUnfulfilledAppUserOrder.get)

Órdenes Pendientes de Respuesta:

# Filtros de búsqueda
UnfulfilledOrder.objects.filter(
    app_user__id_provider=request.user,
    finished=False,
    user_answer__isnull=True,
).order_by("-id")

# Respuesta: Solo la primera orden pendiente (más reciente)
# Si no hay órdenes pendientes: order = {}

Órdenes Finalizadas Pendientes de Vista:

# Órdenes resueltas que el usuario no ha visto aún
UnfulfilledOrder.objects.filter(
    app_user__id_provider=request.user,
    finished=True,
    user_finished_view=False,
).order_by("-id")

# Propósito: Mostrar resultado de encuestas completadas
# Permite al usuario ver el outcome sin re-procesar

Para Usuarios de Restaurante (ManageUnfulfilledRestaurantOrder.get)

Órdenes Pendientes con Filtro Temporal:

# Solo órdenes de más de 3 días para evitar respuestas prematuras
past_3_days = datetime.now() - timedelta(days=3)

UnfulfilledOrder.objects.filter(
    store=restaurant_user.store,
    finished=False,
    store_answer__isnull=True,
    created_at__lte=past_3_days,  # Filtro temporal crítico
).order_by("-id")

# Razón del filtro: Dar tiempo de resolución natural antes de encuesta

Métricas del Dashboard:

# Contador total de órdenes pendientes (sin filtro temporal)
orders_amount = UnfulfilledOrder.objects.filter(
    store=restaurant_user.store,
    finished=False,
    store_answer__isnull=True,
).count()

# Última orden finalizada no vista
finished_orders = UnfulfilledOrder.objects.filter(
    store=restaurant_user.store, 
    finished=True, 
    store_finished_view=False
).order_by("-id")

4. Procesamiento de Respuestas (UPDATE)

Fase 1: Primera Respuesta

Lógica de Estado Intermedio:

# Cuando solo una parte ha respondido
if u_order.store_answer is None:
    """Usuario respondió primero, esperando tienda"""
    u_status = 10
    message = "Thank for your answer. We will confirm with store"
    order.status = "14"  # STATUS_IN_REVIEW
    
elif u_order.user_answer is None:
    """Tienda respondió primero, esperando usuario"""
    u_status = 10  
    message = "Thank for your answer. We will confirm with user"
    order.status = "14"  # STATUS_IN_REVIEW

Caso Especial - Cencosud:

# Marcado especial para cuentas corporativas
if (u_order.store_answer == "0" and 
    u_order.order.store_id.restaurant_name.is_cencosud_account):
    order.completed_by_store = True
    order.save()
    
# Propósito: Tracking especial para cuentas Cencosud

Fase 2: Resolución Final

Cuando ambas partes han respondido:

Escenario A: Pedido Completado (0,0)
# Condición: user_answer="0" AND store_answer="0"
elif u_order.user_answer == "0" and u_order.store_answer == "0":
    """Order completed"""
    u_status = 20
    
    # Actualizaciones de estado
    u_order.status = "1"               # STATUS_COMPLETED
    u_order.finished = True
    u_order.user_finished_view = True
    u_order.store_finished_view = True
    
    # Actualización del pedido principal
    order = Order.objects.get(pk=u_order.order.pk)
    order.status = "1"                 # STATUS_COMPLETED
    order.save()
    
    # Eventos y notificaciones
    register_event_drip_order(
        app_user=order.app_user_id,
        u_order=u_order,
        action=EventAction.ORDER_COMPLETED,
        event_client=EventsClient(),
    )
    
    # Notificación al usuario
    order.app_user_id.send_notification_when_unfulfilled_is_completed()
    
    # Mensajes según perspectiva
    message_user = "Dont forget to collect-swipe your package"
    message_restaurant = "Dont forget ask user swipe order"
Escenario B: Culpa del Usuario (1,1)
# Condición: user_answer="1" AND store_answer="1"
elif u_order.user_answer == "1" and u_order.store_answer == "1":
    """Order unfulfilled by user"""
    app_user = u_order.app_user
    
    # Estados base
    u_order.status = "4"               # STATUS_UNFULFILLED_BY_USER
    u_order.finished = True
    u_order.user_finished_view = True
    u_order.store_finished_view = True
    
    # Actualización del pedido principal
    order = Order.objects.get(pk=u_order.order.pk)
    order.status = "4"                 # STATUS_UNFULFILLED_BY_USER
    order.save()
    
    # Procesamiento según tipo de pago
    if u_order.order.payment_type == "0":
        """Pago con Tarjeta"""
        u_status = 30
        message = "We will charge this order"
        
        # Notificación estándar
        u_order.app_user.send_notification_unfulfilled_by_user()
        
    elif u_order.order.payment_type == "1":
        """Pago con Efectivo/Diferido"""
        
        if u_order.is_first_order:
            """Primer pedido - Beneficio de la duda"""
            u_status = 32
            message = "We will charge this order in your next purchase"
            
            # Notificación especial primer pedido
            u_order.app_user.send_notification_unfulfilled_by_user_first_order(
                order_id=u_order.order.pk
            )
        else:
            """Usuario recurrente - Evaluación de deuda"""
            u_status = 31
            message = "We will charge this order in your next purchase"
            
            # Evaluación inteligente de deuda (ver debt_management.md)
            debt_was_generated = app_user.generate_debt(u_order)
            
            # Notificaciones según resultado
            if not debt_was_generated:
                # Deuda fue cancelada por historial positivo
                has_debt = False
            else:
                # Deuda generada - notificación específica
                app_user.send_notification_unfulfilled_by_user_cash_payment()
                has_debt = True
    
    # Evento de marketing automation
    register_event_drip_order(
        app_user=app_user,
        u_order=u_order,
        action=EventAction.ORDER_UNFULFILLED_BY_USER,
        event_client=EventsClient(),
    )
Escenario C: Culpa del Restaurante (2,2)
# Condición: user_answer="2" AND store_answer="2"
elif u_order.user_answer == "2" and u_order.store_answer == "2":
    """Order unfulfilled by restaurant"""
    
    # Estados base
    u_order.status = "12"              # STATUS_UNFULFILLED_BY_STORE
    u_order.finished = True
    u_order.user_finished_view = True
    u_order.store_finished_view = True
    
    # Actualización del pedido principal
    order = Order.objects.get(pk=u_order.order.pk)
    order.status = "12"                # STATUS_UNFULFILLED_BY_STORE
    order.save()
    
    # Procesamiento según tipo de pago
    if u_order.order.payment_type == "0":
        """Pago con Tarjeta - Reembolso Completo"""
        u_status = 40
        message = "We will refound credits"
        
        # Cálculo de créditos a devolver
        add_credits = (
            u_order.order.cost +                    # Costo pagado
            u_order.order.credits_used +            # Créditos utilizados
            u_order.order.coupon_value               # Valor del cupón
        )
        
        if add_credits > 0:
            app_user = AppUser.objects.get(pk=u_order.app_user.pk)
            currency = get_currency(u_order.order.store_id.cities.country)
            
            app_user.add_credits(
                amount=add_credits,
                currency=currency,
                source=CreditsLogs.UNFULFILLED_ORDER,
                unfulfilled_order=u_order,
                order=u_order.order,
            )
            
            # Notificación de disculpas
            app_user.send_notification_unfulfilled_by_store()
            
    elif u_order.order.payment_type == "1":
        """Pago con Efectivo - Solo Promociones"""
        u_status = 41
        message = "This will not happen again"
        
        # Solo créditos y cupones (no el costo principal)
        add_credits = (
            u_order.order.credits_used +            # Créditos utilizados
            u_order.order.coupon_value               # Valor del cupón
        )
        
        # Notificación especial para efectivo
        u_order.app_user.send_notification_unfulfilled_by_store_cash_payment()
        
        if add_credits > 0:
            app_user = AppUser.objects.get(pk=u_order.app_user.pk)
            currency = get_currency(u_order.order.store_id.cities.country)
            
            app_user.add_credits(
                amount=add_credits,
                currency=currency,
                source=CreditsLogs.UNFULFILLED_ORDER,
                unfulfilled_order=u_order,
                order=u_order.order,
            )
Escenario D: Respuestas Diferentes (Conflicto)
# Condición: user_answer != store_answer
elif u_order.user_answer != u_order.store_answer:
    """Different answers - Escalate to support"""
    u_status = 50
    message = "We will check with support"
    order_pk = u_order.order.pk
    
    # Finalización sin resolución automática
    u_order.finished = True
    u_order.user_finished_view = True
    u_order.store_finished_view = True
    
    # Notificación especial para México
    if u_order.order.store_id.cities.country == "MX":
        try:
            send_mail(
                subject=f"(MX) - [SUPPORT]: Pedido {order_pk} requiere investigación",
                message="Support",
                from_email="no-reply@cheaf.com",
                recipient_list=["support@cheaf.com"],
                fail_silently=False,
            )
        except Exception:
            # Log error but don't stop processing
            pass

Reglas de Negocio Específicas

Filosofía del Sistema

  • Bilateralidad: Ambas partes deben proporcionar perspectiva
  • Consenso: Resolución automática cuando hay acuerdo
  • Escalamiento: Intervención humana solo en casos de conflicto
  • Equidad: Tratamiento diferenciado según tipo de pago y historial

Códigos de Estado (u_status)

Estados de Procesamiento

CódigoDescripciónCondiciónAcción
10Esperando confirmaciónSolo una parte respondióMantener en espera
20Pedido completadoAmbos confirman entregaMarcar como exitoso
30Culpa usuario - TarjetaUsuario no recogió + TarjetaCobrar inmediato
31Culpa usuario - EfectivoUsuario no recogió + EfectivoEvaluar deuda
32Primer pedido - EfectivoPrimer pedido no recogidoSin penalización
40Culpa tienda - TarjetaTienda no entregó + TarjetaReembolso completo
41Culpa tienda - EfectivoTienda no entregó + EfectivoReembolso promociones
50ConflictoRespuestas diferentesEscalar a soporte

Gestión de Comentarios

# Campos opcionales para contexto adicional
u_order.user_comment = request.data.get("userComment") or None
u_order.store_comment = request.data.get("storeComment") or None

# Propósito: Información adicional para casos complejos
# Uso: Resolución manual de conflictos (u_status=50)
# Almacenamiento: Persistente en UnfulfilledOrder

Campos de Control de Vista

# Control de UX para evitar mostrar resultados múltiples veces
user_finished_view: bool = False    # Usuario ha visto el resultado
store_finished_view: bool = False   # Restaurante ha visto el resultado

# Flujo de actualización
u_order.user_finished_view = True   # Al completar desde perspectiva usuario
u_order.store_finished_view = True  # Al completar desde perspectiva restaurante

# Reset automático: Al crear nueva UnfulfilledOrder para misma orden

Timestamps de Auditoría

# Trazabilidad completa del proceso
created_at: datetime          # Creación del UnfulfilledOrder
updated_at: datetime          # Última modificación
user_answer_at: datetime      # Momento de respuesta del usuario
store_answer_at: datetime     # Momento de respuesta del restaurante

# Propósito: Análisis de tiempo de respuesta y patrones
# Uso: Métricas de calidad del servicio

Reglas de Filtrado Temporal

Para Restaurantes

# Solo mostrar órdenes de más de 3 días
past_3_days = datetime.now() - timedelta(days=3)
created_at__lte = past_3_days

# Razón: Evitar respuestas prematuras
# Beneficio: Permite resolución natural antes de encuesta
# Excepción: Dashboard de métricas muestra todas las pendientes

Para Usuarios

# Sin filtro temporal - respuesta inmediata disponible
# Razón: El usuario es quien debe recoger el pedido
# Beneficio: Feedback rápido sobre su experiencia

Integración con Sistemas

Sistema de Deuda

Activación: Escenario B con payment_type="1" y no primer pedido
Método: app_user.generate_debt(u_order)
Lógica: Evaluación inteligente basada en historial (ver debt_management.md)

Sistema de Créditos

Escenario: Culpa del restaurante
Cálculo Tarjeta: cost + credits_used + coupon_value
Cálculo Efectivo: credits_used + coupon_value (solo promociones)
Fuente: CreditsLogs.UNFULFILLED_ORDER

Marketing Automation

Eventos registrados:
- ORDER_COMPLETED: Cuando ambos confirman completado
- ORDER_UNFULFILLED_BY_USER: Cuando culpa es del usuario

Cliente: EventsClient() para drip campaigns
Parámetros: app_user, u_order, action, event_client

Sistema de Notificaciones

Push Notifications

Completado: send_notification_when_unfulfilled_is_completed()
Culpa Usuario: send_notification_unfulfilled_by_user()
Primer Pedido: send_notification_unfulfilled_by_user_first_order()
Efectivo Usuario: send_notification_unfulfilled_by_user_cash_payment()
Culpa Restaurante: send_notification_unfulfilled_by_store()
Efectivo Restaurante: send_notification_unfulfilled_by_store_cash_payment()

Email Notifications

Trigger: Respuestas diferentes + País = "MX"
Destinatario: support@cheaf.com
Formato: "(MX) - [SUPPORT]: Pedido {order_id} requiere investigación"

Estados y Transiciones

Diagrama de Estado

[UnfulfilledOrder Created] 

[Waiting for Responses] → user_answer=null, store_answer=null

[Partial Response] → status="14", u_status=10

[Both Responded] → Evaluación de combinación

    ┌────────────┼────────────┐
    ↓            ↓            ↓
[Completed]   [User Fault]  [Store Fault]  [Conflict]
status="1"    status="4"    status="12"    finished=True
u_status=20   u_status=30/31 u_status=40/41 u_status=50

Códigos de Estado (u_status)

10: Esperando confirmación de la otra parte
20: Pedido completado exitosamente
30: Culpa del usuario - pago con tarjeta
31: Culpa del usuario - pago con efectivo/diferido
32: Culpa del usuario - primer pedido con efectivo
40: Culpa del restaurante - pago con tarjeta
41: Culpa del restaurante - pago con efectivo
50: Respuestas diferentes - requiere soporte

Validaciones y Controles

Validaciones de Entrada

orderId: Requerido, debe existir UnfulfilledOrder correspondiente
userAnswer/storeAnswer: Requerido, valores válidos "0"|"1"|"2"
userComment/storeComment: Opcional, texto libre

Controles de Autorización

Usuario App: Solo puede responder sus propias órdenes
Usuario Restaurante: Solo puede responder órdenes de sus tiendas asignadas
Validación: id_provider matching con authentication token

Prevención de Duplicados

Usuario: user_answer__isnull=True (no ha respondido aún)
Restaurante: store_answer__isnull=True (no ha respondido aún)
Propósito: Evitar modificar respuestas ya enviadas

Consideraciones de UX

Experiencia del Usuario

  • Simplicidad: Solo 3 opciones de respuesta claramente definidas
  • Contexto: Comentarios opcionales para casos complejos
  • Feedback: Mensajes claros sobre las consecuencias de cada decisión
  • Estado: Indicadores visuales de qué está esperando

Experiencia del Restaurante

  • Priorización: Solo órdenes de +3 días para evitar respuestas prematuras
  • Volumen: Contador de órdenes pendientes
  • Gestión: Vista de órdenes finalizadas para seguimiento

Casos de Uso Típicos

Caso A: Resolución Exitosa - Consenso Positivo

Contexto: Pedido #12345, Usuario: juan@example.com, Store: Pizza Express
Payment Type: "0" (Tarjeta)

Flujo Cronológico:
1. [Día 1] Pedido marcado como no completado → UnfulfilledOrder creado
2. [Día 2] Usuario abre app, ve encuesta pendiente
3. [Día 2] Usuario responde "0" (sí lo recogí) + comment: "Todo perfecto"
4. [Día 5] Restaurante ve encuesta (después de 3 días de filtro)
5. [Día 5] Restaurante responde "0" (sí se lo entregamos)

Resultado Automático:
├── u_order.status = "1" (COMPLETED)
├── order.status = "1" (COMPLETED)  
├── u_status = 20
├── register_event_drip_order(ORDER_COMPLETED)
└── Notificación: "Pedido confirmado como entregado"

Impacto Negocio: Caso cerrado exitosamente, KPI positivo

Caso B: Usuario Reconoce Responsabilidad - Evaluación Inteligente

Contexto: Pedido #12346, Usuario frecuente con historial de $2000/3 meses
Payment Type: "1" (Efectivo), Order Cost: $150, is_first_order: False

Flujo de Evaluación:
1. Usuario responde "1" (no lo recogí) + comment: "Se me olvidó"
2. Restaurante responde "1" (efectivamente no vino)
3. Sistema ejecuta app_user.generate_debt(u_order)

Evaluación de Deuda:
├── Cálculo: (150 / 2000) * 100 = 7.5% ≤ 10%
├── Resultado: evaluate_debt() = True (cancela deuda)
├── Acción: remove_debt() + send_push_notification_for_cancel_debt()
└── debt_was_generated = False

Resultado Final:
├── u_status = 31
├── has_debt = False (compatibilidad legacy)
├── message = "We will charge this order in your next purchase"
└── Notificación: "Deuda cancelada por ser cliente frecuente"

Impacto Negocio: Retención de cliente leal vs penalización automática

Caso C: Restaurante Reconoce Responsabilidad - Reembolso Diferenciado

Contexto: Pedido #12347, Payment Type: "0" (Tarjeta)
Order Details: cost=$25, credits_used=$5, coupon_value=$3

Flujo de Compensación:
1. Restaurante responde "2" (no teníamos el pedido listo)
2. Usuario responde "2" (efectivamente no estaba)
3. Sistema calcula reembolso completo para tarjeta

Cálculo de Créditos:
├── add_credits = 25 + 5 + 3 = $33 total
├── currency = get_currency(order.store_id.cities.country)
├── source = CreditsLogs.UNFULFILLED_ORDER
└── Registro completo de transacción

Resultado Final:
├── u_status = 40
├── order.status = "12" (UNFULFILLED_BY_STORE)
├── Créditos otorgados: $33
└── send_notification_unfulfilled_by_store()

Comparación Efectivo:
Si payment_type="1": Solo credits_used + coupon_value = $8
Razón: El costo principal ($25) no se reembolsa en efectivo

Impacto Negocio: Gestión justa de responsabilidad del partner

Caso D: Conflicto Requiere Intervención - Escalamiento México

Contexto: Pedido #12348, País: MX, Respuestas contradictorias

Flujo de Conflicto:
1. Usuario responde "0" (sí lo recogí) + comment: "Lo recogí ayer"
2. Restaurante responde "2" (no teníamos nada listo) + comment: "No llegó el pedido"
3. Sistema detecta: user_answer != store_answer

Escalamiento Automático:
├── u_status = 50
├── message = "We will check with support"
├── u_order.finished = True (sin resolución automática)
└── send_mail() to support@cheaf.com

Email Generado:
Subject: "(MX) - [SUPPORT]: Pedido 12348 requiere investigación"
Recipients: ["support@cheaf.com"]

Proceso Manual Posterior:
1. Equipo de soporte recibe notificación
2. Revisión de evidencia (comentarios, historial, timing)
3. Resolución manual basada en criterio humano
4. Actualización manual del estado final

Impacto Negocio: <5% de casos requieren intervención humana

Caso E: Primer Pedido - Beneficio de la Duda

Contexto: Usuario nuevo, primer pedido, payment_type="1" (Efectivo)

Flujo Especial:
├── is_first_order = True detectado
├── u_status = 32 (código especial)
├── No ejecuta generate_debt()
└── send_notification_unfulfilled_by_user_first_order()

Filosofía: Dar oportunidad a usuarios nuevos sin penalización inmediata
Resultado: Mayor tasa de retención de usuarios nuevos

Manejo de Errores

try:
    # Operaciones críticas
    order.status = new_status
    order.save()
except Exception:
    return Response(
        {"message": "Cant update order"}, 
        status=status.HTTP_400_BAD_REQUEST
    )

Compatibilidad Legacy

has_debt = None  # !Important: Only for old app version support.

El campo has_debt se mantiene para compatibilidad con versiones anteriores de la aplicación móvil.

Alcance Geográfico

Cobertura Universal

El sistema de encuestas opera en todos los países donde Cheaf tiene presencia, sin restricciones geográficas específicas.

Particularidades por País

México (MX)

  • Email de soporte: Automático para casos de conflicto
  • Comandos adicionales: Procesamiento cada 6 horas adicional
  • Escalamiento: Notificación prioritaria a support@cheaf.com

Chile y Argentina

  • Integración Cencosud: Marcado especial completed_by_store
  • Procesamiento estándar: Sin comandos adicionales

Otros Países

  • Flujo estándar: Sin particularidades específicas
  • Escalamiento: Solo vía status=50 sin email automático

Modelos y Status Utilizados

Modelos Principales

ModeloPropósitoCampos Clave
UnfulfilledOrderRegistro principal de encuestauser_answer, store_answer, finished, status
OrderPedido original referenciadostatus, payment_type, cost, credits_used
AppUserUsuario de la aplicacióndebt, credits, métodos de deuda
RestaurantUserUsuario del restaurantestore, stores (múltiples tiendas)

Status y Estados

CampoValoresDescripción
user_answernull, "0", "1", "2"Respuesta del usuario
store_answernull, "0", "1", "2"Respuesta del restaurante
u_order.status"1", "4", "12"Estado final del UnfulfilledOrder
order.status"1", "4", "12", "14"Estado del pedido principal
u_status10, 20, 30-32, 40-41, 50Código de respuesta API

Integraciones del Sistema

  • Sistema de Deuda: app_user.generate_debt() - Evaluación inteligente
  • Sistema de Créditos: app_user.add_credits() - Reembolsos automáticos
  • Marketing Automation: register_event_drip_order() - Eventos de seguimiento
  • Notificaciones Push: Múltiples métodos según escenario
  • Email Notifications: Solo México para conflictos

Próximos Pasos y Evolución

Optimizaciones Potenciales

  1. Machine Learning: Predicción de respuestas basada en patrones históricos
  2. Automatización Avanzada: Resolución sin encuesta para casos obvios
  3. Integración Temporal: Datos de GPS/timing para validación automática
  4. Personalización: Mensajes y flujos específicos por segmento de usuario

Expansión Geográfica

  • Replicación: Aplicar lógica a nuevos mercados
  • Localización: Adaptar mensajes y reglas culturales
  • Regulaciones: Cumplimiento con leyes locales de protección al consumidor

Mejoras de UX

  • Interfaz Visual: Mockups de estado del pedido en tiempo real
  • Comunicación Proactiva: Notificaciones preventivas antes de encuestas
  • Feedback Loop: Incorporar satisfacción del usuario en decisiones futuras

Resumen Ejecutivo

El sistema de encuesta para pedidos no completados es un mecanismo bilateral inteligente que:

Fortalezas Clave

  • Automatización: 95%+ de casos resueltos sin intervención manual
  • Equidad: Tratamiento diferenciado según historial y tipo de pago
  • Escalabilidad: Opera en todos los mercados de Cheaf
  • Inteligencia: Evaluación de deuda basada en comportamiento histórico

📊 Impacto en el Negocio

  • Resolución Rápida: <7 días promedio para casos completos
  • Alta Consenso: 95%+ de acuerdo entre usuarios y restaurantes
  • Retención Mejorada: Sistema de perdón de deuda para clientes leales
  • Costos Reducidos: <5% de casos requieren soporte manual

🔧 Características Técnicas

  • API RESTful: Endpoints para usuarios y restaurantes
  • Estados Transaccionales: Consistencia de datos garantizada
  • Integración Completa: Deuda, créditos, marketing automation
  • Monitoreo Avanzado: Métricas en tiempo real y alertas automáticas

🌍 Cobertura Operativa

  • Universal: Todos los países donde opera Cheaf
  • Especializado: Flujos específicos para México (soporte), Chile/Argentina (Cencosud)
  • Flexible: Adaptable a diferentes tipos de partners y usuarios

Este sistema proporciona un mecanismo justo, transparente y automatizado para resolver disputas sobre pedidos no completados, balanceando la responsabilidad entre usuarios y restaurantes mientras mantiene alta satisfacción del cliente y eficiencia operativa.

On this page

¿Cuándo se activa?Cobertura GeográficaFuncionalidad PrincipalServicios de la APIManageUnfulfilledAppUserOrderManageUnfulfilledRestaurantOrderLógica de Procesamiento1. Iniciación del ProcesoCondición de ActivaciónEstados de Respuesta2. Matriz de DecisiónTabla de Resolución3. Consulta de Encuestas (GET)Para Usuarios de App (ManageUnfulfilledAppUserOrder.get)Para Usuarios de Restaurante (ManageUnfulfilledRestaurantOrder.get)4. Procesamiento de Respuestas (UPDATE)Fase 1: Primera RespuestaFase 2: Resolución FinalEscenario A: Pedido Completado (0,0)Escenario B: Culpa del Usuario (1,1)Escenario C: Culpa del Restaurante (2,2)Escenario D: Respuestas Diferentes (Conflicto)Reglas de Negocio EspecíficasFilosofía del SistemaCódigos de Estado (u_status)Estados de ProcesamientoGestión de ComentariosCampos de Control de VistaTimestamps de AuditoríaReglas de Filtrado TemporalPara RestaurantesPara UsuariosIntegración con SistemasSistema de DeudaSistema de CréditosMarketing AutomationSistema de NotificacionesPush NotificationsEmail NotificationsEstados y TransicionesDiagrama de EstadoCódigos de Estado (u_status)Validaciones y ControlesValidaciones de EntradaControles de AutorizaciónPrevención de DuplicadosConsideraciones de UXExperiencia del UsuarioExperiencia del RestauranteCasos de Uso TípicosCaso A: Resolución Exitosa - Consenso PositivoCaso B: Usuario Reconoce Responsabilidad - Evaluación InteligenteCaso C: Restaurante Reconoce Responsabilidad - Reembolso DiferenciadoCaso D: Conflicto Requiere Intervención - Escalamiento MéxicoCaso E: Primer Pedido - Beneficio de la DudaManejo de ErroresCompatibilidad LegacyAlcance GeográficoCobertura UniversalParticularidades por PaísMéxico (MX)Chile y ArgentinaOtros PaísesModelos y Status UtilizadosModelos PrincipalesStatus y EstadosIntegraciones del SistemaPróximos Pasos y EvoluciónOptimizaciones PotencialesExpansión GeográficaMejoras de UXResumen EjecutivoFortalezas Clave📊 Impacto en el Negocio🔧 Características Técnicas🌍 Cobertura Operativa