ChefManager IA 3.16.7 · MÓDULO DE RECLAMOS DE CLIENTES
======================================================

NOTA DE INTEGRACIÓN
-------------------
Esta distribución incorpora las correcciones descritas en
CORRECCIONES_3.16.7_FUNCIONAL.txt. Debe desplegarse como paquete completo sobre
una copia respaldada; no mezclar los servicios abreviados del ZIP de código
externo, porque varios son marcadores y no implementaciones reales.

QUÉ AGREGA
----------
Un reclamo deja de ser una estrella baja suelta y pasa a ser un caso con
responsable, plazo, causa raíz, compensación y cierre trazable.

Canales de entrada (los cuatro comparten numeración, SLA, bitácora y avisos):
  1. Panel interno   · Clientes y CRM › Reclamos de clientes › "Registrar reclamo".
  2. QR / cliente    · reclamo.php y el botón "Reportar un problema" del seguimiento
                       del pedido. Además, una evaluación de 1–2 estrellas abre el
                       caso automáticamente en lugar de quedar solo registrada.
  3. WhatsApp        · Centro de Conversaciones › "Registrar reclamo". El caso queda
                       vinculado a la conversación y hereda contacto y cliente.
  4. Otros canales   · Teléfono, redes o web se registran desde el panel eligiendo
                       el canal correspondiente.

AISLAMIENTO POR SUCURSAL
------------------------
Un usuario con sucursal asignada (users.branch_id) solo ve y opera los reclamos de
esa sucursal. El filtro se aplica en el servidor: pedir el id de un caso de otra
sucursal responde 404, igual que un id inexistente, para no confirmar que existe.
Un usuario sin sucursal asignada supervisa todas las del negocio.

Si un reclamo se vincula a un pedido, el caso se ancla a la sucursal donde ocurrió
el hecho, no a la de quien lo carga.

PERMISOS NUEVOS
---------------
  complaints.view     Consultar        · Local, Admin, Gerente, Cajero, Mesero
  complaints.manage   Registrar y dar seguimiento · Local, Admin, Gerente, Mesero
  complaints.resolve  Resolver, compensar y cerrar · Local, Admin, Gerente

Se pueden reasignar por negocio desde Usuarios y roles, como cualquier otro permiso.

PLAZOS (SLA)
------------
Por defecto: crítico 2 h, alto 8 h, medio 24 h, bajo 72 h. Configurable por negocio
en restaurant_settings, clave `complaints.sla_hours` (JSON por severidad). Cambiar la
gravedad recalcula el plazo sobre la fecha de apertura, nunca sobre "ahora".

ARCHIVOS NUEVOS
---------------
  database/sqlite-v32-customer-complaints.sql
  app/Services/CustomerComplaintService.php
  reclamo.php
  public/assets/reclamo.js
  public/assets/reclamo.css
  tools/smoke-complaints.sh

ARCHIVOS MODIFICADOS
--------------------
  app/Support/Database.php     Registra la migración v32.
  api/index.php                Ruta `complaints`, módulo de plan `crm`.
  api/public.php               Alta pública, seguimiento por token y escalado
                               automático de evaluaciones críticas.
  public/assets/app.js         Página del módulo, menú, ruta y botón de WhatsApp.
  public/assets/app.css        Estilos de la bitácora del caso.
  public/assets/tracking.js    Botón "Reportar un problema" en el seguimiento.
  app/Services/AiInsights.php  Los reclamos alimentan al Gerente Inteligente 24/7.
  VERSION                      3.16.6 → 3.16.7

