diff --git a/medical_invoice.pdf b/medical_invoice.pdf index d65b208..17d6769 100644 Binary files a/medical_invoice.pdf and b/medical_invoice.pdf differ diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java b/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java index 3b6195b..74ab076 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java @@ -1614,25 +1614,42 @@ public class CheckUpPage extends JPanel { log.info("Medicine prescription: {}", (Object) medicinePrescription); break; case "printer": - if ((medicinePrescription == null || medicinePrescription.length == 0) && + if ((medicinePrescription == null || medicinePrescription.length == 0) && (servicePrescription == null || servicePrescription.length == 0)) { return; // Just return silently if there's nothing to print } MedicineInvoice medicineInvoice = new MedicineInvoice(checkupIdField.getText(), customerLastNameField.getText() + " " + customerFirstNameField.getText(), dobPicker.getJFormattedTextField().getText(), customerPhoneField.getText(), - genderComboBox.getSelectedItem().toString(), + genderComboBox.getSelectedItem().toString(), customerAddressField.getText() + ", " + (wardComboBox.getSelectedItem() != null ? wardComboBox.getSelectedItem().toString() : "") + ", " + (districtComboBox.getSelectedItem() != null ? districtComboBox.getSelectedItem().toString() : "") + ", " + (provinceComboBox.getSelectedItem() != null ? provinceComboBox.getSelectedItem().toString() : ""), doctorComboBox.getSelectedItem().toString(), diagnosisField.getText(), - conclusionField.getText(), medicinePrescription, servicePrescription, - // fake supplements - new String[][] { - {"1", "Vitamin D3", "1", "viên", "1 viên/ngày sau ăn sáng", "30", "2000", "60000", "Bổ sung vitamin D"}, - {"2", "Omega 3", "2", "viên", "2 viên/ngày sau ăn", "60", "1500", "90000", "Bổ sung dầu cá"}, - {"3", "Calcium 500mg", "1", "viên", "1 viên/ngày sau ăn tối", "30", "2500", "75000", "Bổ sung canxi"} - } - ); - medicineInvoice.showDirectJasperViewer(); // Use the direct JasperViewer method + conclusionField.getText(), medicinePrescription, servicePrescription, + new String[][]{} // No supplements for now + ); + // First, show the print preview to the user + medicineInvoice.showDirectJasperViewer(); + + // Then, asynchronously generate the PDF bytes and upload them + medicineInvoice.generatePdfBytesAsync().thenAccept(pdfBytes -> { + if (pdfBytes != null && pdfBytes.length > 0) { + String checkupId = checkupIdField.getText(); + String fileName = "medserinvoice.pdf"; + String pdfType = "medserinvoice"; + + log.info("Uploading {} ({}) for checkupId: {}", fileName, pdfType, checkupId); + + UploadCheckupPdfRequest request = new UploadCheckupPdfRequest(checkupId, pdfBytes, fileName, pdfType); + NetworkUtil.sendPacket(ClientHandler.ctx.channel(), request); + } + }).exceptionally(ex -> { + log.error("Failed to generate or upload medicine invoice PDF", ex); + // Show error in the UI thread + SwingUtilities.invokeLater(() -> + JOptionPane.showMessageDialog(this, "Lỗi khi tạo hoặc tải lên file PDF hóa đơn: " + ex.getMessage(), "Lỗi PDF", JOptionPane.ERROR_MESSAGE) + ); + return null; + }); break; case "ultrasound": // This case now handles "Lưu & In" // Step 1: Validate conditions first. diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/MedicineInvoice.java b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/MedicineInvoice.java index b7f58d8..e6292bc 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/MedicineInvoice.java +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/MedicineInvoice.java @@ -29,6 +29,7 @@ import java.time.format.DateTimeFormatter; import java.text.DecimalFormat; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.util.concurrent.CompletableFuture; public class MedicineInvoice{ @@ -48,6 +49,19 @@ public class MedicineInvoice{ private String[][] supplements; // Name, Quantity, Price private static final DecimalFormat vndFormatter = new DecimalFormat("#,##0"); + public CompletableFuture generatePdfBytesAsync() { + return CompletableFuture.supplyAsync(() -> { + try { + return generatePdfBytes(); + } catch (Exception e) { + // Since this runs in a background thread, we can't show a dialog directly. + // We'll wrap the exception and let the caller handle it. + e.printStackTrace(); + throw new RuntimeException("Error generating PDF bytes for invoice: " + e.getMessage(), e); + } + }); + } + public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame("Medicine Invoice Test"); @@ -287,8 +301,38 @@ public class MedicineInvoice{ private JasperPrint jasperPrint; // Store JasperPrint for reuse + private byte[] generatePdfBytes() throws Exception { + try { + // This method is almost identical to generatePdf, but exports to a byte array + fillJasperPrint(); // Ensures jasperPrint is filled + return JasperExportManager.exportReportToPdf(jasperPrint); + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("Error generating PDF byte array with JasperReports: " + e.getMessage(), e); + } + } + private void generatePdf(String pdfPath) throws Exception { try { + // Refactored to use a common method to fill the report + fillJasperPrint(); + // Export to PDF file + JasperExportManager.exportReportToPdfFile(jasperPrint, pdfPath); + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("Error generating PDF with JasperReports: " + e.getMessage(), e); + } + } + + /** + * Common method to fill the JasperPrint object with data and parameters. + * This avoids code duplication between generating a file and a byte array. + */ + private void fillJasperPrint() throws JRException, FileNotFoundException { + // Only fill if it hasn't been filled already + if (jasperPrint != null) { + return; + } // 1. Create data sources for medicines, services, and supplements java.util.List medicines = new ArrayList<>(); java.util.List serviceItems = new ArrayList<>(); @@ -409,16 +453,6 @@ public class MedicineInvoice{ // 4. Fill the report with data jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, new JREmptyDataSource()); - - // 5. Export to PDF - JasperExportManager.exportReportToPdfFile(jasperPrint, pdfPath); - - inputStream.close(); - - } catch (Exception e) { - e.printStackTrace(); - throw new Exception("Error generating PDF with JasperReports: " + e.getMessage(), e); - } } private void displayPdfInLabel(String pdfPath, JPanel pdfPanel) throws Exception { diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/medserinvoice.jrxml b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/medserinvoice.jrxml index c148fc2..3a4d1ac 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/medserinvoice.jrxml +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/medserinvoice.jrxml @@ -90,7 +90,7 @@ - + @@ -111,7 +111,7 @@ - + @@ -120,7 +120,7 @@ - + @@ -141,7 +141,7 @@ - + @@ -160,7 +160,7 @@ - + @@ -180,7 +180,7 @@ - + @@ -191,7 +191,7 @@ - + @@ -204,7 +204,7 @@ - + @@ -225,7 +225,7 @@ - + @@ -236,7 +236,7 @@ - + @@ -253,7 +253,7 @@ - + @@ -301,7 +301,7 @@ - + @@ -322,7 +322,7 @@ - + @@ -331,7 +331,7 @@ - + @@ -351,7 +351,7 @@ - + @@ -370,7 +370,7 @@ - + @@ -390,7 +390,7 @@ - + @@ -401,7 +401,7 @@ - + @@ -413,7 +413,7 @@ - + @@ -434,7 +434,7 @@ - + @@ -445,7 +445,7 @@ - + @@ -462,7 +462,7 @@ - + @@ -506,7 +506,7 @@ - + @@ -528,7 +528,7 @@ - + @@ -537,7 +537,7 @@ - + @@ -557,7 +557,7 @@ - + @@ -576,7 +576,7 @@ - + @@ -596,7 +596,7 @@ - + @@ -607,7 +607,7 @@ - + @@ -619,7 +619,7 @@ - + @@ -640,7 +640,7 @@ - + @@ -651,7 +651,7 @@ - + @@ -668,7 +668,7 @@ - +