40362-vm/includes/store.php
2026-06-30 17:47:46 +00:00

163 lines
8.0 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/../db/config.php';
function h(string $value): string {
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}
function store_logo_path(): string {
return 'assets/pasted-20260630-162052-2e0489d8.png';
}
function store_products(): array {
return [
'combo-24' => [
'id' => 'combo-24',
'name' => 'Combo Mercado 24',
'price' => 24.99,
'stock' => 18,
'category' => 'Supermarket',
'description' => 'Selección esencial para compras rápidas: snacks, bebidas y básicos del día.',
],
'tech-charge' => [
'id' => 'tech-charge',
'name' => 'Carga Tecnológica',
'price' => 39.00,
'stock' => 12,
'category' => 'Tecnología',
'description' => 'Kit tecnológico con cable premium, cargador rápido y soporte compacto.',
],
'fresh-box' => [
'id' => 'fresh-box',
'name' => 'Fresh Box Familiar',
'price' => 54.50,
'stock' => 9,
'category' => 'Despensa',
'description' => 'Caja familiar con productos de alta rotación para abastecer la semana.',
],
];
}
function get_product(string $id): ?array {
$products = store_products();
return $products[$id] ?? null;
}
function cart_items(): array {
if (session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
$cart = $_SESSION['cart'] ?? [];
$items = [];
foreach ($cart as $id => $qty) {
$product = get_product((string)$id);
$qty = max(1, (int)$qty);
if ($product) {
$product['qty'] = min($qty, (int)$product['stock']);
$product['line_total'] = $product['qty'] * (float)$product['price'];
$items[] = $product;
}
}
return $items;
}
function cart_total(): float {
return array_reduce(cart_items(), fn($sum, $item) => $sum + (float)$item['line_total'], 0.0);
}
function cart_count(): int {
return array_reduce(cart_items(), fn($sum, $item) => $sum + (int)$item['qty'], 0);
}
function money(float $amount): string {
return '$' . number_format($amount, 2) . ' USD';
}
function payment_icons_html(string $extraClass = ''): string {
$class = trim('payment-icons ' . $extraClass);
return '<div class="' . h($class) . '" aria-label="Tarjetas aceptadas"><span class="payment-card-icon visa" aria-label="Visa">VISA</span><span class="payment-card-icon mastercard" aria-label="Mastercard">Mastercard</span></div>';
}
function ensure_orders_table(): void {
db()->exec("CREATE TABLE IF NOT EXISTS lb_orders (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
customer_name VARCHAR(120) NOT NULL,
customer_email VARCHAR(180) NOT NULL,
customer_phone VARCHAR(40) NOT NULL,
delivery_notes TEXT NULL,
payment_method VARCHAR(40) NOT NULL,
proof_path VARCHAR(255) NULL,
items_json JSON NOT NULL,
total DECIMAL(10,2) NOT NULL DEFAULT 0,
status VARCHAR(30) NOT NULL DEFAULT 'pending_review',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
}
function create_order(array $data): int {
ensure_orders_table();
$stmt = db()->prepare('INSERT INTO lb_orders (customer_name, customer_email, customer_phone, delivery_notes, payment_method, proof_path, items_json, total, status) VALUES (:name, :email, :phone, :notes, :method, :proof, :items, :total, :status)');
$stmt->execute([
':name' => $data['customer_name'],
':email' => $data['customer_email'],
':phone' => $data['customer_phone'],
':notes' => $data['delivery_notes'],
':method' => $data['payment_method'],
':proof' => $data['proof_path'],
':items' => json_encode($data['items'], JSON_UNESCAPED_UNICODE),
':total' => $data['total'],
':status' => 'pending_review',
]);
return (int)db()->lastInsertId();
}
function list_orders(): array {
ensure_orders_table();
return db()->query('SELECT * FROM lb_orders ORDER BY created_at DESC, id DESC LIMIT 50')->fetchAll();
}
function get_order(int $id): ?array {
ensure_orders_table();
$stmt = db()->prepare('SELECT * FROM lb_orders WHERE id = :id LIMIT 1');
$stmt->execute([':id' => $id]);
$row = $stmt->fetch();
return $row ?: null;
}
function approve_order(int $id): void {
ensure_orders_table();
$stmt = db()->prepare("UPDATE lb_orders SET status = 'approved', updated_at = CURRENT_TIMESTAMP WHERE id = :id");
$stmt->execute([':id' => $id]);
}
function layout_header(string $title, string $description = ''): void {
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? $description;
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
$cartCount = cart_count();
$logoPath = store_logo_path();
echo '<!doctype html><html lang="es"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">';
echo '<title>' . h($title) . ' | LA BORGUITA</title>';
if ($projectDescription) {
echo '<meta name="description" content="' . h($projectDescription) . '">';
echo '<meta property="og:description" content="' . h($projectDescription) . '">';
echo '<meta property="twitter:description" content="' . h($projectDescription) . '">';
}
if ($projectImageUrl) {
echo '<meta property="og:image" content="' . h($projectImageUrl) . '">';
echo '<meta property="twitter:image" content="' . h($projectImageUrl) . '">';
}
echo '<link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>';
echo '<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">';
echo '<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">';
echo '<link rel="stylesheet" href="assets/css/custom.css?v=' . time() . '">';
echo '</head><body><div id="loader" class="tech-loader"><div class="loader-card"><div class="loader-mark"><img src="' . h($logoPath) . '" alt="Logo LA BORGUITA" width="46" height="46"></div><div class="loader-line"></div><p>Cargando tienda segura…</p></div></div>';
echo '<header class="site-header sticky-top"><nav class="navbar navbar-expand-lg"><div class="container"><a class="navbar-brand brand" href="index.php"><span class="brand-logo"><img src="' . h($logoPath) . '" alt="" width="34" height="34"></span><span>LA BORGUITA</span></a><button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#nav" aria-controls="nav" aria-expanded="false" aria-label="Abrir navegación"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="nav"><ul class="navbar-nav ms-auto align-items-lg-center gap-lg-2"><li class="nav-item"><a class="nav-link" href="index.php#catalogo">Catálogo</a></li><li class="nav-item"><a class="nav-link" href="cart.php">Carrito <span class="badge text-bg-dark">' . $cartCount . '</span></a></li><li class="nav-item"><a class="nav-link" href="admin.php">Admin</a></li><li class="nav-item"><a class="btn btn-sm btn-dark" href="https://wa.me/5351746028" target="_blank" rel="noopener">WhatsApp</a></li></ul></div></div></nav></header><main>';
}
function layout_footer(): void {
echo '</main><a class="whatsapp-float" href="https://wa.me/5351746028" target="_blank" rel="noopener" aria-label="Contactar por WhatsApp">WA</a><footer class="footer"><div class="container d-flex flex-column flex-md-row justify-content-between gap-2"><span>© ' . date('Y') . ' LA BORGUITA. Precios en dólares.</span><span>Pago manual con revisión admin · Visa/Mastercard listo para integración MX/US.</span></div></footer><script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script><script src="assets/js/main.js?v=' . time() . '"></script></body></html>';
}