API
---
  GET    api/complaints                  Listado + resumen. Filtros: status, severity,
                                         category, channel, branch_id, assigned_user_id,
                                         pending, overdue, q.
  GET    api/complaints/options          Catálogos, responsables asignables y SLA.
  GET    api/complaints/report           Indicadores de 90 días.
  POST   api/complaints                  Alta.
  GET    api/complaints/{id}             Detalle + bitácora.
  PUT    api/complaints/{id}             Motivo, gravedad, asunto y contacto.
  POST   api/complaints/{id}/assign      Responsable.
  POST   api/complaints/{id}/note        Nota interna o respuesta visible al cliente.
  POST   api/complaints/{id}/status      Abierto / en gestión / esperando / desestimar.
  POST   api/complaints/{id}/resolve     Causa raíz + resolución + compensación.
  POST   api/complaints/{id}/reopen      Reapertura con motivo.

  POST   api/public.php?action=complaint         Alta pública (5 por hora y dispositivo).
  GET    api/public.php?action=complaint-status  Seguimiento por token.

ENLACES PARA EL CLIENTE
-----------------------
  Reclamo general del negocio:  reclamo.php?slug=<slug-del-restaurante>
  Reclamo sobre un pedido:      reclamo.php?pedido=<public_token-del-pedido>
  Seguimiento de un caso:       reclamo.php?token=<token-del-reclamo>

El canal público puede desactivarse por negocio con la clave
`complaints.public_intake_enabled` = false en restaurant_settings.

GERENTE INTELIGENTE 24/7
------------------------
El motor de reglas ahora lee el módulo de reclamos y puede emitir cinco alertas,
cada una con su evidencia numérica y acción directa al módulo:

  · Reclamos fuera del plazo comprometido (crítico desde 3 casos vencidos).
  · Reclamos graves sin resolver (2 o más de gravedad alta/crítica abiertos).
  · Causa de reclamo que se repite: cuando un mismo motivo concentra 3 o más
    casos, el problema es del proceso y no del caso puntual.
  · Reclamos que hubo que reabrir: la resolución no resolvió.
  · Costo de compensaciones: devoluciones y descuentos de 30 días, el costo
    visible de la mala calidad.

Las consultas son defensivas: si la migración v32 todavía no corrió, el panel
registra el detalle en storage/logs/operational-schema.log y sigue funcionando.

Métricas nuevas expuestas por el motor: complaints_30d, complaints_pending,
complaints_overdue, complaints_severe_pending, complaints_reopened_30d y
complaints_compensation_30d.

VALIDACIÓN REALIZADA
--------------------
  SQLite   Esquema completo reconstruido (schema + v2 + seed + v4…v32):
           integrity_check = ok, 0 violaciones de clave foránea, 198 tablas,
           3 permisos nuevos con 12 asignaciones a roles.
           Prueba de aislamiento: un usuario de sucursal ve 2 de 4 casos.
           Ciclo completo ejercitado: alta, listado, resumen, resolución con
           compensación, reapertura, reporte y seguimiento público.
  JavaScript  node --check sobre app.js, tracking.js y reclamo.js.
  PHP        Revisión léxica (comillas, escapes, llaves y paréntesis).

PENDIENTE ANTES DE PRODUCCIÓN
-----------------------------
Los tres pendientes que quedan dependen del servidor y debe ejecutarlos el
propietario. Ninguno pudo hacerse en el entorno de desarrollo.

  1. RESPALDO FECHADO de la base antes de desplegar, con checksum y ubicación de
     rollback anotada. La migración v32 solo crea tablas e índices nuevos y no
     altera ninguna tabla existente, pero el respaldo sigue siendo obligatorio.
     Hazlo ANTES de subir los archivos: la migración corre sola en la primera
     petición, sin confirmación.

  2. php -l. NO se ejecutó: el entorno de desarrollo no tiene runtime PHP, igual
     que en la auditoría 3.16.5. No hace falta un comando aparte:

         bash tools/preflight-production.sh

     ya recorre todos los *.php del proyecto, así que cubre los archivos nuevos
     sin ningún cambio. Debe terminar sin fallos antes de continuar.

  3. PRUEBAS HTTP EN STAGING. Se incluye el script:

         CHEFMANAGER_STAGING_URL=https://staging.ejemplo.com \
         CM_COMPLAINTS_EMAIL_A=gerente@staging.test CM_COMPLAINTS_PASSWORD_A='...' \
         CM_COMPLAINTS_EMAIL_B=otra-sucursal@staging.test CM_COMPLAINTS_PASSWORD_B='...' \
         CM_COMPLAINTS_PUBLIC_SLUG=mi-restaurante \
         bash tools/smoke-complaints.sh

     Verifica el ciclo completo del caso, que resolver sin causa raíz devuelva
     422, la matriz negativa de aislamiento entre sucursales (404 esperado), que
     el canal público limite a 5 reclamos por hora con 429, que rechace un token
     anti-CSRF inválido con 419, y que el seguimiento del cliente no exponga
     campos internos.

     SOLO CONTRA STAGING: crea reclamos reales y agota el cupo público a
     propósito. Nunca contra producción. La cuenta A necesita complaints.resolve
     y sucursal asignada; la B debe ser del mismo negocio pero de otra sucursal.

