v1.0 Inicial

This commit is contained in:
Felipe Murguia 2025-03-12 15:19:57 -06:00
parent 86cda061d8
commit 207e67dd35
5 changed files with 345 additions and 49 deletions

View File

@ -29,6 +29,12 @@
<version>21</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
@ -52,7 +58,7 @@
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.3</version>
<version>2.0.24</version>
</dependency>
</dependencies>

View File

@ -3,6 +3,7 @@ package org.example.saladeconciertos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
@ -10,12 +11,17 @@ import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.scene.control.ButtonType;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class EscogerEvento {
// Datos de conexión a la base de datos
@ -40,6 +46,10 @@ public class EscogerEvento {
Button confirmButton = new Button("Confirmar");
confirmButton.getStyleClass().add("button");
// Crear y configurar el botón de generar reporte
Button reportButton = new Button("Generar Reporte");
reportButton.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";
@ -78,20 +88,116 @@ public class EscogerEvento {
}
});
// Acción del botón de generar reporte
reportButton.setOnAction(e -> {
String selectedEvent = eventComboBox.getValue();
if (selectedEvent != null) {
int eventId = Integer.parseInt(selectedEvent.split(" - ")[0]);
generarReporte(eventId, selectedEvent.split(" - ")[1]);
} 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);
VBox layout = new VBox(20, logo, selectEventLabel, eventComboBox, selectedEventLabel, confirmButton, reportButton);
layout.setAlignment(Pos.CENTER);
layout.setPadding(new Insets(20));
// Crear y configurar la escena
Scene scene = new Scene(layout, 400, 300);
Scene scene = new Scene(layout, 400, 400);
scene.getStylesheets().add(getClass().getResource("/styles.css").toExternalForm());
mainStage.setScene(scene);
mainStage.show();
}
// Método para convertir IDs de asientos a nombres de asientos
private String convertirIdAsientoANombre(int seatId) {
int fila = (seatId - 1) / 5;
int numero = (seatId - 1) % 5 + 1;
char filaLetra = (char) ('A' + fila);
return filaLetra + String.valueOf(numero);
}
// Método para generar el reporte de boletos vendidos
private void generarReporte(int eventId, String eventName) {
List<String> seatDetails = new ArrayList<>();
StringBuilder reportContent = new StringBuilder();
reportContent.append("Reporte de Boletos Vendidos\n");
// Obtener la fecha del evento
String eventDate = "";
try (Connection conexion = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD)) {
String eventQuery = "SELECT fecha FROM conciertos WHERE id = ?";
PreparedStatement eventStatement = conexion.prepareStatement(eventQuery);
eventStatement.setInt(1, eventId);
ResultSet eventResultSet = eventStatement.executeQuery();
if (eventResultSet.next()) {
eventDate = eventResultSet.getDate("fecha").toString();
}
} catch (SQLException e) {
System.out.println("Error al obtener la fecha del evento.");
e.printStackTrace();
}
reportContent.append("Evento: ").append(eventName).append(" - Fecha: ").append(eventDate).append("\n\n");
try (Connection conexion = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD)) {
String query = "SELECT a.id, a.precio_base, b.fechaVenta FROM asientos a JOIN boleto b ON a.id = b.id_asiento WHERE b.idevento = ? AND b.status = 'vendido'";
PreparedStatement statement = conexion.prepareStatement(query);
statement.setInt(1, eventId);
ResultSet resultSet = statement.executeQuery();
while (resultSet.next()) {
int seatId = resultSet.getInt("id");
double price = resultSet.getDouble("precio_base");
Date saleDate = resultSet.getDate("fechaVenta");
String seatName = convertirIdAsientoANombre(seatId);
String seatDetail = "Asiento: " + seatName + ", Precio: $" + price + ", Fecha de Venta: " + saleDate;
seatDetails.add(seatDetail);
reportContent.append(seatDetail).append("\n");
}
} catch (SQLException e) {
System.out.println("Error al generar el reporte.");
e.printStackTrace();
}
// Mostrar el reporte en una alerta
mostrarAlertaConBotonPDF("Reporte de Boletos Vendidos", "Detalles del Reporte", reportContent.toString(), eventName + " - Fecha: " + eventDate, seatDetails);
}
// Método para mostrar una alerta con un botón para generar PDF
private void mostrarAlertaConBotonPDF(String titulo, String encabezado, String contenido, String eventName, List<String> seatDetails) {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle(titulo);
alert.setHeaderText(encabezado);
alert.setContentText(contenido);
ButtonType buttonTypePDF = new ButtonType("Generar PDF");
alert.getButtonTypes().add(buttonTypePDF);
alert.showAndWait().ifPresent(response -> {
if (response == buttonTypePDF) {
// Generar el PDF del reporte usando la clase PDFGenerator
String qrImagePath = "src/main/resources/qrcode.png"; // Cambia esto por la ruta de tu imagen QR
String timestamp = new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date());
String pdfFileName = eventName.replace(" ", "_") + "_" + timestamp + ".pdf";
PDFGenerator.generarPDF(eventName, "", "", 0.0, qrImagePath, String.join("\n", seatDetails), pdfFileName);
}
});
}
// Método para mostrar una alerta
private void mostrarAlerta(String titulo, String encabezado, String contenido) {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle(titulo);
alert.setHeaderText(encabezado);
alert.setContentText(contenido);
alert.showAndWait();
}
}

