refact: correcion de archivos
This commit is contained in:
parent
1fc55bf2bc
commit
11d1f56caa
Before ![]() (image error) Size: 24 KiB After ![]() (image error) Size: 24 KiB ![]() ![]() |
91
conf/bd.sql
91
conf/bd.sql
|
@ -1,91 +0,0 @@
|
||||||
-- Creación de la base de datos
|
|
||||||
CREATE DATABASE IF NOT EXISTS boletos_db;
|
|
||||||
USE boletos_db;
|
|
||||||
|
|
||||||
-- Tabla de salas
|
|
||||||
CREATE TABLE IF NOT EXISTS salas (
|
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
nombre VARCHAR(100) NOT NULL,
|
|
||||||
filas INT NOT NULL,
|
|
||||||
asientos_por_fila INT NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Tabla de boletos
|
|
||||||
CREATE TABLE IF NOT EXISTS boletos (
|
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
id_sala INT NOT NULL,
|
|
||||||
fila INT NOT NULL,
|
|
||||||
numero INT NOT NULL,
|
|
||||||
precio DECIMAL(10,2) NOT NULL,
|
|
||||||
estado ENUM('disponible', 'vendido') DEFAULT 'disponible',
|
|
||||||
FOREIGN KEY (id_sala) REFERENCES salas(id),
|
|
||||||
UNIQUE KEY unique_asiento (id_sala, fila, numero)
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Tabla de ventas
|
|
||||||
CREATE TABLE IF NOT EXISTS ventas (
|
|
||||||
id VARCHAR(36) PRIMARY KEY,
|
|
||||||
fecha DATETIME NOT NULL,
|
|
||||||
nombre_cliente VARCHAR(100) NOT NULL,
|
|
||||||
total DECIMAL(10,2) NOT NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
select * from ventas;
|
|
||||||
|
|
||||||
select * from venta_boletos;
|
|
||||||
|
|
||||||
select * from boletos;
|
|
||||||
|
|
||||||
-- Tabla relacional venta-boletos
|
|
||||||
CREATE TABLE IF NOT EXISTS venta_boletos (
|
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
id_venta VARCHAR(36) NOT NULL,
|
|
||||||
id_boleto INT NOT NULL,
|
|
||||||
FOREIGN KEY (id_venta) REFERENCES ventas(id),
|
|
||||||
FOREIGN KEY (id_boleto) REFERENCES boletos(id),
|
|
||||||
UNIQUE KEY unique_venta_boleto (id_venta, id_boleto)
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Insertar una sala de ejemplo
|
|
||||||
INSERT INTO salas (id, nombre, filas, asientos_por_fila)
|
|
||||||
VALUES (1, 'Sala Principal', 10, 15);
|
|
||||||
|
|
||||||
-- Procedimiento para inicializar boletos
|
|
||||||
DELIMITER //
|
|
||||||
CREATE PROCEDURE InicializaBoletos(IN sala_id INT, IN precio DECIMAL(10,2))
|
|
||||||
BEGIN
|
|
||||||
DECLARE i INT DEFAULT 1;
|
|
||||||
DECLARE j INT DEFAULT 1;
|
|
||||||
DECLARE total_filas INT DEFAULT 0;
|
|
||||||
DECLARE total_asientos INT DEFAULT 0;
|
|
||||||
|
|
||||||
-- Obtener dimensiones de la sala
|
|
||||||
SELECT filas, asientos_por_fila INTO total_filas, total_asientos
|
|
||||||
FROM salas WHERE id = sala_id;
|
|
||||||
|
|
||||||
-- Depuración: Verificar valores obtenidos
|
|
||||||
SELECT CONCAT('Filas:', total_filas, ' Asientos:', total_asientos) AS Debug_Info;
|
|
||||||
|
|
||||||
-- Si no se encuentran filas/asientos, salir del procedimiento
|
|
||||||
IF total_filas = 0 OR total_asientos = 0 THEN
|
|
||||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Sala no encontrada o sin dimensiones definidas';
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Eliminar boletos existentes de la sala
|
|
||||||
DELETE FROM boletos WHERE id_sala = sala_id;
|
|
||||||
|
|
||||||
-- Crear nuevos boletos
|
|
||||||
SET i = 1;
|
|
||||||
WHILE i <= total_filas DO
|
|
||||||
SET j = 1;
|
|
||||||
WHILE j <= total_asientos DO
|
|
||||||
INSERT INTO boletos (id_sala, fila, numero, precio, estado)
|
|
||||||
VALUES (sala_id, i, j, precio, 'disponible');
|
|
||||||
SET j = j + 1;
|
|
||||||
END WHILE;
|
|
||||||
SET i = i + 1;
|
|
||||||
END WHILE;
|
|
||||||
END //
|
|
||||||
DELIMITER ;
|
|
||||||
|
|
||||||
CALL InicializaBoletos(1, 50.00);
|
|
|
@ -1,38 +0,0 @@
|
||||||
<?php
|
|
||||||
// api/asientos.php - API para obtener el mapa de asientos
|
|
||||||
session_start();
|
|
||||||
|
|
||||||
require_once '../modelo/BaseDatos.php';
|
|
||||||
require_once '../modelo/Sala.php';
|
|
||||||
require_once '../modelo/Boleto.php';
|
|
||||||
require_once '../modelo/Venta.php';
|
|
||||||
require_once 'VendedorController.php';
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
// Conexión a base de datos
|
|
||||||
$db = new BaseDatos('localhost:3306', 'root', 'password', 'boletos_db');
|
|
||||||
|
|
||||||
// Inicializar el controlador
|
|
||||||
$vendedorController = new VendedorController($db);
|
|
||||||
|
|
||||||
// Cargar sala (solo hay una sala con id=1)
|
|
||||||
$sala = $vendedorController->cargarSala(1);
|
|
||||||
|
|
||||||
// Si no hay sala, podríamos inicializarla para desarrollo
|
|
||||||
if (!$sala) {
|
|
||||||
$sala = new Sala(1, 'Sala Principal');
|
|
||||||
$sala->inicializarBoletos(10, 15, 50.00); // 10 filas, 15 asientos por fila, $50 cada uno
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtener mapa de asientos
|
|
||||||
$mapaAsientos = $vendedorController->mostrarDisponibilidadAsientos();
|
|
||||||
|
|
||||||
// Preparar respuesta
|
|
||||||
$response = [
|
|
||||||
'success' => true,
|
|
||||||
'mapa' => $mapaAsientos,
|
|
||||||
'precio' => 50.00 // Agregamos el precio de los boletos a la respuesta
|
|
||||||
];
|
|
||||||
|
|
||||||
echo json_encode($response);
|
|
|
@ -1,64 +0,0 @@
|
||||||
<?php
|
|
||||||
require_once '../modelo/BaseDatos.php';
|
|
||||||
require_once '../modelo/Venta.php';
|
|
||||||
require_once '../modelo/Boleto.php';
|
|
||||||
require_once '../modelo/Sala.php';
|
|
||||||
|
|
||||||
error_reporting(E_ALL);
|
|
||||||
ini_set('display_errors', 1);
|
|
||||||
|
|
||||||
// Configuración de la base de datos
|
|
||||||
$host = 'localhost';
|
|
||||||
$usuario = 'root';
|
|
||||||
$password = 'password';
|
|
||||||
$nombreBD = 'boletos_db';
|
|
||||||
$bd = new BaseDatos($host, $usuario, $password, $nombreBD);
|
|
||||||
|
|
||||||
// Verificar que los datos fueron recibidos correctamente
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
||||||
$nombreCliente = $_POST['nombre_cliente'] ?? '';
|
|
||||||
$asientosSeleccionados = $_POST['asientos'] ?? [];
|
|
||||||
$idSala = 1; // Asegúrate de que el ID de la sala está definido
|
|
||||||
|
|
||||||
if (empty($nombreCliente) || empty($asientosSeleccionados) || !$idSala) {
|
|
||||||
echo json_encode(['success' => false, 'message' => 'Datos incompletos']);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cargar la sala desde la base de datos
|
|
||||||
$sala = $bd->cargarSala($idSala);
|
|
||||||
if (!$sala) {
|
|
||||||
echo json_encode(['success' => false, 'message' => 'Sala no encontrada']);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtener los boletos seleccionados
|
|
||||||
$boletosDisponibles = $sala->obtenerBoletosPorId($asientosSeleccionados);
|
|
||||||
if (count($boletosDisponibles) !== count($asientosSeleccionados)) {
|
|
||||||
echo json_encode(['success' => false, 'message' => 'Uno o más boletos no están disponibles']);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calcular el total de la venta
|
|
||||||
$total = array_reduce($boletosDisponibles, function($sum, $boleto) {
|
|
||||||
return $sum + $boleto->getPrecio();
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
// Crear una nueva venta
|
|
||||||
$venta = new Venta($nombreCliente);
|
|
||||||
$venta->agregarBoletos($boletosDisponibles);
|
|
||||||
|
|
||||||
// Guardar la venta en la base de datos
|
|
||||||
if ($bd->guardarVenta($venta)) {
|
|
||||||
// Guardar comprobante en sesión
|
|
||||||
$_SESSION['comprobante'] = $venta->generarComprobante();
|
|
||||||
echo json_encode(['success' => true, 'message' => 'Venta realizada con éxito', 'redirect' => '../vista/comprobante.html']);
|
|
||||||
} else {
|
|
||||||
echo json_encode(['success' => false, 'message' => 'Error al registrar la venta']);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
echo json_encode(['success' => false, 'message' => 'Método no permitido']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$bd->cerrarConexion();
|
|
||||||
?>
|
|
|
@ -1,71 +0,0 @@
|
||||||
<?php
|
|
||||||
// api/venta.php - API para procesar ventas
|
|
||||||
session_start();
|
|
||||||
|
|
||||||
require_once '../modelo/BaseDatos.php';
|
|
||||||
require_once '../modelo/Sala.php';
|
|
||||||
require_once '../modelo/Boleto.php';
|
|
||||||
require_once '../modelo/Venta.php';
|
|
||||||
require_once 'VendedorController.php';
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
// Verificar método de solicitud
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
||||||
echo json_encode(['success' => false, 'mensaje' => 'Método no permitido']);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtener datos JSON del cuerpo de la solicitud
|
|
||||||
$data = json_decode(file_get_contents('php://input'), true);
|
|
||||||
|
|
||||||
if (!$data || !isset($data['asientos']) || !isset($data['nombre_cliente'])) {
|
|
||||||
echo json_encode(['success' => false, 'mensaje' => 'Datos incompletos']);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extraer datos
|
|
||||||
$idsBoletos = $data['asientos'];
|
|
||||||
$nombreCliente = $data['nombre_cliente'];
|
|
||||||
|
|
||||||
// Validar que haya asientos seleccionados
|
|
||||||
if (empty($idsBoletos)) {
|
|
||||||
echo json_encode(['success' => false, 'mensaje' => 'No se han seleccionado asientos']);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Conexión a base de datos
|
|
||||||
$db = new BaseDatos('localhost:3306', 'root', '481037', 'boletos_db');
|
|
||||||
|
|
||||||
// Inicializar el controlador
|
|
||||||
$vendedorController = new VendedorController($db);
|
|
||||||
|
|
||||||
// Cargar la sala (agregando esta línea)
|
|
||||||
$vendedorController->cargarSala(1); // O el ID de sala correspondiente
|
|
||||||
|
|
||||||
// Seleccionar boletos
|
|
||||||
$boletosSeleccionados = $vendedorController->seleccionarBoletos($idsBoletos);
|
|
||||||
|
|
||||||
if (count($boletosSeleccionados) == 0) {
|
|
||||||
echo json_encode(['success' => false, 'mensaje' => 'No se han seleccionado asientos disponibles']);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Procesar venta
|
|
||||||
$comprobante = $vendedorController->procesarVenta($boletosSeleccionados, $nombreCliente);
|
|
||||||
|
|
||||||
if (!$comprobante) {
|
|
||||||
echo json_encode(['success' => false, 'mensaje' => 'Error al procesar la venta. Intente nuevamente']);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Guardar comprobante en sesión
|
|
||||||
$_SESSION['comprobante'] = $comprobante;
|
|
||||||
|
|
||||||
// Respuesta exitosa
|
|
||||||
echo json_encode([
|
|
||||||
'success' => true,
|
|
||||||
'mensaje' => 'Venta procesada con éxito',
|
|
||||||
'redirect' => '../vista/comprobante.html',
|
|
||||||
'comprobante' => $comprobante
|
|
||||||
]);
|
|
|
@ -1,48 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
require_once '../modelo/BaseDatos.php';
|
|
||||||
require_once '../modelo/Sala.php';
|
|
||||||
require_once '../modelo/Boleto.php';
|
|
||||||
require_once '../modelo/Venta.php';
|
|
||||||
|
|
||||||
class VendedorController {
|
|
||||||
private $baseDatos;
|
|
||||||
private $sala;
|
|
||||||
|
|
||||||
public function __construct($baseDatos) {
|
|
||||||
$this->baseDatos = $baseDatos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function cargarSala($idSala) {
|
|
||||||
$this->sala = $this->baseDatos->cargarSala($idSala);
|
|
||||||
return $this->sala;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function mostrarDisponibilidadAsientos() {
|
|
||||||
if ($this->sala) {
|
|
||||||
return $this->sala->disponibilidadAsientos();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function seleccionarBoletos($idsBoletos) {
|
|
||||||
if ($this->sala) {
|
|
||||||
return $this->sala->obtenerBoletosPorId($idsBoletos);
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function procesarVenta($boletos, $nombreCliente) {
|
|
||||||
$venta = new Venta($nombreCliente);
|
|
||||||
$venta->agregarBoletos($boletos);
|
|
||||||
|
|
||||||
if (count($venta->getBoletos()) > 0) {
|
|
||||||
$resultado = $this->baseDatos->guardarVenta($venta);
|
|
||||||
if ($resultado) {
|
|
||||||
return $venta->generarComprobante();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
<?php
|
|
||||||
// comprobante.php - Lógica de servidor para el comprobante de venta
|
|
||||||
session_start();
|
|
||||||
|
|
||||||
// Verificar si hay un comprobante en la sesión
|
|
||||||
if (!isset($_SESSION['comprobante'])) {
|
|
||||||
header('Location: ../vista/index.html');
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtener el comprobante de la sesión
|
|
||||||
$comprobante = $_SESSION['comprobante'];
|
|
||||||
|
|
||||||
// Devolver datos en formato JSON para ser consumidos por JavaScript
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
echo json_encode($comprobante);
|
|
||||||
?>
|
|
|
@ -1,5 +0,0 @@
|
||||||
<?php
|
|
||||||
// Redirigir a la página principal del sistema
|
|
||||||
header("Location: vista/index.html");
|
|
||||||
exit();
|
|
||||||
?>
|
|
|
@ -1,94 +0,0 @@
|
||||||
<?php
|
|
||||||
require_once 'Sala.php';
|
|
||||||
require_once 'Boleto.php';
|
|
||||||
require_once 'Venta.php';
|
|
||||||
|
|
||||||
class BaseDatos {
|
|
||||||
private $conexion;
|
|
||||||
|
|
||||||
public function __construct($host, $usuario, $password, $nombreBD) {
|
|
||||||
$this->conexion = new mysqli($host, $usuario, $password, $nombreBD);
|
|
||||||
|
|
||||||
if ($this->conexion->connect_error) {
|
|
||||||
die("Error de conexión: " . $this->conexion->connect_error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function cargarSala($idSala) {
|
|
||||||
$sala = null;
|
|
||||||
$query = "SELECT id, nombre FROM salas WHERE id = ?";
|
|
||||||
$stmt = $this->conexion->prepare($query);
|
|
||||||
$stmt->bind_param("i", $idSala);
|
|
||||||
$stmt->execute();
|
|
||||||
$result = $stmt->get_result();
|
|
||||||
|
|
||||||
if ($fila = $result->fetch_assoc()) {
|
|
||||||
$sala = new Sala($fila['id'], $fila['nombre']);
|
|
||||||
|
|
||||||
// Cargar boletos de la sala
|
|
||||||
$queryBoletos = "SELECT id, fila, numero, precio, estado FROM boletos WHERE id_sala = ?";
|
|
||||||
$stmtBoletos = $this->conexion->prepare($queryBoletos);
|
|
||||||
$stmtBoletos->bind_param("i", $idSala);
|
|
||||||
$stmtBoletos->execute();
|
|
||||||
$resultBoletos = $stmtBoletos->get_result();
|
|
||||||
|
|
||||||
$boletos = [];
|
|
||||||
while ($filaBoleto = $resultBoletos->fetch_assoc()) {
|
|
||||||
$boleto = new Boleto($filaBoleto['id'], $filaBoleto['fila'], $filaBoleto['numero'], $filaBoleto['precio']);
|
|
||||||
if ($filaBoleto['estado'] === 'vendido') {
|
|
||||||
$boleto->marcarComoVendido();
|
|
||||||
}
|
|
||||||
$boletos[] = $boleto;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Asignar boletos a la sala
|
|
||||||
$sala->setBoletos($boletos);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sala;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function guardarVenta($venta) {
|
|
||||||
// Iniciar transacción
|
|
||||||
$this->conexion->begin_transaction();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Insertar venta
|
|
||||||
$query = "INSERT INTO ventas (id, fecha, nombre_cliente, total) VALUES (?, ?, ?, ?)";
|
|
||||||
$stmt = $this->conexion->prepare($query);
|
|
||||||
$id = $venta->getId();
|
|
||||||
$fecha = $venta->getFecha();
|
|
||||||
$nombreCliente = $venta->getNombreCliente();
|
|
||||||
$total = $venta->getTotal();
|
|
||||||
$stmt->bind_param("sssd", $id, $fecha, $nombreCliente, $total);
|
|
||||||
$stmt->execute();
|
|
||||||
|
|
||||||
// Actualizar estado de boletos
|
|
||||||
foreach ($venta->getBoletos() as $boleto) {
|
|
||||||
$queryBoleto = "UPDATE boletos SET estado = 'vendido' WHERE id = ?";
|
|
||||||
$stmtBoleto = $this->conexion->prepare($queryBoleto);
|
|
||||||
$idBoleto = $boleto->getId();
|
|
||||||
$stmtBoleto->bind_param("i", $idBoleto);
|
|
||||||
$stmtBoleto->execute();
|
|
||||||
|
|
||||||
// Insertar relación venta-boleto
|
|
||||||
$queryRelacion = "INSERT INTO venta_boletos (id_venta, id_boleto) VALUES (?, ?)";
|
|
||||||
$stmtRelacion = $this->conexion->prepare($queryRelacion);
|
|
||||||
$stmtRelacion->bind_param("si", $id, $idBoleto);
|
|
||||||
$stmtRelacion->execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Confirmar transacción
|
|
||||||
$this->conexion->commit();
|
|
||||||
return true;
|
|
||||||
} catch (Exception $e) {
|
|
||||||
// Revertir transacción en caso de error
|
|
||||||
$this->conexion->rollback();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function cerrarConexion() {
|
|
||||||
$this->conexion->close();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
<?php
|
|
||||||
class Boleto {
|
|
||||||
private $id;
|
|
||||||
private $fila;
|
|
||||||
private $numero;
|
|
||||||
private $precio;
|
|
||||||
private $estado; // 'disponible' o 'vendido'
|
|
||||||
|
|
||||||
public function __construct($id, $fila, $numero, $precio) {
|
|
||||||
$this->id = $id;
|
|
||||||
$this->fila = $fila;
|
|
||||||
$this->numero = $numero;
|
|
||||||
$this->precio = $precio;
|
|
||||||
$this->estado = 'disponible';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getters y setters
|
|
||||||
public function getId() {
|
|
||||||
return $this->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFila() {
|
|
||||||
return $this->fila;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNumero() {
|
|
||||||
return $this->numero;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPrecio() {
|
|
||||||
return $this->precio;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEstado() {
|
|
||||||
return $this->estado;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function marcarComoVendido() {
|
|
||||||
$this->estado = 'vendido';
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function estaDisponible() {
|
|
||||||
return $this->estado === 'disponible';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
<?php
|
|
||||||
require_once 'Boleto.php';
|
|
||||||
|
|
||||||
class Sala {
|
|
||||||
private $id;
|
|
||||||
private $nombre;
|
|
||||||
private $boletos = [];
|
|
||||||
|
|
||||||
public function __construct($id, $nombre) {
|
|
||||||
$this->id = $id;
|
|
||||||
$this->nombre = $nombre;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId() {
|
|
||||||
return $this->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNombre() {
|
|
||||||
return $this->nombre;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function inicializarBoletos($filas, $asientosPorFila, $precio) {
|
|
||||||
$this->boletos = [];
|
|
||||||
$contador = 1;
|
|
||||||
|
|
||||||
for ($i = 1; $i <= $filas; $i++) {
|
|
||||||
for ($j = 1; $j <= $asientosPorFila; $j++) {
|
|
||||||
$this->boletos[] = new Boleto($contador, $i, $j, $precio);
|
|
||||||
$contador++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function obtenerBoletos() {
|
|
||||||
return $this->boletos;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function obtenerBoletosPorEstado($estado) {
|
|
||||||
return array_filter($this->boletos, function($boleto) use ($estado) {
|
|
||||||
return $boleto->getEstado() === $estado;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function obtenerBoletosPorId($ids) {
|
|
||||||
return array_filter($this->boletos, function($boleto) use ($ids) {
|
|
||||||
return in_array($boleto->getId(), $ids);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function disponibilidadAsientos() {
|
|
||||||
$mapa = [];
|
|
||||||
foreach ($this->boletos as $boleto) {
|
|
||||||
$mapa[$boleto->getFila()][$boleto->getNumero()] = $boleto->getEstado();
|
|
||||||
}
|
|
||||||
return $mapa;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setter para asignar boletos desde la base de datos
|
|
||||||
public function setBoletos($boletos) {
|
|
||||||
$this->boletos = $boletos;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
<?php
|
|
||||||
require_once 'Boleto.php';
|
|
||||||
|
|
||||||
class Venta {
|
|
||||||
private $id;
|
|
||||||
private $fecha;
|
|
||||||
private $boletos = [];
|
|
||||||
private $total;
|
|
||||||
private $nombreCliente;
|
|
||||||
|
|
||||||
public function __construct($nombreCliente) {
|
|
||||||
$this->id = bin2hex(random_bytes(8));
|
|
||||||
date_default_timezone_set('America/Mexico_City');
|
|
||||||
$this->fecha = date('Y-m-d H:i:s');
|
|
||||||
$this->nombreCliente = $nombreCliente;
|
|
||||||
$this->total = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId() {
|
|
||||||
return $this->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFecha() {
|
|
||||||
return $this->fecha;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getNombreCliente() {
|
|
||||||
return $this->nombreCliente;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function agregarBoletos($boletos) {
|
|
||||||
foreach ($boletos as $boleto) {
|
|
||||||
if ($boleto->estaDisponible()) {
|
|
||||||
$this->boletos[] = $boleto;
|
|
||||||
$this->total += $boleto->getPrecio();
|
|
||||||
$boleto->marcarComoVendido();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function generarComprobante() {
|
|
||||||
$comprobante = [
|
|
||||||
'id_venta' => $this->id,
|
|
||||||
'fecha' => $this->fecha,
|
|
||||||
'cliente' => $this->nombreCliente,
|
|
||||||
'boletos' => [],
|
|
||||||
'total' => $this->total
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($this->boletos as $boleto) {
|
|
||||||
$comprobante['boletos'][] = [
|
|
||||||
'id' => $boleto->getId(),
|
|
||||||
'fila' => $boleto->getFila(),
|
|
||||||
'numero' => $boleto->getNumero(),
|
|
||||||
'precio' => $boleto->getPrecio()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $comprobante;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTotal() {
|
|
||||||
return $this->total;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getBoletos() {
|
|
||||||
return $this->boletos;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="es">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Comprobante de Venta</title>
|
|
||||||
<link rel="stylesheet" href="css/comprobante.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<h1>Comprobante de Venta</h1>
|
|
||||||
|
|
||||||
<div class="comprobante" id="comprobante-imprimible">
|
|
||||||
<div class="header">
|
|
||||||
<h2>Boletos para Concierto - Sala Principal</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="info-venta">
|
|
||||||
<div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Nº de Venta:</span>
|
|
||||||
<span id="id-venta"></span>
|
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Fecha:</span>
|
|
||||||
<span id="fecha-venta"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">Cliente:</span>
|
|
||||||
<span id="cliente-venta"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h3>Detalle de Boletos</h3>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>#</th>
|
|
||||||
<th>Ubicación</th>
|
|
||||||
<th>Precio</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="detalle-boletos">
|
|
||||||
<!-- El contenido de la tabla se generará dinámicamente con JavaScript -->
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<div class="total">
|
|
||||||
Total: $<span id="total-venta"></span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="qr-container">
|
|
||||||
<div id="qr-code"></div>
|
|
||||||
<p class="qr-info">Este QR contiene el número de venta para verificación</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mensaje">
|
|
||||||
<p>¡Gracias por su compra!</p>
|
|
||||||
<p>Este comprobante es su entrada oficial para el evento.</p>
|
|
||||||
<p>Por favor, preséntelo en la entrada del concierto.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="acciones">
|
|
||||||
<a href="index.html" class="btn">Volver a Ventas</a>
|
|
||||||
<button class="btn btn-print" onclick="imprimirComprobante()">Imprimir Comprobante</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
|
|
||||||
<script src="js/comprobante.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,103 +0,0 @@
|
||||||
body {
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
margin: 0;
|
|
||||||
padding: 20px;
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
max-width: 800px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background-color: #fff;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
h1, h2 {
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
.comprobante {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 4px;
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
.header {
|
|
||||||
border-bottom: 2px solid #333;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
.info-venta {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
.info-item {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.info-label {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
th, td {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 8px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
th {
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
}
|
|
||||||
.total {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: bold;
|
|
||||||
text-align: right;
|
|
||||||
margin-top: 20px;
|
|
||||||
padding-top: 10px;
|
|
||||||
border-top: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
.acciones {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
.btn {
|
|
||||||
background-color: #007bff;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
padding: 10px 20px;
|
|
||||||
border-radius: 4px;
|
|
||||||
text-decoration: none;
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
.btn-print {
|
|
||||||
background-color: #6c757d;
|
|
||||||
}
|
|
||||||
.btn:hover {
|
|
||||||
opacity: 0.9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.qr-container {
|
|
||||||
text-align: center;
|
|
||||||
margin: 30px 0;
|
|
||||||
padding: 10px;
|
|
||||||
border-top: 1px dashed #ccc;
|
|
||||||
padding-top: 20px;
|
|
||||||
}
|
|
||||||
#qr-code {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
.qr-info {
|
|
||||||
font-size: 14px;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mensaje {
|
|
||||||
margin-top: 40px;
|
|
||||||
font-size: 14px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
|
@ -1,199 +0,0 @@
|
||||||
body {
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
margin: 0;
|
|
||||||
padding: 20px;
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background-color: #fff;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-content {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 20px;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sala {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 300px;
|
|
||||||
margin: 20px 0;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
flex: 0 0 350px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2 {
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mensaje {
|
|
||||||
background-color: #f8d7da;
|
|
||||||
color: #721c24;
|
|
||||||
padding: 10px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
border-radius: 4px;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.escenario {
|
|
||||||
background-color: #ddd;
|
|
||||||
padding: 10px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
border-radius: 4px;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filas {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fila {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.numero-fila {
|
|
||||||
width: 30px;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asientos {
|
|
||||||
display: flex;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asiento {
|
|
||||||
width: 35px;
|
|
||||||
height: 35px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
border-radius: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.disponible {
|
|
||||||
background-color: #28a745;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vendido {
|
|
||||||
background-color: #dc3545;
|
|
||||||
color: white;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.seleccionado {
|
|
||||||
background-color: #007bff;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-group {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="text"] {
|
|
||||||
width: 100%;
|
|
||||||
padding: 8px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
background-color: #007bff;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
padding: 10px 20px;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn:hover {
|
|
||||||
background-color: #0069d9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.resumen, .concierto-detalles, #formularioVenta {
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.resumen {
|
|
||||||
margin-top: 20px;
|
|
||||||
padding: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.concierto-detalles {
|
|
||||||
border-left: 4px solid #6c757d;
|
|
||||||
}
|
|
||||||
|
|
||||||
#formularioVenta {
|
|
||||||
padding: 20px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
height: fit-content;
|
|
||||||
}
|
|
||||||
|
|
||||||
.concierto-detalles i {
|
|
||||||
color: #6c757d;
|
|
||||||
margin-right: 5px;
|
|
||||||
width: 20px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#formularioVenta i {
|
|
||||||
color: #495057;
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leyenda {
|
|
||||||
display: flex;
|
|
||||||
gap: 15px;
|
|
||||||
margin-top: 20px;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leyenda-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leyenda-color {
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 992px) {
|
|
||||||
.main-content {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,86 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="es">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Sistema de Venta de Boletos</title>
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
|
|
||||||
<link rel="stylesheet" href="css/index.css">
|
|
||||||
<style>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
<script src="jspdf.plugin.autotable.min.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<h1>TicketFlow</h1>
|
|
||||||
|
|
||||||
<div id="mensajeAlerta" class="alert alert-warning d-none" role="alert"></div>
|
|
||||||
|
|
||||||
<div class="sala">
|
|
||||||
<h2>Selección de Asientos - Sala Principal</h2>
|
|
||||||
<div class="escenario">ESCENARIO</div>
|
|
||||||
|
|
||||||
<div class="filas" id="mapaAsientos">
|
|
||||||
<!-- El mapa de asientos se cargará dinámicamente con JavaScript -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="leyenda">
|
|
||||||
<div class="leyenda-item">
|
|
||||||
<div class="leyenda-color" style="background-color: #28a745;"></div>
|
|
||||||
<span>Disponible</span>
|
|
||||||
</div>
|
|
||||||
<div class="leyenda-item">
|
|
||||||
<div class="leyenda-color" style="background-color: #007bff;"></div>
|
|
||||||
<span>Seleccionado</span>
|
|
||||||
</div>
|
|
||||||
<div class="leyenda-item">
|
|
||||||
<div class="leyenda-color" style="background-color: #dc3545;"></div>
|
|
||||||
<span>Vendido</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form id="formularioVenta">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="nombre_cliente">Nombre del Cliente:</label>
|
|
||||||
<input type="text" id="nombre_cliente" name="nombre_cliente" class="form-control" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="resumen" id="resumen">
|
|
||||||
<h3>Resumen de Selección</h3>
|
|
||||||
<p>Asientos seleccionados: <span id="asientosSeleccionados">Ninguno</span></p>
|
|
||||||
<p>Total: $<span id="totalVenta">0.00</span></p>
|
|
||||||
<button type="submit" id="btnVender" class="btn btn-primary">Confirmar Venta</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Campo oculto para almacenar IDs de asientos seleccionados -->
|
|
||||||
<div id="asientosSeleccionadosInput"></div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="resumen" id="resumen">
|
|
||||||
<h3>Graficos</h3>
|
|
||||||
<table>
|
|
||||||
|
|
||||||
<thead>
|
|
||||||
|
|
||||||
</thead>
|
|
||||||
|
|
||||||
<tbody>
|
|
||||||
|
|
||||||
</tbody>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<!-- Campo oculto para almacenar IDs de asientos seleccionados -->
|
|
||||||
<div id="asientosSeleccionadosInput"></div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="js/index.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,110 +0,0 @@
|
||||||
// comprobante.js - Maneja la comunicación entre el PHP y el HTML
|
|
||||||
|
|
||||||
// Cuando el documento esté listo, cargar los datos del comprobante
|
|
||||||
document.addEventListener('DOMContentLoaded', cargarComprobante);
|
|
||||||
|
|
||||||
// Función para cargar los datos del comprobante desde el servidor
|
|
||||||
function cargarComprobante() {
|
|
||||||
fetch('../controlador/comprobante.php')
|
|
||||||
.then(response => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Error al obtener los datos del comprobante');
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then(comprobante => {
|
|
||||||
// Llenar los datos básicos del comprobante
|
|
||||||
document.getElementById('id-venta').textContent = comprobante.id_venta;
|
|
||||||
document.getElementById('fecha-venta').textContent = comprobante.fecha;
|
|
||||||
document.getElementById('cliente-venta').textContent = comprobante.cliente;
|
|
||||||
document.getElementById('total-venta').textContent = formatearNumero(comprobante.total);
|
|
||||||
|
|
||||||
// Generar las filas de la tabla de boletos
|
|
||||||
const tablaBoletos = document.getElementById('detalle-boletos');
|
|
||||||
let contenidoTabla = '';
|
|
||||||
|
|
||||||
comprobante.boletos.forEach((boleto, index) => {
|
|
||||||
contenidoTabla += `
|
|
||||||
<tr>
|
|
||||||
<td>${index + 1}</td>
|
|
||||||
<td>Fila ${boleto.fila}, Asiento ${boleto.numero}</td>
|
|
||||||
<td>$${formatearNumero(boleto.precio)}</td>
|
|
||||||
</tr>
|
|
||||||
`;
|
|
||||||
});
|
|
||||||
|
|
||||||
tablaBoletos.innerHTML = contenidoTabla;
|
|
||||||
|
|
||||||
// Generar código QR con el ID de la venta
|
|
||||||
generarQR(comprobante.id_venta);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Error:', error);
|
|
||||||
alert('No se pudo cargar el comprobante. Por favor, inténtelo de nuevo.');
|
|
||||||
window.location.href = 'index.html';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Función para generar el código QR
|
|
||||||
function generarQR(idVenta) {
|
|
||||||
// Verificar si existe el elemento donde se mostrará el QR
|
|
||||||
const qrContainer = document.getElementById('qr-code');
|
|
||||||
if (!qrContainer) {
|
|
||||||
console.error('No se encontró el elemento para mostrar el código QR');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Limpiar el contenedor por si ya tiene contenido
|
|
||||||
qrContainer.innerHTML = '';
|
|
||||||
|
|
||||||
// Crear una nueva instancia de QRCode
|
|
||||||
new QRCode(qrContainer, {
|
|
||||||
text: idVenta.toString(),
|
|
||||||
width: 128,
|
|
||||||
height: 128,
|
|
||||||
colorDark: "#000000",
|
|
||||||
colorLight: "#ffffff",
|
|
||||||
correctLevel: QRCode.CorrectLevel.H // Alta corrección de errores
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Función para imprimir el comprobante
|
|
||||||
function imprimirComprobante() {
|
|
||||||
const contenido = document.getElementById('comprobante-imprimible').innerHTML;
|
|
||||||
const ventanaImpresion = window.open('', '_blank');
|
|
||||||
|
|
||||||
ventanaImpresion.document.write(`
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Comprobante de Venta</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: Arial, sans-serif; }
|
|
||||||
.header { border-bottom: 2px solid #333; padding-bottom: 10px; margin-bottom: 20px; }
|
|
||||||
.info-venta { display: flex; justify-content: space-between; margin-bottom: 20px; }
|
|
||||||
.info-item { margin-bottom: 10px; }
|
|
||||||
.info-label { font-weight: bold; }
|
|
||||||
table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
|
|
||||||
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
|
||||||
th { background-color: #f8f9fa; }
|
|
||||||
.total { font-size: 18px; font-weight: bold; text-align: right; margin-top: 20px; padding-top: 10px; border-top: 1px solid #ddd; }
|
|
||||||
.qr-container { text-align: center; margin: 20px 0; border-top: 1px dashed #ccc; padding-top: 20px;}
|
|
||||||
#qr-code { display: inline-block; margin: 0 auto; }
|
|
||||||
.qr-info { font-size: 14px; margin-top: 10px; }
|
|
||||||
.mensaje { margin-top: 40px; font-size: 14px; text-align: center;}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
${contenido}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
`);
|
|
||||||
|
|
||||||
ventanaImpresion.document.close();
|
|
||||||
ventanaImpresion.focus();
|
|
||||||
ventanaImpresion.print();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Función auxiliar para formatear números con dos decimales
|
|
||||||
function formatearNumero(numero) {
|
|
||||||
return Number(numero).toFixed(2);
|
|
||||||
}
|
|
|
@ -1,208 +0,0 @@
|
||||||
// js/index.js - Script para manejar la interfaz de usuario y la comunicación con el backend
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
let seleccionados = [];
|
|
||||||
const precioBoleto = 50.00; // Precio por boleto
|
|
||||||
|
|
||||||
// Cargar el mapa de asientos al iniciar
|
|
||||||
cargarMapaAsientos();
|
|
||||||
|
|
||||||
// Agregar manejador para el formulario
|
|
||||||
const formulario = document.getElementById('formularioVenta');
|
|
||||||
formulario.addEventListener('submit', validarYEnviarFormulario);
|
|
||||||
|
|
||||||
// Función para cargar el mapa de asientos desde la API
|
|
||||||
async function cargarMapaAsientos() {
|
|
||||||
try {
|
|
||||||
const response = await fetch('../controlador/asientos.php');
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
console.log('Datos recibidos:', data); // Agregar este log para ver los datos recibidos
|
|
||||||
|
|
||||||
|
|
||||||
if (!data.success) {
|
|
||||||
mostrarMensaje('Error al cargar el mapa de asientos', 'error');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderizarMapaAsientos(data.mapa);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error al cargar el mapa de asientos:', error);
|
|
||||||
mostrarMensaje('Error de conexión con el servidor', 'error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Función para renderizar el mapa de asientos
|
|
||||||
function renderizarMapaAsientos(mapa) {
|
|
||||||
console.log('Mapa de asientos:', mapa); // Agregar este log para ver el mapa de asientos
|
|
||||||
const contenedor = document.getElementById('mapaAsientos');
|
|
||||||
contenedor.innerHTML = '';
|
|
||||||
|
|
||||||
Object.entries(mapa).forEach(([numeroFila, asientosEnFila]) => {
|
|
||||||
const filaElement = document.createElement('div');
|
|
||||||
filaElement.className = 'fila';
|
|
||||||
|
|
||||||
// Crear elemento para el número de fila
|
|
||||||
const numeroFilaElement = document.createElement('div');
|
|
||||||
numeroFilaElement.className = 'numero-fila';
|
|
||||||
numeroFilaElement.textContent = `F${numeroFila}`;
|
|
||||||
filaElement.appendChild(numeroFilaElement);
|
|
||||||
|
|
||||||
// Crear contenedor para los asientos
|
|
||||||
const asientosContainer = document.createElement('div');
|
|
||||||
asientosContainer.className = 'asientos';
|
|
||||||
|
|
||||||
// Crear cada asiento
|
|
||||||
Object.entries(asientosEnFila).forEach(([numeroAsiento, estado]) => {
|
|
||||||
const idBoleto = ((parseInt(numeroFila) - 1) * Object.keys(asientosEnFila).length) + parseInt(numeroAsiento);
|
|
||||||
const asiento = document.createElement('div');
|
|
||||||
|
|
||||||
// Determinar la clase según el estado
|
|
||||||
asiento.className = `asiento ${estado === 'disponible' ? 'disponible' : 'vendido'}`;
|
|
||||||
asiento.dataset.id = idBoleto;
|
|
||||||
asiento.textContent = numeroAsiento;
|
|
||||||
|
|
||||||
asientosContainer.appendChild(asiento);
|
|
||||||
});
|
|
||||||
|
|
||||||
filaElement.appendChild(asientosContainer);
|
|
||||||
contenedor.appendChild(filaElement);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Una vez que se ha renderizado, añadir los eventos
|
|
||||||
configurarEventosAsientos();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configurar eventos para los asientos
|
|
||||||
function configurarEventosAsientos() {
|
|
||||||
const asientos = document.querySelectorAll('.asiento.disponible');
|
|
||||||
|
|
||||||
asientos.forEach(asiento => {
|
|
||||||
asiento.addEventListener('click', function() {
|
|
||||||
const asientoId = parseInt(this.getAttribute('data-id'));
|
|
||||||
|
|
||||||
// Verificar si ya está seleccionado
|
|
||||||
const indice = seleccionados.findIndex(a => a.id === asientoId);
|
|
||||||
|
|
||||||
if (indice === -1) {
|
|
||||||
// Agregar a seleccionados
|
|
||||||
seleccionados.push({
|
|
||||||
id: asientoId,
|
|
||||||
elemento: this
|
|
||||||
});
|
|
||||||
this.classList.remove('disponible');
|
|
||||||
this.classList.add('seleccionado');
|
|
||||||
} else {
|
|
||||||
// Quitar de seleccionados
|
|
||||||
seleccionados.splice(indice, 1);
|
|
||||||
this.classList.remove('seleccionado');
|
|
||||||
this.classList.add('disponible');
|
|
||||||
}
|
|
||||||
|
|
||||||
actualizarResumen();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Función para actualizar el resumen de venta
|
|
||||||
function actualizarResumen() {
|
|
||||||
const resumenAsientos = document.getElementById('asientosSeleccionados');
|
|
||||||
const resumenTotal = document.getElementById('totalVenta');
|
|
||||||
const asientosInput = document.getElementById('asientosSeleccionadosInput');
|
|
||||||
|
|
||||||
if (seleccionados.length === 0) {
|
|
||||||
resumenAsientos.textContent = 'Ninguno';
|
|
||||||
resumenTotal.textContent = '0.00';
|
|
||||||
|
|
||||||
// Limpiar los inputs ocultos
|
|
||||||
if (asientosInput) {
|
|
||||||
asientosInput.innerHTML = '';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Mostrar los asientos seleccionados
|
|
||||||
const detalles = seleccionados.map(asiento => {
|
|
||||||
const fila = Math.floor((asiento.id - 1) / 15) + 1;
|
|
||||||
const numero = ((asiento.id - 1) % 15) + 1;
|
|
||||||
return `F${fila}-${numero}`;
|
|
||||||
});
|
|
||||||
|
|
||||||
resumenAsientos.textContent = detalles.join(', ');
|
|
||||||
resumenTotal.textContent = (seleccionados.length * precioBoleto).toFixed(2);
|
|
||||||
|
|
||||||
// Actualizar campo oculto para el envío del formulario
|
|
||||||
if (asientosInput) {
|
|
||||||
asientosInput.innerHTML = '';
|
|
||||||
seleccionados.forEach(asiento => {
|
|
||||||
const input = document.createElement('input');
|
|
||||||
input.type = 'hidden';
|
|
||||||
input.name = 'asientos[]';
|
|
||||||
input.value = asiento.id;
|
|
||||||
asientosInput.appendChild(input);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function validarYEnviarFormulario(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
if (seleccionados.length === 0) {
|
|
||||||
mostrarMensaje('Por favor, seleccione al menos un asiento.');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nombreCliente = document.getElementById('nombre_cliente').value.trim();
|
|
||||||
if (nombreCliente === '') {
|
|
||||||
mostrarMensaje('Por favor, ingrese el nombre del cliente.');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('nombre_cliente', nombreCliente);
|
|
||||||
seleccionados.forEach(asiento => {
|
|
||||||
formData.append('asientos[]', asiento.id);
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch('../controlador/procesarVenta.php', {
|
|
||||||
method: 'POST',
|
|
||||||
body: formData
|
|
||||||
});
|
|
||||||
|
|
||||||
const responseText = await response.text(); // Capturar respuesta como texto para depurar
|
|
||||||
console.log('Respuesta del servidor:', responseText);
|
|
||||||
|
|
||||||
// Intentar parsear como JSON
|
|
||||||
const data = JSON.parse(responseText);
|
|
||||||
|
|
||||||
if (!data.success) {
|
|
||||||
mostrarMensaje(data.message || 'Error en la venta'); // Cambiar 'mensaje' a 'message'
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Redirigir al comprobante
|
|
||||||
window.location.href = data.redirect;
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error al enviar la venta:', error);
|
|
||||||
mostrarMensaje('Error de conexión con el servidor', 'error');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Función para mostrar mensajes
|
|
||||||
function mostrarMensaje(texto, tipo = 'warning') {
|
|
||||||
const mensajeElement = document.getElementById('mensajeAlerta');
|
|
||||||
if (mensajeElement) {
|
|
||||||
mensajeElement.textContent = texto;
|
|
||||||
mensajeElement.className = `alert alert-${tipo === 'error' ? 'danger' : 'warning'}`;
|
|
||||||
mensajeElement.classList.remove('d-none');
|
|
||||||
|
|
||||||
// Ocultar después de 5 segundos
|
|
||||||
setTimeout(() => {
|
|
||||||
mensajeElement.classList.add('d-none');
|
|
||||||
}, 5000);
|
|
||||||
} else {
|
|
||||||
// Si no existe el elemento, usar alert
|
|
||||||
alert(texto);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
Loading…
Reference in New Issue