Lo que sigue fuera del alcance de una revisión de código, igual que en la
auditoría 3.16.5: la definición legal por país sobre plazos de retención de los
datos personales que ahora guarda el módulo (nombre, teléfono y correo del
cliente reclamante) y el responsable legal de esos datos.

PANTALLAS DE SUPERADMIN DIFERENCIADAS (3.16.7)
----------------------------------------------
Antes, `Patios de comidas` y `Franquicias` se veían casi idénticas: las dos listaban
"grupo + miembros". Ahora cada una abre por lo que de verdad la define.

PATIO DE COMIDAS · se administra en presente
  Endpoint nuevo: GET api/food-courts/overview  (solo Control Center)
  Métricas: patios, pedidos combinados abiertos, cobrado hoy en caja central y
  dinero por liquidar a operadores desde el último corte cerrado.
  Tabla: operadores sobre el límite contratado, abiertos frente al total del día,
  venta y cobro del día, saldo por liquidar con la fecha del último corte, hora pico.
  Modal "Operadores": qué operador está frenando la entrega ahora (subpedidos sin
  entregar) y comparación de desempeño de 7 días entre operadores.

  Un pedido cuenta como abierto por marca de tiempo (completed_at y cancelled_at en
  NULL), no por el vocabulario de estados, que puede cambiar sin avisar.

FRANQUICIA · se controla en el tiempo largo
  Endpoint nuevo: GET api/franchises/compliance  (solo Control Center)
  Métricas: redes, empresas activas, locales fuera de estándar y regalías por cobrar.
  Tabla: estándares corporativos activos, porcentaje de conformidad, locales
  desviados y regalías pendientes con el último período emitido.
  Modal "Ver desvíos": qué empresa, en qué territorio, cuántas recetas sin conformar
  y desde cuándo, más el conteo de verificaciones de precio de 90 días.

  Un local cuenta como fuera de estándar si tiene al menos un despliegue que no
  llegó a `compliant`, sin importar cuántas recetas corporativas sean.

QUÉ SE TOMÓ DE LITHOSPOS
  Su enfoque de patio es multi-tienda: panel centralizado, menús independientes por
  local y reportes consolidados para comparar desempeño entre locales. De ahí sale
  la comparación entre operadores y la hora pico, que no existían.
  Lo que ellos NO tienen y ChefManager sí: pedido combinado con un solo pago y
  liquidación por período. Eso no se copió porque ya estaba resuelto y es la
  diferencia real frente a tratar el patio como simple multi-sucursal.

ARCHIVOS TOCADOS POR ESTE BLOQUE
  app/Services/FoodCourtService.php   Endpoint overview.
  app/Services/FranchiseService.php   Endpoint compliance.
  public/assets/app.js                Ambas pantallas reescritas.

PENDIENTE
  Estas dos consultas no pudieron probarse contra datos reales de producción, solo
  contra el esquema. En staging conviene abrir ambas pantallas con un patio que
  tenga pedidos del día y una red con estándares desplegados, y contrastar los
  números con los de las pantallas operativas del patio y del panel de red.
