CHEFMANAGER IA 3.8.0 · FOOD COURT FASES 2 Y 3
==============================================

RESUMEN

Sobre la Fase 1 (3.7.0: catálogo agregado y directorio de locales), esta
entrega agrega el pedido maestro con subpedidos por operador y el estado
conjunto para el cliente. Sigue sin interfaz de usuario: todo lo nuevo es
API + esquema, igual que la Fase 1.

QUÉ SE AGREGÓ

- Pedido maestro (Fase 2): el cliente arma un solo carrito con productos de
  varios operadores del patio de comidas. Por cada operador involucrado se
  crea un pedido normal en la tabla `orders` existente, con las mismas
  reglas de disponibilidad, variantes, grupos de opciones y estaciones de
  cocina que ya usa la acción pública "order". Cada negocio ve y trabaja su
  subpedido exactamente igual que cualquier otro pedido en su Control Center,
  cocina o caja — sin pantalla nueva y sin tocar su aislamiento por
  restaurant_id. Por ahora el patio de comidas solo admite "para recoger" en
  el propio local de cada operador (sin delivery ni cupones todavía; el
  cliente puede indicar una mesa/zona común del patio como texto libre).
- Estado conjunto (Fase 3): el pedido maestro avanza tan rápido como el
  operador más lento (regla de FoodCourtService::aggregateStatus). Si todos
  los subpedidos se cancelan, el conjunto se marca cancelado. El cliente
  consulta este estado con el token público de su pedido maestro, igual que
  ya puede hacerlo con un pedido normal.
- Panel de pedidos del patio para quien lo administra (Control Center o
  administrador acotado del patio): lista y detalle de los pedidos maestros
  con su estado conjunto y el desglose por operador. No sustituye la vista
  de pedidos de cada negocio; es una vista adicional para quien coordina el
  patio completo, y por eso queda restringida a esa administración (expone
  datos de contacto del cliente y el detalle de varios negocios a la vez).

ARCHIVOS NUEVOS

- database/sqlite-v20-food-court-orders.sql: tablas food_court_orders y
  food_court_order_operators.
- (modificado) app/Support/Database.php: aplica la migración anterior y
  agrega la columna orders.food_court_order_id.
- (modificado) app/Services/FoodCourtService.php: aggregateStatus(),
  orderGroupDetail(), orderGroupsList() y la acción "orders" del dispatch.
- (modificado) api/public.php: acciones "food-court-order" (POST) y
  "food-court-track" (GET); también se sembraba el token CSRF de sesión en
  la acción "food-court" existente (ver CORRECCIONES).
- (modificado) api/index.php: se agregó "food-courts" a la lista de recursos
  permitidos para cuentas de plataforma (ver CORRECCIONES).

CORRECCIONES ENCONTRADAS DURANTE ESTA ENTREGA

1. Falta de token CSRF de sesión para el flujo público del patio. Los demás
   flujos públicos de pedido (menu.php, kiosk.php, tracking.php) siembran
   $_SESSION['cm_public_csrf'] al cargar su página HTML antes de que el
   cliente pueda enviar un pedido. El patio de comidas no tiene página propia
   todavía, así que ninguna carga anterior sembraba ese token: cualquier
   intento real de food-court-order habría fallado siempre con "Sesión de
   pedido vencida". Se corrigió haciendo que la acción "food-court" (el
   directorio, que sí ya se llama antes de pedir) siembre el token y lo
   devuelva en la respuesta como "csrf_token", igual que el patrón data-csrf
   de las páginas HTML existentes.
2. Cuentas de plataforma no podían administrar patios de comidas por HTTP
   real. api/index.php tiene una barrera que solo permite a una cuenta de
   plataforma tocar un conjunto fijo de recursos ('platform', 'restaurants',
   'plans', 'subscriptions', 'backups', 'franchises',
   'franchise-dashboard'); "food-courts" no estaba en esa lista, así que todo
   intento de un Super Administrador o administrador de plataforma de crear
   un patio, invitar un operador o ver sus pedidos habría sido rechazado con
   403 antes de llegar siquiera a FoodCourtService. Esto afectaba también a
   la Fase 1 (3.7.0), pero solo se detectó ahora: la validación de la Fase 1
   invocó FoodCourtService::dispatch directamente en una prueba de CLI, sin
   pasar por el enrutador real de api/index.php, así que esta barrera nunca
   se ejecutó en esa prueba. La validación de esta entrega sí monta un
   servidor HTTP real (ver docs/VALIDACION-3.8.0.txt) y encontró el bloqueo
   en el primer intento de crear un patio como cuenta de plataforma. Se
   corrigió agregando "food-courts" a esa lista.

ALCANCE NO INCLUIDO EN ESTA ENTREGA

- Delivery ni cupones en el pedido de patio de comidas (solo "para recoger").
- Pago dividido entre operadores (Fase 4) ni liquidaciones/comisiones del
  patio (Fase 5) — siguen en docs/ROADMAP-FOOD-COURT.txt como propuesta.
- Interfaz de usuario: ni el carrito multi-operador del cliente, ni la
  pantalla de seguimiento del pedido conjunto, ni el panel de pedidos del
  patio tienen pantalla todavía. Todo lo de esta entrega es API + esquema.
- El campo food_court_orders.status queda con su valor por defecto
  ('pending'); el estado real que se muestra siempre se calcula en el
  momento a partir de los subpedidos (aggregateStatus). Ese campo queda
  disponible para una futura optimización o para marcar completed_at /
  cancelled_at cuando se implemente cierre explícito del pedido conjunto,
  pero hoy no se actualiza y no debe leerse como el estado vigente.

ANTES DE PRODUCCIÓN

- Diseñar la interfaz de usuario del carrito multi-operador, el seguimiento
  del cliente y el panel de pedidos del patio antes de ofrecer esta fase a
  un cliente final.
- Confirmar la política de pago-antes-de-cocina de cada operador para
  pedidos "para recoger" (payment_moment_takeaway): por defecto cada
  subpedido de patio de comidas requiere cobro antes de pasar a cocina,
  igual que cualquier otro pedido para recoger del negocio. No hay excepción
  especial para pedidos de patio de comidas todavía (eso es, en parte, lo
  que resolverá la Fase 4 de pago dividido).