View File

@ -3,7 +3,6 @@ package org.example.saladeconciertos;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
@ -11,12 +10,11 @@ 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) {
// Método para generar un PDF con los detalles del reporte de ventas
public static void generarPDF(String eventName, String eventDate, String clientName, double totalPrice, String qrImagePath, String ticketDetails, String pdfFileName) {
// Ruta donde se guardará el PDF
String downloadsPath = System.getProperty("user.home") + "/Downloads/";
String fileName = "Ticket_" + eventName.replace(" ", "_") + ".pdf";
String pdfPath = downloadsPath + fileName;
String pdfPath = downloadsPath + pdfFileName;
try (PDDocument document = new PDDocument()) {
// Crear una nueva página
@ -25,26 +23,87 @@ public class PDFGenerator {
// Crear un flujo de contenido para la página
try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
// Configurar la fuente y el tamaño (usando Standard14Fonts)
PDType1Font font = new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD);
contentStream.setFont(font, 12);
// Escribir los detalles del ticket
// Configurar la fuente y el tamaño para el título del evento
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 24);
contentStream.beginText();
contentStream.newLineAtOffset(50, 700);
contentStream.showText("Evento: " + eventName);
contentStream.newLineAtOffset(0, -20);
contentStream.showText("Fecha: " + eventDate);
contentStream.newLineAtOffset(0, -20);
contentStream.showText("Cliente: " + clientName);
contentStream.newLineAtOffset(0, -20);
contentStream.showText("Total: $" + String.format("%.2f", totalPrice));
contentStream.newLineAtOffset(50, 750);
contentStream.showText(eventName);
contentStream.endText();
// Configurar la fuente y el tamaño para la fecha del evento
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 18);
contentStream.beginText();
contentStream.newLineAtOffset(50, 720);
contentStream.endText();
// Configurar la fuente y el tamaño para el contenido del reporte
contentStream.setFont(PDType1Font.HELVETICA, 12);
contentStream.beginText();
contentStream.newLineAtOffset(50, 680);
// Dividir el texto en líneas y escribir cada línea por separado
String[] lines = ticketDetails.split("\n");
for (String line : lines) {
contentStream.showText(line);
contentStream.newLineAtOffset(0, -15); // Mover hacia abajo para la siguiente línea
}
contentStream.endText();
// Agregar la imagen del código QR (si existe)
if (qrImagePath != null && !qrImagePath.isEmpty()) {
PDImageXObject qrImage = PDImageXObject.createFromFile(qrImagePath, document);
contentStream.drawImage(qrImage, 50, 500, 150, 150); // Ajusta la posición y el tamaño de la imagen
contentStream.drawImage(qrImage, 50, 50, 150, 150); // Ajusta la posición y el tamaño de la imagen
}
}
// Guardar el PDF en la carpeta de descargas
document.save(pdfPath);
System.out.println("Reporte generado y guardado en: " + pdfPath);
} catch (IOException e) {
e.printStackTrace();
System.out.println("Error al generar el PDF del reporte.");
}
}
// Método para generar un PDF con los detalles del ticket de compra
public static void generarTicketPDF(String eventName, String eventDate, String clientName, double totalPrice, String qrImagePath, String ticketDetails, String pdfFileName) {
// Ruta donde se guardará el PDF
String downloadsPath = System.getProperty("user.home") + "/Downloads/";
String pdfPath = downloadsPath + pdfFileName;
try (PDDocument document = new PDDocument()) {
// Crear una nueva página
PDPage page = new PDPage();
document.addPage(page);
// Crear un flujo de contenido para la página
try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
// Configurar la fuente y el tamaño para el título
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 20);
contentStream.beginText();
contentStream.newLineAtOffset(50, 750);
contentStream.showText("Ticket de Compra");
contentStream.endText();
// Configurar la fuente y el tamaño para el contenido
contentStream.setFont(PDType1Font.HELVETICA, 12);
contentStream.beginText();
contentStream.newLineAtOffset(50, 700);
// Dividir el texto en líneas y escribir cada línea por separado
String[] lines = ticketDetails.split("\n");
for (String line : lines) {
contentStream.showText(line);
contentStream.newLineAtOffset(0, -15); // Mover hacia abajo para la siguiente línea
}
contentStream.endText();
// Agregar la imagen del código QR
if (qrImagePath != null && !qrImagePath.isEmpty()) {
PDImageXObject qrImage = PDImageXObject.createFromFile(qrImagePath, document);
contentStream.drawImage(qrImage, 50, 50, 150, 150); // Ajusta la posición y el tamaño de la imagen
}
}

