From 207e67dd35436acaf033857a8a5cfd47560544de Mon Sep 17 00:00:00 2001
From: Felipe Murguia <murguialeal@proton.me>
Date: Wed, 12 Mar 2025 15:19:57 -0600
Subject: [PATCH] v1.0 Inicial

---
 pom.xml                                       |   8 +-
 .../saladeconciertos/EscogerEvento.java       | 110 ++++++++++++-
 .../saladeconciertos/PDFGenerator.java        |  97 +++++++++---
 .../saladeconciertos/VentaBoletos.java        |  35 ++++-
 .../example/saladeconciertos/VentanaPago.java | 144 +++++++++++++++---
 5 files changed, 345 insertions(+), 49 deletions(-)

diff --git a/pom.xml b/pom.xml
index a5d5f46..a3f416f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -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>
diff --git a/src/main/java/org/example/saladeconciertos/EscogerEvento.java b/src/main/java/org/example/saladeconciertos/EscogerEvento.java
index 2995b9f..6af9fe3 100644
--- a/src/main/java/org/example/saladeconciertos/EscogerEvento.java
+++ b/src/main/java/org/example/saladeconciertos/EscogerEvento.java
@@ -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();
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/org/example/saladeconciertos/PDFGenerator.java b/src/main/java/org/example/saladeconciertos/PDFGenerator.java
index 4a2ffac..ac29bdc 100644
--- a/src/main/java/org/example/saladeconciertos/PDFGenerator.java
+++ b/src/main/java/org/example/saladeconciertos/PDFGenerator.java
@@ -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
                 }
             }
 
diff --git a/src/main/java/org/example/saladeconciertos/VentaBoletos.java b/src/main/java/org/example/saladeconciertos/VentaBoletos.java
index e901f85..bcd0ea5 100644
--- a/src/main/java/org/example/saladeconciertos/VentaBoletos.java
+++ b/src/main/java/org/example/saladeconciertos/VentaBoletos.java
@@ -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);
     }
diff --git a/src/main/java/org/example/saladeconciertos/VentanaPago.java b/src/main/java/org/example/saladeconciertos/VentanaPago.java
index 384037c..5d29319 100644
--- a/src/main/java/org/example/saladeconciertos/VentanaPago.java
+++ b/src/main/java/org/example/saladeconciertos/VentanaPago.java
@@ -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);
+    }
 }
\ No newline at end of file