Tul xxx Tul
User / IP
:
216.73.216.217
Host / Server
:
45.84.207.204 / aircan.me
System
:
Linux lt-bnk-web1726.main-hosting.eu 5.14.0-611.36.1.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Mar 3 11:23:52 EST 2026 x86_64
Command
|
Upload
|
Create
Mass Deface
|
Jumping
|
Symlink
|
Reverse Shell
Ping
|
Port Scan
|
DNS Lookup
|
Whois
|
Header
|
cURL
:
/
home
/
u931257429
/
domains
/
aircan.me
/
public_html
/
piscina
/
app
/
models
/
Viewing: Restaurante.php
<?php namespace App\Models; require_once dirname(__DIR__, 2) . '/config/database.php'; use mysqli; class Restaurante { private const DEFAULT_CATEGORIES = []; public static function productos(): array { $conn = self::connection(); $sql = 'SELECT id, nombre, categoria, precio, stock, COALESCE(imagen, "img/producto-default.jpg") AS imagen FROM productos ORDER BY nombre'; $resultado = $conn->query($sql); if (!$resultado) { return []; } $productos = []; while ($row = $resultado->fetch_assoc()) { $productos[] = self::mapProducto($row); } return $productos; } public static function productosPorCategoria(?string $categoria = null): array { if ($categoria === null || $categoria === 'Todos') { return self::productos(); } $conn = self::connection(); $sql = 'SELECT id, nombre, categoria, precio, stock, COALESCE(imagen, "img/producto-default.jpg") AS imagen FROM productos WHERE categoria = ? ORDER BY nombre'; $stmt = $conn->prepare($sql); $stmt->bind_param('s', $categoria); $stmt->execute(); $resultado = $stmt->get_result(); if (!$resultado) { return []; } $productos = []; while ($row = $resultado->fetch_assoc()) { $productos[] = self::mapProducto($row); } return $productos; } public static function categorias(): array { $conn = self::connection(); $resultado = $conn->query('SELECT DISTINCT categoria FROM productos WHERE categoria IS NOT NULL AND categoria <> "" ORDER BY categoria'); $categorias = self::DEFAULT_CATEGORIES; if ($resultado) { while ($row = $resultado->fetch_assoc()) { $categorias[] = $row['categoria']; } } $categorias = array_values(array_unique($categorias)); sort($categorias, SORT_NATURAL | SORT_FLAG_CASE); return $categorias; } public static function findProducto(int $id): ?array { $conn = self::connection(); $sql = 'SELECT id, nombre, categoria, precio, stock, COALESCE(imagen, "img/producto-default.jpg") AS imagen FROM productos WHERE id = ? LIMIT 1'; $stmt = $conn->prepare($sql); $stmt->bind_param('i', $id); $stmt->execute(); $resultado = $stmt->get_result()->fetch_assoc(); return $resultado ? self::mapProducto($resultado) : null; } public static function crearProducto(array $data): array { $conn = self::connection(); $sql = 'INSERT INTO productos (nombre, categoria, precio, stock, imagen) VALUES (?, ?, ?, ?, ?)'; $imagen = $data['imagen'] ?? 'img/producto-default.jpg'; $stmt = $conn->prepare($sql); $nombre = $data['nombre']; $categoria = $data['categoria'] ?? null; $precio = (float) $data['precio']; $stock = (int) $data['stock']; $stmt->bind_param('ssdis', $nombre, $categoria, $precio, $stock, $imagen); $stmt->execute(); $id = $stmt->insert_id; return self::findProducto($id) ?? []; } public static function actualizarProducto(int $id, array $data): bool { $producto = self::findProducto($id); if (!$producto) { return false; } $conn = self::connection(); $sql = 'UPDATE productos SET nombre = ?, categoria = ?, precio = ?, stock = ?, imagen = ? WHERE id = ?'; $stmt = $conn->prepare($sql); $nombre = $data['nombre']; $categoria = $data['categoria'] ?? null; $precio = (float) $data['precio']; $stock = (int) $data['stock']; $imagen = $data['imagen'] ?? $producto['imagen']; $stmt->bind_param('ssdisi', $nombre, $categoria, $precio, $stock, $imagen, $id); $stmt->execute(); return $stmt->affected_rows >= 0; } public static function eliminarProducto(int $id): bool { $conn = self::connection(); $stmt = $conn->prepare('DELETE FROM productos WHERE id = ?'); $stmt->bind_param('i', $id); $stmt->execute(); return $stmt->affected_rows > 0; } public static function stockDisponible(int $id, int $cantidad): bool { $conn = self::connection(); $stmt = $conn->prepare('SELECT stock FROM productos WHERE id = ?'); $stmt->bind_param('i', $id); $stmt->execute(); $resultado = $stmt->get_result()->fetch_assoc(); if (!$resultado) { return false; } return (int) $resultado['stock'] >= $cantidad; } public static function ventasDelDia(?string $fecha = null): array { if (!ini_get('date.timezone')) { date_default_timezone_set('America/Bogota'); } $conn = self::connection(); if ($fecha === null) { $sql = 'SELECT v.id, v.cliente_id, v.fecha, v.total, c.nombre AS cliente_nombre, c.apellido AS cliente_apellido FROM ventas v LEFT JOIN clientes c ON c.id = v.cliente_id WHERE DATE(v.fecha) = CURDATE() ORDER BY v.fecha DESC'; $stmt = $conn->prepare($sql); } else { $sql = 'SELECT v.id, v.cliente_id, v.fecha, v.total, c.nombre AS cliente_nombre, c.apellido AS cliente_apellido FROM ventas v LEFT JOIN clientes c ON c.id = v.cliente_id WHERE DATE(v.fecha) = ? ORDER BY v.fecha DESC'; $stmt = $conn->prepare($sql); $stmt->bind_param('s', $fecha); } $stmt->execute(); $resultado = $stmt->get_result(); if (!$resultado) { return []; } $ventas = []; while ($row = $resultado->fetch_assoc()) { $venta = self::mapVentaResumen($row); $venta['numero_ticket'] = self::numeroTicketDiario($row['fecha']); $ventas[] = $venta; } return $ventas; } public static function resumenDiario(?string $fecha = null): array { $ventas = self::ventasDelDia($fecha); $total = array_sum(array_map(fn ($venta) => $venta['total'], $ventas)); $tickets = count($ventas); $promedio = $tickets > 0 ? $total / $tickets : 0.0; return [ 'total' => $total, 'tickets' => $tickets, 'promedio' => $promedio, ]; } public static function ventasHistoricas(?string $desde = null, ?string $hasta = null): array { $conn = self::connection(); $sql = 'SELECT v.id, v.cliente_id, v.fecha, v.total, c.nombre AS cliente_nombre, c.apellido AS cliente_apellido FROM ventas v LEFT JOIN clientes c ON c.id = v.cliente_id WHERE DATE(v.fecha) < CURDATE()'; $params = []; $types = ''; if ($desde !== null) { $sql .= ' AND DATE(v.fecha) >= ?'; $types .= 's'; $params[] = $desde; } if ($hasta !== null) { $sql .= ' AND DATE(v.fecha) <= ?'; $types .= 's'; $params[] = $hasta; } $sql .= ' ORDER BY v.fecha DESC'; $stmt = $conn->prepare($sql); if (!$stmt) { return []; } if (!empty($params)) { $stmt->bind_param($types, ...$params); } $stmt->execute(); $resultado = $stmt->get_result(); if (!$resultado) { return []; } $ventas = []; while ($row = $resultado->fetch_assoc()) { $ventas[] = self::mapVentaResumen($row); } return $ventas; } public static function resumenHistorico(?string $desde = null, ?string $hasta = null): array { $ventas = self::ventasHistoricas($desde, $hasta); $total = array_sum(array_map(fn ($venta) => $venta['total'], $ventas)); $tickets = count($ventas); $promedio = $tickets > 0 ? $total / $tickets : 0.0; return [ 'total' => $total, 'tickets' => $tickets, 'promedio' => $promedio, ]; } public static function findVenta(int $id): ?array { $conn = self::connection(); $sql = 'SELECT v.id, v.cliente_id, v.fecha, v.total, c.nombre AS cliente_nombre, c.apellido AS cliente_apellido FROM ventas v LEFT JOIN clientes c ON c.id = v.cliente_id WHERE v.id = ? LIMIT 1'; $stmt = $conn->prepare($sql); $stmt->bind_param('i', $id); $stmt->execute(); $ventaRow = $stmt->get_result()->fetch_assoc(); if (!$ventaRow) { return null; } $detalleSql = 'SELECT vd.producto_id, vd.cantidad, vd.subtotal, p.nombre AS producto_nombre FROM venta_detalle vd INNER JOIN productos p ON p.id = vd.producto_id WHERE vd.venta_id = ?'; $stmtDetalle = $conn->prepare($detalleSql); $stmtDetalle->bind_param('i', $id); $stmtDetalle->execute(); $detalleResultado = $stmtDetalle->get_result(); $productos = []; if ($detalleResultado) { while ($row = $detalleResultado->fetch_assoc()) { $cantidad = (int) $row['cantidad']; $subtotal = (float) $row['subtotal']; $precio = $cantidad > 0 ? $subtotal / $cantidad : 0.0; $productos[] = [ 'producto_id' => (int) $row['producto_id'], 'nombre' => $row['producto_nombre'], 'cantidad' => $cantidad, 'precio' => $precio, 'subtotal' => $subtotal, ]; } } $venta = self::mapVentaResumen($ventaRow); $venta['numero_ticket'] = self::numeroTicketDiario($ventaRow['fecha']); $venta['productos'] = $productos; return $venta; } public static function registrarVenta(array $data): array { $clienteId = isset($data['cliente_id']) ? (int) $data['cliente_id'] : 0; if ($clienteId <= 0) { throw new \InvalidArgumentException('Selecciona un cliente válido.'); } $items = $data['items'] ?? []; if (empty($items)) { throw new \InvalidArgumentException('Registra al menos un producto.'); } $conn = self::connection(); $conn->begin_transaction(); try { $detalles = []; $total = 0.0; foreach ($items as $item) { $productoId = (int) ($item['id'] ?? 0); $cantidad = (int) ($item['cantidad'] ?? 0); if ($productoId <= 0 || $cantidad <= 0) { throw new \InvalidArgumentException('Producto o cantidad inválidos.'); } $stmtProducto = $conn->prepare('SELECT id, nombre, precio, stock FROM productos WHERE id = ? FOR UPDATE'); $stmtProducto->bind_param('i', $productoId); $stmtProducto->execute(); $producto = $stmtProducto->get_result()->fetch_assoc(); $stmtProducto->close(); if (!$producto) { throw new \RuntimeException('Producto no encontrado.'); } if ((int) $producto['stock'] < $cantidad) { throw new \RuntimeException('Stock insuficiente para ' . $producto['nombre']); } $nuevoStock = (int) $producto['stock'] - $cantidad; $stmtUpdate = $conn->prepare('UPDATE productos SET stock = ? WHERE id = ?'); $stmtUpdate->bind_param('ii', $nuevoStock, $productoId); $stmtUpdate->execute(); $stmtUpdate->close(); $subtotal = (float) $producto['precio'] * $cantidad; $detalles[] = [ 'producto_id' => $productoId, 'nombre' => $producto['nombre'], 'cantidad' => $cantidad, 'precio' => (float) $producto['precio'], 'subtotal' => $subtotal, ]; $total += $subtotal; } $stmtVenta = $conn->prepare('INSERT INTO ventas (cliente_id, fecha, total) VALUES (?, NOW(), ?)'); $stmtVenta->bind_param('id', $clienteId, $total); $stmtVenta->execute(); $ventaId = $stmtVenta->insert_id; $stmtVenta->close(); $stmtDetalle = $conn->prepare('INSERT INTO venta_detalle (venta_id, producto_id, cantidad, subtotal) VALUES (?, ?, ?, ?)'); foreach ($detalles as $detalle) { $stmtDetalle->bind_param('iiid', $ventaId, $detalle['producto_id'], $detalle['cantidad'], $detalle['subtotal']); $stmtDetalle->execute(); } $stmtDetalle->close(); $conn->commit(); $venta = self::findVenta($ventaId); if (!$venta) { throw new \RuntimeException('No fue posible recuperar la venta registrada.'); } $cliente = Cliente::find($clienteId); $clienteNombre = $cliente ? trim(($cliente['nombre'] ?? '') . ' ' . ($cliente['apellido'] ?? '')) : 'Cliente #' . $clienteId; Caja::registrarCobro([ 'origen' => 'Restaurante', 'cliente' => $clienteNombre, 'concepto' => 'Venta restaurante #' . $venta['id'], 'monto' => $total, 'metodo' => 'Efectivo', 'fecha' => $venta['fecha'], 'hora' => $venta['hora'], ]); Cliente::agregarHistorial($clienteId, [ 'fecha' => $venta['fecha'], 'concepto' => 'Consumo en restaurante', 'monto' => $total, ]); return $venta; } catch (\Throwable $e) { $conn->rollBack(); throw $e; } } public static function eliminarVenta(int $id): bool { $conn = self::connection(); $conn->begin_transaction(); try { $stmtDetalle = $conn->prepare('SELECT producto_id, cantidad FROM venta_detalle WHERE venta_id = ?'); $stmtDetalle->bind_param('i', $id); $stmtDetalle->execute(); $resultadoDetalle = $stmtDetalle->get_result(); $detalles = $resultadoDetalle ? $resultadoDetalle->fetch_all(MYSQLI_ASSOC) : []; $stmtDetalle->close(); foreach ($detalles as $detalle) { $productoId = (int) ($detalle['producto_id'] ?? 0); $cantidad = (int) ($detalle['cantidad'] ?? 0); if ($productoId > 0 && $cantidad > 0) { $stmtUpdate = $conn->prepare('UPDATE productos SET stock = stock + ? WHERE id = ?'); $stmtUpdate->bind_param('ii', $cantidad, $productoId); $stmtUpdate->execute(); $stmtUpdate->close(); } } $stmtDeleteDetalle = $conn->prepare('DELETE FROM venta_detalle WHERE venta_id = ?'); $stmtDeleteDetalle->bind_param('i', $id); $stmtDeleteDetalle->execute(); $stmtDeleteDetalle->close(); $stmtDeleteVenta = $conn->prepare('DELETE FROM ventas WHERE id = ?'); $stmtDeleteVenta->bind_param('i', $id); $stmtDeleteVenta->execute(); $eliminada = $stmtDeleteVenta->affected_rows > 0; $stmtDeleteVenta->close(); $conn->commit(); return $eliminada; } catch (\Throwable $e) { $conn->rollBack(); return false; } } public static function estadoStock(array $producto): string { if ((int) $producto['stock'] <= 0) { return 'agotado'; } return (int) $producto['stock'] < 10 ? 'bajo' : 'suficiente'; } private static function mapProducto(array $row): array { return [ 'id' => (int) $row['id'], 'nombre' => $row['nombre'], 'categoria' => $row['categoria'] ?? 'Otros', 'precio' => (float) $row['precio'], 'stock' => (int) $row['stock'], 'imagen' => $row['imagen'] ?? 'img/producto-default.jpg', ]; } private static function mapVentaResumen(array $row): array { $fecha = new \DateTime($row['fecha']); $clienteNombre = trim(($row['cliente_nombre'] ?? '') . ' ' . ($row['cliente_apellido'] ?? '')); if ($clienteNombre === '') { $clienteNombre = 'Cliente #' . $row['cliente_id']; } return [ 'id' => (int) $row['id'], 'cliente_id' => $row['cliente_id'] ? (int) $row['cliente_id'] : null, 'cliente' => $clienteNombre, 'fecha' => $fecha->format('Y-m-d'), 'hora' => $fecha->format('h:i A'), 'total' => (float) $row['total'], 'numero_ticket' => null, ]; } private static function numeroTicketDiario(string $fechaHora): int { $conn = self::connection(); $sql = 'SELECT COUNT(*) AS total FROM ventas WHERE DATE(fecha) = DATE(?) AND fecha <= ?'; $stmt = $conn->prepare($sql); $stmt->bind_param('ss', $fechaHora, $fechaHora); $stmt->execute(); $resultado = $stmt->get_result()->fetch_assoc(); return (int) ($resultado['total'] ?? 0); } private static function connection(): mysqli { static $conn = null; if ($conn instanceof mysqli) { return $conn; } $db = new \Database(); $conn = $db->getConnection(); return $conn; } }
Coded With 💗 by
0x6ick