Beta 0.1 Funcional

This commit is contained in:
Felipe Murguia 2025-03-09 16:45:02 -06:00
parent 4d91e64c2e
commit 86cda061d8
7 changed files with 250 additions and 90 deletions

25
pom.xml
View File

@ -12,24 +12,28 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.10.2</junit.version>
<javafx.version>21</javafx.version>
<itext.version>9.1.0</itext.version>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>21</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>21</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
@ -37,22 +41,20 @@
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>SalaDeConciertos</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.3</version>
</dependency>
</dependencies>
<build>
@ -75,8 +77,7 @@
<!-- Default configuration for running with: mvn clean javafx:run -->
<id>default-cli</id>
<configuration>
<mainClass>org.example.saladeconciertos/org.example.saladeconciertos.HelloApplication
</mainClass>
<mainClass>org.example.saladeconciertos/org.example.saladeconciertos.VentaBoletos</mainClass>
<launcher>app</launcher>
<jlinkZipName>app</jlinkZipName>
<jlinkImageName>app</jlinkImageName>

View File

@ -1,10 +1,10 @@
module org.example.saladeconciertos {
requires javafx.controls;
requires javafx.fxml;
requires javafx.graphics;
requires java.sql;
requires org.apache.pdfbox;
opens org.example.saladeconciertos to javafx.fxml;
exports org.example.saladeconciertos;
}

View File

@ -0,0 +1,97 @@
package org.example.saladeconciertos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class EscogerEvento {
// Datos de conexión a la base de datos
private static final String DB_URL = "jdbc:mysql://sql10.freesqldatabase.com:3306/sql10766655";
private static final String DB_USER = "sql10766655";
private static final String DB_PASSWORD = "7BZbRjEkXZ";
// Método para mostrar la ventana de selección de eventos
public void mostrarVentanaSeleccionEvento(Stage mainStage, VentaBoletos ventaBoletos) {
// Crear y configurar el label para seleccionar un evento
Label selectEventLabel = new Label("Seleccione un evento:");
selectEventLabel.getStyleClass().add("label");
// Crear y configurar el ComboBox para listar los eventos
ComboBox<String> eventComboBox = new ComboBox<>();
// Crear y configurar el label para mostrar el evento seleccionado
Label selectedEventLabel = new Label("Evento seleccionado: Ninguno");
selectedEventLabel.getStyleClass().add("label");
// Crear y configurar el botón de confirmación
Button confirmButton = new Button("Confirmar");
confirmButton.getStyleClass().add("button");
// Cargar eventos desde la base de datos
try (Connection conexion = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD)) {
String query = "SELECT id, nombre FROM conciertos";
Statement statement = conexion.createStatement();
ResultSet resultSet = statement.executeQuery(query);
// Añadir los eventos al ComboBox
while (resultSet.next()) {
int id = resultSet.getInt("id");
String nombre = resultSet.getString("nombre");
eventComboBox.getItems().add(id + " - " + nombre);
}
} catch (SQLException e) {
System.out.println("Error al cargar los eventos.");
e.printStackTrace();
}
// Actualizar el label cuando se selecciona un evento
eventComboBox.setOnAction(e -> {
String selectedEvent = eventComboBox.getValue();
if (selectedEvent != null) {
selectedEventLabel.setText("Evento seleccionado: " + selectedEvent);
}
});
// Acción del botón de confirmación
confirmButton.setOnAction(e -> {
String selectedEvent = eventComboBox.getValue();
if (selectedEvent != null) {
int eventId = Integer.parseInt(selectedEvent.split(" - ")[0]);
ventaBoletos.setEventId(eventId);
ventaBoletos.cargarInformacionEvento();
ventaBoletos.mostrarVentanaVentaBoletos(mainStage);
} else {
ventaBoletos.mostrarAlerta("Advertencia", "No se ha seleccionado un evento", "Por favor, seleccione un evento.");
}
});
// Agregar el logo de la aplicación
ImageView logo = new ImageView(new Image(getClass().getResourceAsStream("/logo.png")));
logo.setFitWidth(100);
logo.setFitHeight(100);
// Crear y configurar el layout principal
VBox layout = new VBox(20, logo, selectEventLabel, eventComboBox, selectedEventLabel, confirmButton);
layout.setAlignment(Pos.CENTER);
layout.setPadding(new Insets(20));
// Crear y configurar la escena
Scene scene = new Scene(layout, 400, 300);
scene.getStylesheets().add(getClass().getResource("/styles.css").toExternalForm());
mainStage.setScene(scene);
mainStage.show();
}
}