View File

@ -4,9 +4,9 @@ import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Alert;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
@ -16,11 +16,12 @@ import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
public class VentaBoletos extends Application {
private static final String DB_URL = "jdbc:mysql://sql10.freesqldatabase.com:3306/sql10766655";
@ -41,6 +42,10 @@ public class VentaBoletos extends Application {
escogerEvento.mostrarVentanaSeleccionEvento(mainStage, this);
}
public int getEventId() {
return eventId;
}
public void setEventId(int eventId) {
this.eventId = eventId;
}
@ -255,6 +260,24 @@ public class VentaBoletos extends Application {
alert.showAndWait();
}
public void actualizarEstadoBoletos(List<Integer> selectedSeats, int idevento) {
try (Connection conexion = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD)) {
String updateQuery = "UPDATE boleto SET status = 'vendido', fechaVenta = CURDATE() WHERE id_asiento = ? AND idevento = ?";
PreparedStatement preparedStatement = conexion.prepareStatement(updateQuery);
for (int seat : selectedSeats) {
preparedStatement.setInt(1, seat);
preparedStatement.setInt(2, idevento);
preparedStatement.executeUpdate();
}
System.out.println("Estado de los boletos actualizado correctamente.");
} catch (SQLException e) {
System.out.println("Error al actualizar el estado de los boletos.");
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}

View File

@ -7,6 +7,8 @@ import javafx.stage.Stage;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -45,11 +47,19 @@ public class VentanaPago {
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
// Campos para ingresar el nombre del cliente
TextField nameField = new TextField();
nameField.setPromptText("Nombre del cliente");
nameField.setPromptText("Nombre");
nameField.setMaxWidth(200);
TextField lastNameField = new TextField();
lastNameField.setPromptText("Apellido Paterno");
lastNameField.setMaxWidth(200);
TextField secondLastNameField = new TextField();
secondLastNameField.setPromptText("Apellido Materno");
secondLastNameField.setMaxWidth(200);
// Selección de método de pago
ChoiceBox<String> paymentMethod = new ChoiceBox<>();
paymentMethod.getItems().addAll("Tarjeta de Crédito/Débito", "PayPal");
@ -88,6 +98,11 @@ public class VentanaPago {
payButton.getStyleClass().add("button"); // Aplicar clase CSS
payButton.setDisable(true); // Deshabilitar al inicio
// Botón para generar el PDF
Button pdfButton = new Button("Generar PDF");
pdfButton.getStyleClass().add("button"); // Aplicar clase CSS
pdfButton.setDisable(true); // Deshabilitar al inicio
// Contenedor dinámico para campos y botón
VBox dynamicContainer = new VBox(10);
dynamicContainer.setAlignment(Pos.TOP_CENTER); // Centrar el contenido
@ -102,22 +117,27 @@ public class VentanaPago {
// Habilitar el botón de pago si se selecciona un método
payButton.setDisable(newVal == null);
pdfButton.setDisable(newVal == null);
// Actualizar el contenedor dinámico
dynamicContainer.getChildren().clear();
if (isCard) {
dynamicContainer.getChildren().addAll(cardFields, payButton);
dynamicContainer.getChildren().addAll(cardFields, payButton, pdfButton);
} else if (isPayPal) {
dynamicContainer.getChildren().addAll(paypalFields, payButton);
dynamicContainer.getChildren().addAll(paypalFields, payButton, pdfButton);
} else {
dynamicContainer.getChildren().add(payButton);
dynamicContainer.getChildren().addAll(payButton, pdfButton);
}
});
payButton.setOnAction(e -> {
String clientName = nameField.getText();
if (clientName.isEmpty()) {
mostrarAlerta("Advertencia", "Nombre del cliente vacío", "Por favor, ingrese el nombre del cliente.");
String name = nameField.getText();
String lastName = lastNameField.getText();
String secondLastName = secondLastNameField.getText();
String clientName = name + " " + lastName + " " + secondLastName;
if (name.isEmpty() || lastName.isEmpty() || secondLastName.isEmpty()) {
mostrarAlerta("Advertencia", "Nombre del cliente vacío", "Por favor, ingrese el nombre completo del cliente.");
return;
}
@ -140,15 +160,50 @@ public class VentanaPago {
}
// Si todo está correcto, generar el ticket
generarTicket(clientName, selectedSeats, seatPrices, eventName, eventDate, totalPrice);
generarTicket(clientName, selectedSeats, seatPrices, eventName, eventDate, totalPrice, paymentLayout, method);
paymentStage.close();
ventaBoletos.refrescarInterfaz();
});
pdfButton.setOnAction(e -> {
String name = nameField.getText();
String lastName = lastNameField.getText();
String secondLastName = secondLastNameField.getText();
String clientName = name + " " + lastName + " " + secondLastName;
if (name.isEmpty() || lastName.isEmpty() || secondLastName.isEmpty()) {
mostrarAlerta("Advertencia", "Nombre del cliente vacío", "Por favor, ingrese el nombre completo del cliente.");
return;
}
String method = paymentMethod.getValue();
if (method.equals("Tarjeta de Crédito/Débito")) {
String cardNumber = cardNumberField.getText();
String expiryDate = expiryDateField.getText();
String cvv = cvvField.getText();
if (!validarTarjeta(cardNumber, expiryDate, cvv)) {
mostrarAlerta("Error", "Datos de tarjeta inválidos", "Por favor, ingrese un número de tarjeta válido (13 dígitos), fecha (MM/YY) y CVV.");
return;
}
} else if (method.equals("PayPal")) {
String email = emailField.getText();
if (!validarEmail(email)) {
mostrarAlerta("Error", "Correo inválido", "Por favor, ingrese un correo electrónico válido.");
return;
}
}
// Generar el PDF del ticket
generarPDF(clientName, selectedSeats, seatPrices, eventName, eventDate, totalPrice, method);
});
// Agregar elementos al layout
paymentLayout.getChildren().addAll(
titleLabel, eventLabel, dateLabel, totalLabel,
new Label("Nombre del cliente:"), nameField,
new Label("Nombre:"), nameField,
new Label("Apellido Paterno:"), lastNameField,
new Label("Apellido Materno:"), secondLastNameField,
new Label("Método de pago:"), paymentMethod,
dynamicContainer
);
@ -175,26 +230,52 @@ public class VentanaPago {
return email.matches("^[A-Za-z0-9+_.-]+@(.+)$"); // Validación básica de correo
}
private void generarTicket(String clientName, List<Integer> selectedSeats, Map<Integer, Double> seatPrices, String eventName, String eventDate, double totalPrice) {
// Mostrar el ticket en una ventana (como antes)
private void generarTicket(String clientName, List<Integer> selectedSeats, Map<Integer, Double> seatPrices, String eventName, String eventDate, double totalPrice, VBox paymentLayout, String paymentMethod) {
// Mostrar el ticket en una ventana
StringBuilder ticketDetails = new StringBuilder();
ticketDetails.append("Evento: ").append(eventName).append("\n");
ticketDetails.append("Fecha: ").append(eventDate).append("\n");
ticketDetails.append("Cliente: ").append(clientName).append("\n");
ticketDetails.append("Asientos: ");
ticketDetails.append("Evento: ").append(eventName).append("\n");
ticketDetails.append("Fecha de evento: ").append(eventDate).append("\n");
ticketDetails.append("Fecha de compra: ").append(new SimpleDateFormat("yyyy/MM/dd").format(new Date())).append("\n");
ticketDetails.append("Método de pago: ").append(paymentMethod).append("\n");
ticketDetails.append("Asientos: ").append(selectedSeats.size() > 1 ? "\n" : "");
for (int seat : selectedSeats) {
ticketDetails.append(seat).append(" ($").append(String.format("%.2f", seatPrices.get(seat))).append("), ");
String seatName = convertirIdAsientoANombre(seat);
ticketDetails.append(seatName).append(" ($").append(String.format("%.2f", seatPrices.get(seat))).append("), ");
}
ticketDetails.append("\nTotal: $").append(String.format("%.2f", totalPrice));
mostrarAlerta("Ticket Generado", "Detalles del Ticket", ticketDetails.toString());
// Generar el PDF del ticket usando la clase PDFGenerator
String qrImagePath = "src/main/resources/qrcode.png"; // Cambia esto por la ruta de tu imagen QR
PDFGenerator.generarPDF(eventName, eventDate, clientName, totalPrice, qrImagePath);
// Actualizar el estado de los boletos comprados en la base de datos
actualizarEstadoBoletos(selectedSeats, 1); // Cambia el idevento según corresponda
actualizarEstadoBoletos(selectedSeats, ventaBoletos.getEventId()); // Cambia el idevento según corresponda
// Generar el PDF del ticket usando la clase PDFGenerator
String qrImagePath = "src/main/resources/qrcode.png"; // Ruta de tu imagen QR
String pdfFileName = "ticket_" + System.currentTimeMillis() + ".pdf";
PDFGenerator.generarTicketPDF(eventName, eventDate, clientName, totalPrice, qrImagePath, ticketDetails.toString(), pdfFileName);
// Mostrar alerta de que el ticket fue guardado
mostrarAlertaTicketGuardado(pdfFileName, paymentLayout);
}
private void generarPDF(String clientName, List<Integer> selectedSeats, Map<Integer, Double> seatPrices, String eventName, String eventDate, double totalPrice, String paymentMethod) {
// Generar el PDF del ticket usando la clase PDFGenerator
String qrImagePath = "src/main/resources/qrcode.png"; // Ruta de tu imagen QR
StringBuilder ticketDetails = new StringBuilder();
ticketDetails.append("Evento: ").append(eventName).append("\n");
ticketDetails.append("Fecha: ").append(new SimpleDateFormat("dd/MM/yyyy").format(new Date())).append("\n");
ticketDetails.append("Cliente: ").append(clientName).append("\n");
ticketDetails.append("Método de pago: ").append(paymentMethod).append("\n");
ticketDetails.append("Asientos: ");
for (int seat : selectedSeats) {
String seatName = convertirIdAsientoANombre(seat);
ticketDetails.append(seatName).append(" ($").append(String.format("%.2f", seatPrices.get(seat))).append("), ");
}
ticketDetails.append("\nTotal: $").append(String.format("%.2f", totalPrice));
String pdfFileName = "ticket_" + System.currentTimeMillis() + ".pdf";
PDFGenerator.generarTicketPDF(eventName, eventDate, clientName, totalPrice, qrImagePath, ticketDetails.toString(), pdfFileName);
}
private void actualizarEstadoBoletos(List<Integer> selectedSeats, int idevento) {
@ -222,4 +303,25 @@ public class VentanaPago {
alert.setContentText(contenido);
alert.showAndWait();
}
private void mostrarAlertaTicketGuardado(String pdfFileName, VBox paymentLayout) {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Ticket Guardado");
alert.setHeaderText("Ticket Guardado");
alert.setContentText("El ticket ha sido guardado en la carpeta Descargas como " + pdfFileName);
alert.showAndWait().ifPresent(response -> {
// Cerrar la ventana de pago y regresar a la ventana de selección de asientos
Stage stage = (Stage) paymentLayout.getScene().getWindow();
stage.close();
ventaBoletos.refrescarInterfaz();
});
}
private String convertirIdAsientoANombre(int seatId) {
int fila = (seatId - 1) / 5;
int numero = (seatId - 1) % 5 + 1;
char filaLetra = (char) ('A' + fila);
return filaLetra + String.valueOf(numero);
}
}