CHEFMANAGER IA · PROPUESTA DE MÓDULO FOOD COURT

ESTADO

ChefManager IA 3.7.0 implementó la Fase 1 (catálogo agregado y directorio de
locales). ChefManager IA 3.8.0 agregó las Fases 2 y 3 (pedido maestro +
subpedidos, y estado conjunto). ChefManager IA 3.9.0 agregó la Fase 4 (pago
dividido). ChefManager IA 3.10.0 agrega la Fase 5 (liquidaciones) y, por
primera vez, una interfaz de usuario básica para las cinco fases (directorio
y pedido público, seguimiento público, y un panel de administración), sin
reemplazar módulos ni crear una aplicación paralela. Ver
docs/RELEASE-3.10.0.txt y docs/VALIDACION-3.10.0.txt para el detalle y la
evidencia de prueba real (servidor PHP real + navegador real headless para
las páginas nuevas). Con esto, las cinco fases propuestas originalmente
están implementadas.

MODELO RECOMENDADO

Food Court no debe confundirse con una franquicia. Un patio de comidas coordina
varios operadores independientes que comparten el canal de compra y la experiencia
del cliente, pero no necesariamente inventario, impuestos, caja ni propiedad.

CAPA FOOD COURT

- Patio, zonas, mesas y kioscos comunes.
- Operadores/locales vinculados; cada uno mantiene su restaurant_id.
- Menú agregado con filtros por local y categoría.
- Carrito común que se divide en subpedidos por operador.
- Número maestro para el cliente y comandas separadas por KDS/local.
- Estado consolidado: esperando, preparando, parcialmente listo y listo completo.
- Pago central o pago por local, según contrato del patio.
- Liquidación por operador: venta bruta, comisión, alquiler, descuentos, impuestos,
  costos de pasarela, devoluciones y neto a pagar.
- Reglas de disponibilidad y horario propias de cada local.
- Auditoría y permisos del administrador del patio sin acceso operativo indebido.

MULTI-TENANT

ChefManager ya separa cada negocio mediante restaurant_id. La implementación Food
Court debe añadir un identificador de patio y referencias autorizadas, no sustituir
ni debilitar ese aislamiento. El menú agregado puede leer datos publicados; las
escrituras se ejecutan en transacciones controladas por cada tenant.

FASES SUGERIDAS

1. Catálogo agregado y directorio de locales. [IMPLEMENTADA EN 3.7.0]
2. Pedido maestro + subpedidos por local/KDS. [IMPLEMENTADA EN 3.8.0]
3. Estado conjunto. [IMPLEMENTADA EN 3.8.0 · pantalla de retiro pendiente, es UI]
4. Pago dividido y conciliación. [IMPLEMENTADA EN 3.9.0 · pago dividido; la conciliación contable es Fase 5]
5. Liquidaciones, comisiones y reportes del patio. [IMPLEMENTADA EN 3.10.0]

INTERFAZ DE USUARIO · LO QUE QUEDÓ CONSTRUIDO (3.10.0)

- food-court.php + public/assets/food-court.{css,js}: directorio público y
  pedido, mismo patrón que menu.php/kiosk.php (shell PHP + JS plano, sin
  tocar el bundle principal de la SPA). Usa las acciones "food-court" y
  "food-court-order" ya existentes desde las Fases 1-2, sin cambios de
  backend.
- food-court-tracking.php + public/assets/food-court-tracking.js:
  seguimiento público del pedido maestro, usando "food-court-track"
  (Fase 3), mismo patrón que tracking.php.
- food-court-admin.php + public/assets/food-court-admin.{css,js}: panel de
  administración básico, con la misma sesión/CSRF del Control Center.
  Vista de administrador (patios, operadores con comisión/alquiler,
  pedidos con pago central, liquidaciones) y vista de negocio (unirse o
  salir de un patio). Ver docs/RELEASE-3.10.0.txt para el detalle
  completo y el alcance no incluido todavía.

FASE 1 · LO QUE QUEDÓ CONSTRUIDO

- Tablas food_courts, food_court_operators y food_court_managers
  (database/sqlite-v19-food-court.sql), aditivas e idempotentes.
- app/Services/FoodCourtService.php: API de administración (Control Center o
  administrador acotado del patio) para crear patios, invitar operadores
  (sucursales concretas de negocios existentes) y que cada negocio acepte,
  edite o abandone su propia participación — nunca la de otro negocio.
- api/public.php, acción "food-court": catálogo agregado de solo lectura,
  filtrable por operador y por categoría, que reutiliza los mismos criterios
  de publicación que la acción "menu" existente. No crea pedidos ni toca pagos.
- Aislamiento multi-tenant intacto: cada operador conserva su restaurant_id,
  catálogo, caja e inventario; food_court_operators solo autoriza y muestra
  la referencia.
- Sin interfaz de usuario todavía: esta fase es solo backend (API + esquema).
  La pantalla de directorio/menú del patio queda para cuando se aborde el
  frontend del módulo.

FASES 2-3 · LO QUE QUEDÓ CONSTRUIDO (3.8.0)

- Tablas food_court_orders y food_court_order_operators
  (database/sqlite-v20-food-court-orders.sql) y la columna
  orders.food_court_order_id, aditivas e idempotentes.