View File

@ -7,11 +7,11 @@ import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import java.io.File;
import java.io.IOException;
public class PDFGenerator {
// Método para generar un PDF con los detalles del ticket
public static void generarPDF(String eventName, String eventDate, String clientName, double totalPrice, String qrImagePath) {
// Ruta donde se guardará el PDF
String downloadsPath = System.getProperty("user.home") + "/Downloads/";

View File

@ -6,11 +6,14 @@ import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Alert; // Nuevo: Importación para usar Alert
import javafx.scene.image.Image; // Nuevo: Importación para usar Image
import javafx.scene.image.ImageView; // Nuevo: Importación para usar ImageView
import javafx.scene.control.Alert;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.sql.*;
@ -24,47 +27,59 @@ public class VentaBoletos extends Application {
private static final String DB_USER = "sql10766655";
private static final String DB_PASSWORD = "7BZbRjEkXZ";
private List<Integer> selectedSeats = new ArrayList<>();
private Map<Integer, Double> seatPrices = new HashMap<>(); // Nuevo: Mapa para almacenar precios de asientos
private String eventName = ""; // Nuevo: Variable para almacenar el nombre del evento
private String eventDate = ""; // Nuevo: Variable para almacenar la fecha del evento
private GridPane seatGrid; // Nuevo: Referencia a la cuadrícula de asientos
private Stage mainStage; // Nuevo: Referencia al Stage principal
private Map<Integer, Double> seatPrices = new HashMap<>();
private String eventName = "";
private String eventDate = "";
private int eventId = 0;
private GridPane seatGrid;
private Stage mainStage;
@Override
public void start(Stage mainStage) {
this.mainStage = mainStage; // Nuevo: Guardar referencia al Stage principal
this.mainStage = mainStage;
EscogerEvento escogerEvento = new EscogerEvento();
escogerEvento.mostrarVentanaSeleccionEvento(mainStage, this);
}
public void setEventId(int eventId) {
this.eventId = eventId;
}
public void cargarInformacionEvento() {
try (Connection conexion = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD)) {
String eventQuery = "SELECT nombre, fecha FROM conciertos WHERE id = ?";
PreparedStatement eventStatement = conexion.prepareStatement(eventQuery);
eventStatement.setInt(1, eventId);
ResultSet eventResultSet = eventStatement.executeQuery();
if (eventResultSet.next()) {
eventName = eventResultSet.getString("nombre");
eventDate = eventResultSet.getString("fecha");
}
} catch (SQLException e) {
System.out.println("Error al cargar la información del evento.");
e.printStackTrace();
}
}
public void mostrarVentanaVentaBoletos(Stage mainStage) {
int totalSeats = 0;
Map<Integer, String> seatStatus = new HashMap<>();
try {
Connection conexion = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
System.out.println("Conexión realizada correctamente");
// Nuevo: Obtener información del evento (nombre y fecha)
String eventQuery = "SELECT nombre, fecha FROM conciertos WHERE id = 1";
Statement eventStatement = conexion.createStatement();
ResultSet eventResultSet = eventStatement.executeQuery(eventQuery);
if (eventResultSet.next()) {
eventName = eventResultSet.getString("nombre"); // Nuevo: Almacenar nombre del evento
eventDate = eventResultSet.getString("fecha"); // Nuevo: Almacenar fecha del evento
}
// Nuevo: Obtener información de los asientos (precio base y estado)
String seatQuery = "SELECT a.id, a.precio_base, b.status FROM asientos a JOIN boleto b ON a.id = b.id_asiento WHERE b.idevento = 1";
Statement seatStatement = conexion.createStatement();
ResultSet seatResultSet = seatStatement.executeQuery(seatQuery);
try (Connection conexion = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD)) {
String seatQuery = "SELECT a.id, a.precio_base, b.status FROM asientos a JOIN boleto b ON a.id = b.id_asiento WHERE b.idevento = ?";
PreparedStatement seatStatement = conexion.prepareStatement(seatQuery);
seatStatement.setInt(1, eventId);
ResultSet seatResultSet = seatStatement.executeQuery();
while (seatResultSet.next()) {
int seatId = seatResultSet.getInt("id");
double precio = seatResultSet.getDouble("precio_base"); // Nuevo: Obtener precio del asiento
double precio = seatResultSet.getDouble("precio_base");
String status = seatResultSet.getString("status");
seatStatus.put(seatId, status);
seatPrices.put(seatId, precio); // Nuevo: Almacenar precio del asiento en el mapa
seatPrices.put(seatId, precio);
totalSeats++;
}
conexion.close();
} catch (SQLException e) {
System.out.println("Error en la conexión a la base de datos.");
e.printStackTrace();
@ -72,19 +87,26 @@ public class VentaBoletos extends Application {
mainStage.setTitle("Gestión de Boletos");
// Nuevo: Título y logo
Label titleLabel = new Label("Sala de Conciertos");
titleLabel.getStyleClass().add("title"); // Nuevo: Aplicar clase CSS
// Modificado: Título con el nombre del evento
Label titleLabel = new Label(eventName);
titleLabel.getStyleClass().add("title");
ImageView logo = new ImageView(new Image(getClass().getResourceAsStream("/logo.png"))); // Nuevo: Cargar imagen del logo
logo.setFitWidth(100); // Nuevo: Ajustar ancho del logo
logo.setFitHeight(100); // Nuevo: Ajustar altura del logo
// Agregar el logo de la aplicación
ImageView logo = new ImageView(new Image(getClass().getResourceAsStream("/logo.png")));
logo.setFitWidth(100);
logo.setFitHeight(100);
// Crear y configurar el label de bienvenida
Label welcomeLabel = new Label("Seleccione sus asientos");
seatGrid = new GridPane(); // Nuevo: Inicializar la cuadrícula de asientos
seatGrid.getStyleClass().add("seat-grid"); // Nuevo: Aplicar clase CSS
seatGrid = new GridPane();
seatGrid.getStyleClass().add("seat-grid");
seatGrid.setHgap(10); // Espaciado horizontal entre celdas
seatGrid.setVgap(10); // Espaciado vertical entre celdas
seatGrid.setPadding(new Insets(20)); // Padding alrededor del GridPane
// Crear y configurar el botón de confirmación
Button confirmButton = new Button("Confirmar Compra");
confirmButton.getStyleClass().add("button"); // Nuevo: Aplicar clase CSS
confirmButton.getStyleClass().add("button");
int cols = 5;
int rows = (int) Math.ceil((double) totalSeats / cols);
@ -92,8 +114,13 @@ public class VentaBoletos extends Application {
for (int seatNumber = 1; seatNumber <= totalSeats; seatNumber++) {
int row = (seatNumber - 1) / cols;
int col = (seatNumber - 1) % cols;
Button seatButton = new Button("Asiento " + seatNumber);
seatButton.getStyleClass().add("seat-button"); // Nuevo: Aplicar clase CSS
char rowLetter = (char) ('A' + row);
String seatLabel = rowLetter + String.valueOf(col + 1);
Button seatButton = new Button(seatLabel);
seatButton.getStyleClass().add("seat-button");
seatButton.setMinSize(80, 40); // Tamaño mínimo de cada botón
seatButton.setMaxSize(80, 40); // Tamaño máximo de cada botón
seatButton.setPadding(new Insets(10)); // Padding dentro de cada botón
int finalSeatNumber = seatNumber;
if ("vendido".equals(seatStatus.getOrDefault(finalSeatNumber, "disponible"))) {
@ -102,7 +129,7 @@ public class VentaBoletos extends Application {
seatButton.setOnAction(e -> {
if (!selectedSeats.contains(finalSeatNumber)) {
selectedSeats.add(finalSeatNumber);
seatButton.setStyle("-fx-background-color: #45a049;"); // Nuevo: Cambiar color a verde más oscuro
seatButton.setStyle("-fx-background-color: #45a049;");
} else {
selectedSeats.remove(Integer.valueOf(finalSeatNumber));
seatButton.setStyle("");
@ -112,7 +139,6 @@ public class VentaBoletos extends Application {
seatGrid.add(seatButton, col, row);
}
// Nuevo: Lógica para el botón de confirmar compra
confirmButton.setOnAction(e -> {
if (selectedSeats.isEmpty()) {
mostrarAlerta("Advertencia", "No se han seleccionado asientos", "Por favor, seleccione al menos un asiento.");
@ -122,23 +148,45 @@ public class VentaBoletos extends Application {
final String finalEventName = eventName;
final String finalEventDate = eventDate;
VentanaPago ventanaPago = new VentanaPago(this); // Nuevo: Crear ventana de pago
VentanaPago ventanaPago = new VentanaPago(this);
ventanaPago.mostrarVentanaPago(finalSelectedSeats, finalSeatPrices, finalEventName, finalEventDate);
}
});
// Nuevo: Layout principal con logo, título, cuadrícula y botón
VBox mainLayout = new VBox(20, logo, titleLabel, welcomeLabel, seatGrid, confirmButton);
mainLayout.setAlignment(Pos.TOP_CENTER); // Nuevo: Centrar elementos
mainLayout.setPadding(new Insets(20)); // Nuevo: Agregar padding
// Nuevo: Botón para regresar a la ventana de selección de eventos
Button backButton = new Button("Regresar");
backButton.getStyleClass().add("button");
backButton.setOnAction(e -> {
EscogerEvento escogerEvento = new EscogerEvento();
escogerEvento.mostrarVentanaSeleccionEvento(mainStage, this);
});
Scene mainScene = new Scene(mainLayout, 600, 500); // Nuevo: Aumentar tamaño de la ventana
mainScene.getStylesheets().add(getClass().getResource("/styles.css").toExternalForm()); // Nuevo: Aplicar CSS
// Añadir sombra al botón "Regresar"
DropShadow shadow = new DropShadow();
shadow.setColor(Color.rgb(0, 0, 0, 0.25));
shadow.setRadius(10);
shadow.setOffsetX(0);
shadow.setOffsetY(2);
backButton.setEffect(shadow);
// Colocar el botón "Regresar" en la esquina superior izquierda
BorderPane borderPane = new BorderPane();
borderPane.setPadding(new Insets(10));
borderPane.setTop(backButton);
BorderPane.setAlignment(backButton, Pos.TOP_LEFT);
VBox mainLayout = new VBox(20, logo, titleLabel, welcomeLabel, seatGrid, confirmButton);
mainLayout.setAlignment(Pos.TOP_CENTER);
mainLayout.setPadding(new Insets(20));
borderPane.setCenter(mainLayout);
Scene mainScene = new Scene(borderPane, 540, 600);
mainScene.getStylesheets().add(getClass().getResource("/styles.css").toExternalForm());
mainStage.setScene(mainScene);
mainStage.show();
}
// Nuevo: Método para refrescar la interfaz después de una compra
public void refrescarInterfaz() {
selectedSeats.clear();
Map<Integer, String> seatStatus = cargarEstadoAsientos();
@ -151,8 +199,13 @@ public class VentaBoletos extends Application {
for (int seatNumber = 1; seatNumber <= totalSeats; seatNumber++) {
int row = (seatNumber - 1) / cols;
int col = (seatNumber - 1) % cols;
Button seatButton = new Button("Asiento " + seatNumber);
seatButton.getStyleClass().add("seat-button"); // Nuevo: Aplicar clase CSS
char rowLetter = (char) ('A' + row);
String seatLabel = rowLetter + String.valueOf(col + 1);
Button seatButton = new Button(seatLabel);
seatButton.getStyleClass().add("seat-button");
seatButton.setMinSize(80, 40); // Tamaño mínimo de cada botón
seatButton.setMaxSize(80, 40); // Tamaño máximo de cada botón
seatButton.setPadding(new Insets(10)); // Padding dentro de cada botón
int finalSeatNumber = seatNumber;
if ("vendido".equals(seatStatus.getOrDefault(finalSeatNumber, "disponible"))) {
@ -161,7 +214,7 @@ public class VentaBoletos extends Application {
seatButton.setOnAction(e -> {
if (!selectedSeats.contains(finalSeatNumber)) {
selectedSeats.add(finalSeatNumber);
seatButton.setStyle("-fx-background-color: #45a049;"); // Nuevo: Cambiar color a verde más oscuro
seatButton.setStyle("-fx-background-color: #45a049;");
} else {
selectedSeats.remove(Integer.valueOf(finalSeatNumber));
seatButton.setStyle("");
@ -172,14 +225,14 @@ public class VentaBoletos extends Application {
}
}
// Nuevo: Método para cargar el estado de los asientos desde la base de datos
private Map<Integer, String> cargarEstadoAsientos() {
Map<Integer, String> seatStatus = new HashMap<>();
try (Connection conexion = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD)) {
String query = "SELECT id_asiento, status FROM boleto WHERE idevento = 1";
Statement statement = conexion.createStatement();
ResultSet resultSet = statement.executeQuery(query);
String query = "SELECT id_asiento, status FROM boleto WHERE idevento = ?";
PreparedStatement statement = conexion.prepareStatement(query);
statement.setInt(1, eventId);
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
int seatId = resultSet.getInt("id_asiento");
@ -194,8 +247,7 @@ public class VentaBoletos extends Application {
return seatStatus;
}
// Nuevo: Método para mostrar alertas
private void mostrarAlerta(String titulo, String encabezado, String contenido) {
public void mostrarAlerta(String titulo, String encabezado, String contenido) {
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle(titulo);
alert.setHeaderText(encabezado);

View File

@ -6,8 +6,6 @@ import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import java.sql.*;
import java.util.List;
import java.util.Map;
@ -38,11 +36,14 @@ public class VentanaPago {
// Detalles del evento
Label eventLabel = new Label("Evento: " + eventName);
eventLabel.getStyleClass().add("label"); // Aplicar clase CSS
Label dateLabel = new Label("Fecha: " + eventDate);
dateLabel.getStyleClass().add("label"); // Aplicar clase CSS
// Calcular el precio total
double totalPrice = selectedSeats.stream().mapToInt(seat -> seat).mapToDouble(seatPrices::get).sum();
Label totalLabel = new Label("Total a pagar: $" + String.format("%.2f", totalPrice));
totalLabel.getStyleClass().add("label"); // Aplicar clase CSS
// Campo para ingresar el nombre del cliente
TextField nameField = new TextField();

View File

@ -1,20 +1,24 @@
/* styles.css */
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
.root {
-fx-background-color: #f4f4f4; /* Fondo claro */
-fx-font-family: 'Roboto', 'Helvetica Neue', 'Arial', sans-serif;
-fx-background-color: rgba(248, 248, 248, 0.9); /* Fondo con transparencia */
}
.seat-button {
-fx-background-color: #4CAF50; /* Verde */
-fx-text-fill: white;
-fx-background-color: #e0e0e0;
-fx-text-fill: #333;
-fx-font-size: 14px;
-fx-font-weight: bold;
-fx-padding: 10px;
-fx-border-radius: 5px;
-fx-background-radius: 5px;
-fx-background-radius: 10px;
-fx-border-radius: 10px;
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.25), 10, 0, 0, 2);
}
.seat-button:disabled {
-fx-background-color: #f44336; /* Rojo para asientos vendidos */
-fx-background-color: #d0d0d0;
-fx-text-fill: #999;
}
.seat-grid {
@ -38,19 +42,24 @@
.title {
-fx-font-size: 24px;
-fx-font-weight: bold;
-fx-text-fill: #333333;
-fx-text-fill: #333;
}
.button {
-fx-background-color: #2196F3; /* Azul */
-fx-background-color: #007aff;
-fx-text-fill: white;
-fx-font-size: 14px;
-fx-font-weight: bold;
-fx-padding: 10px 20px;
-fx-border-radius: 5px;
-fx-background-radius: 5px;
-fx-background-radius: 10px;
-fx-border-radius: 10px;
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.25), 10, 0, 0, 2);
}
.button:hover {
-fx-background-color: #1976D2; /* Azul más oscuro al pasar el mouse */
-fx-background-color: #005bb5;
}
.label {
-fx-font-size: 16px;
-fx-text-fill: #333;
}