= htmlspecialchars((string)$product['name']) ?>
= htmlspecialchars((string)$product['unit_label']) ?> · = htmlspecialchars((string)$stock) ?> en stock
$_meta) { $groupedProducts[$category] = []; } foreach ($products as $product) { $groupedProducts[$product['category']][] = $product; } $groupedProducts = array_filter($groupedProducts, static fn (array $items): bool => $items !== []); $cartSummary = pos_cart_summary(); $recentSales = pos_recent_sales(8); $metrics = pos_today_metrics(); $lowStockCount = pos_low_stock_count(); $lowStockProducts = pos_low_stock_products(6); $cssVersion = file_exists(__DIR__ . '/assets/css/custom.css') ? (string)filemtime(__DIR__ . '/assets/css/custom.css') : (string)time(); $jsVersion = file_exists(__DIR__ . '/assets/js/main.js') ? (string)filemtime(__DIR__ . '/assets/js/main.js') : (string)time(); $flashClassMap = [ 'success' => 'text-bg-success', 'danger' => 'text-bg-danger', 'warning' => 'text-bg-warning', 'secondary' => 'text-bg-secondary', 'info' => 'text-bg-primary', ]; $toLower = static function (string $value): string { if (function_exists('mb_strtolower')) { return mb_strtolower($value, 'UTF-8'); } return strtolower($value); }; ?>
Catálogo por categorías, canasta siempre visible, recibos claros y alertas de stock bajo. Este primer MVP está listo para conectar con NestJS más adelante sin cambiar la experiencia de caja.
Elige una categoría con botones grandes y visibles.
Presiona “Agregar” una sola vez para llevarlo a la canasta.
Registra la venta y genera un recibo simple al instante.
Usa un código corto y un PIN de cuatro dígitos. Esto es ideal para una caja con operadores frecuentes.
Ajusta stock y supervisa alertas críticas.
Vende rápido sin entrar a pantallas complejas.
Consulta la venta al detalle con un clic.
Usa el flujo corto: categoría, agregar a canasta y confirmar venta. Todo lo esencial está visible en la misma pantalla.
Esto ayuda a evitar ventas fallidas y a reponer inventario a tiempo.
Filtros grandes, categorías claras y botones de acción directos.
= htmlspecialchars($meta['description']) ?>
= htmlspecialchars((string)$product['unit_label']) ?> · = htmlspecialchars((string)$stock) ?> en stock
Prueba otra categoría o borra la búsqueda.
Cada venta queda guardada con total, fecha y enlace al recibo.
Cuando confirmes una venta aparecerá aquí automáticamente.
| Recibo | Fecha | Cajero | Items | Total | |
|---|---|---|---|---|---|
|
= htmlspecialchars((string)$sale['receipt_number']) ?>
= htmlspecialchars((string)$sale['cashier_role']) ?>
|
= htmlspecialchars(pos_format_datetime((string)$sale['created_at'])) ?> | = htmlspecialchars((string)$sale['cashier_name']) ?> | = htmlspecialchars((string)$sale['item_count']) ?> | = htmlspecialchars(pos_format_money((float)$sale['total'])) ?> | Ver detalle |
Ajusta inventario con botones directos y alertas visibles cuando la cantidad sea crítica.
| Producto | Categoría | Stock actual | Umbral | Acciones |
|---|---|---|---|---|
| = htmlspecialchars((string)$product['name']) ?> | = htmlspecialchars((string)$product['category']) ?> | = htmlspecialchars((string)$product['stock']) ?> Bajo | = htmlspecialchars((string)$product['low_stock_threshold']) ?> |
|
Como cajero puedes ver qué productos están por acabarse para pedir reposición.
No hay alertas activas por ahora.