Welcomeback POS — MVP
QSR · Welcomeback · Primer POS nativo en IA para la recurrencia · Stack: React + Node.js
| Métrica | Target | Medición |
|---|---|---|
| Tiempo transacción compleja | ≤15 segundos | Timestamp tap → DTE emitido |
| Uptime operacional | ≥99.5% | 07:00–21:00 monitoreo |
| Boletas sin emitir al cierre | 0 | Reconciliación DTE vs ventas |
| NPS cajeros (semana 1) | ≥50 | Survey in-app |
| Retención beta (30 días) | ≥80% | Locales activos / ingresados |
Llevar una "pre-cuenta" al cliente antes de emitir la boleta electrónica viola el Art. 55 DL 825 (Ley de IVA). Si un fiscalizador de incógnito recibe ese papel para pagar, cursa la infracción en el acto.
Referencias legales: Art. 55 DL 825 ↗ · Art. 97 N°10 Código Tributario ↗
Análisis Competitivo
Mercado chileno de POS para QSR (Quick Service Restaurant). Foco en cafeterías, barra, locales de almuerzo rápido.
Ventajas de Welcomeback POS vs. competidores
| Eje | Toteat | Bsale | SumUp | Redelcom | Welcomeback POS |
|---|---|---|---|---|---|
| Precio/mes | $80–150 USD | $63–98 USD | $0 + % | $199k + comisión | $45–70 USD |
| DTE nativo | Sí | Parcial | No | Add-on | Sí (default) |
| Mercado Pago nativo | No | No | Solo SumUp | No | Point + QR dinámico ⭐ |
| Modificadores 1-clic | No optimizado | No tiene | No | No | Core feature |
| Foco QSR | Secundario | No | No | No | Core use case |
| Ticket dual barra | Sí | No | No | No | Sí |
| Offline mode | Sí | No | No | No | Sí |
| Inteligencia de recurrencia | No | No | No | No | Nativo (Welcomeback) |
| Onboarding | Demo requerida | Autoservicio | Inmediato | Trámite bancario | ≤30 min |
| Clientes en Chile | 3.000–4.000 | 12.000 (total) | 15.000–30.000 | Nacional | 50 (beta) |
Lo que tomamos de cada competidor
| Competidor | Qué hacen bien | Qué hacen mal |
|---|---|---|
| Toteat | KDS, SII nativo, offline, integraciones LATAM | Caro, complejo para cafeterías, sin modificadores optimizados, requiere demo |
| Bsale | Pricing transparente, autoservicio, omnicanal | No es para restaurantes, sin KDS, sin foco takeaway |
| SumUp | Entrada sin fricción ($49 hardware), muchos clientes | Solo procesa pagos, no es un POS real, sin modificadores ni DTE |
| Redelcom | Liquidación rápida (48h), cobertura nacional | DTE como add-on pago, procesador de pagos disfrazado de POS |
| Poster POS | Setup 2–3 días, trial 15 días, soporte 24/7, analytics | Sin presencia fuerte en Chile, sin SII |
| Square | UX limpia, hardware agnóstico, ecosistema de apps | Sin SII chileno, orientado al mercado anglófono |
La brecha de mercado
El gap está en el segmento QSR mid-market: SumUp es demasiado básico (sin modificadores, sin KDS, sin DTE), Toteat es demasiado complejo y costoso para un local de barra. Pero el vacío más grande es otro: ningún POS del mercado chileno tiene inteligencia de recurrencia nativa. Todos tratan cada transacción como si fuera la primera vez. Welcomeback POS + Welcomeback saben que Juan viene todos los martes, siempre pide NotMilk, y lleva 16 días sin aparecer.
Para agregar "Latte Grande + NotMilk + shot extra" en Toteat se necesitan 5–7 clics. En Welcomeback POS: 2 taps.
M1 — Pantalla de Venta "Fast-Lane"
Pantalla principal del cajero. Optimizada para touch con una mano en tablet 10" horizontal (1280×800 mínimo). Archivo de prototipo interactivo: prototipo_POS.html.
Layout general (implementado)
┌──────────────────────────────────────────────────────────────────┐
│ [🏠 Inicio] [📦 Para llevar] [👤 Cliente Welcomeback] │ ← Topbar 56px
├────────────┬───────────────────────────────────┬────────────────┤
│ │ 🔥 Más pedidos [🔎 Buscar...] │ BOLETA │
│ 🔥 Más ped │ ───────────────────────────── │ ───────── │
│ ☕Calientes│ ┌───────┐ ┌───────┐ ┌───────┐ │ [chip client] │
│ 🧊 Fríos │ │ ☕ │ │ 🥐 │ │ ☕ │ │ [💡 WB sug.] │
│ 🍺 Alcohol │ │ Latte │ │Croiss.│ │Espress│ │ [alertas] │
│ ⭐ Especial│ │$3.500 │ │$1.800 │ │$1.800 │ │ │
│ 🍵 Tés │ └───────┘ └───────┘ └───────┘ │ ítems +/− │
│ 🥐 Desay. │ │ ───────── │
│ 🥪 Sándw. │ ┌───────┐ ┌───────┐ ┌───────┐ │ Subtotal │
│ 🥗 Bowls │ │ 🧊 │ │ ☕ │ │ 🧁 │ │ IVA 19% │
│ 🍰 Postres │ │ Cold │ │Cappu. │ │Muffin │ │ TOTAL │
│ │ │$2.800 │ │$3.200 │ │$1.600 │ │ [COBRAR] │
│ (centradas)│ └───────┘ └───────┘ └───────┘ │ │
└────────────┴───────────────────────────────────┴────────────────┘
Anchos y orden (CSS order): order:1 — Categorías 130px | order:2 — Productos flex | order:3 — Boleta 260px fijo.
Topbar — 3 botones principales
| Botón | Estado activo | Acción |
|---|---|---|
| 🏠 Inicio | Siempre activo | Vuelve a "Más pedidos", limpia búsqueda |
| 📦 Para llevar | Toggle on/off | Activa modo para llevar (badge visual en la orden) |
| 👤 Cliente Welcomeback | Verde cuando identificado | Abre modal de identificación (email o QR) |
Layout: Logo izquierda (Orig_Logotipo-03.png, verde #1a5c38) | 3 botones centrados (position:absolute) | Perfil derecha (cajero activo).
Bottom Nav — 5 tabs fijos
| Tab | Ícono | Comportamiento |
|---|---|---|
| Orden | Documento | Vista principal: categorías + productos + boleta |
| Mesas | Mesa | Mapa de mesas por zonas. Tap en mesa libre → abre orden nueva. Tap en mesa ocupada → carga directamente la orden activa de esa mesa |
| Delivery | Moto + badge rojo | Grid de tarjetas de pedidos. Filtros: Todos / Nuevos / En prep. / Listos |
| Ventas | Gráfico | Grid de tickets cuadrados con estado Activo / En progreso / Cerrado |
| Ajustes | Engranaje | Configuración del local, SII, hardware, preferencias, sesión |
View Mesas
Canvas libre con grid punteado de fondo. Cada mesa es un div posicionado absolutamente con coordenadas x,y,w,h (mínimo 88×88px). Zonas: Interior, Terraza, Barra.
| Estado | Borde | Dot | Descripción |
|---|---|---|---|
| Libre | Verde dashed 2px | Verde | Mesa disponible. Tap → abre panel lateral para iniciar orden o asignar reserva. |
| Ocupada | Ámbar sólido 2.5px | Ámbar | Orden activa, cliente sin WB. |
| En preparación | Azul sólido 2.5px + pulso | Azul pulsante | Orden enviada a cocina pendiente de entrega. |
| Welcomeback | Naranja 2.5px | Naranja | Cliente WB identificado. Badge con nombre del cliente. |
| Reservada | Morado dashed 2px | Morado | Reserva asignada, cliente aún no llegó. Muestra hora y nombre del grupo. |
Flujo de clic en mesa
Mesa libre / reservada → se activa como nueva orden y navega directo a la vista de orden.
Mesa ocupada / en prep. → navega directo a la vista de orden. El header se adapta al contexto de mesa.
Al cambiar de tab (Mesas, Ventas, etc.) el contexto de mesa se limpia automáticamente.
Vista de orden con mesa activa — 2 filas
El componente se reduce al mínimo para maximizar el espacio de la orden:
+-------------------------------------------+ | Mesa 2 · 32m [+] | +-------------------------------------------+ | [ Juan ] [ 2 ] (+) | +-------------------------------------------+
| Elemento | Acción / Descripción |
|---|---|
| Nombre de mesa · tiempo | Toca el texto → abre el panel lateral de mesa |
| [+] (derecha) | Abre nueva orden — el único botón de nueva orden |
| Chips de comensales | Tap → editar nombre del comensal. Con nombre asignado aparece en verde/naranja (WB) |
| (+) circular | Añade un comensal más a esta mesa |
| Ocultos automáticamente | Tabs de multi-orden · badge de número de orden · chip "Identificar cliente" |
Sin mesa activa el flujo es el estándar: "Orden actual" en el header, tabs de órdenes visibles, chip de cliente visible.
Panel lateral de mesa
Accesible tocando el nombre de la mesa en el header. Muestra:
- Tiempo transcurrido y número de comensales
- Chips de comensales con nombre · tap para editar o marcar como WB
- Resumen de la orden activa con total
- Formulario de reserva manual si la mesa está libre
- Acciones: Abrir mesa / Cerrar mesa
Comensales y nombre de mesa
Cada mesa tiene un array comensales[] con {num, nombre, wb, clienteId}. La identificación del cliente ocurre vía los chips de comensales, no mediante el banner genérico de cliente.
Nombre editable: en modo edición, doble clic sobre la tarjeta → input inline. El nombre reemplaza al número en la tarjeta y en el header de la orden.
Modo edición (botón "✏️ Editar mapa"): drag para mover mesa, drag en esquina inferior derecha para redimensionar. Tamaño mínimo 88×88px. Integración Cover Manager: en V1.3 las reservas del día se sincronizarán automáticamente; hasta entonces se asignan manualmente desde el panel lateral.
View Delivery
Grid de tarjetas de pedidos de plataformas (Rappi 🟠, Uber Eats ⬛, PedidosYa 🟡). Flujo: Nuevo → [Aceptar] → En preparación → [Listo] → Listo → [Entregado] → desaparece.
View Ventas
Grid de tickets cuadrados (minmax(178px, 1fr)). 3 estados: Activo (azul) / En progreso (ámbar) / Cerrado (verde). Resumen del día en subheader. Filtro por franja horaria: alimenta el algoritmo de "Más pedidos dinámico" que cambia según la hora.
M1.4 — Multi-orden con tabs (Fase 2)
Sistema Multi-Orden (tabs)
- + — nueva orden. La orden actual pasa a "en progreso" si tiene ítems.
- Tab activo — verde sólido con número de orden (#002).
- Punto naranja — en tabs inactivos con ítems pendientes.
- ✕ en tab — cierra esa orden (confirmación si tiene ítems). No se puede cerrar la última.
- Al cobrar: la orden desaparece de tabs, se crea una nueva vacía automáticamente.
Botón "Enviar a Cocina" (configurable)
Aparece encima de COBRAR cuando está habilitado en Ajustes → Preferencias. Al tocar cambia a "✓ Enviado", se deshabilita hasta la siguiente orden. Toggle en Ajustes → "Botón Enviar a cocina".
M1.2 — Panel de ticket + descuentos manuales
Panel boleta — chip del cliente
| Estado | Visualización |
|---|---|
| Sin cliente | Avatar 👤, texto "Toca para identificar". Tap → abre modal WB. |
| Identificado | Borde verde, avatar ⭐, nombre, tier y visitas. Fondo verde translúcido. |
Gestión de descuentos
Disponible desde el panel del ticket antes de cobrar. El cajero puede aplicar un descuento sobre el total de la orden o sobre un ítem específico.
| Tipo | Cómo activarlo | Comportamiento |
|---|---|---|
| Sobre el total | Botón 🏷 Desc. en el panel de totales | Se muestra fila "Descuento" entre subtotal e IVA. El total y el cobro se recalculan en tiempo real. |
| Sobre un ítem | Botón 🏷 en la fila del ítem en el ticket | El precio del ítem muestra el original tachado + precio con descuento. Badge con el porcentaje o monto aplicado. |
| Campo | Opciones rápidas | Campo libre | Tipo por defecto |
|---|---|---|---|
| Monto fijo ($) | — | Monto en pesos (capped al total del ítem o pedido) | Predeterminado |
| Porcentaje (%) | 5% · 10% · 15% · 20% | Cualquier valor entre 0 y 100 | Toggle $ → % |
El panel abre con tipo $ (pesos) por defecto — el más frecuente en operación. El toggle $ / % permite cambiar. El panel incluye un botón ✕ en la esquina superior derecha para cerrarlo sin aplicar cambios. El botón "✓ Aplicar" ocupa todo el ancho para facilitar el toque. El descuento se elimina al iniciar una nueva venta. Solo puede haber un descuento activo por orden (total o ítem, no ambos simultáneamente).
Promociones automáticas (Ajustes → Carta)
A diferencia de los descuentos manuales, las promociones se configuran de antemano y se aplican automáticamente cada vez que un ítem elegible entra al ticket — sin que el cajero tenga que hacer nada.
| Tipo | Lógica | Ejemplo |
|---|---|---|
| 2x1 | Por cada 2 unidades elegibles, la de menor precio es gratis (100% de descuento). Si hay 3 unidades, solo 1 es gratis. Si hay 4, 2 son gratis. | Happy Hour bebidas 18:00–21:00: añadir 2 Lattes → el más barato queda a $0 |
| % descuento | Porcentaje aplicado al precio de cada ítem elegible en tiempo real. | 20% en postres todos los lunes |
| Monto fijo | Descuento fijo en pesos por ítem elegible (capped al precio del ítem). | −$500 en sándwiches |
| Parámetro | Descripción |
|---|---|
| Nombre | Etiqueta visible para el admin y en el badge del ticket |
| Tipo | 2x1 / % descuento / monto fijo |
| Categorías | A qué productos aplica: por categoría o todos |
| Horario | Rango HH:MM–HH:MM o "Todo el día". El sistema compara la hora actual al calcular |
| Activa/Inactiva | Toggle manual para activar o pausar sin eliminar la configuración |
Prioridad: el descuento manual sobre un ítem tiene prioridad sobre la promo automática para ese ítem. Las promos automáticas coexisten con el descuento manual sobre el total.
Badge en ticket: los ítems con promo activa muestran un badge naranja con la etiqueta (ej: "2x1 ×1 gratis") y el precio original tachado.
Alertas contextuales Welcomeback
| Tipo | Color | Ejemplo |
|---|---|---|
stamp | Ámbar | ⭐ 1 visita para café gratis |
bday | Violeta | 🎂 Cumpleaños en 3 días |
allergy | Rojo — siempre visible | ⚠️ ALÉRGICA A NUECES |
churn | Rojo suave | ⚠️ No venía hace 18 días |
Panel de categorías (130px, vertical)
| # | Nombre | Ícono | Color barra |
|---|---|---|---|
| 1 | Más pedidos | 🔥 | Rojo |
| 2 | Calientes | ☕ | Ámbar |
| 3 | Fríos | 🧊 | Azul |
| 4 | Alcoholes | 🍺 | Rosa |
| 5 | Especiales | ⭐ | Violeta |
| 6 | Tés | 🍵 | Verde |
| 7 | Desayunos | 🥐 | Naranja |
| 8 | Sándwiches | 🥪 | Amarillo |
| 9 | Bowls | 🥗 | Esmeralda |
| 10 | Postres | 🍰 | Rosa claro |
Categorías centradas verticalmente. Ícono SVG fino 24×24 + nombre + barra de color en borde inferior. "Más pedidos": productos con cat.includes('top'). Vista por defecto al abrir el POS.
M1.1 — Grid de productos + tarjetas visuales
Grid de productos
Columnas: repeat(auto-fill, minmax(152px, 1fr)). Tap sin modificadores → directo a boleta. Tap con modificadores → Modal M2. Producto agotado: overlay gris + tag "Agotado", no clickeable.
Preselección de modificadores: al abrir el modal de modificadores, la primera opción de cada grupo single queda seleccionada automáticamente (o la marcada como default:true si existe). El botón "Agregar" está activo desde el primer momento sin necesidad de tocar nada si las opciones por defecto son aceptables.
Diseño de tarjeta (v2 — full-card photo)
- Aspect-ratio 1:1; imagen cubre 100% de la tarjeta con
object-fit: cover - Overlay con gradiente:
transparent 30% → rgba(0,0,0,0.72) 100%para legibilidad del texto - Nombre y precio en blanco sobreimpuestos en la parte inferior de la tarjeta
- Badge pill translúcido en esquina superior izquierda: 🔥 Popular / ⭐ Top
- Hover:
scale(1.03)+ zoom interno de la foto - Imágenes servidas por Unsplash con IDs fijos en
PIC_MAP(37 entradas; sin API aleatoria) - Fallback: emoji del producto si la imagen no carga (
onerrorhandler)
Productos implementados (22)
| Producto | Categorías | Modificadores |
|---|---|---|
| Latte Grande | top, calientes | Leche (req), Shots (opt), Endulzante (opt), Nota (opt) |
| Croissant | top, desayunos | — |
| Espresso | top, calientes | Intensidad (req) |
| Cold Brew | top, fríos | Tamaño (req) |
| Muffin | top, desayunos | — |
| Cappuccino | top, calientes | Leche (req), Tamaño (req) |
| Americano | calientes | Tamaño (req), Intensidad (req) |
| Flat White | calientes | Leche (req) |
| Frappé | fríos | Sabor (req) |
| Limonada | fríos | — |
| Smoothie Proteico | fríos | Base (req) |
| Cerveza Artesanal | alcoholes | — |
| Aperol Spritz | alcoholes | — |
| Té Verde | tés | — |
| Chai Latte | tés | Leche (opt) |
| Tostada Palta | desayunos | — |
| Bowl Acaí | desayunos | — |
| Sándwich Pollo | sándwiches | Pan (req) |
| Veggie Wrap | sándwiches | — |
| Poke Bowl | bowls | — |
| Cheesecake | postres | — |
| Brownie | postres | — |
M1.3 — Identificación de cliente (modal Welcomeback)
Modal Welcomeback — identificación de cliente
Tab Email: campo + botón "Buscar" por correo exacto. Tab Nombre: campo con autocomplete en tiempo real — al escribir cualquier parte del nombre o apellido aparece un desplegable con avatar, nombre completo, email y tier; se selecciona con clic o Enter. Tab QR: área cámara simulada. Clientes demo:
| Cliente | Tier | Alertas | |
|---|---|---|---|
| juan.garcia@gmail.com | Juan García | VIP (47 visitas) | ⭐ stamp + 🎂 cumpleaños |
| mlopez@hotmail.com | María López | Regular (12 visitas) | ⚠️ alergia nueces + churn 18d |
| c.vega@empresa.cl | Carlos Vega | VIP (89 visitas) | ⭐ 5 visitas para premio |
El email del cliente identificado se autocompleta en el campo de envío de boleta al llegar a la pantalla de pago aprobado.
Edge cases
| Situación | Comportamiento |
|---|---|
| Sin internet | Banner ámbar: "Modo offline — boletas en cola". Opera normal. |
| CAF ≤50 folios | Alerta naranja en header. No bloquea. |
| CAF = 0 | Alerta roja bloqueante. No se puede cobrar. |
| Impresora desconectada | Advertencia en header. Cobro OK, re-impresión desde historial. |
| Inactividad 3 min | Bloqueo automático. PIN → desbloquea. Orden intacta. |
| Orden vacía toca Cobrar | Imposible — botón desactivado |
| Producto sin modificadores | Se agrega directo, sin modal |
| Cliente no encontrado | Toast "Cliente no encontrado" |
| Pago procesado | Toast → boleta limpia → orden #N+1 → cliente reseteado |
Historias de usuario
- US-01 Como cajero, quiero agregar un producto con modificadores en máximo 2 taps.
- US-02 Como cajero, quiero ver los productos más vendidos primero sin navegar.
- US-03 Como cajero, quiero eliminar un ítem del pedido fácilmente.
- US-17 Como cajero, quiero saber si estoy en modo offline antes de cobrar.
- US-24 Como cajero, quiero ver si el cliente tiene "lo de siempre" para ofrecérselo.
- US-25 Como cajero, quiero que los stamps se acumulen sin hacer nada extra.
Criterios de aceptación
- Tap en producto sin modificadores → ítem en boleta en ≤300ms
- "Más pedidos" visible sin scroll al abrir
- Total de la boleta se actualiza en ≤100ms tras cualquier cambio
- Botón COBRAR desactivado con boleta vacía
- Identificación del cliente por teléfono en ≤1 segundo
- "¿Lo de siempre?" carga la orden completa en 1 tap con todos los modificadores
- Alertas de alergia siempre visibles en rojo
- Modal de modificadores bloquea "Agregar" hasta que todos los requeridos estén completos
M2 — Matriz de Modificadores
El diferenciador #1 del producto. Modal de configuración de producto en 1 clic.
M2.1 — Modal de modificadores
Tipos de grupos
| Tipo | Descripción | UI | Ejemplo |
|---|---|---|---|
single |
Máximo 1 opción | Botones radio | Tipo de leche: Entera / NotMilk / Avena |
multi |
1 a N opciones (configurable) | Botones checkbox | Shots extra: +1 / +2 (máx 2) |
input |
Texto libre del cajero | Campo de texto | Nota para barista: "Sin lactosa" |
M2.2 — Estructura de datos + preselección automática
Estructura de datos
{
"nombre": "Latte Grande",
"precio_base": 3500,
"grupos_modificadores": [
{
"nombre": "Tipo de leche",
"tipo": "single",
"requerido": true,
"opciones": [
{ "nombre": "Entera", "precio_extra": 0 },
{ "nombre": "NotMilk", "precio_extra": 500 },
{ "nombre": "Avena", "precio_extra": 800 }
]
},
{
"nombre": "Shots extra",
"tipo": "multi",
"requerido": false,
"max_seleccion": 2,
"opciones": [
{ "nombre": "+1 shot", "precio_extra": 600 },
{ "nombre": "+2 shots", "precio_extra": 1200 }
]
}
]
}
Reglas de validación
- Botón "AGREGAR" desactivado si hay grupos
requerido=truesin selección - Al tocar "AGREGAR" con requeridos vacíos: grupos faltantes se resaltan en rojo + scroll al primero
- El precio se recalcula sin debounce (instantáneo) con cada cambio
- Máximo 5 grupos visibles antes de activar scroll interno
Criterios de aceptación
- Modal carga en ≤200ms (datos desde IndexedDB)
- Precio se recalcula en ≤50ms por cambio de selección
- Botón AGREGAR bloqueado hasta completar requeridos
- Todos los botones ≥44px para uso con una mano en tablet
- En modo edición, valores previos pre-seleccionados
M3 — Flujo de Cobro y Pago
6 estados. Soporta Transbank, Mercado Pago Point, QR dinámico, efectivo y mixto. El cajero nunca reingresa el monto en el terminal.
M3.1 — Resumen de cobro + propina
Diagrama de estados
M3.2 — Selección de método de pago
Configuración de métodos de pago (Ajustes)
Desde Ajustes → Métodos de pago habilitados el dueño activa o desactiva cada método con un toggle. Solo los métodos activos aparecen en la pantalla de cobro del cajero.
| Toggle | Método | Descripción |
|---|---|---|
| ON | 💳 Débito — Transbank | Terminal Webpay Plus · ~1.5% |
| ON | 💳 Crédito — Transbank | Terminal Webpay Plus · ~2.5% |
| ON | 📲 Mercado Pago Point | Terminal Point Smart/Plus · 0.79% débito ⭐ |
| ON | 📱 QR Mercado Pago | Sin terminal · cliente escanea desde su app · 0.79% |
| ON | 💵 Efectivo | Sin comisión · vuelto automático |
| ON | 🔀 Pago mixto | Efectivo + tarjeta en la misma boleta |
Si todos los toggles están apagados, la pantalla de cobro muestra un aviso para ir a configurarlos. El cajero nunca queda bloqueado sin saber por qué.
Métodos de pago — completo
| Método | Procesador | Hardware | Tasa |
|---|---|---|---|
| Débito / Crédito | Transbank Webpay Plus | Terminal Ingenico / Verifone | ~1.5% / ~2.5% |
| MP Point Débito/Créd. | Mercado Pago | Point Smart / Plus (~$50k) | 0.79% / 1.49% ⭐ |
| QR Dinámico ⭐ | Mercado Pago | Solo pantalla del POS | 0.79% — sin hardware |
| QR Estático | Mercado Pago | Impresión en mostrador | 0.79% |
| Efectivo | Local | Ninguno | 0% |
| Mixto | Cualquier combo | Según método | Proporcional |
| Factura empresa | — | — | — DTE Tipo 33 |
Estado 1: RESUMEN_COBRO
Incluye sección de propina opcional antes del total. El cliente o cajero selecciona porcentaje; el total se actualiza en tiempo real.
┌─────────────────────────────────────────────────┐
│ [← VOLVER] RESUMEN DE COBRO │
├─────────────────────────────────────────────────┤
│ PEDIDO #042 │
│ ┌──────────────────────────────────────────────┐│
│ │ Juan (nombre, opt.) ││
│ └──────────────────────────────────────────────┘│
│ ────────────────────────────────────────────── │
│ 1x Latte Grande $4.100 │
│ > NotMilk, +1 shot │
│ 1x Croissant $1.800 │
│ ────────────────────────────────────────────── │
│ 💚 ¿Desea agregar propina? │
│ [ Sin propina ] [ 5% ] [ 10% ] [ 15% ] │
│ ────────────────────────────────────────────── │
│ Subtotal (sin IVA) $4.957 │
│ IVA 19% (incluido) $943 │
│ Propina (10%) $590 │
│ ────────────────────────────────────────────── │
│ TOTAL A COBRAR $6.490 │
│ │
│ [Facturar a empresa →] (botón secundario) │
│ ┌────────────────────────┐ │
│ │ CONTINUAR → │ │
│ └────────────────────────┘ │
└─────────────────────────────────────────────────┘
| Opción propina | Comportamiento |
|---|---|
| Sin propina (default) | Total sin cambio. Opción activa al abrir el modal. |
| 5% / 10% / 15% | Suma propina al total. Aparece línea "Propina" en el desglose. |
| Cambio de opción | El total se recalcula en tiempo real. La propina se incluye en el monto cobrado y registrado en venta. |
Estado 2: SELECCION_PAGO
┌─────────────────────────────────────────────────┐
│ [← VOLVER] #042 — Juan $5.900 │
├─────────────────────────────────────────────────┤
│ ¿CÓMO PAGA? │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ 💳 DÉBITO │ │ 💳 CRÉDITO │ │
│ │ Transbank │ │ Transbank │ │
│ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ 📲 MP POINT │ │ 📱 QR MP │ │
│ │ 0.79% déb. │ │ Sin terminal│ │
│ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ 💵 EFECTIVO │ │ 🔀 MIXTO │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────┘
Solo aparecen los métodos activos en la configuración del local (Backoffice → Pagos).
M3.5 — Transbank / MP Point
Estado 3a: PROCESANDO_PAGO (Transbank / MP Point)
┌─────────────────────────────────────────────────┐
│ 💳 ACERQUE LA TARJETA │
│ Total: $5.900 │
│ [ ~~~ Animación NFC ~~~ ] │
│ Esperando respuesta del terminal... │
│ Timeout: 60s │
│ [CANCELAR] │
└─────────────────────────────────────────────────┘
UI bloqueada — no se puede navegar. Si customer display activo: total + logo + animación para el cliente. Timeout 60s → Reintentar / Cambiar método / Cancelar.
M3.4 — QR dinámico Mercado Pago
Estado 3b: ESPERANDO_QR (Mercado Pago QR Dinámico)
┌─────────────────────────────────────────────────┐
│ [←] #042 — Juan $5.900 │
├─────────────────────────────────────────────────┤
│ 📱 ESCANEA CON MERCADO PAGO │
│ │
│ [█████████████████████████████████] │
│ [██ QR DINÁMICO — $5.900 ██] │
│ [██ (10 min · se renueva) ██] │
│ [█████████████████████████████████] │
│ │
│ ⏱ Esperando pago... [CANCELAR] │
└─────────────────────────────────────────────────┘
- QR generado en tiempo real con el monto exacto — polling cada 5 segundos.
- Timeout 10 minutos: toast "QR expirado" + botón "Generar nuevo QR".
- Si webhook tarda >3 min sin respuesta: opción de cambiar a efectivo.
Estado 4: PAGO_APROBADO
┌─────────────────────────────────────────────────┐
│ ✅ PAGO APROBADO │
│ PEDIDO #042 — JUAN │
│ $5.900 — Débito MP Point │
│ 🖨 Imprimiendo tickets... │
│ 📄 Emitiendo boleta SII... ⏳ │
│ ┌──────────────────────────────────────────┐ │
│ │ 💳 Pagar con transferencia — Fintoc │ │
│ │ ┌────────┐ Escanea para pagar $5.900 │ │
│ │ │ [QR] │ vía transferencia bancaria │ │
│ │ └────────┘ instantánea │ │
│ └──────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────┐ │
│ │ [MP] Pagar con Mercado Pago │ │
│ │ ┌────────┐ Escanea con tu app MP │ │
│ │ │ [QR] │ o billetera digital — $5.900 │ │
│ │ └────────┘ │ │
│ └──────────────────────────────────────────┘ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ 🖨 Imprimir │ │ ✉️ Enviar email │ │
│ └──────────────────┘ └──────────────────┘ │
│ [campo email si se elige esa opción] │
│ ┌─────────────────────────────────────────┐ │
│ │ NUEVA VENTA │ │
│ └─────────────────────────────────────────┘ │
│ [Ver detalle boleta] │
└─────────────────────────────────────────────────┘
Tickets se imprimen automáticamente. DTE en background — no bloquea "NUEVA VENTA". ⏳ cambia a ✅ en ~1-2s. Si hay cliente Welcomeback: "⭐ Stamp sumado a Juan" durante 3s.
Los botones 🖨 Imprimir y ✉️ Enviar por email permiten al cajero entregar la boleta al cliente de la forma que prefiera. Al pulsar "Enviar email" aparece un campo de texto para ingresar el correo. Ambos botones cambian a estado ✅ verde tras completarse. Se resetean al iniciar una nueva venta.
El bloque Fintoc muestra un QR con el monto exacto (vía transferencia bancaria instantánea, sin comisión porcentual). El bloque Mercado Pago QR permite al cliente escanear con la app de Mercado Pago o cualquier billetera digital compatible. Ambos QR se generan dinámicamente con el monto de cada cobro y requieren que el cliente tenga cuenta en el servicio respectivo. En producción el QR de MP se genera vía API de Mercado Pago (POST /instore/orders/qr/seller/collectors/{user_id}/pos/{external_pos_id}/qrs) usando el modelo QR Dinámico Asistido (Attended); la confirmación llega por webhook.
Estado 5: PAGO_RECHAZADO
┌─────────────────────────────────────────────────┐
│ ❌ PAGO RECHAZADO │
│ Motivo: Fondos insuficientes │
│ Código: -4 (Transbank) / cc_rejected (MP) │
│ ┌─────────────────────────────────────────┐ │
│ │ REINTENTAR │ │
│ └─────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────┐ │
│ │ CAMBIAR MÉTODO DE PAGO │ │
│ └─────────────────────────────────────────┘ │
│ [Cancelar venta] │
└─────────────────────────────────────────────────┘
M3.3 — Efectivo + numpad + vuelto
Flujo efectivo (detalle)
Total a cobrar: $5.900
Monto recibido: [ $10.000 ]
[7][8][9] Accesos rápidos:
[4][5][6] [Exacto] [$10.000] [$20.000]
[1][2][3]
[ 0 ][⌫]
VUELTO: $4.100
[ CONFIRMAR COBRO EFECTIVO ]
[Exacto] rellena el total (vuelto $0). Vuelto se recalcula en tiempo real. Botón "CONFIRMAR" activo solo cuando monto_recibido ≥ total.
Flujo pago mixto
Efectivo: [ $2.000 ] ← cajero ingresa
Tarjeta: [ $3.900 ] ← automático (total - efectivo)
[CONFIRMAR DIVISIÓN]
1. Registra $2.000 en efectivo
2. Activa terminal para cobrar $3.900
3. Si tarjeta rechazada → vuelve a la división
4. Boleta única por $5.900
Flujo factura a empresa (Tipo 33)
Los descuentos aplicados en M1.2 se reflejan automáticamente en el total del resumen de cobro y en el monto cobrado.
Edge cases
| # | Situación | Comportamiento |
|---|---|---|
| EC-01 | Tarjeta rechazada | PAGO_RECHAZADO → Reintentar / Cambiar método / Cancelar |
| EC-02 | Terminal sin respuesta (60s) | Timeout → Reintentar / Efectivo / Cancelar. Monto NO fue cobrado. |
| EC-03 | QR expirado sin escanear | Toast "QR expirado" → botón "Generar nuevo QR" |
| EC-04 | Webhook MP tardío (>3 min) | Polling cada 5s. Sin confirmación → opción cambiar a efectivo |
| EC-05 | Sin papel en impresora | Toast error. Cobro OK, boleta OK. Re-impresión desde historial. |
| EC-06 | Internet cae durante cobro | Efectivo: OK. Terminal: puede seguir (conexión local). DTE en cola offline. |
| EC-07 | Vuelto mal ingresado | Campo numpad editable antes de confirmar. Recalcula en tiempo real. |
| EC-08 | Cliente pide factura con RUT empresa | Botón "Facturar a empresa" → ingresa RUT → DTE Tipo 33 |
| EC-09 | Doble cobro accidental | Botón bloqueado durante PROCESANDO_PAGO — imposible duplicar. |
| EC-10 | Efectivo supera el total en mixto | Si efectivo ≥ total → cobra todo efectivo, tarjeta ignorada. |
Historias de usuario
- US-07 Como cajero, quiero cobrar en efectivo y que el sistema me diga el vuelto exacto.
- US-08 Como cajero, quiero que el pago con tarjeta sea automático sin reingresarlo en el terminal.
- US-09 Como cajero, quiero asociar un nombre al pedido para llamarlo en barra.
- US-19 Como cajero, quiero poder cambiar el método de pago si la tarjeta es rechazada.
- US-32 Como cajero, quiero cobrar con QR de Mercado Pago sin necesitar terminal físico — el cliente escanea desde su app MP al ver la pantalla de pago aprobado.
- US-33 Como dueño, quiero usar Mercado Pago para pagar menos comisión por transacción.
- US-34 Como cajero, quiero ofrecer al cliente la opción de pagar por transferencia bancaria escaneando un QR Fintoc directamente en la pantalla de pago aprobado, sin hardware adicional.
Criterios de aceptación
- Vuelto calculado automáticamente para efectivo
- Transbank / MP Point envían el monto correcto sin que el cajero lo reingrese
- QR dinámico generado en ≤1 segundo tras seleccionar ese método
- QR expira a los 10 minutos con opción de renovar
- Flujo completo en ≤3 taps desde "COBRAR" hasta PAGO_APROBADO
- Botones de pago ≥64px de altura
- Número de pedido visible en ≥48px en el estado PAGO_APROBADO
- DTE en background no bloquea el botón "NUEVA VENTA"
- Doble cobro imposible — botón bloqueado durante PROCESANDO_PAGO
- Con internet caído: efectivo funciona normal, DTE en cola offline
M4 — Emisión DTE (Boleta Electrónica SII)
Completamente automática. El cajero no hace nada adicional después del pago.
M4.1 — Boleta Tipo 39 automática
Tipos de documento
| Tipo | Código SII | Cuándo | Requisitos adicionales |
|---|---|---|---|
| Boleta Electrónica | 39 | Default — consumidores finales. Todos los productos tributan IVA 19%, incluidos alcoholes. | Ninguno |
| Factura Electrónica | 33 | Cliente corporativo solicita factura por consumo de empresa | e-RUT empresa (obligatorio) + glosa del consumo (Res. Ex. 121 SII) |
| Nota de Crédito | 61 | Anulación de boleta emitida — única vía legal para corregir | Referencia al folio original |
Flujo de emisión
- Pago confirmado → POS genera JSON de la orden
- Backend construye XML del DTE firmado (RSA-SHA1)
- Envío al SII o intermediario (Acepta / Bsale API)
- SII retorna timbre electrónico (TED)
- PDF generado con QR del timbre → impresión automática
Sincronización al cierre: además del envío en tiempo real, al cerrar caja el sistema sube automáticamente todas las boletas del día al SII en lote.
Marco legal — obligatoriedad y sanciones
El SII exige emitir la boleta en el instante en que el cliente pide la cuenta. No existe margen legal para diferirla.
| Norma | Contenido clave | Referencia |
|---|---|---|
| Art. 55, DL 825 (Ley de IVA) |
Obliga a emitir el documento tributario al momento de la entrega del bien o servicio o al recibir el pago, lo que ocurra primero. | bcn.cl ↗ |
| Art. 97 N°10 (Código Tributario) |
No emitir boleta → multa hasta 10× el monto. Reincidencia → multa doble. Infracciones reiteradas o públicas → clausura del local hasta 20 días. | bcn.cl ↗ |
Tratamiento tributario de bebidas alcohólicas — Art. 43 DL 825
Los alcoholes vendidos por un restaurante o bar al consumidor final no generan Impuesto Adicional (ILA) en la etapa de venta al público. El ILA ya fue pagado por el local al proveedor en la compra. Para el cliente, una cerveza o un pisco sour tributan exactamente igual que una hamburguesa: IVA 19% solamente.
| Aspecto | Definición |
|---|---|
| Tipo de impuesto en boleta al consumidor | IVA 19% — igual que cualquier otro ítem del menú. Sin líneas adicionales de ILA. |
| Desglose en el pie del ticket | Solo tres campos legales obligatorios: Total Neto · IVA 19% · Total. No se añaden líneas de otros impuestos. |
| Catálogo de productos | Los productos de barra (alcoholes) se tipifican como Afectos a IVA General 19%. No requieren campos ni etiquetas especiales de impuesto adicional en el módulo POS. |
| Libro de ventas electrónico | Las ventas de alcohol se registran como operaciones afectas a IVA normales, de forma unificada con el resto del ticket. |
| Norma | Art. 43, DL 825 — el ILA en bebidas alcohólicas aplica en la cadena de distribución, no en la venta minorista al consumidor final. |
Excepción: Factura electrónica Tipo 33 a empresa
Cuando un cliente corporativo solicita factura en lugar de boleta (consumo de oficina, representación), el sistema debe:
- Exigir el ingreso del e-RUT de la empresa (validado formato Chilean RUT)
- Solicitar una glosa del consumo (ej: "Almuerzo de negocios", "Reunión de directorio") — requerimiento de la Resolución Exenta 121 del SII
- Emitir DTE Tipo 33 con los datos ingresados
A nivel de ítems y cálculo de impuestos, la lógica es idéntica: IVA 19% sobre el total. No se crean subtotales diferenciados por tipo de producto en la factura.
Referencia: Resolución Exenta SII N°121 — fiscalización de facturas emitidas por consumo gastronómico.
El "Ticket de Preventa": ilegal y riesgo real de clausura
Práctica generalizada en restaurantes chilenos que expone al negocio a clausura inmediata:
- El local lleva al cliente un papel informal (la "pre-cuenta") antes de emitir la boleta real.
- Para el SII, si ese papel se usa para iniciar el cobro, reemplaza ilegalmente a la boleta electrónica — es evasión de IVA directa.
- Si un fiscalizador de incógnito recibe ese papel para pagar, cursa la infracción en el acto → multa + clausura hasta 20 días.
Welcomeback POS elimina este riesgo por diseño: la boleta se emite automáticamente al confirmar el pago. No hay pantalla de "pre-cuenta". El cajero nunca puede entregar un documento no tributario como instrumento de cobro.
Este cumplimiento estricto es un argumento comercial directo: los restaurantes que usan pre-cuentas están operando en riesgo de clausura hoy mismo.
M4.2 — Nota de Crédito Tipo 61
Anulación de boletas — Nota de Crédito
Si una boleta quedó mal o el cliente pide un cambio de última hora, no se puede editar. El único flujo legal es:
- Emitir una Nota de Crédito (Tipo 61) que anula la boleta original.
- Generar una boleta nueva con los datos correctos.
Welcomeback POS gestiona este flujo desde el backoffice con 2 clics. Sin intervención del cajero. Ver flujo completo, causales y criterios de aceptación en .
M4.3 — Modo offline + folios CAF
Modo offline — Contingencia SII
| Estado | Comportamiento |
|---|---|
| Online | DTE emitido en ≤2 segundos |
| Offline | Transacción a cola local (IndexedDB) con folio asignado del pool CAF local |
| Reconexión | Cola procesada FIFO en ≤30 segundos |
| >20h offline | Alerta urgente (quedan 4h de margen legal) |
| >24h offline | DTEs marcados VENCIDOS — acción manual del dueño |
Gestión de folios CAF
| Folios disponibles | Estado | Acción |
|---|---|---|
| >50 | Normal | Ninguna |
| 20–50 | Alerta | Banner naranja + email al dueño |
| 1–19 | Urgente | Banner rojo |
| 0 | Crítico | BLOQUEO de cobros |
Criterios de aceptación
- Boleta emitida en ≤2s tras confirmación de pago (online)
- CAF gestionado automáticamente, alerta a <50 folios
- Cola offline: hasta 200 transacciones
- Libro de ventas exportable en formato XML válido para SII
- Certificado SII encriptado en reposo (AES-256)
- Onboarding SII en ≤15 minutos
- Anulación de boleta vía Nota de Crédito disponible desde backoffice en ≤2 clics
- Ningún flujo del cajero produce un documento no tributario como instrumento de cobro
M5 — Sistema de Impresión de Tickets
6 tipos de ticket cubriendo todos los escenarios del local. Los 2 principales (boleta + barra) se imprimen automáticamente al confirmar el pago. Los demás se disparan manualmente o por condición.
Resumen de los 6 tipos
| # | Tipo | Trigger | Impresora | Destinatario | Tributario |
|---|---|---|---|---|---|
| T1 | Boleta cliente | Auto — pago aprobado | Caja (80mm) | Cliente | ✅ DTE válido |
| T2 | Ticket barra | Auto — pago aprobado | Barra (58/80mm) | Barista | ❌ No |
| T3 | Reporte Z / cierre | Manual — cerrar turno | Caja (80mm) | Cajero / dueño | ❌ Uso interno |
| T4 | Nota interna / cortesía | Manual — botón cajero | Caja o barra | Equipo | ❌ Leyenda obligatoria |
| T5 | Comprobante vuelto | Auto — pago efectivo (si ON) | Caja (58mm) | Cliente | ❌ Complemento T1 |
| T6 | Duplicado boleta | Manual — reimprimir | Caja (80mm) | Cliente | ✅ Mismo folio |
Con 1 sola impresora, orden de impresión: T2 → T1 → T5
M5.1 — Boleta cliente 80mm
T1 — Boleta Cliente (80mm)
Documento tributario. Se emite automáticamente al confirmar el pago. El cajero no interviene.
Zonas personalizables desde backoffice
| Campo | Tipo | Límite | Posición |
|---|---|---|---|
| Logo del local | PNG/JPG → bitmap | Máx 400px ancho | Zona superior, centrado |
| Título / eslogan | Texto libre | ≤40 caracteres | Bajo el logo, centrado |
| Mensaje de cierre | Texto libre | ≤80 caracteres | Antes del QR / folio |
| Estilo de separador | Selector (4 opciones) | — | Todas las líneas divisorias |
Opciones de separador
| Valor | Muestra |
|---|---|
thick (default) | ━━━━━━━━━━━━━━━━━━━━━━━━━ |
normal | ───────────────────────── |
double | ═════════════════════════ |
dotted | ························· |
Diseño completo (80mm)
━━━━━━━━━━━━━━━━━━━━━━━━━
[LOGO DEL LOCAL]
CAFÉ BERLÍN · PROVIDENCIA
Av. Providencia 1234
RUT: 76.123.456-7
━━━━━━━━━━━━━━━━━━━━━━━━━
¡Bienvenido a Café Berlín! ← título (config)
━━━━━━━━━━━━━━━━━━━━━━━━━
BOLETA ELECTRÓNICA N°42156
03/06/2026 09:34 AM
━━━━━━━━━━━━━━━━━━━━━━━━━
PEDIDO #042
JUAN
━━━━━━━━━━━━━━━━━━━━━━━━━
1x Latte Grande
> NotMilk, +1 shot $4.100
1x Croissant $1.800
━━━━━━━━━━━━━━━━━━━━━━━━━
Neto: $5.042
IVA 19%: $958
TOTAL: $6.000
Débito: $6.000
━━━━━━━━━━━━━━━━━━━━━━━━━
Síguenos @cafeberlın ← mensaje cierre (config)
━━━━━━━━━━━━━━━━━━━━━━━━━
Timbre SII · www.sii.cl
[█████████████████████]
[██ QR 2.5×2.5cm ██]
[█████████████████████]
Folio: 42156
━━━━━━━━━━━━━━━━━━━━━━━━━
Si pago en efectivo: línea adicional Recibido: $XX.XXX / Vuelto: $X.XXX. Si logo falla: fallback a nombre del local en texto centrado.
M5.2 — Ticket barra / cocina
T2 — Ticket Barra (58mm o 80mm)
Solo lo que el barista necesita para preparar el pedido. Sin precios, sin datos tributarios, sin logo.
████████████████████████
PEDIDO #042 — JUAN
████████████████████████
📦 PARA LLEVAR
LATTE GRANDE
> NotMilk
> +1 shot extra
> Sin azúcar
NOTA: Sin lactosa
CROISSANT
> Sin modificadores
────────────────────────
09:34 AM
- Número de pedido: doble tamaño (
GS ! 0x11), negrilla. Legible desde 80cm. - Badge de tipo (
PARA LLEVAR / MESA 3 / RAPPI) si aplica. - Si producto sin modificadores: imprimir
> Sin modificadores— nunca dejar línea en blanco. - Nota del cajero:
NOTA: [texto]bajo los modificadores del ítem correspondiente.
M5.3 — Reporte Z / cierre de turno
T3 — Reporte Z / Cierre de Turno (80mm)
Impresión interna al cerrar turno. Trigger: botón "Cerrar turno" en POS o backoffice. Nunca se entrega al cliente.
━━━━━━━━━━━━━━━━━━━━━━━━━
CAFÉ BERLÍN
REPORTE DE CIERRE
━━━━━━━━━━━━━━━━━━━━━━━━━
Cajero: Camila Rojas
Turno: 08:00 — 16:30
Fecha: 03/06/2026
━━━━━━━━━━━━━━━━━━━━━━━━━
VENTAS
Transacciones: 87
Ticket promedio: $4.218
━━━━━━━━━━━━━━━━━━━━━━━━━
MÉTODOS DE PAGO
Débito: $284.100
Crédito: $87.500
Efectivo: $32.000
Mixto: $9.200
─────────────────────────
TOTAL VENDIDO: $412.800
━━━━━━━━━━━━━━━━━━━━━━━━━
BOLETAS SII
Emitidas: 87
Pendientes: 0
Errores: 0
━━━━━━━━━━━━━━━━━━━━━━━━━
EFECTIVO EN CAJA
Ventas efectivo: $32.000
Fondo inicial: $50.000
Total esperado: $82.000
━━━━━━━━━━━━━━━━━━━━━━━━━
*** USO INTERNO ***
*** NO ES DOCUMENTO ***
*** TRIBUTARIO ***
━━━━━━━━━━━━━━━━━━━━━━━━━
03/06/2026 16:32
Leyenda USO INTERNO — NO ES DOCUMENTO TRIBUTARIO en negrilla: obligatoria. También disponible desde backoffice → Reporte de caja → "Imprimir" por fecha/turno.
T4 — Nota Interna / Cortesía (58mm o 80mm)
Impresión manual del cajero para revisar la orden en curso. Nunca se entrega al cliente para cobrar. Cumplimiento Art. 55 DL 825.
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
*** NOTA INTERNA ***
*** NO ES BOLETA ***
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
Mesa 3 / Para llevar
PEDIDO #042 — JUAN
1x Latte Grande
NotMilk · +1 shot
1x Croissant
─────────────────────
Total aprox.: $5.900
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
09:34 AM · BORRADOR
─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
- Separador punteado
─ ─ ─para diferenciarlo visualmente de la boleta oficial. - Leyenda
NOTA INTERNA / NO ES BOLETAen header y footer — obligatoria. - Muestra total aproximado (sin desglose IVA) — solo referencia para el cajero.
- Botón activable desde Ajustes → Preferencias. Por defecto: oculto.
T5 — Comprobante de Vuelto / Efectivo (58mm)
Ticket corto opcional para pago en efectivo. Default: OFF. Activable desde Ajustes → Preferencias.
━━━━━━━━━━━━━━━━━━━━━━━━━
CAFÉ BERLÍN
━━━━━━━━━━━━━━━━━━━━━━━━━
Pedido: #042
Total: $5.900
━━━━━━━━━━━━━━━━━━━━━━━━━
Recibido: $10.000
VUELTO: $4.100
━━━━━━━━━━━━━━━━━━━━━━━━━
Ver boleta en:
www.sii.cl · folio 42156
03/06/2026 09:34
Solo se imprime cuando el método de pago incluye efectivo. Se imprime después de T1.
T6 — Duplicado de Boleta (80mm)
Reimpresión de la boleta original. Misma información tributaria (mismo folio, mismo QR). Válido ante el SII.
━━━━━━━━━━━━━━━━━━━━━━━━━
*** DUPLICADO ***
━━━━━━━━━━━━━━━━━━━━━━━━━
[resto igual que T1]
━━━━━━━━━━━━━━━━━━━━━━━━━
Reimpreso: 03/06/2026 11:45
━━━━━━━━━━━━━━━━━━━━━━━━━
Accesible desde: pantalla de pago aprobado (≥30s), historial del día en el POS, backoffice en móvil. No disponible si DTE en estado ERROR o VENCIDO.
Personalización de boleta — modelo de datos
{
"ticket_config": {
"logo_url": "https://r2.speedandgo.cl/logos/cafe-berlin.png",
"titulo": "¡Bienvenido a Café Berlín!",
"eslogan": "Hecho con amor desde 2018",
"mensaje_cierre": "Síguenos @cafeberlın · cafeberlın.cl",
"separador": "thick",
"imprimir_comprobante_efectivo": false,
"imprimir_barra": true,
"barra_ancho_mm": 58
}
}
Procesamiento del logo: el dueño sube PNG/JPG al backoffice → se guarda en Cloudflare R2 → al imprimir se convierte a bitmap con canvas.toDataURL() → se envía como bytes ESC/POS con GS v 0. Si falla: fallback a nombre del local en texto.
Lógica de disparo
| Ticket | Automático | Condición |
|---|---|---|
| T1 Boleta | Siempre | Pago aprobado |
| T2 Barra | Si imprimir_barra=true | Pago aprobado O cajero toca "Enviar a cocina" |
| T3 Reporte Z | Manual | Botón "Cerrar turno" |
| T4 Nota interna | Manual | Botón secundario en orden activa (activable en Ajustes) |
| T5 Vuelto | Si activado | Pago incluye efectivo + imprimir_comprobante_efectivo=true |
| T6 Duplicado | Manual | DTE con estado CONFIRMADO o ENVIADO |
Comandos ESC/POS por tipo
| Comando | Código hex | Uso |
|---|---|---|
| Initialize | 1B 40 | Inicio, reset estado |
| Align Center | 1B 61 01 | Logo, número pedido, separadores |
| Align Left | 1B 61 00 | Ítems, modificadores |
| Align Right | 1B 61 02 | Precios alineados derecha |
| Bold On / Off | 1B 45 01/00 | Productos, totales, identificadores |
| Font size 2x | 1D 21 11 | Número de pedido en T2 |
| Font size normal | 1D 21 00 | Restaurar tamaño |
| Small font | 1B 4D 01 | Notas, texto secundario |
| Image print (logo) | 1D 76 30 | Bitmap del logo |
| Feed & Cut | 1D 56 42 03 | Corte del papel (3mm feed) |
| Open Cash Drawer | 1B 70 00 19 FA | Abrir cajón de dinero post-pago |
Impresoras compatibles certificadas
| Modelo | Conexión | Ancho | Estado |
|---|---|---|---|
| Epson TM-T20III | USB / Ethernet / Serie | 80mm | ✅ Certificada |
| Star TSP100III | USB / Ethernet / BT | 80mm | ✅ Certificada |
| Bixolon SRP-350plusIII | USB / Ethernet | 80mm | ✅ Certificada |
| Epson TM-T88VII | USB / Ethernet | 80mm | ✅ Certificada |
| Sewoo SLK-TE112 | USB / Bluetooth | 58mm | ✅ Certificada |
| ESC/POS genérica | USB | 80mm | Compatible (no certif.) |
Historias de usuario
- US-13 Como barista, quiero ver solo lo que necesito preparar, sin precios ni datos tributarios.
- US-14 Como cliente, quiero un ticket con mi número de pedido claramente visible.
- US-22 Como cajero, quiero que los dos tickets se impriman automáticamente sin que yo haga nada.
- US-23 Como cajero, quiero poder reimprimir la boleta si la impresora se traba.
- US-29 Como dueño, quiero imprimir el reporte de cierre con desglose por método de pago.
- US-30 Como dueño, quiero personalizar el logo y el mensaje que ve mi cliente en el ticket.
- US-31 Como cajero, quiero imprimir una nota interna de la orden sin generar una boleta.
Criterios de aceptación
- T1 y T2 enviados a impresión en ≤500ms tras confirmar pago
- T2: SOLO número, nombre, productos, modificadores, hora. Sin precios ni datos tributarios
- T1: QR del timbre SII válido y escaneable (≥2.5cm × 2.5cm)
- Con 1 impresora: T2 imprime ANTES que T1
- T1: logo del local impreso si está configurado; fallback a texto si falla
- T1: título, mensaje de cierre y separador reflejan la configuración del backoffice
- T3: incluye desglose por método de pago, estado boletas SII y efectivo del turno
- T3 y T4: contienen leyenda de uso interno / no tributario — obligatoria
- T5: solo imprime cuando pago incluye efectivo y opción activada
- T6: banner DUPLICADO + fecha de reimpresión + mismo folio y QR que el original
- T6: no disponible si DTE en estado ERROR o VENCIDO
- Cambiar separador en backoffice se refleja en el próximo ticket sin reiniciar el POS
M6 — Backoffice
Panel web accesible desde cualquier browser. Responsive para móvil (el dueño revisa desde su celular).
M6.1 — Panel de ajustes generales
Módulos incluidos en MVP
| Módulo | Descripción |
|---|---|
| Gestión de Carta | Crear/editar productos, fotos, precios, categorías, activar/desactivar |
| Modificadores | Crear grupos de modificadores, opciones, precios extra, asignar a productos |
| Configuración Local | Nombre, logo, RUT, certificado SII, Transbank/SumUp, impresoras |
| Reporte de Caja | Ventas del día, desglose por método de pago, boletas emitidas. Exportar CSV |
| Cierre de Caja | Proceso guiado de conteo de efectivo vs. ventas registradas |
| Cajeros | Usuarios, PINs, turnos históricos |
Criterios de aceptación
- Crear producto con 2 grupos de modificadores en ≤3 minutos
- Reporte de ventas del día disponible en tiempo real
- Backoffice responsive y funcional en iPhone / Android
- Exportación CSV compatible con Excel
M7 — Welcomeback IA: El POS que Conoce a Tus Clientes
El diferenciador estratégico del producto. Convierte Welcomeback POS de "otro POS rápido" en "el primer POS QSR nativo en IA centrado en la recurrencia del cliente."
Todos los demás POS del mercado tratan cada transacción como si fuera la primera vez. Welcomeback POS + Welcomeback saben que Juan viene todos los martes a las 9am, que siempre pide NotMilk, y que lleva 16 días sin aparecer.
Experiencia objetivo
Cliente llega a la caja (reconocido por email o QR)
↓
Cajero ve en pantalla:
"👤 Juan García — 47 visitas — VIP"
"💡 ¿Lo de siempre? Latte Grande NotMilk + Croissant $5.300"
→ solo aparece si ese pedido se ha repetido ≥10 veces
"⭐ Le falta 1 visita para café gratis"
↓
Cajero toca [Sí, lo de siempre] → orden completa en 1 tap
↓
Tiempo total para un cliente recurrente: ≤5 segundos
Integración con Welcomeback
Datos que Welcomeback ya tiene (y el POS activa)
- Historial de compras por cliente (fecha, productos, modificadores, local)
- Frecuencia de visita y tendencias (días de la semana, horarios)
- Preferencias detectadas (NotMilk siempre, nunca azúcar, siempre doble shot)
- Nivel de fidelización (stamps, puntos, tier VIP)
- Datos de contacto (teléfono, email, RUT)
- Notas del cliente ("alérgico a frutos secos", "cumpleaños 14 de julio")
Datos que el POS agrega a Welcomeback
- Transacciones en tiempo real con modificadores completos
- Respuesta a sugerencias (¿aceptó "lo de siempre"? ¿qué modificó?)
- Métodos de pago preferidos
- Tiempo de espera del cliente en fila
Métodos de identificación del cliente
| Método | Velocidad | Cómo |
|---|---|---|
| QR Welcomeback | ≤1s | El cliente muestra el QR de su app; el cajero escanea |
| ≤3s | Cajero ingresa el correo del cliente en el modal | |
| Nombre / apellido | ≤3s | Autocomplete en tiempo real — desplegable con avatar, email y tier al escribir |
| RUT | ≤3s | Cajero ingresa RUT |
| Búsqueda por nombre | ≤5s | Para clientes sin app, búsqueda rápida en la base |
| Sin identificar | 0s | Transacción anónima, sin personalización |
M7.1 — Motor IA "¿Lo de siempre?"
Motor de IA — "¿Lo de siempre?"
Condición mínima (regla de negocio):
El mismo pedido (productos + modificadores) debe haberse
repetido ≥10 veces para activar la sugerencia.
Con menos de 10 repeticiones, no hay suficiente señal.
Entrada (cuando se supera el umbral de 10):
historial del cliente (últimas 30 visitas)
contexto: día de semana, hora, local
Ponderación:
orden más frecuente en el mismo horario: 0.5
última orden: 0.3
orden más frecuente en general: 0.2
Umbral de confianza:
≥70% → sugerencia "¿Lo de siempre?" (1 tap)
40-69% → sugerencia "¿Quizás...?" (confirmación)
<40% → sin sugerencia automática
Aprendizaje de preferencias
El motor aprende los modificadores favoritos a lo largo del tiempo:
- Si Juan siempre selecciona "NotMilk" → esa opción aparece pre-seleccionada cuando abre el modal
- Si Juan nunca selecciona azúcar → "Sin azúcar" es el default para él
- Si Juan agregó nota "sin lactosa" en 3 visitas → esa nota se sugiere automáticamente
Esto reduce el tiempo de personalización de 10–15 segundos a 2–3 segundos.
M7.2 — Alertas contextuales para el cajero
Alertas contextuales para el cajero
| Alerta | Cuándo | Lo que ve el cajero |
|---|---|---|
| Cumpleaños | Día o 3 días antes | 🎂 Cumpleaños de Juan esta semana |
| Primera visita del día | Primera tx en el local hoy | ☀️ Primera visita de hoy |
| Cliente VIP | Tier más alto | ⭐ Cliente VIP — 100+ visitas |
| Alergia registrada | Siempre cuando hay alergia | ⚠️ ALÉRGICO A FRUTOS SECOS (rojo, siempre) |
| Recompensa disponible | Tiene reward sin usar | 🎁 Tiene 1 recompensa disponible |
| Churn risk | >14 días sin visitar (siendo recurrente) | ⚠️ No venía hace 16 días |
Las alertas son para el cajero, no para el cliente. El cajero las usa para humanizar la interacción.
M7.3 — Loyalty + stamps automáticos
Loyalty automático al cobrar
Stamps / Puntos
- Al confirmar pago → sistema suma 1 stamp en Welcomeback sin acción del cajero
- Si completa la meta → pantalla muestra "🎉 ¡Tu próximo café es GRATIS!" durante 3 segundos
Activación de recompensas
Panel del cajero muestra:
"🎁 JUAN tiene 1 recompensa activa:
→ CAFÉ GRATIS (cualquier tamaño)
¿Aplicar a este pedido? [Sí] [No]"
Si el cajero toca [Sí]:
→ Se agrega el café como ítem $0 en la orden
→ Se descuenta de los stamps en Welcomeback
→ La boleta refleja el descuento correctamente
Churn prevention
Si el cliente lleva >14 días sin visitar: panel muestra badge naranja con opción de ofrecer stamp doble para reactivar.
Pantalla post-pago (Customer Display)
┌─────────────────────────────────────────────────┐
│ ¡Gracias, Juan! 👋 │
│ PEDIDO #042 │
│ Retira en barra cuando llamemos │
│ │
│ ⭐ Acumulaste 1 stamp │
│ Te falta 1 para tu café gratis │
│ [LOGO DEL LOCAL] │
└─────────────────────────────────────────────────┘
Sin pantalla secundaria: el número de pedido se muestra en grande en la pantalla del cajero.
Modelo de datos — integración Welcomeback
Cliente (Welcomeback DB)
├── id_welcomeback
├── telefono, rut, nombre
├── tier (REGULAR | FRECUENTE | VIP)
├── cumpleaños
├── notas (alergias, preferencias manuales)
├── stamps_actuales, stamps_meta
└── Historial[]
├── fecha, local_id, orden_id
└── items_con_modificadores (snapshot)
PreferenciasAprendidas (generadas por IA)
├── cliente_id
├── producto_id
├── modificadores_default[] (ej: NotMilk siempre)
├── score_confianza
└── ultima_actualizacion
Impacto en métricas del negocio
| Métrica | Sin Welcomeback POS | Con Welcomeback POS |
|---|---|---|
| % transacciones identificadas | 0% | Target ≥60% a 90 días |
| Tiempo tx cliente recurrente | ≤15s (igual que nuevo) | ≤5s |
| Frecuencia promedio de visita | Desconocida | Medible y mejorable |
| Tasa de retención mensual | Desconocida | Target ≥40% mes a mes |
| Churn detectado | Imposible | Alertas en tiempo real |
| Ticket promedio VIP vs nuevo | Desconocido | Medible (+15–25% esperado) |
API de integración POS ↔ Welcomeback
GET /wb/customers/lookup?phone=9XXXXXXXX → cliente + tier + stamps
GET /wb/customers/:id/suggestion?local=X → orden sugerida "lo de siempre"
POST /wb/customers/:id/stamp → suma 1 stamp (al confirmar pago)
POST /wb/customers/:id/redeem → canjear recompensa activa
POST /wb/customers/:id/transaction → datos de la transacción completa
La integración se hace en el momento del pago, no en tiempo real durante la selección de productos (para no añadir latencia al flujo de caja).
Historias de usuario
- US-24 Como cajero, quiero ver si el cliente tiene "lo de siempre" para ofrecérselo sin preguntar.
- US-25 Como cajero, quiero que los stamps se acumulen automáticamente sin que el cliente haga nada.
- US-26 Como dueño, quiero saber cuántos clientes son recurrentes vs nuevos cada día.
- US-27 Como cliente, quiero que mi pedido personalizado esté listo con un tap cuando me reconocen.
- US-28 Como dueño, quiero recibir alertas cuando un cliente fiel no ha venido en más de 2 semanas.
Criterios de aceptación
- Identificación por teléfono completa en ≤1 segundo
- Sugerencia "¿Lo de siempre?" aparece en ≤500ms tras identificar al cliente
- 1 tap en "Sí, lo de siempre" agrega la orden completa con todos los modificadores
- Stamp sumado automáticamente al confirmar pago (sin acción del cajero)
- Alertas de alergia siempre visibles en rojo, nunca omitidas
- Tx cliente recurrente identificado: ≤5 segundos
- Dueño puede ver % de transacciones identificadas en reporte del día
Flujo Cajero
Happy path completo + 10 edge cases. Actor: Camila, turno 08:00–16:00, 150 transacciones diarias.
Happy path — 15 segundos
| Tiempo | Acción |
|---|---|
| t=0s | Cajero toca "Latte Grande" en el grid |
| t=1s | Modal de modificadores aparece (<200ms) |
| t=4s | Selecciona: NotMilk / +1 shot / Sin azúcar (3 taps) |
| t=5s | Toca "Agregar" → ítem en resumen con precio actualizado |
| t=6s | Toca "COBRAR" (botón footer verde) |
| t=9s | Toca "DÉBITO" → terminal Transbank se activa |
| t=12s | Cliente pasa tarjeta → APROBADO |
| t=12s | DTE a SII (background) + Tickets impresos en ambas impresoras |
| t=13s | Cajero toca "NUEVA VENTA" → listo para el siguiente |
Edge cases
| # | Situación | Comportamiento |
|---|---|---|
| EC-01 | Cliente agrega ítem después de ir a cobro | [← VOLVER] → orden intacta → agregar → volver a cobrar |
| EC-02 | Cajero se equivocó de producto | Tap en ítem → editar modificadores, o swipe → eliminar → agregar correcto |
| EC-03 | Tarjeta rechazada | ❌ RECHAZADO → Reintentar / Cambiar método / Cancelar |
| EC-04 | Terminal sin respuesta (60s) | Timeout → Reintentar / Efectivo / Cancelar. El monto NO fue cobrado. |
| EC-05 | Sin papel en impresora | Toast de error. Cobro OK, boleta OK. Re-imprimir cuando se resuelva. |
| EC-06 | Internet se cae durante cobro | Efectivo: OK. Tarjeta: el terminal puede seguir. DTE queda en cola offline. |
| EC-07 | Vuelto mal ingresado | Campo editable antes de confirmar. Recalcula en tiempo real. |
| EC-08 | Cliente pide factura con RUT empresa | Botón "Facturar a empresa" → ingresa RUT → DTE tipo 33 |
| EC-09 | Orden vacía, toca COBRAR | Imposible — botón desactivado con orden vacía |
| EC-10 | Inactividad 3 minutos | Bloqueo automático. PIN → desbloquea. Orden intacta. |
Tiempos objetivo
| Tipo de transacción | Objetivo | Máximo |
|---|---|---|
| Ítem simple, sin modificadores, débito | 8s | 12s |
| Ítem con modificadores, débito | 10s | 15s |
| 3 ítems con modificadores, débito | 15s | 20s |
| Efectivo exacto | 10s | 15s |
| Efectivo con vuelto | 12s | 18s |
| Pago mixto | 18s | 25s |
Flujo Barista
En el MVP, el barista recibe información del pedido exclusivamente a través del ticket impreso de barra. No hay pantalla KDS hasta Fase 2.
Flujo completo
Criterios de calidad del ticket de barra
- Número de pedido legible desde 80cm de distancia
- El barista entiende qué preparar en ≤5 segundos de lectura
- Sin abreviaciones confusas
- Modificadores de cada producto claramente asociados (sangría)
- La hora del pedido ayuda a priorizar en acumulación
- Ticket NO contiene: precios, total, RUT, QR SII, datos del emisor
- Nota libre del cliente aparece bajo los modificadores del producto
Rush hour — gestión de cola
En hora peak el barista puede tener 5–8 tickets pendientes. Las mejores prácticas:
- Rack de pinchos (spike): Tickets en orden de llegada, de izquierda a derecha.
- Número grande: Legible desde 1 metro. Se imprime en doble tamaño ESC/POS.
- Señal sonora: La impresora de barra tiene su pitido. Es la señal de "llegó pedido nuevo".
Escalación Fase 2 — KDS preview
COLA DE PEDIDOS — 09:41 AM [5 pendientes]
─────────────────────────────────────────────────
#042 JUAN │ #043 ANA │ #044
2:15 min │ 1:30 min │ 0:45 min
│ │
LATTE GRANDE │ ESPRESSO │ CAPPUCCINO
> NotMilk │ > Doble │ > Soya
> +1 shot │ │
CROISSANT │ MUFFIN │
│ │
[✓ COMPLETADO]│[✓ COMPLETADO] │[✓ COMPLETADO]
Arquitectura Técnica
Stack
| Capa | Tecnología | Por qué |
|---|---|---|
| POS Frontend | React 18 + TypeScript + Vite + Zustand + Dexie.js | Rápido, offline-first, estado simple |
| Backoffice | Next.js 14 (App Router) + shadcn/ui | SSR, routing simple, componentes listos |
| Backend API | Node.js 20 + Fastify 4 + Prisma 5 | ~50k req/s, ORM type-safe, migrations |
| Base de datos | PostgreSQL 16 | ACID, JSON support, maduro |
| Cache / Queue | Redis 7 + BullMQ | Cola DTE offline, sesiones |
| Hosting | Railway | Simplicidad, sin ops, Docker incluido |
| Storage | Cloudflare R2 | Fotos productos, logos. Sin egress fees |
Diagrama simplificado
TABLET CAJERO (Chrome / PWA)
React POS App
│ HTTPS
▼
CLOUD (Railway)
Fastify API
│
┌─────┼─────┐
│ │ │
PG Redis BullMQ
│
┌─────┼─────┐
│ │ │
SII Transbank Impresoras (vía servidor local)
Offline strategy
- Service Worker (Workbox): Cache de assets + catálogo de productos (stale-while-revalidate, TTL 5min)
- IndexedDB (Dexie.js): Tabla
pending_dtes,products_cache,folio_pool - Background sync: Al recuperar conexión, procesa
pending_dtesen FIFO
Servidor de impresión
Opción MVP (recomendada): Servidor Node.js local en el equipo de caja. El browser del POS se conecta via WebSocket a localhost:9200. Más flexible para iterar.
Opción Fase 2: Empaquetado como Electron. Mejor UX, acceso directo a USB.
Costos de infraestructura (beta, 50 locales)
| Servicio | Plan | Costo/mes |
|---|---|---|
| Railway (backend) | Hobby | $5 USD |
| Railway (PostgreSQL) | Hobby DB | $5 USD |
| Railway (Redis) | Hobby | $5 USD |
| Cloudflare (CDN + R2) | Free tier | $0 |
| Sentry (error tracking) | Free tier | $0 |
| Total | ~$15-20 USD |
Integraciones
SII — Estrategia de integración
| Opción | Pros | Contras | MVP |
|---|---|---|---|
| Intermediario (Acepta / Bsale) | Certificación rápida, soporte | Costo por DTE (~$0.5-2 CLP/doc) | Usar |
| API SII directa | Sin costo por DTE, control total | Certificación meses, gestión XML compleja | Fase 2+ |
Transbank Webpay Plus
import { WebpayPlus } from 'transbank-sdk'
const response = await new WebpayPlus.Transaction().create(
buyOrder, // orden única del local
sessionId, // sesión del cajero
amount, // monto en pesos CLP
returnUrl // URL de confirmación del backend
)
Códigos de respuesta Transbank relevantes
| Código | Significado | Mensaje al cajero |
|---|---|---|
| 0 | Aprobado | ✅ Pago aprobado |
| -1 | Rechazo | ❌ Tarjeta rechazada |
| -4 | Fondos insuficientes | ❌ Fondos insuficientes |
| -2 | Reintentar | ⚠️ Reintentar |
Mercado Pago — El diferenciador en tasas
Mercado Pago es la razón número uno por la que los locales están migrando de Transbank. Ser el POS con la mejor integración a Mercado Pago es un diferenciador directo de ventas.
| Aspecto | Transbank | SumUp | Mercado Pago ⭐ |
|---|---|---|---|
| Comisión débito | ~1.5% | 1.95% | 0.79% |
| Comisión crédito | ~2.5% | 1.95% | 1.49% |
| Hardware | Terminal bancario | Lector $49 USD | Point desde ~$50k CLP |
| QR sin hardware | ❌ | ❌ | ✅ |
| Liquidación | 1-3 días | 1-2 días | 1 día / inmediato |
| Onboarding | 5-15 días | 1-2 días | 1-2 días |
Welcomeback POS soporta los 3 procesadores. El dueño configura cuál usar en Backoffice → Pagos. Puede activar Mercado Pago como principal y Transbank como respaldo.
Métodos de pago vía Mercado Pago
| Método | Cómo | Hardware requerido |
|---|---|---|
| Tarjeta débito / crédito | Terminal Point Smart o Plus | Point (~$50k CLP) |
| QR estático | Cliente escanea QR impreso en mostrador | Ninguno — solo impresión |
| QR dinámico ⭐ | POS genera QR por el monto exacto de la orden | Pantalla del POS |
| Saldo Mercado Pago / ML | Wallet del cliente | Ninguno |
Integración Point — flujo
// Iniciar cobro en terminal Point
POST /point/integration-api/devices/{device_id}/payment-intents
{
"amount": 5900,
"additional_info": {
"external_reference": "ORDER-042",
"print_on_terminal": false // Welcomeback POS maneja la impresión
}
}
// Webhook al aprobar → state: "FINISHED", payment.state: "approved"
QR Dinámico — flujo
// POS genera QR único por orden
POST /instore/orders/qr/seller/collectors/{user_id}/pos/{pos_id}/qrs
{
"external_reference": "ORDER-042",
"total_amount": 5900,
"items": [
{ "title": "Latte Grande NotMilk +1 shot", "quantity": 1, "unit_price": 4100 },
{ "title": "Croissant", "quantity": 1, "unit_price": 1800 }
],
"notification_url": "https://api.welcomebackpos.cl/webhooks/mercadopago"
}
// Respuesta: qr_data → se renderiza en pantalla del POS. Timeout: 10 min.
Checklist onboarding Mercado Pago
- Cuenta Mercado Pago del local activa y verificada
- Access Token de producción obtenido en developers.mercadopago.com
- Device ID del terminal Point registrado (si se usa hardware)
- QR estático impreso en mostrador (si se usa QR)
- Webhook configurado en Backoffice → Pagos
- Pago de prueba de $1 realizado y confirmado
Checklist de onboarding por local
SII
- RUT del local válido y activo en SII
- Certificado digital subido (.pfx)
- CAF solicitado y subido (Tipo 39 y 33)
- Boleta de prueba emitida y verificada en www.sii.cl
Transbank / SumUp
- Commerce code y API key configurados
- Pago de prueba de $1 realizado
- Terminal físico conectado al equipo de caja
Impresoras
- Impresora de caja conectada (USB o IP)
- Impresora de barra conectada (si hay 2)
- Ticket de prueba impreso
Tiempo estimado total de onboarding: 20–30 minutos con todo el material a mano.
Priorización de integraciones — Tier List
Hoja de ruta de todas las integraciones externas, ordenadas por impacto en el negocio del cliente y viabilidad técnica para el MVP.
💳 Terminales de pago
| Prioridad | Integración | Por qué | Estado |
|---|---|---|---|
| Tier S | Mercado Pago Point + QR | Tasa más baja del mercado (0.79% débito). QR sin hardware es diferenciador único. Onboarding en 1-2 días. | ✅ Implementado (demo) |
| Tier A | Transbank Webpay Plus | Estándar de facto en Chile. El dueño ya tiene terminal Transbank en el 80% de los casos. SDK maduro. | ✅ Implementado (demo) |
| Tier B | Fintoc | Transferencia bancaria instantánea vía QR en la boleta. Sin comisión por transacción. QR generado al confirmar el pago — el cliente paga desde su app bancaria escaneando. Ideal como opción adicional sin hardware. | ✅ Demo (QR en boleta) |
| Tier B | Mercado Pago QR | QR dinámico generado por la API de MP al confirmar el cobro. El cliente escanea con la app Mercado Pago o cualquier billetera digital compatible (modelo Attended). La confirmación llega al POS vía webhook. Sin terminal físico. Comisión: ~1.29–1.99% según volumen. Requiere cuenta vendedor MP con user_id y external_pos_id configurados. |
✅ Demo (QR en boleta) |
| Tier B | SumUp | Alternativa sin contrato. Lector físico barato (~$49 USD). Buena para locales nuevos sin terminal bancario. | Fase 2 |
| Tier B | Getnet (Santander) | Terminal bancario alternativo a Transbank. Creciendo en locales medianos en Chile. | Fase 2 |
| Tier C | Kushki | Gateway LATAM multi-país. Relevante cuando el producto escale fuera de Chile. | Fase 3 |
🛵 Apps de delivery
| Prioridad | Integración | Por qué | Estado |
|---|---|---|---|
| Tier B | Rappi | Mayor cuota de mercado en Chile para delivery de restaurantes. API pública disponible. Alta demanda de los locales. | Fase 2 |
| Tier B | Uber Eats | Segunda plataforma en volumen. Integración via Uber Eats Manager API. Tickets automáticos al KDS. | Fase 2 |
| Tier B | PedidosYa | Fuerte presencia en regiones. API abierta. Mismo flujo que Rappi y Uber Eats. | Fase 2 |
| Tier C | Justo | Plataforma con comisión 0% para el local (modelo de suscripción). Nicho pero creciendo en Chile. | Fase 3 |
Flujo objetivo para todas las apps de delivery: orden entra → aparece automáticamente en el KDS con badge 🛵 Delivery → barista prepara → marca LISTO → notificación a la plataforma. Sin tablet separada por app.
📅 Apps de reserva
| Prioridad | Integración | Por qué | Estado |
|---|---|---|---|
| Tier B | Cover Manager | Líder en reservas para restaurantes en España y LATAM. Muy extendido en Chile. Sincroniza reservas del día con el mapa de mesas del POS. | Fase 2 |
| Tier C | OpenTable | Presente en locales de mayor ticket promedio. API bien documentada. | Fase 3 |
| Tier C | Resy | Alternativa premium. Menor presencia en Chile actualmente. | Fase 3 |
Integración objetivo Cover Manager: reservas confirmadas del día aparecen en el mapa de mesas de M1 con estado "Reservada" y nombre del cliente. Al llegar el cliente, el cajero abre la mesa con 1 tap.
🔌 Otras integraciones relevantes
| Prioridad | Integración | Caso de uso | Estado |
|---|---|---|---|
| Tier A | SII / DTE (via Acepta) | Emisión automática de boletas y NCE. Core legal. | ✅ Demo |
| Tier B | WhatsApp Business API | Notificación "tu pedido está listo" al cliente. | Fase 2 |
| Tier B | Bsale / Defontana (ERP) | Sincronización de ventas con contabilidad del local. | Fase 2 |
| Tier C | Soprole / Colun (proveedores) | Orden de compra directa desde inventario a proveedor a precio partner. Ver M14 Fase 3. | Fase 3 |
Modelo de Datos
Esquema Prisma. Multi-tenant aislado por local_id.
Diagrama de relaciones
Local
├── Cajeros[]
├── Configuracion
├── FoliosCAF[]
└── Categorias[]
└── Productos[]
└── GruposModificadores[]
└── OpcionesModificador[]
Local
└── Ordenes[]
├── ItemsOrden[]
│ └── ModificadoresSeleccionados[]
├── Pagos[]
└── DTE (1:1)
Tablas principales
| Tabla | Campos clave | Notas |
|---|---|---|
| Local | id, rut, certificadoSii (encrypted), planActivo | Un registro por negocio |
| Cajero | nombre, pin (bcrypt), rol (ADMIN|CAJERO) | PIN de 4 dígitos |
| Producto | nombre, precio (entero CLP), frecuenciaUso | frecuenciaUso ordena el grid |
| GrupoModificador | tipo (SINGLE|MULTI|INPUT), requerido, min/max | Pertenece a un Producto |
| Orden | numeroDiario, nombreCliente, estado, subtotal, iva, total | Estado sigue el enum de flujo |
| ItemOrden | cantidad, precioUnitario, nombreSnapshot | Snapshot del nombre al momento de venta |
| ModificadorSeleccionado | nombreSnapshot, precioExtra, esTextoLibre, textoLibre | Snapshot — no depende del catálogo |
| Pago | metodo (EFECTIVO|DEBITO|CREDITO|MIXTO), monto, referenciaExterna | referenciaExterna = código Transbank |
| DTE | folio, tipo (39|33), xml, timbre, estado (PENDIENTE|CONFIRMADO|ERROR) | 1:1 con Orden |
| FolioCAF | desde, hasta, actual, tipo, cafXml | Pool de folios autorizados por SII |
Enums
EstadoOrden { ACTIVA | PROCESANDO_PAGO | PAGO_APROBADO | PAGO_RECHAZADO | CERRADA | CANCELADA }
EstadoDTE { PENDIENTE | ENVIADO | CONFIRMADO | ERROR | VENCIDO }
MetodoPago { EFECTIVO | DEBITO | CREDITO | MIXTO }
TipoGrupo { SINGLE | MULTI | INPUT }
Rol { ADMIN | CAJERO }
Nota de diseño — Snapshots
Los campos nombreSnapshot y precioExtra en ModificadorSeleccionado e ItemOrden guardan el nombre y precio al momento de la venta. Esto garantiza que si el dueño cambia el nombre de un modificador o su precio extra, las ventas históricas siguen siendo correctas e imprimibles.
M8 — KDS (Kitchen Display System)
Pantalla standalone para el barista / cocinero. Mismo sistema de variables CSS que M1. Comunicación con el POS via localStorage + evento storage (tiempo real entre pestañas). Acceso: Ajustes → Preferencias → "Abrir pantalla KDS".
M8.1 — Display de órdenes por estación
Layout general
┌─────────────────────────────────────────────────────────────────────────┐
│ 🍳 Cocina [🔴 5 pend.] [⏱ 6.1 prom.] [✅ 18 hoy] 14:32:05 │ ← Stats
├─────────────────────────────────────────────────────────────────────────┤
│ Estación: [🍽 Todas] [🍳 Cocina] [🍺 Bar] [☕ Cafetería] │ ← Estaciones
├─────────────────────────────────────────────────────────────────────────┤
│ [Todos 6] [📦 Para llevar 3] [🪑 Mesa 2] [🛵 Delivery 1] │ ← Filtros tipo
├──────────────────────────────────────────────────────────┬──────────────┤
│ #038·14min⚠ #039·11min⚠ #040·8min R-4821·5min #041 │ En prod. ◀ │
│ ┌───────────────┐ ┌───────────────┐ ┌─────────────┐ │─────────────│
│ │📦 #038 — Juan │ │🪑 MESA 3 #039 │ │📦 #040 │ │[4] LATTE G. │
│ │───────────────│ │───────────────│ │─────────────│ │ 14 min │
│ │1× LATTE G. ⚠️ │ │2× LATTE G. │ │2× ESPRESSO │ │─────────────│
│ │ > NotMilk │ │ > Entera │ │ > Extra │ │[3] ESPRESSO │
│ │ > +1 shot │ │1× CAPPUCCINO G│ │1× MUFFIN │ │ 8 min │
│ │1× CROISSANT │ │2× BROWNIE │ │─────────────│ │─────────────│
│ │───────────────│ │───────────────│ │⏱ 08:03 │ │[3] CROISSANT│
│ │⏱ 14:21 [LISTO]│ │⏱ 11:05 [LISTO]│ │ [LISTO] │ │ 11 min │
│ └───────────────┘ └───────────────┘ └─────────────┘ │[3] BROWNIE │
│ │ 11 min │
└──────────────────────────────────────────────────────────┴──────────────┘
Stats bar
| Elemento | Descripción |
|---|---|
| Pendientes | Órdenes en estado pending. En rojo si hay alguna con >6 minutos |
| Tiempo promedio | Promedio de los últimos 20 pedidos completados (en minutos) |
| Completadas hoy | Contador persistido en localStorage.kds_stats_today, se reinicia con el día |
| Reloj | Hora actual en tiempo real HH:MM:SS |
| Botón "Cargar demo" | Pre-carga 4 órdenes de ejemplo para probar sin el POS |
| Botón "Limpiar todo" | Borra todas las órdenes del localStorage |
M8.3 — Urgencia por tiempo + colores
Sistema de urgencia — colores por tiempo
| Tiempo | Clase CSS | Borde | Fondo | Timer |
|---|---|---|---|---|
| 0–3 min | urg-new | Gris | Base | Gris |
| 3–6 min | urg-medium | Ámbar | Ámbar muy suave | Ámbar |
| 6–10 min | urg-high | Naranja | Naranja muy suave | Naranja |
| >10 min | urg-crit | Rojo + glow | Rojo suave | Rojo + ⚠️ |
Diferenciación por tipo de orden
| Tipo | Badge | Color badge |
|---|---|---|
| Para llevar | 📦 PARA LLEVAR | #92400e (marrón) sobre blanco |
| Mesa | 🪑 MESA X | #1d4ed8 (azul oscuro) sobre blanco |
| Delivery Rappi | 🛵 RAPPI | #7c3aed (violeta) sobre blanco |
De un vistazo el barista sabe si hay que embolsar, dejar en mesa o esperar al rider.
Flujo completo POS → KDS
POS: cajero toca "Enviar a cocina" o confirma pago (autoKitchenOnPay=true)
↓
pushToKDS() → escribe en localStorage.kds_orders
↓
KDS escucha evento `storage` → renderKDS() → nueva card con animación slideIn
↓
Barista puede:
a) Tocar ítem individual → se tacha (preparado parcialmente)
b) Tocar [✓ LISTO] → animación slideOut → orden marcada como done
↓
Si cliente tiene nombre WB → banner verde:
"🔔 ¡Juan García! Pedido #038 listo para retirar" (visible 4 segundos)
↓
Stats: completadas++ y tiempo promedio recalculado
Interacciones del barista
Tap en ítem individual
Marca/desmarca el ítem como preparado. El nombre queda tachado con opacidad 0.4. Los modificadores también se atenúan. Útil en órdenes con varios ítems que se van terminando de a uno.
Botón LISTO
Animación de salida (escala a 0, opacidad 0) en 280ms. Elimina la card del DOM, marca status: 'done' en localStorage, muestra banner WB si aplica, actualiza stats en tiempo real.
Estructura del objeto en localStorage
{
"id": "#042",
"num": 42,
"llevar": true,
"mesa": null,
"delivery": false,
"platform": null,
"clientName": "Juan García",
"items": [
{ "name": "Latte Grande", "mods": ["NotMilk", "+1 shot"], "qty": 1, "done": false },
{ "name": "Croissant", "mods": [], "qty": 1, "done": false }
],
"source": "manual",
"ts": 1748990123456,
"status": "pending"
}
Configuración desde Ajustes del POS
| Toggle / Botón | ID | Default | Efecto |
|---|---|---|---|
| Botón "Enviar a cocina" | toggle-cocina | ON | Muestra/oculta el botón en la boleta |
| Auto-envío al cobrar | toggle-autoKitchen | ON | Si ON, processPay() envía automáticamente al KDS |
| Abrir pantalla KDS | — | — | window.open('KDS_cocina.html', '_blank') |
M8.2 — Panel "En producción" (acumulador)
Panel lateral — "En producción"
Sidebar derecho colapsable que acumula en tiempo real todos los ítems de todas las órdenes pendientes. Permite al barista preparar en lote sin tener que sumar mentalmente entre tarjetas.
┌──────────────────────┐
│ EN PRODUCCIÓN ◀ │ ← botón colapsar
├──────────────────────┤
│ [4] Latte Grande │ ← badge cantidad + nombre
│ 1054 min │ ← tiempo orden más antigua (rojo)
├──────────────────────┤
│ [1] Croissant │
│ 1054 min │
├──────────────────────┤
│ [2] Muffin │
│ 1048 min │
├──────────────────────┤
│ [3] Espresso Simple│
│ 1048 min │
├──────────────────────┤
│ [1] Cappuccino G. │
│ 1041 min │
└──────────────────────┘
Color del badge: gris <3 min · ámbar 3-6 · naranja 6-10 · rojo >10
| Elemento | Descripción |
|---|---|
| Cantidad acumulada | Suma de todas las unidades pendientes de ese ítem en todas las órdenes activas. Los ítems ya marcados como ✓ no cuentan. |
| Orden (arriba → abajo) | Por tiempo en producción: el ítem cuya orden más antigua lleva más tiempo esperando aparece primero. |
| Tiempo | Minutos desde que entró la orden más antigua que contiene ese ítem. Mismos colores de urgencia que las tarjetas. |
| Badge rojo pulsante | Aparece cuando alguna orden que contiene ese ítem está en estado crítico (>10 min). |
| Actualización | Al marcar un ítem ✓ en cualquier tarjeta, el acumulador se actualiza inmediatamente (no espera al tick de 1s). |
| Colapsar | Botón ◀/▶ para contraer el sidebar y ganar espacio en monitores pequeños. El estado persiste. |
Ejemplo: si hay 3 órdenes activas con Latte Grande (2 + 1 + 1 unidades), el barista ve directamente [4] Latte Grande · 14 min en lugar de tener que contar entre tarjetas.
Estaciones de trabajo
Barra de selección encima de los filtros de tipo que permite a cada pantalla KDS mostrar solo los ítems relevantes para su puesto. Una cafetería con barra y cocina separadas puede tener un monitor por estación mostrando el mismo archivo con distinto filtro activo.
| Estación | Ítems que muestra | Caso de uso |
|---|---|---|
| 🍽 Todas | Todos los ítems de todas las órdenes | Locales pequeños con un solo monitor y un solo preparador |
| 🍳 Cocina | Bowls, sándwiches, tostadas, pasteles, brownies, muffins, croissants… | Monitor en zona de preparación de comida |
| 🍺 Bar | Cervezas, vinos, cócteles, pisco, gin, ron, aperol… | Monitor en barra de alcoholes |
| ☕ Cafetería | Lattes, cappuccinos, espressos, americanos, cold brew, tés, matcha… | Monitor en barra de café / máquina espresso |
Cuando hay una estación activa, los ítems de otras estaciones en la misma tarjeta se atenúan (opacidad 25%) en lugar de ocultarse — el barista puede ver el contexto completo de la orden pero focaliza solo en lo suyo. Las tarjetas sin ningún ítem de la estación activa no aparecen en el canvas.
Ordenamiento de tarjetas
Las tarjetas se ordenan siempre de más antiguo a más reciente (izquierda a derecha, o de arriba a abajo según el grid). La orden con más tiempo en producción está siempre en primer lugar, independientemente del tipo o la estación activa. El DOM se reordena en cada ciclo de render (cada segundo) para reflejar este criterio aunque entren nuevas órdenes.
Anti-duplicado
Si una orden ya fue enviada manualmente con el botón "Enviar a cocina", el flujo de pago NO la reenvía al KDS. Flag source: 'manual' en el objeto previene duplicados.
Datos demo (6 órdenes — ítems repetidos para ver agrupación)
| Orden | Tipo | Cliente | Ítems | Tiempo |
|---|---|---|---|---|
| #038 | 📦 Para llevar | Juan García (WB) | Latte Grande NotMilk+1shot · Croissant | 14 min → 🔴 crítico |
| #039 | 🪑 Mesa 3 | — | Latte Grande x2 · Cappuccino G. Avena · Brownie x2 | 11 min → 🔴 crítico |
| #040 | 📦 Para llevar | — | Espresso Simple x2 · Muffin | 8 min → 🟠 alto |
| R-4821 | 🛵 Rappi | — | Poke Bowl · Cold Brew Grande | 5 min → 🟡 medio |
| #041 | 🪑 Mesa 7 | María López (WB) | Latte Grande Descafeinado · Croissant x2 | 3 min → gris |
| #042 | 📦 Para llevar | — | Espresso Simple · Cappuccino G. NotMilk · Brownie | 1 min → gris |
Resultado en el sidebar "En producción": [4] LATTE GRANDE · 14 min — [3] ESPRESSO · 8 min — [3] CROISSANT · 11 min — [3] BROWNIE · 11 min — [2] CAPPUCCINO G. · 8 min
Criterios de aceptación
- Orden enviada desde el POS aparece en el KDS en ≤1 segundo (via storage event)
- Timer de cada card se actualiza cada segundo sin re-render completo
- Cambios de color de urgencia son automáticos (sin acción del barista)
- Tap en ítem → tachado inmediato, sin recargar la página
- Botón LISTO → animación + card desaparece + stats se actualizan
- Si cliente tiene nombre WB → banner de llamado visible 4 segundos
- Órdenes "Para llevar" tienen badge marrón, Mesa azul, Delivery violeta
- Filtro por tipo funciona sin recargar
- Stats "completadas hoy" persisten al recargar la página (mismo día)
- Si
autoKitchenOnPay=false, cobrar NO envía al KDS - Si la orden ya fue enviada manualmente, cobrar NO la duplica
- El sidebar "En producción" muestra la suma acumulada de todos los ítems pendientes, ordenados por tiempo de espera descendente
- Al marcar un ítem como ✓ en una tarjeta, desaparece del acumulador en el siguiente ciclo (≤1s)
- El badge de cantidad pulsa en rojo cuando alguna orden del ítem supera 10 minutos
- El tiempo mostrado bajo cada ítem refleja la orden más antigua que lo contiene
- El sidebar es colapsable con un tap sin perder ninguna funcionalidad
- Seleccionar estación filtra tarjetas y atenúa ítems de otras estaciones (opacidad 25%)
- Las tarjetas se ordenan siempre de más antiguo a más reciente — el DOM se reordena cada segundo
- Al pulsar LISTO, los ítems de esa orden desaparecen del sidebar "En producción" inmediatamente (no espera al tick de 1 segundo)
- Al tachar un ítem individual con tap, el sidebar se actualiza inmediatamente descontando ese ítem del acumulador
- El panel 86 muestra todos los productos del catálogo con toggle verde/rojo — al desactivar uno, el cambio se propaga al POS en ≤1s via
localStorage('wb_unavailable') - El botón 86 en la barra del KDS muestra un contador rojo con el número de productos actualmente deshabilitados
- Al reactivar un producto en el panel 86, el POS lo muestra disponible en el siguiente render del grid
Fase 2 — Mejoras planeadas
| Feature | Descripción |
|---|---|
| Sonido al llegar orden | Pitido configurable cuando entra una orden nueva |
| Modo pantalla completa | Botón fullscreen para monitores de cocina |
| Historial del día | Ver órdenes completadas con sus tiempos |
| Alerta escalada | Notificación push al manager si una orden lleva >10 min sin marcar |
| 🚫 86 — Deshabilitar productos | Panel en la barra del KDS que permite al barista marcar un producto como agotado. Se sincroniza con el POS via localStorage('wb_unavailable') en tiempo real — la tarjeta del producto aparece como "Agotado" e inclickeable en el grid del POS sin necesidad de que el cajero haga nada. |
M9 — Gestión de Devoluciones y Nota de Crédito Electrónica
Flujo legal y operacional para corregir cobros incorrectos en locales chilenos. Aplica siempre que una boleta ya fue emitida y el SII ya la registró. No existe el "reembolso simple": la única vía legal es la Nota de Crédito Electrónica (NCE) Tipo 61.
Marco legal — por qué no se puede "borrar" una boleta
Una vez que el SII recibe y acusa el DTE (Boleta Electrónica Tipo 39), ese documento queda en el libro de ventas del emisor. Editarlo o eliminarlo unilateralmente es evasión de IVA. La única corrección legal es emitir un documento de referencia que lo anule o ajuste parcialmente.
| Norma | Relevancia para devoluciones |
|---|---|
| Art. 57, DL 825 (IVA) | Autoriza la Nota de Crédito como instrumento de corrección de documentos tributarios ya emitidos. Es el fundamento legal de la NCE Tipo 61. |
| Resolución SII Ex. N°45/2003 | Regula los DTE electrónicos. Las NCE deben referenciar el folio del DTE original y enviarse al SII en el mismo ciclo de envío que los DTEs normales. |
| Práctica SII | La NCE debe emitirse "oportunamente", idealmente dentro del mismo período tributario mensual en que ocurrió la transacción original. |
Documento que se emite
| Tipo SII | Nombre | Cuándo se usa | Referencia obligatoria |
|---|---|---|---|
| 61 | Nota de Crédito Electrónica | Anulación total o ajuste parcial de una Boleta Tipo 39 ya emitida | Folio y fecha de la boleta original |
Si la devolución es total: la NCE cubre el 100% del monto y el libro de ventas queda en cero para esa transacción. Si se debe rehacer el cobro, se emite una nueva Boleta Tipo 39. Si es parcial: la NCE cubre solo la diferencia (el delta).
Causales de devolución
| Código | Causal | Tipo | Ejemplo real QSR |
|---|---|---|---|
DUP | Cobro duplicado de una orden | Anulación total | El cajero procesó dos veces la misma mesa |
NE | Producto no entregado pero cobrado | Parcial o total | Se cobró un Brownie agotado que no se entregó |
PI | Precio incorrecto aplicado | Parcial | Se cobró el precio de Latte Grande en lugar de Chico |
PE | Pago en exceso (error de digitación) | Parcial | El cajero ingresó $15.000 en lugar de $5.000 en efectivo |
AR | Arrepentimiento antes de retirar | Anulación total | Cliente pide cancelar inmediatamente después de pagar |
OT | Otro (requiere descripción manual) | Total o parcial | Cualquier situación no cubierta por los códigos anteriores |
M9.1 — Anulación total + NCE Tipo 61
Flujo A — Anulación total (venta ya cerrada)
El reembolso del dinero al cliente es operacional — el supervisor lo gestiona por el medio original (efectivo de caja, reversa Transbank, nota de crédito MP). La NCE solo corrige el libro de ventas del SII.
Flujo B — Cobro nuevo tras anulación total
M9.2 — Ajuste parcial
Flujo C — Ajuste parcial (sin nueva boleta)
Historias de usuario
| ID | Como... | Quiero... | Para... |
|---|---|---|---|
| US-90 | Supervisor de turno | Buscar una venta cerrada por número de orden en el historial del POS | Iniciar el proceso de devolución sobre la transacción correcta |
| US-91 | Supervisor de turno | Seleccionar la causal de devolución de una lista predefinida | Que el sistema genere la NCE con el código correcto y quede auditada |
| US-92 | Supervisor de turno | Ver un resumen claro antes de confirmar: venta original, monto a anular, causal y aviso "Se emitirá NCE Tipo 61" | No cometer errores en la anulación y entender las consecuencias legales |
| US-93 | Sistema (POS) | Emitir automáticamente la NCE Tipo 61 referenciando el folio original y enviarla al SII | Cumplir con la normativa tributaria sin acciones manuales del supervisor |
| US-94 | Dueño del local | Que el historial de ventas refleje las boletas anuladas con el folio de la NCE asociada | Tener trazabilidad completa para auditorías del SII y conciliación de caja |
| US-95 | Cajero | No poder iniciar una devolución — que esté bloqueado para mí | Que el proceso tenga control de acceso y no sea susceptible a fraude interno |
Criterios de aceptación
- Solo usuarios con rol Supervisor o Dueño pueden iniciar el flujo de devolución — el cajero no tiene acceso
- El flujo solo está disponible para ventas con status
cerrado(boleta ya emitida y acusada por el SII) - La selección de causal es obligatoria — no se puede avanzar sin elegir una
- La pantalla de confirmación muestra: número de orden, folio boleta original, hora, método de pago, monto total y aviso "Se emitirá NCE Tipo 61 al SII — esta acción no se puede deshacer"
- La NCE se genera con referencia explícita al folio de la boleta original (campo
ReferenciaDTEen el XML enviado al SII) - NCE emitida en ≤2s si hay conexión; en modo offline entra a la misma cola CAF que las boletas normales
- Tras la NCE, la venta en el historial cambia a status
anuladoy muestra el folio de la NCE asociada - Si la causal es
OT("Otro"), se requiere texto descriptivo de al menos 10 caracteres - No es posible emitir dos NCE para la misma boleta — el sistema bloquea el intento con mensaje claro
- El folio asignado a la NCE consume un folio del pool CAF de Tipo 61 (pool separado del Tipo 39)
- El log de auditoría registra: timestamp, usuario, causal, folio boleta original, folio NCE emitida
Restricciones del sistema
| Restricción | Valor | Justificación |
|---|---|---|
| Rol mínimo requerido | Supervisor | Control de fraude interno — los cajeros no pueden anular sus propias ventas |
| Ventana recomendada | Mismo día (mismo período tributario) | El SII procesa las NCE con mayor facilidad dentro del mismo mes |
| NCE por boleta | Máximo 1 | Una boleta no puede tener dos notas de crédito de anulación total |
| Ventas elegibles | Solo status cerrado | Las órdenes en progreso se cancelan directamente sin DTE |
| Pool CAF requerido | Tipo 61 (separado del Tipo 39) | El SII gestiona folios por tipo de documento — los pools no se mezclan |
| Timeout de confirmación | 60 segundos | Si el supervisor no confirma en 60s, el flujo se cancela para evitar errores por distracción |
| Reembolso de dinero | Fuera del scope del POS MVP | La NCE anula el libro tributario; el reembolso físico es responsabilidad operacional del local |
Estructura del XML — NCE Tipo 61
{
"TipoDTE": 61,
"Folio": <folio_del_pool_CAF_tipo61>,
"FchEmis": "<fecha_actual>",
"MntNeto": <monto_neto_a_anular>,
"TasaIVA": 19,
"IVA": <iva_calculado>,
"MntTotal": <total_a_anular>,
"Referencia": {
"NroLinRef": 1,
"TpoDocRef": 39,
"FolioRef": "<folio_boleta_original>",
"FchRef": "<fecha_boleta_original>",
"CodRef": 1,
"RazonRef": "<causal_legible>"
}
}
CodRef: 1 = anula el documento de referencia. Referencias: Formato DTE SII ↗
Fase 2 — Mejoras planeadas
| Feature | Descripción |
|---|---|
| Ajuste parcial multi-ítem | Selección de ítems específicos a anular, no solo el monto total de la venta |
| Reversa automática Transbank | Integración con Webpay para reversar automáticamente el cargo bancario cuando la NCE se emite el mismo día |
| Notificación al dueño | Push/email al dueño cada vez que se emite una NCE, con detalle de causal y supervisor responsable |
| Reporte de devoluciones | Tabla en Backoffice con todas las NCE del período, agrupadas por causal y supervisor |
M10 — Login y Control de Accesos
Pantalla de bienvenida con autenticación por PIN de 4 dígitos que bloquea el POS al abrir el archivo. Dos roles con permisos diferenciados. El usuario activo queda visible en el topbar durante toda la sesión.
M10.1 — Login PIN + roles
Flujo de acceso
M10.2 — Permisos admin / operador
Roles y permisos
| Permiso | Admin | Operador |
|---|---|---|
| Cobrar, modificar, cancelar órdenes | ✅ | ✅ |
| Ver historial de ventas | ✅ | ✅ |
| Iniciar devolución / NCE (con PIN) | ✅ | ✅ |
| Fichar asistencia (entrada/colación/salida) | ✅ | ✅ |
| Acceder a Ajustes | ✅ Completo | ⚠️ Limitado |
| Ajustes: Preferencias, asistencia, sesión | ✅ | ✅ |
| Ajustes: Local, pagos, hardware, métodos de pago | ✅ | ❌ Oculto |
| Gestión de usuarios (agregar / modificar PINs) | ✅ | ❌ |
| Cierre de turno y reporte Z | ✅ | ❌ |
El botón de Ajustes aparece atenuado para operadores. Si intentan acceder, el sistema muestra un toast de aviso. Si logran entrar, las secciones de administración están ocultas y ven un banner explicativo.
Usuarios precargados (prototipo)
| Usuario | Rol | PIN | Iniciales |
|---|---|---|---|
| Camila Torres | Admin | 1234 | CT |
| Diego Muñoz | Operador | 5678 | DM |
| Ana Reyes | Operador | 9012 | AR |
Comportamiento de seguridad
- PIN incorrecto: puntos rojos + animación shake + reset automático tras 1s
- Preview del nombre del usuario aparece al reconocer los primeros 2 dígitos (feedback inmediato)
- Click en el chip de usuario en el topbar → cierra sesión y vuelve al login
- El POS completo queda oculto hasta autenticarse — no es posible acceder sin PIN
- El PIN de autorización de devoluciones acepta el código de cualquier usuario válido del sistema
Historias de usuario
- US-100 Como dueño, quiero que nadie pueda abrir el POS sin identificarse, para tener trazabilidad de quién realizó cada operación
- US-101 Como cajero, quiero que mi nombre aparezca en el topbar durante mi turno, para confirmar que estoy logueado correctamente
- US-102 Como administrador, quiero poder cerrar mi sesión con un clic, para que el siguiente cajero deba identificarse con su propio PIN
- US-103 Como dueño, quiero que los operadores no puedan gestionar usuarios ni cerrar turno, para proteger la integridad de la caja
Criterios de aceptación
- Al abrir el archivo, el POS muestra únicamente la pantalla de login — el contenido del sistema no es visible
- PIN correcto → sesión iniciada en ≤300ms, topbar actualizado con nombre, iniciales y rol
- PIN introducido desde el teclado físico (teclas 0–9 y Backspace) funciona igual que tocar los botones en pantalla — el listener solo está activo cuando el overlay de login está visible
- 3 intentos fallidos consecutivos bloquean el login por 30 segundos (Fase 2)
- En producción los PINs se almacenan hasheados (bcrypt) — nunca en texto plano
Fase 2
| Feature | Descripción |
|---|---|
| Bloqueo por intentos fallidos | 3 intentos incorrectos → bloqueo 30s con contador visible |
| Gestión de usuarios en backoffice | Pantalla Admin para crear/eliminar usuarios y asignar PINs |
| Auto-logout por inactividad | Si no hay actividad en 15 min, vuelve a la pantalla de login |
| Log de accesos | Registro de login/logout con timestamp para auditoría |
M11 — Asistencia y Personal
Módulo integral de gestión de personas. Cubre desde el fichaje digital (conforme al Art. 33 CT) hasta la planificación inteligente de calendarios de turnos cruzando demanda horaria con la normativa laboral chilena. En Fase 3 se expande como app mobile independiente.
Fase 1 (implementada): Fichaje por PIN, libro digital, resumen mensual para liquidaciones
Fase 2 (este sprint): Configuración de equipo y zonas + Generador automático de calendarios con análisis de demanda
Fase 3 (roadmap): App mobile PWA tipo Teams — turnos en el móvil del empleado, solicitudes, notificaciones push
Marco legal aplicado
| Norma | Valor | Aplicación en el sistema |
|---|---|---|
| Art. 33 CT | Libro de asistencia obligatorio | Registro digital de entrada/salida por trabajador y fecha |
| Art. 75 CT | Colación mín. 30 min, no remunerada | Se descuenta automáticamente en jornadas ≥ 6 horas |
| Ley 21.561 (2026) | Jornada ordinaria 42 h/semana (desde abril 2026) | Barra de progreso y alerta al superar el límite |
| Art. 31 CT | Horas extra: máx 2h/día · 10h/semana | Cálculo automático al fichar salida; badge de alerta |
| Art. 32 CT | Recargo horas extra: 50% | Mostrado como referencia en resumen mensual |
| Art. 71 CT | Domingo trabajado = descanso compensatorio | Domingos marcados con 🟠; contador en resumen mensual |
M11.1 — Fichaje entrada / colación / salida
Flujo de fichaje (desde pantalla de login)
El trabajador no entra al POS al fichar. El sistema muestra únicamente las opciones válidas según su estado actual — es imposible fichar en orden incorrecto.
Máquina de estados por trabajador
| Último fichaje del día | Opciones que aparecen |
|---|---|
| Ninguno (o tras salida) | 🟢 Entrada |
| Entrada | 🍽 Inicio colación · 🔴 Salida |
| Inicio colación | ✅ Fin colación |
| Fin colación | 🔴 Salida |
| Salida | Mensaje "Jornada finalizada · hasta mañana" |
Cálculo automático al fichar salida
| Campo calculado | Fórmula |
|---|---|
| Minutos brutos | hora_salida − hora_entrada (en minutos) |
| Colación real | Si fichó inicio y fin de colación ese día: hora_fin_col − hora_ini_col |
| Colación automática | Si no fichó colación: 30 min cuando minutos_brutos ≥ 360 (6h) — Art. 75 CT |
| Minutos ordinarios | min(minutos_brutos − colación, máx_diario) |
| Minutos extra | max(0, minutos_netos − máx_diario), cap a 120 min (2h) — Art. 31 CT |
M11.2 — Resumen mensual para liquidaciones
Vistas del libro de asistencia (en Ajustes)
Tab Hoy
Tabla con columnas: Trabajador · Entrada · Salida · Colación · Jornada. Muestra badge naranja con horas extra si las hay. Marca 🟠 si el día es domingo.
Tab Esta semana
Una fila por trabajador con barra de progreso visual ██████░░ 36h / 42h. Alertas rojas ⚠ Jornada y ⚠ H.Extra si se superan los límites legales. Barra secundaria de horas extra vs. límite de 10h.
Tab Resumen mensual
Selector de mes. Tabla por trabajador: días trabajados · horas ordinarias · horas extra · domingos trabajados. Fila de totales. Bloque de marco legal como referencia. Botón "Exportar para contador" que genera texto copiable.
Ejemplo de exportación
RESUMEN ASISTENCIA — JUNIO 2026
──────────────────────────────────────────
Camila Torres (Admin)
Días trabajados: 22
Horas ordinarias: 184:00
Horas extra: 4:30
Domingos trabajados: 2
Diego Muñoz (Operador)
Días trabajados: 20
Horas ordinarias: 168:00
Horas extra: 2:00
Domingos trabajados: 1
──────────────────────────────────────────
Generado por Welcomeback POS · Art. 33 CT
Jornada ordinaria máx: 42 h/sem (Ley 21.561)
H.extra recargo 50% (Art. 32 CT)
Historias de usuario
- US-110 Como trabajador, quiero fichar mi entrada y salida con mi PIN desde la pantalla de inicio, sin necesidad de un lector de huella
- US-111 Como trabajador, quiero que el sistema detecte automáticamente si es entrada o salida, para no equivocarme
- US-112 Como administrador, quiero ver las horas trabajadas de cada empleado por semana con alertas si superan la jornada legal
- US-113 Como administrador, quiero un resumen mensual listo para llevar a mi contador, con días trabajados, horas ordinarias, horas extra y domingos
- US-114 Como dueño, quiero que el sistema aplique automáticamente el descuento de colación (30 min) en jornadas ≥ 6h, para cumplir con el Art. 75 CT
- US-115 Como dueño, quiero ver qué empleados trabajaron domingos para gestionar los descansos compensatorios (Art. 71 CT)
Criterios de aceptación
- Fichar con PIN correcto registra el fichaje en ≤200ms y muestra confirmación 2.5s
- PIN incorrecto: flash rojo en dots, sin registro, sin mensaje de nombre
- Colación de 30 min descontada automáticamente en jornadas ≥ 6 horas (Art. 75 CT)
- Tab Semana muestra alerta visual si cualquier trabajador supera 42h ordinarias o 10h extra
- Tab Mes permite seleccionar cualquier mes del año
- Botón "Exportar para contador" copia texto al portapapeles con toast de confirmación
- Domingos trabajados marcados con 🟠 en todas las vistas
- El registro es inmutable: no se puede editar un fichaje ya realizado (Fase 2: solo Admin puede corregir con nota de auditoría)
Fase 1 — Features adicionales (pendientes)
| Feature | Descripción |
|---|---|
| Corrección de fichaje | Solo Admin puede modificar un registro con nota de auditoría obligatoria |
| Exportación PDF | Generar PDF firmable del libro de asistencia mensual para enviar a DT |
| Persistencia real | Guardar registros en base de datos (hoy son en memoria — se pierden al cerrar) |
| Integración liquidaciones | Conexión directa con Remunet o BUK via API para importar datos de horas |
Fase 2 — Planificación inteligente de turnos
El generador automático de calendarios cruza tres fuentes de datos: ventas hora a hora (del módulo M16), disponibilidad declarada del equipo y restricciones legales chilenas. El resultado es un calendario semanal óptimo que el administrador puede ajustar antes de publicar.
M11.3 — Configuración del equipo y zonas
Pantalla de administración donde se define la estructura operacional del local antes de generar cualquier calendario.
Zonas de trabajo
| Campo | Tipo | Descripción |
|---|---|---|
id | string | Identificador único (Z1, Z2…) |
nombre | string | Ej: "Caja", "Barra", "Cocina", "Delivery" |
coberturaMín | number | Personas mínimas que deben cubrir esta zona en todo momento |
activa | boolean | Si la zona opera este establecimiento |
Perfil extendido del operario
| Campo nuevo | Tipo | Descripción |
|---|---|---|
zonas | string[] | IDs de zonas en las que está habilitado (ej: ['Z1','Z2']) |
contrato | 'full'|'part' | Jornada completa (42h/sem) o parcial |
horasTarifa | number | CLP por hora trabajada — para cálculo de costo laboral |
disponibilidad | object | Días disponibles: {lun:true, mar:true, …, dom:false} |
domingosMes | number | Domingos trabajados en el mes en curso (0, 1 o 2 — máx legal) |
┌──────────────────────────────────────────────────────┐
│ ⚙ Configuración del equipo │
├──────────────────────────────────────────────────────┤
│ ZONAS DE TRABAJO [+ Agregar zona] │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 🏷 Caja Cobertura mín: [1] [✓ Activa] [🗑] │ │
│ │ 🏷 Barra Cobertura mín: [1] [✓ Activa] [🗑] │ │
│ │ 🏷 Cocina Cobertura mín: [1] [✓ Activa] [🗑] │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ PERFIL DE OPERARIOS │
│ ┌─────────────────────────────────────────────────┐ │
│ │ CT Camila Torres · Admin │ │
│ │ Zonas: [✓Caja] [✓Barra] [ Cocina] │ │
│ │ Disponible: [L][M][X][J][V][S][ D] │ │
│ │ Contrato: (●) Full ( ) Part $4.200/h │ │
│ ├─────────────────────────────────────────────────┤ │
│ │ DM Diego Muñoz · Operador │ │
│ │ Zonas: [ Caja] [✓Barra] [✓Cocina] │ │
│ │ Disponible: [L][M][X][J][V][✓S][✓D] │ │
│ └─────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
M11.4 — Análisis de demanda horaria
El sistema cruza el historial de ventas (VENTAS_DATA de M16) para construir una curva de demanda promedio por día de la semana y franja horaria. De esta curva se deriva el personal mínimo necesario en cada franja.
Fórmula de conversión ventas → personal
personal_necesario(franja) = ceil(tickets_franja / tickets_por_persona_hora)
Donde:
tickets_franja = ventas de esa hora ese día / ticket_promedio
tickets_por_persona_hora = capacidad estimada (default: 12 tickets/persona/hora)
ceil() = redondear hacia arriba
Franjas peak = top 30% de franjas por ventas (highlight visual naranja)
| Día | Franja | Ventas prom. | Tickets est. | Personal sugerido | Tipo |
|---|---|---|---|---|---|
| Lunes | 08:00–09:00 | $42.000 | 14 | 2 | Normal |
| Lunes | 12:00–13:00 | $180.000 | 60 | 5 | 🔥 Peak |
| Sábado | 10:00–11:00 | $210.000 | 70 | 6 | 🔥 Peak |
| Domingo | 11:00–14:00 | $150.000 | 50 | 5 | 🔥 Peak |
M11.5 — Generador automático de calendarios
Algoritmo que produce un calendario mensual completo en un click (todos los días del mes seleccionado), respetando disponibilidad individual, cobertura de zonas y toda la normativa laboral chilena.
Equipo mínimo viable para cobertura 7 días
Con 3 personas y descansos legales es imposible cubrir 7 días × N zonas. El mínimo operacional es 5 operarios con descansos escalonados:
| Operario | Zonas | Descanso semanal | Dom. disponible |
|---|---|---|---|
| Camila Torres (Admin) | Caja, Barra | Domingo | No |
| Diego Muñoz | Barra, Cocina | Lunes | Sí |
| Ana Reyes | Caja, Cocina | Martes | Sí |
| Luis Pino | Caja, Barra, Cocina | Miércoles | Sí |
| Sofía Vera | Barra, Cocina | Jueves | Sí |
Cada persona tiene un campo descansoSemanal en su perfil. El generador respeta ese día como no disponible salvo compensatorios.
Cálculo del turno diario
El algoritmo no usa toda la franja con demanda como turno (eso generaría jornadas de 13+ horas). En cambio calcula un turno de 8 horas centrado en la hora de máxima demanda del día:
peak_hora = hora con mayor valor en DEMANDA_HORARIA[dia]
hora_ini = max(07:00, peak_hora - 4h)
hora_fin = min(22:00, hora_ini + 8h)
duracion = hora_fin - hora_ini ← siempre ≤ 8h
Ejemplo lunes (peak=12:00): turno 08:00–16:00. Ejemplo domingo (peak=12:00): turno 08:00–16:00.
Reglas legales aplicadas
| Norma | Restricción | Cómo el algoritmo la aplica |
|---|---|---|
| Art. 38 CT | Máx 2 domingos trabajados/mes por persona | Si domingosMes ≥ 2 → no asignar ese domingo. Si es 1 → puede trabajar pero genera compensatorio automático |
| Art. 38 CT | Compensatorio obligatorio si trabaja domingo o festivo | Se asigna automáticamente el día de menor demanda de la semana siguiente como descanso compensatorio (badge 🔄) |
| Art. 38 CT + Ley 19.973 | Festivos irrenunciables equiparados a domingos | Los 15 festivos legales chilenos 2026 se detectan automáticamente desde el array FESTIVOS_CL. En esos días: demanda base sábado/domingo +30% (mayor afluencia de público), mismas reglas de compensatorio que domingo. Badge 🎉 en el calendario. |
| Ley 21.561 (2026) | Jornada ordinaria máx 42h/semana (vigente desde abril 2026) | Si asignar un turno supera 42h semanales → el trabajador se marca como no disponible para días adicionales esa semana |
| Art. 31 CT | Horas extra máx 2h/día, 10h/semana | No se programan horas extra — los turnos generados son dentro de jornada ordinaria |
| Art. 75 CT | Colación ≥ 30 min en jornadas ≥ 6h | Todos los turnos de ≥ 6h incluyen 30 min de colación no remunerada en el horario |
Algoritmo (pseudocódigo)
función generarCalendario(semana):
para cada día (lun → dom):
si es domingo:
filtrar USERS donde domingosMes < 2 Y disponible[dom] = true
si_no:
filtrar USERS disponibles ese día
calcular franja_horaria_óptima:
inicio = primera_franja_peak - 1h
fin = última_franja_peak + 1h
(mín 6h para jornada ordinaria full-time)
para cada zona (ordenadas por coberturaMín desc):
candidatos = USERS filtrados que:
- tienen esa zona habilitada
- no superan 42h/sem al agregar este turno
- no ya asignados ese día
- preferir al de menos horas asignadas (balanceo)
asignar candidato_óptimo al turno
si es domingo: marcar esDomingo=true, generar compensatorio día siguiente semana
retornar CALENDARIO_SEMANAL
Estructura de un turno generado
| Campo | Tipo | Descripción |
|---|---|---|
id | string | UUID del turno |
userId | string | ID del operario asignado |
zona | string | ID de la zona (Z1, Z2…) |
dia | 0–6 | 0=Lunes, 6=Domingo |
horaInicio | 'HH:MM' | Inicio del turno |
horaFin | 'HH:MM' | Fin del turno |
esDomingo | boolean | true si aplican reglas de domingo |
compensatorio | boolean | true si es el día de descanso compensatorio |
semana | 'YYYY-WNN' | Semana ISO a la que pertenece |
editado | boolean | true si fue modificado manualmente post-generación |
Antes de activar el módulo de planificación en cualquier mercado fuera de Chile, el equipo de producto debe revisar y codificar los siguientes puntos específicos de ese país:
- Lista de festivos legales del año en curso (equivalente a
FESTIVOS_CL). En algunos países (ej. Perú, México) los festivos sectoriales del HoReCa difieren de los nacionales. - Regla de compensatorio por festivo: ¿es obligatorio? ¿qué plazo? ¿recargo salarial en vez de día libre? (En Chile: compensatorio libre o recargo 50%. En España: recargo 75%. En México: triple salario sin descanso compensatorio obligatorio.)
- Límite de domingos/festivos trabajados por mes: en Chile son 2. Otros países no tienen límite mensual pero sí exigen compensatorio en cada ocasión.
- Jornada semanal ordinaria: Chile 42h (Ley 21.561, vigente abril 2026), España 40h, Colombia 47h → afecta directamente el algoritmo de asignación.
- Factor de demanda en festivos: el +30% aplicado en Chile es una estimación operacional. Debe validarse con datos reales de ventas del mercado local.
M11.5b — Especificación de backend para ingenieros
Todas las reglas de negocio deben validarse en el servidor, no solo en el cliente. Esta sección es la fuente de verdad para el equipo de desarrollo.
Entidades de base de datos
| Tabla | Campo | Tipo | Descripción / Constraint |
|---|---|---|---|
| turnos | id | UUID PK | Generado en servidor |
| usuario_id | UUID FK → usuarios | NOT NULL | |
| zona_id | UUID FK → zonas | NOT NULL | |
| fecha | DATE | NOT NULL · Índice compuesto con zona_id | |
| hora_inicio | TIME | NULL si compensatorio=true | |
| hora_fin | TIME | NULL si compensatorio=true · CHECK hora_fin > hora_inicio | |
| es_domingo | BOOLEAN | Derivable de fecha, se almacena para eficiencia | |
| es_festivo | BOOLEAN | Derivable de tabla festivos, se almacena para eficiencia | |
| compensatorio | BOOLEAN DEFAULT false | Si true, el trabajador NO trabaja ese día | |
| aprobado | BOOLEAN DEFAULT false | Solo visible para empleados cuando true | |
| editado | BOOLEAN DEFAULT false | true si fue modificado después de la generación automática | |
| local_id | UUID FK → locales | Multi-tenant: cada local tiene sus propios turnos | |
| created_at / updated_at | TIMESTAMPTZ | Auditoría | |
| solicitudes_cambio | id | UUID PK | |
| turno_id | UUID FK → turnos | NOT NULL · 1 solicitud activa por turno (CHECK estado='rechazada' OR count=1) | |
| tipo | ENUM | 'cambio' | 'permiso' | 'vacacion' | |
| estado | ENUM DEFAULT 'pendiente' | 'pendiente' | 'aprobada' | 'rechazada' | |
| motivo_solicitante | TEXT NOT NULL | Mínimo 10 caracteres | |
| sustituto_id | UUID FK → usuarios NULL | Solo para tipo='cambio'. Si aprobado → turno.usuario_id = sustituto_id | |
| motivo_rechazo | TEXT NULL | Obligatorio cuando estado='rechazada' | |
| creado_por | UUID FK → usuarios | El empleado que solicitó | |
| resuelto_por | UUID FK → usuarios NULL | El admin que aprobó/rechazó | |
| creado_at / resuelto_at | TIMESTAMPTZ | Para SLA y auditoría | |
| zonas | id | UUID PK | |
| nombre | VARCHAR(50) | NOT NULL | |
| cobertura_min | INTEGER DEFAULT 1 | Personas mínimas simultáneas en esta zona | |
| activa | BOOLEAN DEFAULT true | Soft delete | |
| usuario_zona | usuario_id | UUID FK | PK compuesta con zona_id |
| zona_id | UUID FK | PK compuesta | |
| disponibilidad | JSONB | {"lun":true,"mar":true,…,"dom":false} | |
| descanso_semanal | ENUM | 'lun'|'mar'|'mie'|'jue'|'vie'|'sab'|'dom' | |
| horas_tarifa | INTEGER | CLP por hora (para cálculo de costo) | |
| festivos | fecha | DATE PK | |
| nombre | VARCHAR(100) | Ej: "Año Nuevo" | |
| pais | CHAR(2) DEFAULT 'CL' | ISO 3166 — para expansión multi-país |
Diagrama de estados — solicitud_cambio.estado
┌─────────────┐
│ pendiente │ ← Estado inicial al crear la solicitud
└──────┬──────┘
aprobar │ rechazar
┌─────┴─────┐
▼ ▼
┌─────────┐ ┌───────────┐
│aprobada │ │rechazada │
└────┬────┘ └───────────┘
│ Si tipo='cambio' AND sustituto_id IS NOT NULL:
└→ UPDATE turnos SET usuario_id = sustituto_id, editado = true
(transacción atómica con la actualización del estado)
Reglas de validación server-side (obligatorias)
| Regla | Condición | Error a devolver |
|---|---|---|
| RV-01 | Al crear turno: la persona debe tener la zona habilitada en usuario_zona | 422 "Empleado no habilitado para esta zona" |
| RV-02 | Al crear turno: disponibilidad[dia_semana] = true | 422 "Empleado no disponible ese día" |
| RV-03 | Domingo o festivo: COUNT(turnos WHERE es_domingo OR es_festivo AND mes=actual) < 2 | 422 "Límite de 2 domingos/festivos mensuales alcanzado (Art. 38 CT)" |
| RV-04 | Horas en el día: SUM(hora_fin - hora_inicio) <= 9h | 422 "Excede jornada diaria máxima de 9h (Art. 31 CT)" |
| RV-05 | Horas en la semana: SUM(hora_fin - hora_inicio) <= 42h | 422 "Excede jornada semanal máxima de 42h (Ley 21.561, vigente abril 2026)" |
| RV-06 | Al aprobar solicitud tipo='cambio': el sustituto debe cumplir RV-01 a RV-05 | 422 "El sustituto no puede cubrir ese turno por [motivo]" |
| RV-07 | hora_fin > hora_inicio | 400 "Horario inválido" |
| RV-08 | No puede haber 2 solicitudes activas (estado='pendiente') para el mismo turno | 409 "Ya existe una solicitud pendiente para este turno" |
| RV-09 | Solo el propietario del turno puede crear solicitudes (operador) | 403 "Solo el empleado asignado puede solicitar un cambio" |
| RV-10 | Solo admin puede crear/editar/eliminar turnos directamente | 403 "Requiere rol admin" |
Endpoints REST (mínimo viable para el backend)
| Método | Ruta | Rol | Descripción |
|---|---|---|---|
| GET | /api/turnos?mes=2026-06&local_id=X | Admin | Todos los turnos del mes. Incluye campo solicitud si existe |
| GET | /api/turnos/mis-turnos?mes=2026-06 | Operador | Solo los turnos del usuario autenticado. Solo aprobado=true |
| POST | /api/turnos/generar | Admin | Body: {mes, local_id}. Ejecuta el algoritmo y devuelve array de turnos (draft, aprobado=false). No persiste hasta POST /publicar |
| POST | /api/turnos/publicar | Admin | Body: {mes, local_id}. SET aprobado=true a todos los turnos del mes. Dispara notificaciones push |
| PUT | /api/turnos/:id | Admin | Editar usuario_id, zona_id, hora_inicio, hora_fin. Aplica RV-01 a RV-07. SET editado=true |
| DELETE | /api/turnos/:id | Admin | Soft delete (activo=false). No elimina físicamente para auditoría |
| POST | /api/turnos/:id/solicitudes | Operador | Crear solicitud de cambio. Aplica RV-08 y RV-09 |
| PATCH | /api/solicitudes/:id | Admin | Body: {estado: 'aprobada'|'rechazada', motivo_rechazo}. Si aprobada+cambio: transacción atómica |
| GET | /api/zonas?local_id=X | Admin | Lista de zonas del local |
| PUT | /api/usuario-zona/:userId | Admin | Actualizar zonas habilitadas y disponibilidad de un empleado |
Historias de usuario
- US-116 Como administrador, quiero configurar las zonas del local y habilitar qué empleados pueden cubrir cada zona, para que el generador tenga la información necesaria
- US-117 Como administrador, quiero ver la curva de demanda horaria derivada de ventas reales para entender cuándo necesito más personal antes de generar el calendario
- US-118 Como administrador, quiero presionar un botón y obtener el calendario del mes completo (todos los días cubiertos), respetando disponibilidad individual y la ley laboral, para no tener que armarlo manualmente
- US-119 Como administrador, quiero que el sistema me avise automáticamente si un empleado ya trabajó 2 domingos este mes y no lo incluya en el turno dominical, para no incumplir el Art. 38 CT
- US-120 Como administrador, quiero que al asignar a alguien para un domingo, el sistema genere automáticamente su día compensatorio en la semana siguiente, para no olvidarlo
- US-121 Como administrador, quiero poder editar manualmente cualquier turno del calendario generado antes de publicarlo, para ajustar casos especiales
- US-122 Como administrador, quiero ver el costo laboral estimado del calendario generado (horas × tarifa), para controlar el presupuesto de personal
- US-123 Como operador, quiero poder solicitar un cambio de turno indicando un compañero sustituto, para que el manager lo apruebe o rechace sin perder cobertura
- US-124 Como administrador, quiero ver todas las solicitudes de cambio pendientes directamente en el calendario (badge ⏳) y aprobarlas o rechazarlas con un motivo, para gestionar el equipo sin salir del módulo
- US-125 Como administrador, quiero que el sistema me alerte visualmente qué días del mes tienen cobertura incompleta (alguna zona sin nadie), para poder corregirlos antes de publicar el calendario
M11.6 — Vista del calendario mensual
El mes se muestra dividido en semanas (Semana 1, Semana 2…). Cada semana es una tabla Zona × Día con chips de turno. Navegable con ◄ ► entre meses. Los turnos son borradores (aprobado=false) hasta que el admin publique.
◄ junio de 2026 ►
Semana 1 · 1–7 jun
┌────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┐
│ │ Lu 1 │ Ma 2 │ Mi 3 │ Ju 4 │ Vi 5 │ Sá 6 │ Do 7 ☀ │
├────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┼──────────┤
│ Caja │ CT 08-16 │ CT 08-16 │ CT 08-16 │ CT 08-16 │ CT 08-16 │ AR 08-16 │ LP 08-16 │
│ Barra │ DM 08-16 │ DM 08-16 │🔄 DM │ LP 08-16 │ LP 08-16 │ CT 08-16 │ AR 08-16 │
│ Cocina │ AR 08-16 │ LP 08-16 │ LP 08-16 │🔄 LP │ AR 08-16 │ DM 08-16 │ SV 08-16 │
└────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┘
Semana 2 · 8–14 jun …
Chips de turno — badges visuales
| Badge | Significado |
|---|---|
| Iniciales + color de fondo | Persona asignada — color único por empleado |
| HH–HH debajo | Horario compacto del turno (8h centradas en peak) |
| ☀ naranja | Domingo trabajado — incrementa contador mensual (máx 2) |
| 🎉 ámbar | Festivo legal — demanda +30%, compensatorio obligatorio |
| 🔄 (chip gris) | Día compensatorio — empleado no trabaja |
| ⏳ amarillo | Solicitud de cambio pendiente de aprobación |
| ✏ blanco | Turno modificado manualmente tras la generación |
| — rojo | Celda sin cobertura — zona no cubierta ese día |
Modal de turno — comportamiento según rol
| Acción | Admin | Operador |
|---|---|---|
| Ver detalle del turno | ✅ | ✅ |
| Cambiar empleado asignado | ✅ Directo | ❌ |
| Cambiar zona / horario | ✅ Directo | ❌ |
| Eliminar turno | ✅ | ❌ |
| Solicitar cambio de turno | ❌ | ✅ Con motivo + sustituto sugerido |
| Solicitar permiso / vacación | ❌ | ✅ Con motivo |
| Aprobar / rechazar solicitud | ✅ Con motivo de rechazo | ❌ |
Resumen legal automático (pie del calendario)
| Empleado | Horas mes | Dom/Fest | Costo est. | Estado |
|---|---|---|---|---|
| Camila Torres | 160h | 0 / 2 | $672.000 | ✅ OK |
| Diego Muñoz | 152h | 2 / 2 | $577.600 | ⚠️ Límite dom/fest |
| Ana Reyes | 156h | 1 / 2 | $592.800 | ✅ OK |
| Luis Pino | 158h | 2 / 2 | $600.400 | ⚠️ Límite dom/fest |
| Sofía Vera | 154h | 1 / 2 | $585.200 | ✅ OK |
Fase 3 — App mobile de personal (PWA)
Extensión del módulo como aplicación móvil independiente para empleados y managers. Referencia de diseño: teams_v1.html (prototipo interno Welcomeback Teams).
Visión
El empleado instala la PWA en su teléfono. El día anterior recibe una notificación con su turno del día siguiente. Puede solicitar cambios, ver sus horas acumuladas y acceder a sus liquidaciones, todo sin necesidad de ir al local o consultar un papel.
| Feature | Empleado | Manager | Prioridad |
|---|---|---|---|
| Ver mis turnos de la semana | ✅ | ✅ | Alta |
| Notificación push turno mañana | ✅ | — | Alta |
| Marcar entrada/salida desde móvil (geofencing) | ✅ | — | Alta |
| Solicitar cambio de turno | ✅ | Aprobar | Media |
| Solicitar vacaciones / permiso | ✅ | Aprobar | Media |
| Ver liquidaciones y documentos | ✅ | Subir PDF | Media |
| Chat de equipo / anuncios | ✅ | Publicar | Baja |
| Propinas del turno | ✅ | — | Baja |
| Publicar/editar calendario desde móvil | — | ✅ | Media |
Stack técnico sugerido
| Capa | Tecnología | Razón |
|---|---|---|
| Frontend | Next.js 16 + PWA | Consistente con el resto del stack Welcomeback; installable sin app store |
| Notificaciones push | Web Push API + service worker | Sin costo de FCM/APNS para prototipo; nativo en Android, limitado en iOS 16.4+ |
| Geofencing | Geolocation API + radio 100m | Verifica que el empleado esté en el local al fichar desde móvil |
| Backend | Express API (misma capa del POS) | Reutilizar endpoints de usuarios, turnos y asistencia |
| Auth | PIN + JWT (mobile) / PIN + sessionStorage (POS) | PIN unificado — misma credencial en POS y app |
M12 — Manejo de Efectivo
Sistema de control del flujo de efectivo en caja durante el turno. Registra entradas automáticamente al cobrar, permite salidas manuales auditadas, y genera el arqueo al cierre. Solo visible para el rol Admin.
Problema que resuelve
Sin control de efectivo, el dueño no sabe cuánto debería haber en caja al cierre del turno. Cualquier diferencia —sea error del cajero o manipulación— pasa desapercibida. El arqueo manual en papel es lento, propenso a errores y fácilmente falsificable.
M12.1 — Fondo de caja + arqueo
Flujo del turno
Componentes del panel
| Componente | Descripción | Quién lo ve |
|---|---|---|
| Fondo inicial | Efectivo con que abre la caja al inicio del turno. Lo registra el Admin manualmente. | Admin |
| KPIs del turno | 4 tarjetas: Ventas efectivo · Salidas / retiros · Efectivo esperado · Diferencia | Admin |
| Registro de salida | Formulario para registrar retiros manuales con descripción y monto. Aparece en el log de movimientos. | Admin |
| Movimientos del turno | Tabla cronológica inversa: hora · descripción · tipo (Entrada/Salida) · monto. Las ventas se marcan como automáticas, los retiros como manuales. | Admin |
| Arqueo de caja | Cálculo: Fondo inicial + Ventas efectivo − Salidas = Efectivo esperado en caja. | Admin |
M12.2 — Movimientos manuales auditables
Registro automático vs manual
| Movimiento | Origen | Requiere acción del Admin |
|---|---|---|
| Venta cobrada en Efectivo | Automático — hook en processPay() | No |
| Venta cobrada en Mixto | Automático — se registra el total | No |
| Venta en tarjeta / QR | No genera movimiento en caja | No |
| Fondo inicial | Manual — Admin lo ingresa al abrir turno | Sí |
| Retiro / gasto | Manual — Admin lo registra con descripción | Sí |
Fórmula del arqueo
Efectivo esperado = Fondo inicial
+ Σ ventas cobradas en efectivo o mixto
− Σ salidas manuales registradas
Diferencia = Efectivo real contado − Efectivo esperado
→ 0 : caja cuadrada ✅
→ > 0 : sobrante (posible cobro de más) ⚠️
→ < 0 : faltante (posible error o manipulación) 🔴
Historias de usuario
- US-120 Como dueño, quiero ingresar el fondo inicial de la caja al empezar el turno para tener una base de cálculo
- US-121 Como dueño, quiero que cada venta en efectivo se registre automáticamente sin que el cajero tenga que hacer nada extra
- US-122 Como dueño, quiero registrar retiros de efectivo con una descripción para saber exactamente a qué se destinó el dinero
- US-123 Como dueño, quiero ver al final del turno cuánto debería haber en caja y compararlo con lo que hay físicamente
- US-124 Como cajero, quiero no tener que preocuparme del control de caja — que sea el sistema el que lo haga automáticamente
Criterios de aceptación
- La sección solo es visible para el rol Admin — el cajero no tiene acceso
- Cada venta cobrada en Efectivo o Mixto añade un movimiento automático al log en ≤100ms
- El arqueo se recalcula en tiempo real cada vez que se registra un movimiento
- Una salida manual requiere obligatoriamente descripción y monto positivo
- Los movimientos muestran la hora, descripción, tipo (badge) y monto con color verde/rojo
- La diferencia muestra +/− con color: verde (=0), naranja (>0), rojo (<0)
- El fondo inicial se puede actualizar durante el turno — el log refleja el cambio
Fase 2
| Feature | Descripción |
|---|---|
| Cierre de turno con PDF | Generar un reporte de arqueo firmable para archivar físicamente |
| Alerta de diferencia | Notificación push al dueño si la diferencia supera un umbral configurado (ej: $5.000) |
| Histórico de cierres | Ver el arqueo de turnos anteriores con fecha, cajero y diferencia |
| Conteo por denominación | Ingresar cuántos billetes de cada tipo hay para calcular el total real automáticamente |
M13 — Modo Offline: Ventas sin Internet
El POS opera con total normalidad cuando no hay conexión a internet. Las ventas se registran, los DTEs se encolan con folio CAF local, y todo se sincroniza automáticamente en cuanto vuelve la red. El cajero nunca queda bloqueado por problemas de conectividad.
Por qué es crítico en un QSR
Un local de café en hora punta no puede dejar de vender por un corte de internet de 10 minutos. En Chile, el SII acepta DTEs offline siempre que se emitan con folio CAF válido y se sincronicen dentro del mismo día (Art. 9, Res. Ex. N°45/2003).
Estados del sistema
| Estado | Indicador visible | Comportamiento del POS |
|---|---|---|
| Online | 🟢 Badge WiFi verde en esquina inferior derecha: "Online" | DTE emitido y confirmado por SII en ≤2s tras cada venta |
| Offline | 🔴 Banner ámbar superior + badge WiFi rojo: "Sin conexión" | Venta se procesa normal. DTE se guarda en cola local con folio CAF preinstalado. El badge en la pantalla de pago aprobado dice "En cola de sincronización" |
| Reconexión | Banner desaparece, badge WiFi vuelve a verde | Cola procesada FIFO automáticamente. Toast de confirmación con número de DTEs sincronizados |
| >20h offline | Alerta urgente en header | Aviso al admin: quedan 4h de margen legal |
| >24h offline | Banner rojo bloqueante | DTEs marcados VENCIDOS — requiere acción manual del dueño con el SII |
M13.1 — Cola de ventas offline + sincronización
Flujo de una venta offline
M13.2 — Indicador WiFi flotante
Componentes del sistema
| Componente | Descripción |
|---|---|
| Banner offline | Barra superior ámbar con contador de pendientes y botón "Sincronizar" (activo solo al reconectar) |
| Indicador de señal | 4 barras en el topbar: verde completo = online, 2 barras rojas = offline. Clickable para simular en el prototipo. |
| SYNC_QUEUE | Array de objetos con: id, tipo de DTE, folio CAF, orden, total, método, hora, estado (pendiente / sincronizado / error) |
| Panel en Ajustes | Tabla de todos los elementos de la cola con estado, hora, folio y total. Botón de sincronización manual. |
| Pool CAF local | Folios descargados anticipadamente. El admin recibe alerta cuando quedan ≤50 folios. |
Operaciones disponibles sin conexión
| Operación | Offline | Nota |
|---|---|---|
| Cobrar (efectivo, tarjeta, QR) | ✅ | Pago local en terminal; DTE en cola |
| Emitir boleta electrónica | ✅ | Con folio CAF local preinstalado |
| Imprimir ticket físico | ✅ | Red local con impresora ESC/POS |
| Modificadores, descuentos, promos | ✅ | Todo local |
| KDS cocina (localStorage) | ✅ | Comunicación local sin internet |
| Identificar cliente Welcomeback | ⚠️ Parcial | Solo clientes cacheados localmente |
| Stamps Welcomeback | ⏳ En cola | Se suman al reconectar |
| Devolución / NCE | ❌ | Requiere confirmación SII en tiempo real |
Historias de usuario
- US-130 Como cajero, quiero seguir cobrando aunque se corte el internet, sin tener que hacer nada diferente
- US-131 Como cajero, quiero saber visualmente si estoy en modo offline para entender por qué el badge del DTE dice "en cola"
- US-132 Como dueño, quiero que los DTEs se sincronicen solos al volver la conexión, sin tener que intervenir
- US-133 Como dueño, quiero ver qué boletas están pendientes de sincronizar y poder forzar la sincronización manualmente
- US-134 Como dueño, quiero recibir una alerta si llevamos más de 20 horas sin conexión, antes de llegar al límite legal de 24h
Criterios de aceptación
- El POS detecta pérdida de conexión en ≤5 segundos y activa el banner automáticamente
- Cada venta offline genera un folio CAF válido y un registro en la cola de sincronización
- Al reconectar, la sincronización comienza automáticamente en ≤3 segundos
- La cola se procesa en orden FIFO — la primera venta offline es el primer DTE enviado al SII
- El cajero ve en la pantalla de pago aprobado si el DTE fue emitido en tiempo real o está en cola
- El admin puede ver la cola completa en Ajustes → Conexión y sincronización con estado por elemento
- Si un DTE de la cola falla al sincronizar, queda con estado "Error" y requiere acción manual
- Con ≤50 folios CAF disponibles: alerta naranja. Con 0 folios: no se puede cobrar.
Fase 2
| Feature | Descripción |
|---|---|
| Persistencia real (IndexedDB) | Cola sobrevive a reinicios del navegador — actualmente es en memoria |
| Alerta >20h offline | Notificación push al dueño antes de llegar al límite legal de 24h |
| Reintento automático | DTEs con error se reintentan automáticamente cada 5 minutos |
| Service Worker | Para app instalable (PWA): funciona aunque se cierre el navegador |
| Cache de clientes WB | Los últimos 500 clientes cacheados localmente para identificar en modo offline |
M14 — Gestión de Inventario
Sistema completo de control de stock basado en ingredientes y recetas. Cada venta descuenta automáticamente los ingredientes consumidos. El admin puede monitorear en tiempo real, crear órdenes de compra, ajustar stock manualmente y consultar la valoración del inventario.
M14.1 — Stock + alertas de mínimo
Modelo de datos: ingredientes + recetas
El inventario opera a nivel de ingredientes / materias primas. Cada producto del menú tiene una receta que define qué ingredientes consume y en qué cantidad. Al confirmar una venta, el sistema descuenta automáticamente los ingredientes sin que el cajero tenga que hacer nada.
| Campo | Tipo | Descripción | Ejemplo |
|---|---|---|---|
id | string | Identificador interno del sistema | i01 |
sku | string | Código de referencia externo (SKU) — formato PREFIJO-NNN. Aparece en la tabla de stock, en el selector de recetas y en el historial de movimientos. | LAC-001 |
nombre | string | Nombre legible del ingrediente | Leche entera |
unidad | string | Unidad de medida: ml, g, u | ml |
stock | number | Cantidad actual en inventario | 12000 |
minimo | number | Umbral de alerta de stock bajo | 2000 |
costo | number | Costo unitario en CLP (por ml/g/u) | 0.8 |
proveedor | string | ID del proveedor en PROVEEDORES[] | p1 |
Prefijos SKU usados en el prototipo: LAC- Lácteos · CAF- Café/cacao · PAN- Panadería · BEB- Bebidas · ALH- Alcoholes · DUL- Dulces/secos · BOL- Bowls. El dueño puede definir sus propios prefijos en Fase 2.
Las recetas soportan dos tipos de ingredientes:
| Tipo | Definición | Ejemplo |
|---|---|---|
| Fijo | Se descuenta siempre, independiente de los modificadores elegidos | 18g café en todo café con leche |
Variable (ifOpt) | Solo se descuenta si el cliente eligió esa opción de modificador específica | 200ml NotMilk solo si eligió "NotMilk"; 200ml leche entera solo si eligió "Entera" |
Receta: Latte Grande
Café en grano 18 g ← FIJO — siempre se descuenta
Azúcar 5 g ← FIJO — siempre se descuenta
Leche entera 200 ml ifOpt:'o1' ← solo si eligió "Entera"
Leche descremada 200 ml ifOpt:'o2' ← solo si eligió "Descremada"
NotMilk 200 ml ifOpt:'o3' ← solo si eligió "NotMilk"
Leche de avena 200 ml ifOpt:'o4' ← solo si eligió "Avena"
Leche de soya 200 ml ifOpt:'o5' ← solo si eligió "Soya"
Receta: Poke Bowl (todo variable)
Arroz 180 g ifOpt:'o50' ← solo si eligió base "Arroz"
Quinoa 160 g ifOpt:'o51' ← solo si eligió base "Quinoa"
Salmón 120 g ifOpt:'o52' ← solo si eligió proteína "Salmón"
Atún 120 g ifOpt:'o53' ← solo si eligió proteína "Atún"
Tofu 120 g ifOpt:'o54' ← solo si eligió proteína "Tofu"
Al vender 1 Latte Grande con NotMilk → descuenta:
INGREDIENTES['Café en grano'].stock −= 18 (fijo)
INGREDIENTES['Azúcar'].stock −= 5 (fijo)
INGREDIENTES['NotMilk'].stock −= 200 (variable, ifOpt coincide)
— Leche entera NO se descuenta (ifOpt no coincide)
M14.2 — Recetas fijas + variables (ifOpt)
Sub-módulos del sistema
| Módulo | Función | Acceso |
|---|---|---|
| 📊 Stock | Tabla de todos los ingredientes con stock actual, mínimo, proveedor y valor. Alertas de bajo stock y agotados. | Admin |
| 📋 Recetas | Ver y editar ingredientes de cada producto. Soporta ingredientes fijos (siempre) y variables (ifOpt — solo si el cliente eligió esa opción de modificador). Costo calculado, margen y porciones disponibles según stock actual. | Admin |
| 🏭 Proveedores | Directorio de proveedores con contacto, plazo de entrega y productos que suministran. | Admin |
| 🛒 Órdenes de compra | Crear, enviar y recibir órdenes. Al marcar "recibida" el stock se actualiza automáticamente. | Admin |
| ✏️ Ajuste de stock | Registro manual de entradas, salidas y correcciones con motivo auditable. Historial de movimientos. | Admin |
| ⬆ Importar | Carga masiva desde CSV o lectura de facturas de proveedor: foto/PDF → resumen interactivo con cantidades y precios por unidad ($/L, $/kg, $/u) → confirmar líneas a ingresar → stock actualizado automáticamente. | Admin |
| 💰 Valoración | Valor total del stock, ventas potenciales calculadas desde recetas, distribución por ingrediente. | Admin |
Flujo de descuento automático al vender
El paso "Filtra por opciones" extrae todos los optId seleccionados por el cliente (modsFlat = Object.values(item.mods).flat()) y solo descuenta los ingredientes cuyo ifOpt está en ese array. Ingredientes sin ifOpt siempre se descuentan.
M14.3 — Órdenes de compra
Órdenes de compra — estados
| Estado | Descripción | Acción disponible |
|---|---|---|
| Borrador | Creada pero no enviada al proveedor | Enviar al proveedor |
| Enviada | Proveedor notificado, esperando entrega | Marcar como recibida |
| Recibida | Mercancía ingresada — stock actualizado automáticamente | Ver detalle |
M14.5 — Ajuste manual + historial
Alertas de stock bajo
Cuando el stock de un ingrediente cae por debajo del mínimo configurado, aparece un banner de alerta en la vista Stock y un badge "⚠ Bajo" o "Agotado" junto al ingrediente. En Fase 2 se envía notificación push diaria al dueño.
M14.4 — Lectura de facturas IA (Fase 2)
Importación y lectura de facturas
| Método | Descripción | Estado |
|---|---|---|
| CSV | Plantilla estándar: nombre, unidad, stock, mínimo, costo, proveedor | MVP (maqueta) |
| Lectura de factura | Fotografía o PDF de factura de proveedor → animación de procesado IA → resumen interactivo → confirmar | Implementado (demo) |
Flujo de lectura de factura
El resumen muestra: proveedor, RUT, folio, fecha, tabla de productos con cantidad + unidad real (ml, g, u) y precio por unidad práctica ($/L, $/kg, $/u). Cada línea tiene checkbox — el admin puede desmarcar lo que no quiera ingresar. El botón de confirmación indica cuántos productos se agregarán. Al confirmar, actualiza INGREDIENTES[].stock y registra en MOV_STOCK con referencia al folio de la factura.
| Campo en factura | Formato mostrado | Ejemplo |
|---|---|---|
| Cantidad en ml | X.XXX ml · precio en $/L | 10.000 ml · $800/L |
| Cantidad en g | XXX g · precio en $/kg | 500 g · $8.000/kg |
| Cantidad en unidades | XX u · precio en $/u | 48 u · $1.800/u |
| Match con inventario | Badge verde "✓ En inventario" o ámbar "+ Nuevo" | Muestra stock antes → después |
En producción, el paso de procesado IA llamaría a un endpoint de OCR (Claude Vision / Google Document AI). En el prototipo se simula con datos demo de Lácteos del Sur.
Historias de usuario
- US-140 Como dueño, quiero que cada vez que se vende un producto se descuenten automáticamente sus ingredientes, sin que el cajero tenga que hacer nada
- US-141 Como dueño, quiero ver en tiempo real cuántas porciones de cada producto puedo preparar con el stock actual
- US-142 Como dueño, quiero recibir una alerta cuando un ingrediente esté por debajo del mínimo para hacer el pedido a tiempo
- US-143 Como dueño, quiero crear una orden de compra y enviársela al proveedor directamente desde el POS
- US-144 Como dueño, quiero registrar una merma o pérdida con motivo para tener trazabilidad total del stock
- US-145 Como dueño, quiero saber cuánto vale el inventario actual y cuánto podría facturar si vendiera todo
- US-146 Como dueño, quiero importar cientos de ingredientes desde un CSV en lugar de ingresarlos uno a uno
- US-147 Como dueño, quiero que al vender un Latte con NotMilk se descuente NotMilk del inventario, no leche entera
- US-148 Como dueño, quiero fotografiar una factura de proveedor y que el sistema extraiga automáticamente los productos y cantidades para actualizar el stock sin reingresarlos manualmente
Criterios de aceptación
- Cada venta descuenta ingredientes según receta en ≤100ms tras confirmar el pago, usando solo los ingredientes que corresponden a las opciones seleccionadas por el cliente
- Un Latte con NotMilk descuenta NotMilk; un Latte con Entera descuenta leche entera. Nunca se descuenta un ingrediente de leche si no fue seleccionado
- Lectura de factura: el resumen muestra precio en formato $/L, $/kg o $/u según la unidad del ingrediente
- Al confirmar la importación de factura, el stock de cada ingrediente seleccionado se incrementa y queda registrado en MOV_STOCK con el folio de la factura
- Ingrediente con stock ≤ mínimo muestra badge "⚠ Bajo" en naranja
- Ingrediente con stock = 0 muestra badge "Agotado" en rojo
- Al marcar una orden de compra como "recibida", el stock se incrementa automáticamente
- Los ajustes manuales requieren motivo y quedan en el historial con usuario y timestamp
- La vista Recetas muestra el costo calculado y el margen de cada producto
- La valoración muestra el valor total del inventario y las ventas potenciales en tiempo real
Fase 2
| Feature | Descripción |
|---|---|
| Lectura de facturas con IA | Fotografía → OCR + LLM → extrae artículos, cantidades y precios automáticamente |
| Notificación diaria de stock bajo | Push/email al dueño cada mañana con lista de ingredientes por reponer |
| Análisis de desviación | Contrastar stock teórico (calculado por ventas) vs. stock físico (conteo) para detectar mermas no registradas |
| Recuentos con lector de código de barras | Modo de conteo: escanear EAN → incrementar contador → confirmar para actualizar stock |
| Órdenes de transferencia multi-local | Crear órdenes para mover stock entre sucursales |
| Producciones | Registrar una producción (ej: hornear 20 croissants) que consume ingredientes y crea unidades de producto terminado |
| Impresión de etiquetas | Generar etiquetas con código de barras desde el módulo de inventario |
Fase 3 — Red de Partnerships con Proveedores
La visión a largo plazo es convertir Welcomeback POS en un canal de distribución directa para marcas de insumos alimentarios. El restaurante se beneficia de precios competitivos y pedidos automáticos; el proveedor gana visibilidad y acceso a miles de locales en un solo canal. Una relación gana-gana con Welcomeback como intermediario.
Cómo funcionaría
Propuesta de valor por actor
| Actor | Beneficio |
|---|---|
| Restaurante / local | Precio partner más bajo que canal tradicional · pedido en 1 tap · sin llamadas ni emails · sin quedarse sin stock |
| Proveedor partner (ej: Soprole) | Acceso directo a miles de locales en la red Welcomeback · pedidos automáticos basados en consumo real · menos intermediarios |
| Welcomeback | Fee de transacción por cada orden gestionada · datos de consumo agregado (anonimizados) como activo diferenciador · nuevo revenue stream |
Criterios para un partnership
- El proveedor debe tener API de pedidos (o acuerdo de integración con Welcomeback)
- El precio partner debe ser ≤ precio de mercado habitual del local — si no es competitivo, la sugerencia no aparece
- El local siempre puede ignorar la sugerencia y hacer el pedido a su proveedor habitual
- La sugerencia es no intrusiva: aparece como banner en la vista Stock, no como pop-up bloqueante
- Los datos de consumo del local son del local — Welcomeback solo usa datos agregados y anonimizados para mejorar el modelo
Ejemplo real: Soprole + Welcomeback
Stock actual de Mantequilla: 180g (mínimo: 300g)
→ Sistema detecta: bajo mínimo desde hace 2h
Sugerencia automática:
🧈 Soprole Partner
Mantequilla 250g × 10 unidades = $24.500
Precio habitual en distribuidor: $28.000 (-12%)
Entrega estimada: mañana 08:00
[ Confirmar pedido · 1 tap ] [ Ignorar ]
El modelo de partnerships se activa en Fase 3, una vez que la red de locales sea suficientemente grande para ser atractiva para los proveedores. El MVP (Fase 1-2) construye la base: historial de consumo por ingrediente, que es el activo que hace valiosa la propuesta para el proveedor.
M15 — Gestión de Carta
Editor visual completo para gestionar todos los elementos de la oferta del local: productos, categorías, grupos de modificadores y recetas con costos. Vive en Ajustes → Local → "Carta y categorías" como panel expandible con 4 tabs. Vinculado en tiempo real con M14 (Inventario) y preparado para conectar con M16 (Historial de ventas avanzado).
M15.1 — Productos + categorías
Los 4 tabs del editor
📦 Productos
Tabla de todos los productos con: icono, nombre, categorías, precio de venta, margen calculado (desde receta) y toggle de disponibilidad. Click en cualquier fila abre el formulario de edición inline en secciones colapsables, inspirado en el editor de Square Dashboard.
Estructura del formulario de edición (secciones)
| Sección | Campo | Tipo | Notas |
|---|---|---|---|
| Tipo de artículo | Tipo | Cards seleccionables | 🍽 Bebidas y alimentos · 📦 Producto físico · 🛠 Servicio · 🔖 Otro |
| El tipo afecta qué campos adicionales aparecen en fases futuras (peso de envío, fechas de evento, etc.) | |||
| Información básica | Nombre | Texto | Obligatorio — visible al cliente en el POS y ticket |
| Nombre en cocina | Texto | Opcional — aparece en el KDS si difiere del nombre al cliente | |
| Descripción | Textarea | Opcional — visible en carta QR y modal de producto | |
| Icono y apariencia | Icono | Emoji + selector 18 opciones | Aparece en la tarjeta del grid de venta |
| Color de fondo | 6 presets de gradiente | Afecta la tarjeta en el grid de venta | |
| Precio y disponibilidad | Precio (CLP) | Número | Obligatorio, > 0. IVA 19% siempre incluido. |
| Disponible en POS | Toggle | Inactivo → aparece como "Agotado" en el POS y se puede reactivar desde el KDS | |
| Badge | Select | Sin badge / 🔥 Popular / ⭐ Destacado / 🆕 Nuevo | |
| Categorías | Categorías | Chips multi-select | Un producto puede estar en varias. La categoría "Más pedidos" se asigna automáticamente. |
| Impuestos | IVA 19% | Informativo (no editable) | Todos los productos aplican IVA 19% — Art. 43 DL 825. Sin campo de ILA. |
| Identificador | SKU | Texto | Opcional — código interno para inventario y reportes. Formato sugerido: PROD-XXX-001 |
| Canales de venta | Surfaces | Checkboxes multi-select | Canales donde aparece el producto: 🏪 Mostrador POS · 📱 Tótem · 📲 Mobile orders · 🛵 Delivery · 📋 Carta QR. Si no se selecciona ninguno, el producto no aparece en ningún canal. |
| Regla alcohol | — | Los productos alcohólicos deben incluir solo pos y qr_menu — nunca kiosk ni mobile (restricción de edad). El sistema no lo fuerza automáticamente; es responsabilidad del administrador. | |
| Estación | Estación de preparación | Select | ☕ Barra · 🍳 Cocina · 📦 Externo. Determina en qué pantalla KDS aparece el pedido. Si está vacío, va al KDS general. |
| Modificadores | Grupos de mods | Lectura + link a tab Modificadores | Muestra los grupos ya asignados al producto. Cada opción de modificador tiene su propio SKU y puede tener una receta de ingredientes para descontar del inventario al elegirse. |
Modelo de surfaces (canales)
| ID | Nombre | Descripción | Regla especial |
|---|---|---|---|
pos | Mostrador POS | Pantalla del cajero en tienda | — |
kiosk | Tótem | Autoservicio físico en tienda | No incluir alcohol — menores sin supervisión |
mobile | Mobile orders | App o web del cliente | No incluir alcohol sin verificación de edad |
delivery | Delivery | Rappi, Uber Eats, pedido propio | Puede tener precioDelivery distinto al precio base |
qr_menu | Carta QR | Menú digital escaneado en mesa | Solo lectura — el cliente no puede pedir, solo ver |
Las surfaces de la categoría actúan como filtro adicional: si la categoría "Alcohol" no incluye kiosk, ningún producto de esa categoría aparece en el tótem aunque el producto individualmente tenga kiosk en su lista.
Modelo de modificadores con inventario
Cada opción de modificador tiene ahora un sku propio y puede llevar una receta de ingredientes. Al confirmar el ítem en el KDS, el sistema descuenta los ingredientes de la receta del producto base más los ingredientes de la receta de la opción de modificador elegida.
Ejemplo: Latte Grande con Leche de Avena seleccionada
Al marcar "listo" en KDS:
→ Receta del producto p1 (Latte Grande):
café en grano 18g → descuenta ING-CAFE
agua 50ml → descuenta ING-AGUA
→ Receta del modificador MOD-OPT-AVENA (Leche de Avena):
leche de avena 200ml × (1+0.02 merma) → descuenta ING-LECHE-AVE
(NO descuenta ING-LECHE-ENT)
Si el cliente hubiera elegido Leche Entera (MOD-OPT-ENTERA):
→ Receta del modificador MOD-OPT-ENTERA:
leche entera 200ml × (1+0.02 merma) → descuenta ING-LECHE-ENT
🗂 Categorías
Lista de las categorías existentes con su color, cantidad de productos y toggle de visibilidad. Formulario para crear nuevas: nombre + emoji + color + surfaces (filtro macro por canal). Al crear, la categoría aparece inmediatamente en el menú lateral del POS. Si la categoría no incluye pos en sus surfaces, ninguno de sus productos aparece en el POS aunque los productos individualmente lo tengan.
M15.2 — Editor de modificadores
✏️ Modificadores
Muestra todos los grupos de modificadores del sistema. Por cada grupo: tipo (single/multi/input), si es requerido, y listado de productos que lo usan. Cada opción tiene nombre, precio extra, SKU propio y una receta opcional con los ingredientes que descuenta del inventario al ser elegida. Los cambios se aplican en tiempo real a todos los productos que usan ese grupo.
M15.3 — Recetas + costos + margen
📋 Recetas & Costos
Para cada producto muestra sus ingredientes con cantidades editables, el costo total calculado y el margen sobre el precio de venta. Los cambios se sincronizan en tiempo real con el módulo de Inventario (M14) — el campo "porciones disponibles" en el tab Stock se recalcula automáticamente.
Latte Grande — Precio: $3.500
Leche entera 200 ml × $0.8/ml = $160
Café en grano 18 g × $12/g = $216
Azúcar 5 g × $1.2/g = $6
─────────────────────────────────
Costo total: $382 · Margen: 89%
Acceso y flujo
Vinculación con otros módulos
| Módulo | Vinculación |
|---|---|
| M14 · Inventario | Tab Recetas edita RECETAS[] directamente. El tab Stock de inventario refleja el cambio inmediatamente en "porciones disponibles". |
| M1 · Pantalla de venta | Editar nombre/precio/disponibilidad actualiza el grid de productos y el modal de modificadores en tiempo real (mismos arrays en memoria). |
| M16 · Historial avanzado (Fase 2) | Cuando M16 esté implementado, la vista de producto mostrará ventas del día/semana/mes y productos más vendidos. |
Historias de usuario
- US-150 Como dueño, quiero cambiar el precio de un producto sin tener que tocar el código fuente
- US-151 Como dueño, quiero marcar un producto como "agotado" cuando se acaba, y volverlo disponible cuando llegue el stock
- US-152 Como dueño, quiero crear un nuevo producto con sus categorías e icono desde el backoffice
- US-153 Como dueño, quiero ver el costo y margen de cada producto calculados automáticamente desde los ingredientes
- US-154 Como dueño, quiero añadir una nueva opción de leche al grupo "Tipo de leche" y que aparezca en todos los productos que lo usan
- US-155 Como dueño, quiero crear una nueva categoría (ej: Smoothies) y que aparezca inmediatamente en el menú del POS
Criterios de aceptación
- Editar nombre o precio de un producto → el grid del POS se actualiza sin recargar la página
- Toggle de disponibilidad → el producto aparece/desaparece como "Agotado" en el grid en ≤200ms
- Crear nuevo producto → aparece en el grid al guardar y el contador de Ajustes se actualiza
- Editar opción de modificador → el modal de modificadores refleja el cambio al abrirlo
- Editar receta → costo y margen se recalculan en tiempo real sin pulsar "guardar"
- Crear categoría → aparece en el menú lateral del POS inmediatamente
- El módulo solo es accesible para rol Admin
Fase 2 — Mejoras planeadas
| Feature | Descripción |
|---|---|
| Fotos de productos | Subir imagen desde cámara o URL. Se muestra en la tarjeta del grid. |
| Historial de precios | Registrar quién cambió el precio y cuándo, con el valor anterior. |
| Variantes de producto | Talla S/M/L como variantes de un mismo producto base con precios distintos. |
| Importación CSV | Cargar masivamente desde plantilla (ya documentado en M14). |
| Stats por producto | Ver ventas del día/semana/mes directamente en la ficha del producto (requiere M16). |
Integración con carta digital QR (ya disponible)
Welcomeback ya dispone de carta digital QR para el cliente. El editor de carta de M15 es la fuente de verdad que alimenta esa carta digital — cualquier cambio de precio, disponibilidad o nuevo producto se refleja en el QR sin pasos adicionales.
Fase 3
| Feature | Descripción |
|---|---|
| Traducciones | Carta en inglés / portugués para locales con turismo extranjero. |
| Sugerencia de precio | IA sugiere precio óptimo basado en costo + margen objetivo + precios de la competencia. |
M16 — Análisis de Ventas
Dashboard de inteligencia comercial en tiempo real. Convierte el tab "Ventas" del bottomnav en un módulo completo de análisis con 6 vistas: resumen ejecutivo, tendencias, productos más vendidos, desglose de pagos e impuestos, historial detallado y exportación para Excel o contador.
M16.1 — Dashboard KPIs + gráfico por hora
Los 6 tabs del módulo
| Tab | Contenido |
|---|---|
| 📊 Resumen | 6 KPIs (ventas, transacciones, ticket prom., efectivo, tarjeta, IVA) · Mini-gráfico de barras por hora (SVG inline) · Descuentos y promos aplicadas · Cuadre de caja vs CAJA |
| 📈 Tendencias | Ventas por día (tabla con fecha, transacciones, total, ticket prom., método top) · Top franjas horarias con barra visual |
| 🏆 Productos | Ranking top 10 por unidades vendidas con ingresos y % del total · Agrupado por categoría |
| 💳 Pagos | Desglose por método de pago con % · Tabla de impuestos: bruto, descuentos, neto, IVA 19%, base imponible |
| 🧾 Detalle | Historial completo de todas las ventas del período con cajero, botón de devolución y NCE |
| ⬇ Exportar | 3 formatos copiables: resumen de turno (texto), CSV de ventas, CSV por producto |
Selector de período
Los tabs Resumen, Tendencias, Productos, Pagos y Exportar tienen un selector global: Hoy · Esta semana · Este mes. Los cálculos se recalculan al cambiar el período sin recargar la vista.
M16.2 — Top productos + rentabilidad
Estructura de datos enriquecida (VENTAS_DATA)
A partir de M16, cada venta registrada en processPay() guarda campos adicionales:
{
// campos anteriores (retrocompatibles)
id, status, time, items, total, method,
// nuevos campos M16
fecha: 'YYYY-MM-DD',
iva: number, // Math.round(total - total/1.19)
neto: number, // total - iva
cajero: string, // currentUser.name
itemsArr: [ { name, qty, price, prodId, cats[] } ],
descuento: { tipo, valor, monto } | null,
promos: [ { nombre, monto } ] | null,
}
M16.3 — Exportación CSV
Exportación
| Formato | Uso | Columnas |
|---|---|---|
| Resumen del turno | Texto plano para llevar al contador o WhatsApp | KPIs clave en formato legible |
| CSV de ventas | Excel / Google Sheets — registro transaccional | Orden, Fecha, Hora, Cajero, Items, Total, Método, IVA, Descuento |
| CSV por producto | Análisis de oferta y demanda | Producto, Categoría, Unidades, Ingresos, % del total |
Todos usan navigator.clipboard con toast de confirmación. Sin dependencias de librerías externas.
Vinculación con otros módulos
| Módulo | Integración |
|---|---|
| M3 · Cobro y Pago | processPay() enriquece el objeto de venta con itemsArr, IVA, cajero, descuentos y promos automáticamente |
| M12 · Caja | Tab Resumen muestra el cuadre de caja (efectivo esperado vs. diferencia) usando CAJA directamente |
| M14 · Inventario | Tab Productos usa los mismos PRODUCTS/CATS para mostrar categorías correctas |
| M9 · Devoluciones | Tab Detalle incluye el botón "Devolver/Anular" para ventas cerradas |
Historias de usuario
- US-160 Como dueño, quiero ver en 5 segundos cuánto vendí hoy, cuántas transacciones hice y cuál es mi ticket promedio
- US-161 Como dueño, quiero saber a qué hora del día vendo más para decidir cuándo necesito más personal
- US-162 Como dueño, quiero ver qué productos se venden más para tomar decisiones sobre la carta
- US-163 Como dueño, quiero ver el IVA recaudado del día para llevar la contabilidad correcta
- US-164 Como dueño, quiero exportar las ventas del día a Excel con un click sin necesitar al programador
- US-165 Como administrador, quiero ver qué cajero generó cada venta para hacer seguimiento de rendimiento
- US-166 Como dueño, quiero comparar ventas de esta semana vs. la semana pasada para detectar tendencias
Criterios de aceptación
- Tab Resumen muestra KPIs actualizados al abrir la vista, sin recargar la app
- Mini-gráfico de barras por hora generado con SVG inline, sin librerías externas
- Cambiar período (Hoy/Semana/Mes) recalcula todos los datos en ≤200ms
- Tab Productos muestra correctamente las categorías de cada producto usando CATS
- IVA calculado como Math.round(total − total/1.19) en cada venta
- Exportar CSV → copiar → pegar en Excel → columnas correctas sin texto corrupto
- Tab Detalle incluye cajero en cada card y botón de devolución para ventas cerradas
- El cuadre de caja en Resumen usa los mismos datos que CAJA (M12)
Fase 2 — Mejoras planeadas
| Feature | Descripción |
|---|---|
| Comparativa semanas | Esta semana vs. semana anterior con % de variación por KPI |
| Gráfico de tendencia (línea) | Evolución del total de ventas día a día en el período seleccionado |
| Informe de modificadores | Opciones de modificadores más pedidas (ej: "NotMilk ×47 veces esta semana") |
| Descarga PDF | Generar PDF del resumen del turno para archivar |
| Filtro por cajero | Ver las métricas de un cajero específico por período |
M17 — Flujo de Clicks del Operador (End-to-End)
Recorrido cronológico de cada acción que realiza un garzón/cajero desde el inicio de turno hasta el cierre legal de la transacción. Cada paso describe: la acción del operador, el efecto en pantalla / sistema y la regla de negocio asociada.
┌──────────────┐ ┌──────────────┐ ┌────────────────────┐ ┌────────────────┐ ┌──────────────────┐
│ Etapa 1 │ → │ Etapa 2 │ → │ Etapa 3 │ → │ Etapa 4 │ → │ Etapa 5 │
│ Login / │ │ Apertura │ │ Comensales y │ │ Envío a │ │ Pago y │
│ Turno │ │ de Mesa │ │ Pedido │ │ Cocina │ │ Facturación │
└──────────────┘ └──────────────┘ └────────────────────┘ └────────────────┘ └──────────────────┘
Etapa 1 — Autenticación e Ingreso
| # | Acción del operador | Efecto en UI / Sistema | Regla de negocio |
|---|---|---|---|
| 1 | Navega a la URL del sistema en el navegador del terminal | Gate de clave aparece en pantalla completa sobre fondo gris claro | — |
| 2 | Escribe la clave de acceso en el campo y pulsa Enter o toca "Entrar" | SHA-256 de la clave se verifica en el cliente (sin enviar al servidor); si es correcta → localStorage wb_access = '1' y overlay desaparece | 5 intentos fallidos → bloqueo automático 60 s (M10). La clave nunca viaja en texto plano. |
| 3 | Tap en "Prototipo POS" en la pantalla de inicio | Carga prototipo_POS.html; pantalla de login de operador aparece | Sin wb_access = '1' el gate vuelve a mostrarse |
| 4 | Ingresa PIN de 4 dígitos asignado a su perfil | Sistema verifica PIN → state.operadorActivo asignado con nombre y rol | Solo operadores con rol "cajero" o "admin" pueden acceder; el PIN es por persona (M10) |
| 5 | Confirma apertura de turno (modal de inicio) | state.turnoAbierto = true; se registra hora de inicio del turno | El operador no puede procesar ventas sin turno abierto. El sistema verifica que no haya otro turno activo para ese terminal. |
| 6 | BottomNav aparece; pantalla principal cargada | Vista principal: catálogo de productos (centro) + ticket vacío (derecha) | — |
Etapa 2 — Apertura de Mesa
| # | Acción del operador | Efecto en UI / Sistema | Regla de negocio |
|---|---|---|---|
| 1 | Tap en tab "Mesas" del BottomNav | Se renderiza el mapa de mesas; mesas libres en verde, ocupadas en naranja/rojo | — |
| 2 | Tap en una mesa verde (libre) u ocupada | openMesa(id) ejecuta. Si libre → abre como nueva orden. Si ocupada → busca en orders[] la orden con ese mesaId y la activa directamente, mostrando solo los ítems de esa mesa | El sistema siempre carga la orden correcta de la mesa seleccionada — nunca muestra la orden de otra mesa. |
| 3 | Ajusta el número de comensales (pax) en el panel | Chips numerados [1] [2] [3]… se generan en la comensales-bar del ticket | Mínimo 1 pax; máximo según capacidad de la mesa |
| 4 | Si hay cliente WB → tap "Identificar" en comensales-bar | Modal de identificación muestra opciones: QR o correo electrónico | — |
| 5 | Escanea el QR del cliente o ingresa su correo | confirmClient() ejecuta → sistema busca cliente en base WB | El cliente debe tener cuenta activa en Welcomeback |
| 6 | Cliente confirmado | Comensal 1 recibe el primer nombre del cliente + badge naranja WB; state.comensalActivo = 1 se asigna automáticamente | Auto-asignación a Comensal 1 evita re-identificar al cliente en el flujo de pedido (M1, Solución 2) |
| 7 | Panel lateral se cierra | Vista orden activa: header muestra "Mesa X · Xm", comensales-bar con chip [Juan] en verde (activo) | — |
Etapa 3 — Gestión de Comensales y Pedido
| # | Acción del operador | Efecto en UI / Sistema | Regla de negocio |
|---|---|---|---|
| 1 | Comensales-bar visible con chips [Juan] [2] [3] (+) | Chip Juan en verde; el siguiente producto que se añada irá asignado a Juan | El chip activo determina el campo comensal en cada ítem del ticket |
| 2 | Tap en chip [Juan] (ya activo) | Chip se desactiva; toast "Asignando a todos los comensales" | Toggle: tap sobre chip activo lo desactiva. Sin comensal activo, los ítems quedan sin asignación de persona. |
| 3 | Tap en chip [2] | Chip 2 se activa en verde; toast "Asignando a Comensal 2" | Solo un chip puede estar activo a la vez; activar uno desactiva el anterior |
| 4 | Tap en un producto del catálogo (sin modificadores) | addDirectToTicket() → ítem aparece en el ticket con etiqueta "→ Comensal 2" | comensal: state.comensalActivo se hereda en cada ítem al momento de añadirlo |
| 5 | Tap en un producto que requiere modificadores | Modal de modificadores se abre mostrando grupos de opciones (ej: tamaño, leche, extras) | Los modificadores obligatorios deben seleccionarse antes de confirmar |
| 6 | Selecciona modificadores y toca "Confirmar" | Ítem aparece en ticket con resumen de mods y etiqueta de comensal; precio unitario calculado con todos los extras | qty × (precio_base + suma_extras) |
| 7 | Doble tap en un chip de comensal | Modal de edición abre; operador puede escribir el nombre del comensal (ej: "Pedro") | El nombre se guarda en MESAS_DATA[id].comensales[num].nombre |
| 8 | Tap en [+] en el header del ticket | addNewOrder() → nueva sub-cuenta (Cuenta 2) dentro de la misma mesa; header cambia a "Mesa X · Cuenta 2" | La cuenta anterior pasa a estado "progreso". Las cuentas comparten la misma mesa pero tienen tickets independientes. |
| 9 | Navega entre sub-cuentas (si existen) | activeOrderIdx cambia; el ticket muestra solo los ítems de la cuenta activa | Cada sub-cuenta puede tener su propio método de pago al momento de cobrar |
Etapa 4 — Envío a Cocina / Comanda
| # | Acción del operador | Efecto en UI / Sistema | Regla de negocio |
|---|---|---|---|
| 1 | Revisa el ticket en la columna derecha | Todos los ítems aparecen con comensal asignado (si aplica), modificadores y cantidades | — |
| 2 | Tap "Enviar a cocina" (botón en el ticket) | Sistema serializa state.ticket incluyendo asignaciones de comensales → datos enviados al KDS | Solo ítems en estado "pendiente" se envían; ítems ya en producción no se duplican |
| 3 | KDS recibe la comanda | Cards aparecen en el KDS de cocina ordenadas por tiempo de creación (más antiguo arriba); cada card muestra mesa, sub-orden y comensales | KDS ordena por tiempoTs ASC (M8). Las modificaciones urgentes pueden reordenarse manualmente. |
| 4 | Cocina prepara el pedido → tap "Listo" en la card del KDS | Card desaparece del KDS; sistema descuenta ingredientes del inventario según la receta del producto (M14) | La confirmación de "Listo" en KDS es el trigger del descuento de stock. Sin confirmación, el inventario no se actualiza. |
| 5 | Operador recibe indicación visual en el POS | Toast o badge en el ticket indicando que el ítem está listo para servir | — |
Etapa 5 — Pago y Facturación
| # | Acción del operador | Efecto en UI / Sistema | Regla de negocio |
|---|---|---|---|
| 1 | Tap "Cobrar" en el ticket | Modal de resumen de cobro se abre; muestra todos los ítems, subtotales por comensal (si aplica) y total de la cuenta | — |
| 2 | Sistema calcula los totales automáticamente | Desglose: Total Neto + IVA 19% + Total mostrado en el pie del resumen | Todos los productos (incluyendo bebidas alcohólicas) aplican solo IVA 19% según Art. 43 DL 825 para ventas al consumidor final. No se desglosa ILA en boleta. |
| 3 | Modal pregunta: "¿Desea agregar propina?" | Opciones: 10% / 15% / monto personalizado / Sin propina | La propina es voluntaria y no modifica la base imponible del IVA |
| 4 | Selecciona el método de pago | Opciones: Efectivo / Tarjeta (débito/crédito) / Transferencia / Pago dividido | — |
| 5 | Si Efectivo → ingresa el monto recibido del cliente | Sistema calcula el vuelto automáticamente y lo muestra | El monto recibido no puede ser menor al total a cobrar |
| 6 | Si Tarjeta → confirmar el pago | Integración con Transbank (fase futura); en el prototipo se confirma manualmente | — |
| 7 | Confirmar cobro (tap "Confirmar pago") | Sistema emite Boleta Electrónica Tipo 39 → DTE enviado al SII; folio consumido del CAF asignado al terminal | Boleta Tipo 39 para consumidor final sin RUT. Si el cliente solicita factura → Tipo 33 requiere e-RUT + glosa del giro (Res. Ex. 121 SII). |
| 8 | Ticket impreso o enviado por correo | Pie del ticket muestra: Total Neto | IVA (19%) | Total — sin desglose de impuesto adicional al alcohol | Formato de boleta cumple con Res. Ex. N°6 SII. El operador puede reenviar la boleta al correo del cliente WB si está identificado. |
| 9 | QR Fintoc aparece en el pie del ticket (alternativa de pago) | Cliente puede escanear el QR con su app bancaria para pago inmediato por transferencia | Fintoc actúa como iniciador de pago (PIS); el monto es exacto al total de la boleta |
- Gate de acceso: 5 intentos fallidos → bloqueo 60 s; la clave nunca viaja en texto plano (M10)
- PIN de operador: solo roles "cajero" y "admin" pueden abrir turno (M10)
- Cliente WB identificado → siempre se asigna automáticamente como Comensal 1 si hay mesa activa (M1)
- El chip de comensal activo determina la asignación de todos los productos añadidos hasta que se cambie o desactive
- Las sub-cuentas (
[+]) pertenecen a la misma mesa y pueden pagarse por separado - El descuento de stock ocurre en KDS al marcar "Listo", no al tomar el pedido (M8 + M14)
- IVA 19% único para todos los productos, incluyendo alcoholes (Art. 43 DL 825 — el ILA lo liquida el distribuidor, no el local)
- Boleta Tipo 39: consumidor final sin RUT · Factura Tipo 33: requiere e-RUT + glosa (Res. Ex. 121 SII)
Roadmap de producto
Objetivo: V1 vendible el 24 de julio de 2026.
El roadmap no es lineal de menos a más — es de adentro hacia afuera: primero conectar lo que ya existe, luego profundizar en la operación.
El tótem y el móvil ya pedían y pagaban — ahora el POS propio une todos los canales en un KDS propio. Datos propios, fidelización unificada, sin depender de terceros para saber qué se está produciendo.
El local ya opera en todos los canales. Ahora toca control total de la operación: mesas, inventario real, liquidaciones y delivery externo integrado al mismo KDS propio.
El tótem y el móvil ya existen y ya venden. En V3 se vuelven más inteligentes: usan los datos reales del KDS y el inventario para mejorar la experiencia del cliente en tiempo real.
De herramienta a plataforma. Cadenas con varios locales, inteligencia de negocio avanzada y apertura a integradores.
¿Cuándo puedo vender a cada tipo de cliente?
Canal = cómo pide y paga el cliente. Tótem y Mobile ya existen en Welcomeback — en V1.3 se conectan al KDS propio. El POS de mostrador es la pieza nueva.
| Momento de atención | Disponible en | Requisitos mínimos | Estado |
|---|---|---|---|
|
🏃 Quick Service
Cafetería, barra, comida rápida
|
V1.3 | Grid, cobro, boleta SII, ticket barra, KDS, caja | ✅ Listo (prototipo) |
|
🪑 Mesas
Restaurante con servicio en mesa
|
V2.1 | Multi-orden por mesa, mapa canvas, gestión de turno por mesa | 🔨 En desarrollo V2 |
|
📱 Mobile Orders
El cliente pide y paga desde su móvil
Ya existe en Welcomeback
|
V1.3 | Conectar al KDS propio — las órdenes llegan con badge "móvil" a la misma pantalla de cocina | ✅ Canal existente — integrar KDS |
|
🔲 Tótem
Kiosco de autoatención sin cajero
Ya existe en Welcomeback
|
V1.3 | Conectar al KDS propio — las órdenes del tótem aparecen en la misma pantalla que las del mostrador | ✅ Canal existente — integrar KDS |
|
🛵 Delivery
Rappi, Uber Eats, PedidosYa
|
V2.4 | Integración API plataformas, orden automática al KDS, gestión de estado | 🔨 En desarrollo V2 |
M18 — Dashboard de Reportes (dashboard.welcomeback.io/reportes)
El módulo de reportes convierte las transacciones del POS en inteligencia accionable para el dueño. Accesible desde dashboard.welcomeback.io/reportes, diseñado mobile-first, y estructurado por fases de implementación.
Filosofía del Módulo
Cada reporte responde "¿qué hago con esto?" y ofrece una acción clara.
El dueño revisa desde el celular entre clientes. Diseño responsive obligatorio.
Los reportes de Guest Engagement convierten data de transacciones en acciones de retención — algo que ningún competidor tiene.
Reportes por Fase de Implementación
📦 FASE 1 (MVP) — Reportes Esenciales
Los reportes de Fase 1 responden las 3 preguntas que un dueño hace todos los días: ¿Cuánto vendí? ¿Están todas las boletas en orden con el SII? ¿Cómo cobraron los pagos?
| Reporte | Qué muestra | Acción principal |
|---|---|---|
| Overview Dashboard | Métricas del día: ventas totales, # transacciones, ticket promedio, top 5 productos, gráfico por hora | Selector de rango de fechas, exportar PDF, banner de alertas críticas (DTE pendientes, caja descuadrada) |
| Sales Summary | Tabla de ventas por día (fecha, # transacciones, total $, ticket promedio) + gráfico de tendencia | Filtros por fecha/cajero/método, exportar Excel/CSV, ordenar por columna |
| Product Mix | Distribución de ventas por categoría (gráfico pie/donut + tabla) | Click en segmento filtra tabla, exportar PDF |
| Payment Methods Breakdown | Desglose de métodos de pago (Efectivo, Débito, Crédito, Mixto) + promedio ticket por método | Filtro por fecha, exportar Excel |
| DTE History | Historial de boletas emitidas (Folio, Fecha, Cliente, Monto, Tipo 39/61, Estado con colores) | Búsqueda por folio/RUT, ver XML, descargar PDF, exportar selección múltiple (ZIP) |
| SII Sync Status | Estado de sincronización con SII: último sync, DTEs pendientes, DTEs con error + log de últimos 10 syncs | Botón "Sincronizar ahora" manual, botón "Reenviar" para DTEs con error, notificación si >10 pendientes |
| Monthly DTE Export | Exportación masiva de DTEs por mes para contabilidad (selector mes/año, resumen total) | Exportar XML (ZIP con estructura {mes}_{año}/DTE_{folio}.xml), exportar Excel con detalle |
| Export Templates (Settings) | Configuración de formatos de exportación predeterminados | Incluir logo en PDFs, formato de fecha, incluir gráficos en Excel, preview antes de exportar |
Dashboard Overview debe cargar en menos de 3 segundos. Actualización automática cada 5 minutos para sync SII.
🚀 FASE 2 — Reportes Avanzados + Guest Engagement ⭐
Los reportes de Fase 2 responden: ¿Qué productos funcionan y cuáles no? ¿Mis clientes vuelven o se van? ¿Mi caja está cuadrada?
Sales Reports Avanzados
| Reporte | Qué muestra | Acción principal |
|---|---|---|
| Hourly Sales | Ventas por hora (gráfico barras 00:00-23:00) + heatmap semanal (días vs horas) | Identificación automática de "peak hours" (top 3), comparar semana actual vs anterior, exportar heatmap PNG |
| Day Part Analysis | Ventas por segmento del día configurable (Desayuno 7-11, Almuerzo 11-16, Once 16-19, Cena 19-22) | Sugerencias automáticas (ej: "Cena genera solo 8% — considera horario extendido"), comparar con mes anterior |
| Sales by Cashier | Ranking de cajeros: # transacciones, total $, ticket promedio, hora más productiva. Badge "Top performer" | Solo admin/dueño ven este reporte (privacidad), comparar vs promedio del local, exportar PDF |
Menu Analysis
| Reporte | Qué muestra | Acción principal |
|---|---|---|
| Top Products | Top 20 productos más vendidos con tendencia (↑↓ vs periodo anterior) | Click abre "Product Performance Detail", exportar top N (10/20/50) |
| Product Performance Detail | Vista detallada de producto: ventas en tiempo, margen de contribución, horarios populares, modificadores más usados, productos comprados junto con este | Sugerencia automática si tendencia a la baja, comparar con benchmark de categoría |
| Modifier Analysis | Uso de modificadores: # veces usado, $ extra generado, tasa de attach (%) | Calcular "missed revenue" si modificadores se usaran más, sugerencias de modificadores a promover |
| Category Mix | Distribución de ventas por categoría (versión avanzada con tendencia mensual y benchmark recomendado) | Comparar con benchmark de tipo de local (ej: cafeterías = 60% bebidas, 30% comida, 10% retail) |
| Low Performers | Productos con <5 ventas en 30 días, % de productos "muertos" en la carta | Recomendación: "Considera eliminar estos productos", marcar para "revisar", excluir productos de temporada |
Cash and Loss Management
| Reporte | Qué muestra | Acción principal |
|---|---|---|
| Cash Drawer Variance | Diferencia efectivo esperado vs real, gráfico de diferencias en el tiempo, acumulado por cajero | Alerta si diferencia >$10.000, agregar "razón" de diferencia, exportar Excel |
| Voids & Refunds | Items cancelados + notas de crédito, total $ perdido, % de órdenes con void | Obligar selección de razón al hacer void, alerta si cajero >10% voids vs promedio |
| Discount Usage | Descuentos aplicados: tipo, # veces usado, $ descontado, aplicado por cajero | Alerta si cajero usa descuentos >2× más que promedio, filtrar por tipo |
| Over/Short Report | Consolidado mensual de sobrantes/faltantes por cajero + política de tolerancia | Benchmark: QSR estándar = <0.5% de ventas, highlight cajeros fuera de política |
⭐ Guest Engagement — DIFERENCIADOR WELCOMEBACK
Esta es la ventaja competitiva. Ningún POS del mercado chileno tiene inteligencia de recurrencia nativa. Todos tratan cada transacción como si fuera nueva. Welcomeback POS sabe quién vuelve, quién se fue, y cuándo actuar.
| Reporte | Qué muestra | Acción principal |
|---|---|---|
| Recurrence Rate | % de clientes que volvieron en 7/14/30 días + gráfico de evolución + cohort analysis | Benchmark QSR = 20-35%, alerta si cae >5% mes a mes, exportar cohort analysis Excel |
| Visit Frequency Distribution | Distribución de clientes: 1 visita, 2-5 visitas, 6-10 visitas, 11+ visitas (últimos 30/90 días) | Objetivo: mover clientes de "1 visita" a "2-5 visitas", click en segmento → lista de clientes |
| Churn Alerts | Clientes "en riesgo": visitaban regularmente, llevan X días sin venir. Priorizado por CLV | Acción sugerida: "Enviar cupón de bienvenida", integración con módulo de campañas, marcar como "contactado" |
| AI Recommendations ⭐ | Motor de IA: "Hoy deberías contactar a estos clientes" (top 5-10) + razón + template de mensaje | Click → abre WhatsApp con mensaje pre-llenado, tracking efectividad (% que volvieron), medir ROI |
| Campaign Performance | ROI de campañas de retención lanzadas: # contactados, tasa apertura, tasa retorno, $ generado | Mejores días/horarios para enviar, comparar campañas, sugerencias de optimización |
Mínimo 90 días de operación para entrenar el modelo de IA. Integración con Welcomeback API para identificación de clientes.
Labor Management
| Reporte | Qué muestra | Acción principal |
|---|---|---|
| Labor Summary | Labor cost % (costo personal / ventas), target range 25-30% para QSR, proyección mensual | Alerta si supera 35%, comparar con benchmark, integración con sistema de marcaje |
| Time & Attendance | Registro entrada/salida personal, retrasos, horas extra acumuladas | Exportar a nómina, integración con sistema de pago |
| Labor Cost % Tracker | Seguimiento diario/semanal de labor cost %, días donde se superó target | Simulador: "Si reduces 2 horas diarias, ahorras $XXX al mes", sugerencia de ajuste de turnos |
🔮 FASE 3 — Benchmarking + Kitchen Operations
Los reportes de Fase 3 responden: ¿Cómo me comparo con locales similares? ¿Mi cocina es eficiente?
Benchmarking (Diferenciador Competitivo)
| Reporte | Qué muestra | Acción principal |
|---|---|---|
| Benchmarking Overview | Comparación anónima vs promedio de locales similares: ticket promedio, recurrence rate, top 3 productos | Gráfico de radar (6 dimensiones), métrica de posición ("Estás en el top 25%"), data anonimizada (opt-in) |
| Menu Insights | Productos populares en locales similares que este local no tiene + estimación $ potencial | Click → formulario para agregar a carta, tracking de performance si se agrega |
| Service Insights | Comparación de tiempos de atención vs benchmark (transacción, preparación KDS, horas peak) | Sugerencias de mejora si estás por debajo del promedio |
Kitchen Operations (Requiere KDS de Fase 2)
| Reporte | Qué muestra | Acción principal |
|---|---|---|
| Ticket Times | Tiempo desde orden confirmada hasta "Lista" en KDS, promedio por producto, histograma distribución | Target configurable (cafetería 3-5 min, comida rápida 2-3 min), identificar productos "lentos" |
| Order Accuracy | % de órdenes sin reclamos/devoluciones (target: >98%), desglose razones de error, costo órdenes rehechas | Integración con sistema de voids/refunds, marcar razón al hacer refund |
| Peak Hour Efficiency | Performance durante horas peak: comparación ticket times peak vs non-peak | Sugerencia de staffing: "Considera +1 barista en peak" (basado en data) |
Diferenciadores vs Competencia
| Feature | Toast | Toteat | Bsale | Welcomeback POS |
|---|---|---|---|---|
| Overview dashboard | ✓ | ✓ | ✓ | ✓ |
| Sales reports básicos | ✓ | ✓ | ✓ | ✓ |
| DTE/SII reports | N/A | Básico | ✓ | ✓ Avanzado + sync status |
| Menu analysis | ✓ | Parcial | No | ✓ + modifier analysis |
| Guest engagement reports | Básico | No | No | ⭐ IA nativa de recurrencia |
| Churn alerts | No | No | No | ⭐ "Juan lleva 16 días sin venir" |
| AI recommendations | No | No | No | ⭐ "Contacta estos 5 hoy" |
| Benchmarking anónimo | No | No | No | ⭐ Comparación con similares |
| Kitchen operations | ✓ | ✓ (KDS) | No | ✓ Fase 3 |
| Labor management | ✓ | Parcial | No | ✓ Fase 2 |
| Mobile-first design | Parcial | No | No | ✓ Diseñado para celular |
Requisitos Técnicos
| Aspecto | Especificación |
|---|---|
| URL | dashboard.welcomeback.io/reportes (subdomain dedicado) |
| Autenticación | JWT + refresh token, sesión compartida con POS |
| Performance | Dashboard Overview <3s, reportes complejos <5s |
| Responsive | Mobile-first (iPhone 12/13/14), tablet, desktop |
| Exportaciones | PDF (con logo), Excel (con gráficos opcionales), CSV |
| Gráficos | Recharts o Chart.js, interactivos (hover, click) |
| Actualización | Datos en tiempo real (WebSocket) para ventas del día, resto cached 5 min |
| Permisos | Roles: Dueño (ve todo), Admin (ve todo excepto benchmarking), Cajero (solo sus ventas) |
| Offline | No requerido (dashboard solo online) |
| Integraciones | Welcomeback API (guest engagement), SII (DTE status), Transbank (settlements) |
Métricas de Éxito
| Fase | Métrica | Target |
|---|---|---|
| Fase 1 (MVP) | Dueños que acceden al dashboard ≥1× por semana | ≥80% |
| Tiempo promedio de carga de Overview | <3 segundos | |
| Exportaciones de DTE mes a mes | ≥90% de locales | |
| NPS del dashboard (Fase 1) | ≥60 | |
| Fase 2 | Dueños que usan Churn Alerts ≥1× por semana | ≥50% |
| Clientes contactados vía AI Recommendations que vuelven | ≥25% | |
| Locales que activan campañas de retención | ≥60% | |
| ROI promedio de campañas ($ generado / $ invertido) | ≥3× | |
| Fase 3 | Locales que opt-in a benchmarking | ≥70% |
| Productos agregados desde "Menu Insights" | ≥0.5 por local/mes | |
| Mejora de ticket times después de ver Kitchen reports | ≥10% |
Roadmap de Implementación
Overview Dashboard · Sales Summary + Product Mix + Payment Methods · DTE History + SII Sync Status + Monthly Export · Export Templates (Settings)
Reportes avanzados de Sales (Hourly, Day Part, By Cashier) · Menu analysis completo (Top Products → Low Performers) · Cash and Loss Management completo · Guest Engagement completo ⭐ (Recurrence → Campaign Performance) · Labor Summary + Time & Attendance
Benchmarking completo (Overview → Service Insights) · Kitchen Operations completo (requiere KDS de Fase 2) · Labor Cost % Tracker avanzado
Dependencias Técnicas
| Reporte | Dependencia |
|---|---|
| Guest Engagement (todos) | Welcomeback API funcionando + mínimo 90 días de data |
| Kitchen Operations (todos) | Módulo KDS implementado (Fase 2) |
| Labor reports (todos) | Sistema de marcaje/reloj control implementado |
| Benchmarking | Mínimo 50 locales activos opt-in |
| AI Recommendations | Modelo de IA entrenado con data del local (90+ días) |