- api/public.php, acción "food-court-order" (POST): el cliente arma un solo
  carrito con productos de varios operadores del patio; por cada operador
  involucrado se crea un pedido normal en `orders` (mismas reglas de
  disponibilidad, variantes y opciones que la acción "order" existente), y
  food_court_orders solo agrupa esos pedidos reales. Cada negocio ve y trabaja
  su subpedido exactamente igual que cualquier otro pedido, sin pantalla nueva.
  Por ahora solo admite "para recoger" en el propio local de cada operador
  (sin delivery ni cupones todavía).
- api/public.php, acción "food-court-track" (GET, por token público): estado
  conjunto para el cliente. FoodCourtService::aggregateStatus() define la
  regla: el pedido maestro avanza tan rápido como el operador más lento; si
  todos los subpedidos se cancelan, el conjunto se marca cancelado.
- app/Services/FoodCourtService.php, acción "orders" (GET, acotada a
  administración del patio): lista y detalle de los pedidos maestros de un
  patio con su estado conjunto y el desglose por operador. Cada negocio ya ve
  sus propios subpedidos como pedidos normales en su Control Center; esta
  vista es para quien administra el patio completo.
- Corrección: se agregó "food-courts" a la lista de recursos permitidos para
  cuentas de plataforma en api/index.php. Sin este cambio, ninguna cuenta de
  plataforma podía administrar un patio de comidas por HTTP real (la barrera
  de recursos del Control Center bloqueaba el recurso antes de llegar a
  FoodCourtService). El error solo aparece probando contra un servidor HTTP
  real, no invocando la clase directamente — ver docs/VALIDACION-3.8.0.txt.
- Sigue sin interfaz de usuario: el carrito multi-operador, el seguimiento del
  cliente y el panel de pedidos del patio son solo API por ahora.

FASE 4 · LO QUE QUEDÓ CONSTRUIDO (3.9.0)

- Tablas food_court_order_payments y food_court_order_payment_operators
  (database/sqlite-v21-food-court-payments.sql), aditivas e idempotentes. No
  tocan `sales`, `payments`, `cash_sessions` ni inventario de ningún negocio.
- app/Services/FoodCourtService.php, acción "orders/{id}/payments" (GET y
  POST, acotada a administración del patio): registra un pago central —
  cobrado en un punto compartido del patio, no en la caja de un operador — y
  lo aplica a los subpedidos que cubre, marcándolos pagados. Admite cubrir
  todos los subpedidos pendientes de una vez o solo los que se indiquen
  (operator_ids), y exige que el monto coincida exactamente con el saldo de
  lo que se está cubriendo, igual que el checkout normal de un pedido.
- Cada negocio conserva su otra opción sin ningún cambio: cobrar su propio
  subpedido en su propia caja con el checkout normal de `orders`, disponible
  desde la Fase 2. Las dos formas conviven sin un interruptor de "modo"
  explícito, según lo que el patio haya acordado con cada operador; un
  subpedido ya pagado por cualquiera de las dos vías queda protegido: ni el
  pago central ni el checkout propio pueden cobrarlo dos veces.
- FoodCourtService::groupPaymentStatus() define el estado de pago conjunto:
  "paid" solo si todos los subpedidos están pagados (por cualquier vía),
  "partial" si al menos uno lo está, "unpaid" si ninguno. Se expone en el
  panel de administración del patio, en el detalle de un pedido maestro y en
  el seguimiento público del cliente (food-court-track).
- Al aplicar un pago central, un subpedido pendiente de pago antes de cocina
  (política de pago-antes-de-cocina normal de "para recoger") pasa de
  "pending" a "confirmed" automáticamente, igual que lo haría el checkout
  normal de ese negocio — así el negocio no queda esperando un cobro que ya
  se hizo en otro punto del patio.
- No crea ninguna fila en `sales`/`payments` ni afecta inventario, caja o
  puntos de lealtad de ningún negocio: eso solo ocurre cuando el negocio
  cobra su propio subpedido con su propio checkout. La conciliación de
  cuánto le corresponde recibir a cada operador de lo cobrado de forma
  central (venta bruta, comisión del patio, neto a pagar) queda para la
  Fase 5.
- Registrar un pago central solo era posible por API hasta la 3.9.0; desde
  la 3.10.0 puede hacerse desde food-court-admin.php.

FASE 5 · LO QUE QUEDÓ CONSTRUIDO (3.10.0)

- Tablas food_court_settlements y food_court_settlement_operators
  (database/sqlite-v22-food-court-settlements.sql), aditivas e
  idempotentes. No tocan `sales`, `payments` ni ninguna tabla contable.
- Columnas nuevas food_court_operators.commission_percent/rent_amount: el
  contrato de liquidación de cada operador, editable solo por quien
  administra el patio (nunca por el propio negocio en su autogestión).
- app/Services/FoodCourtService.php, acción "settlements" (GET/POST/PUT,
  acotada a administración del patio): genera, lista, muestra y cierra
  liquidaciones por período. Por cada operador calcula venta bruta,
  cuánto cobró el patio de forma central (Fase 4), comisión, alquiler y
  el neto resultante (a favor del patio o del operador). No mueve dinero:
  es un reporte para conciliar manualmente.
- Corrección real encontrada durante la construcción del escenario de
  prueba de esta fase: el PUT de operador borraba su estado si la
  petición no incluía "status" explícitamente (por ejemplo, al guardar
  solo comisión y alquiler desde el panel nuevo). El mismo patrón se
  encontró y corrigió en PUT /food-courts/{id} y, fuera de este módulo,
  en PUT /franchises/{id} y PUT /franchises/{id}/members/{id}. Ver
  docs/RELEASE-3.10.0.txt y docs/VALIDACION-3.10.0.txt para el detalle.
