diff --git a/.idea/misc.xml b/.idea/misc.xml index 6546f14..9dfa497 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -8,5 +8,5 @@ - + \ No newline at end of file diff --git a/.idea/runConfigurations/BSK_Server.xml b/.idea/runConfigurations/BSK_Server.xml index dcad2e6..dedfb31 100644 --- a/.idea/runConfigurations/BSK_Server.xml +++ b/.idea/runConfigurations/BSK_Server.xml @@ -1,10 +1,11 @@ - + + + \ No newline at end of file + + \ No newline at end of file diff --git a/database/BSK.db b/database/BSK.db index b45b7ca..3937548 100644 Binary files a/database/BSK.db and b/database/BSK.db differ diff --git a/pom.xml b/pom.xml index eebabc2..3154827 100644 --- a/pom.xml +++ b/pom.xml @@ -138,17 +138,6 @@ swingx 1.6.1 - - org.apache.pdfbox - pdfbox - 2.0.27 - - - com.itextpdf - itext7-core - 7.1.12 - pom - com.github.sarxos webcam-capture @@ -248,4 +237,4 @@ 5.2.5 - + \ No newline at end of file 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 770bd38..dc0772d 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java @@ -1819,28 +1819,33 @@ public class CheckUpPage extends JPanel { supplements.toArray(new String[0][]) // Pass supplements ); // First, show the print preview to the user - medicineInvoice.showDirectJasperViewer(); + try { + 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"; + // 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); + // 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; - }); + // 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; + // }); + } catch (Exception e) { + log.error("Failed to show direct JasperViewer", e); + JOptionPane.showMessageDialog(this, "Lỗi khi hiển thị hộp thoại in: " + e.getMessage(), "Lỗi In", JOptionPane.ERROR_MESSAGE); + } 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/BarcodeGenerator.java b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/BarcodeGenerator.java new file mode 100644 index 0000000..d8aae31 --- /dev/null +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/BarcodeGenerator.java @@ -0,0 +1,410 @@ +package BsK.client.ui.component.CheckUpPage.PrintDialog; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.WriterException; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.oned.Code128Writer; +import com.google.zxing.qrcode.QRCodeWriter; +import lombok.extern.slf4j.Slf4j; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Base64; + +@Slf4j +public class BarcodeGenerator { + + // Fixed paths for saving images + private static final String BARCODE_DIRECTORY = "temp/barcodes"; + private static final String QRCODE_DIRECTORY = "temp/qrcodes"; + + // Ensure directories exist + static { + try { + Files.createDirectories(Paths.get(BARCODE_DIRECTORY)); + Files.createDirectories(Paths.get(QRCODE_DIRECTORY)); + log.info("Created barcode directories: {} and {}", BARCODE_DIRECTORY, QRCODE_DIRECTORY); + } catch (IOException e) { + log.error("Failed to create barcode directories", e); + } + } + + /** + * Generates a Code 128 barcode, saves it to a fixed path, and returns the file path. + * File is saved as: temp/barcodes/barcode_{text}_{timestamp}.png + */ + public static String generateCode128AndSave(String text, int width, int height) throws WriterException, IOException { + if (text == null || text.trim().isEmpty()) { + throw new IllegalArgumentException("Barcode text cannot be null or empty"); + } + + log.info("Generating Code 128 barcode and saving to file for text: {}", text); + + Code128Writer writer = new Code128Writer(); + BitMatrix bitMatrix = writer.encode(text, BarcodeFormat.CODE_128, width, height); + BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); + + // Create filename with timestamp to avoid conflicts + String sanitizedText = sanitizeFileName(text); + String filename = String.format("barcode_%s_%d.png", sanitizedText, System.currentTimeMillis()); + String filePath = Paths.get(BARCODE_DIRECTORY, filename).toString(); + + // Save image to file + File outputFile = new File(filePath); + ImageIO.write(image, "PNG", outputFile); + + log.info("Successfully saved Code 128 barcode to: {}", filePath); + return filePath; + } + + /** + * Generates a QR Code, saves it to a fixed path, and returns the file path. + * File is saved as: temp/qrcodes/qrcode_{text}_{timestamp}.png + */ + public static String generateQRCodeAndSave(String text, int width, int height) throws WriterException, IOException { + if (text == null || text.trim().isEmpty()) { + throw new IllegalArgumentException("QR Code text cannot be null or empty"); + } + + log.info("Generating QR Code and saving to file for text: {}", text); + + QRCodeWriter writer = new QRCodeWriter(); + BitMatrix bitMatrix = writer.encode(text, BarcodeFormat.QR_CODE, width, height); + BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); + + // Create filename with timestamp to avoid conflicts + String sanitizedText = sanitizeFileName(text); + String filename = String.format("qrcode_%s_%d.png", sanitizedText, System.currentTimeMillis()); + String filePath = Paths.get(QRCODE_DIRECTORY, filename).toString(); + + // Save image to file + File outputFile = new File(filePath); + ImageIO.write(image, "PNG", outputFile); + + log.info("Successfully saved QR Code to: {}", filePath); + return filePath; + } + + /** + * Generates a Code 128 barcode with custom directory, saves it, and returns the file path. + */ + public static String generateCode128AndSave(String text, int width, int height, String customDirectory) throws WriterException, IOException { + if (text == null || text.trim().isEmpty()) { + throw new IllegalArgumentException("Barcode text cannot be null or empty"); + } + + // Ensure custom directory exists + Files.createDirectories(Paths.get(customDirectory)); + + log.info("Generating Code 128 barcode and saving to custom directory: {}", customDirectory); + + Code128Writer writer = new Code128Writer(); + BitMatrix bitMatrix = writer.encode(text, BarcodeFormat.CODE_128, width, height); + BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); + + // Create filename + String sanitizedText = sanitizeFileName(text); + String filename = String.format("barcode_%s_%d.png", sanitizedText, System.currentTimeMillis()); + String filePath = Paths.get(customDirectory, filename).toString(); + + // Save image to file + File outputFile = new File(filePath); + ImageIO.write(image, "PNG", outputFile); + + log.info("Successfully saved Code 128 barcode to: {}", filePath); + return filePath; + } + + /** + * Generates a QR Code with custom directory, saves it, and returns the file path. + */ + public static String generateQRCodeAndSave(String text, int width, int height, String customDirectory) throws WriterException, IOException { + if (text == null || text.trim().isEmpty()) { + throw new IllegalArgumentException("QR Code text cannot be null or empty"); + } + + // Ensure custom directory exists + Files.createDirectories(Paths.get(customDirectory)); + + log.info("Generating QR Code and saving to custom directory: {}", customDirectory); + + QRCodeWriter writer = new QRCodeWriter(); + BitMatrix bitMatrix = writer.encode(text, BarcodeFormat.QR_CODE, width, height); + BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); + + // Create filename + String sanitizedText = sanitizeFileName(text); + String filename = String.format("qrcode_%s_%d.png", sanitizedText, System.currentTimeMillis()); + String filePath = Paths.get(customDirectory, filename).toString(); + + // Save image to file + File outputFile = new File(filePath); + ImageIO.write(image, "PNG", outputFile); + + log.info("Successfully saved QR Code to: {}", filePath); + return filePath; + } + + /** + * Generates a Code 128 barcode with fixed filename (overwrites existing), saves it, and returns the file path. + * Useful when you want to reuse the same filename for reports. + */ + public static String generateCode128WithFixedName(String text, int width, int height, String filename) throws WriterException, IOException { + if (text == null || text.trim().isEmpty()) { + throw new IllegalArgumentException("Barcode text cannot be null or empty"); + } + + log.info("Generating Code 128 barcode with fixed filename: {}", filename); + + Code128Writer writer = new Code128Writer(); + BitMatrix bitMatrix = writer.encode(text, BarcodeFormat.CODE_128, width, height); + BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); + + // Ensure filename has .png extension + if (!filename.toLowerCase().endsWith(".png")) { + filename += ".png"; + } + + String filePath = Paths.get(BARCODE_DIRECTORY, filename).toString(); + + // Save image to file (will overwrite if exists) + File outputFile = new File(filePath); + ImageIO.write(image, "PNG", outputFile); + + log.info("Successfully saved Code 128 barcode to: {}", filePath); + return filePath; + } + + /** + * Generates a QR Code with fixed filename (overwrites existing), saves it, and returns the file path. + * Useful when you want to reuse the same filename for reports. + */ + public static String generateQRCodeWithFixedName(String text, int width, int height, String filename) throws WriterException, IOException { + if (text == null || text.trim().isEmpty()) { + throw new IllegalArgumentException("QR Code text cannot be null or empty"); + } + + log.info("Generating QR Code with fixed filename: {}", filename); + + QRCodeWriter writer = new QRCodeWriter(); + BitMatrix bitMatrix = writer.encode(text, BarcodeFormat.QR_CODE, width, height); + BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); + + // Ensure filename has .png extension + if (!filename.toLowerCase().endsWith(".png")) { + filename += ".png"; + } + + String filePath = Paths.get(QRCODE_DIRECTORY, filename).toString(); + + // Save image to file (will overwrite if exists) + File outputFile = new File(filePath); + ImageIO.write(image, "PNG", outputFile); + + log.info("Successfully saved QR Code to: {}", filePath); + return filePath; + } + + /** + * Utility method to clean up temporary barcode files older than specified minutes + */ + public static void cleanupOldBarcodeFiles(int olderThanMinutes) { + cleanupOldFiles(BARCODE_DIRECTORY, olderThanMinutes); + cleanupOldFiles(QRCODE_DIRECTORY, olderThanMinutes); + } + + /** + * Helper method to clean up old files in a directory + */ + private static void cleanupOldFiles(String directory, int olderThanMinutes) { + try { + File dir = new File(directory); + if (!dir.exists()) return; + + long cutoffTime = System.currentTimeMillis() - (olderThanMinutes * 60 * 1000L); + + File[] files = dir.listFiles((file) -> + file.isFile() && + file.getName().toLowerCase().endsWith(".png") && + file.lastModified() < cutoffTime + ); + + if (files != null) { + for (File file : files) { + if (file.delete()) { + log.debug("Deleted old barcode file: {}", file.getName()); + } + } + log.info("Cleaned up {} old files from {}", files.length, directory); + } + } catch (Exception e) { + log.warn("Failed to cleanup old files in directory: {}", directory, e); + } + } + + /** + * Helper method to sanitize text for use in filenames + */ + private static String sanitizeFileName(String text) { + if (text == null) return "empty"; + + // Replace invalid filename characters and limit length + String sanitized = text.replaceAll("[^a-zA-Z0-9._-]", "_"); + if (sanitized.length() > 50) { + sanitized = sanitized.substring(0, 50); + } + return sanitized; + } + + // ============ ORIGINAL METHODS KEPT FOR BACKWARD COMPATIBILITY ============ + + /** + * Generates a Code 128 barcode and returns it as a Base64 encoded string. + * Format: data:image/png;base64,{base64_data} + */ + public static String generateCode128Base64String(String text, int width, int height) throws WriterException, IOException { + if (text == null || text.trim().isEmpty()) { + throw new IllegalArgumentException("Barcode text cannot be null or empty"); + } + + log.info("Generating Code 128 barcode as Base64 string for text: {}", text); + + Code128Writer writer = new Code128Writer(); + BitMatrix bitMatrix = writer.encode(text, BarcodeFormat.CODE_128, width, height); + + BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); + String base64String = bufferedImageToBase64String(image); + + log.info("Successfully generated Code 128 barcode Base64 string"); + return base64String; + } + + /** + * Generates a QR Code and returns it as a Base64 encoded string. + * Format: data:image/png;base64,{base64_data} + */ + public static String generateQRCodeBase64String(String text, int width, int height) throws WriterException, IOException { + if (text == null || text.trim().isEmpty()) { + throw new IllegalArgumentException("QR Code text cannot be null or empty"); + } + + log.info("Generating QR Code as Base64 string for text: {}", text); + + QRCodeWriter writer = new QRCodeWriter(); + BitMatrix bitMatrix = writer.encode(text, BarcodeFormat.QR_CODE, width, height); + + BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); + String base64String = bufferedImageToBase64String(image); + + log.info("Successfully generated QR Code Base64 string"); + return base64String; + } + + /** + * Generates a Code 128 barcode and returns it as a BufferedImage. + * This method is JAR-compatible and works better with JasperReports. + */ + public static BufferedImage generateCode128BufferedImage(String text, int width, int height) throws WriterException, IOException { + if (text == null || text.trim().isEmpty()) { + throw new IllegalArgumentException("Barcode text cannot be null or empty"); + } + + log.info("Generating Code 128 barcode as BufferedImage for text: {}", text); + + Code128Writer writer = new Code128Writer(); + BitMatrix bitMatrix = writer.encode(text, BarcodeFormat.CODE_128, width, height); + + BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); + log.info("Successfully generated Code 128 barcode BufferedImage"); + + return image; + } + + /** + * Generates a QR Code and returns it as a BufferedImage. + * This method is JAR-compatible and works better with JasperReports. + */ + public static BufferedImage generateQRCodeBufferedImage(String text, int width, int height) throws WriterException, IOException { + if (text == null || text.trim().isEmpty()) { + throw new IllegalArgumentException("QR Code text cannot be null or empty"); + } + + log.info("Generating QR Code as BufferedImage for text: {}", text); + + QRCodeWriter writer = new QRCodeWriter(); + BitMatrix bitMatrix = writer.encode(text, BarcodeFormat.QR_CODE, width, height); + + BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix); + log.info("Successfully generated QR Code BufferedImage"); + + return image; + } + + /** + * Legacy method: Generates a Code 128 barcode and returns it as an InputStream. + * Keep this for backward compatibility, but prefer BufferedImage methods for JasperReports. + */ + public static InputStream generateCode128Stream(String text, int width, int height) throws WriterException, IOException { + BufferedImage image = generateCode128BufferedImage(text, width, height); + return bufferedImageToInputStream(image); + } + + /** + * Legacy method: Generates a QR Code and returns it as an InputStream. + * Keep this for backward compatibility, but prefer BufferedImage methods for JasperReports. + */ + public static InputStream generateQRCodeStream(String text, int width, int height) throws WriterException, IOException { + BufferedImage image = generateQRCodeBufferedImage(text, width, height); + return bufferedImageToInputStream(image); + } + + /** + * Helper method to convert BufferedImage to Base64 encoded string + * Returns format: data:image/png;base64,{base64_data} + */ + private static String bufferedImageToBase64String(BufferedImage image) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(image, "PNG", baos); + byte[] imageBytes = baos.toByteArray(); + String base64String = Base64.getEncoder().encodeToString(imageBytes); + return "data:image/png;base64," + base64String; + } + + /** + * Helper method to convert BufferedImage to InputStream + */ + private static InputStream bufferedImageToInputStream(BufferedImage image) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(image, "PNG", baos); + byte[] imageBytes = baos.toByteArray(); + return new ByteArrayInputStream(imageBytes); + } + + /** + * Helper method to convert Base64 string back to BufferedImage if needed + * Accepts both formats: "data:image/png;base64,{data}" or just "{data}" + */ + public static BufferedImage base64StringToBufferedImage(String base64String) throws IOException { + if (base64String == null || base64String.trim().isEmpty()) { + throw new IllegalArgumentException("Base64 string cannot be null or empty"); + } + + // Remove data URL prefix if present + String base64Data = base64String; + if (base64String.startsWith("data:image/")) { + int commaIndex = base64String.indexOf(','); + if (commaIndex != -1) { + base64Data = base64String.substring(commaIndex + 1); + } + } + + byte[] imageBytes = Base64.getDecoder().decode(base64Data); + ByteArrayInputStream bais = new ByteArrayInputStream(imageBytes); + return ImageIO.read(bais); + } +} \ No newline at end of file diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/InvoiceItem.java b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/InvoiceItem.java similarity index 97% rename from src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/InvoiceItem.java rename to src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/InvoiceItem.java index c1bf161..d762766 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/InvoiceItem.java +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/InvoiceItem.java @@ -1,4 +1,4 @@ -package BsK.client.ui.component.CheckUpPage.PrintDialog.print_forms; +package BsK.client.ui.component.CheckUpPage.PrintDialog; /** * Represents a single item on the invoice, which can be a medicine, a service, or a supplement. 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 56daa64..9489b06 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 @@ -1,7 +1,7 @@ package BsK.client.ui.component.CheckUpPage.PrintDialog; import BsK.client.LocalStorage; -import BsK.client.ui.component.CheckUpPage.PrintDialog.print_forms.InvoiceItem; +import BsK.client.ui.component.CheckUpPage.PrintDialog.InvoiceItem; // JasperReports imports import net.sf.jasperreports.engine.*; import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource; @@ -9,8 +9,6 @@ import net.sf.jasperreports.engine.design.JasperDesign; import net.sf.jasperreports.engine.xml.JRXmlLoader; import net.sf.jasperreports.view.JasperViewer; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.rendering.PDFRenderer; import javax.swing.*; import java.awt.*; @@ -23,6 +21,7 @@ import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.io.*; import java.util.ArrayList; +import java.io.ByteArrayInputStream; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.text.DecimalFormat; @@ -30,8 +29,124 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.concurrent.CompletableFuture; import java.io.IOException; +import java.net.URL; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class MedicineInvoice{ + + /** + * Load and compile Jasper report from JRXML following standard pattern: inputstream → load → compile + */ + private static JasperReport loadCompiledReport(String reportName) { + String jrxmlPath = "/print_forms/" + reportName + ".jrxml"; + + try (InputStream inputStream = loadResourceAsStream(jrxmlPath)) { + if (inputStream == null) { + throw new RuntimeException("JRXML resource not found: " + jrxmlPath); + } + + log.info("Loading and compiling JRXML: {}", jrxmlPath); + + // Standard JasperReports pattern: inputstream → load → compile + JasperDesign jasperDesign = JRXmlLoader.load(inputStream); + JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign); + + log.info("Successfully compiled report: {}", reportName); + return jasperReport; + + } catch (Exception e) { + log.error("Failed to load/compile JRXML report {}: {}", jrxmlPath, e.getMessage()); + e.printStackTrace(); + throw new RuntimeException("Could not load or compile report: " + reportName, e); + } + } + + /** + * Robust resource loading method that works in both development and JAR environments + */ + private static InputStream loadResourceAsStream(String resourcePath) { + // Try multiple approaches to load the resource + InputStream inputStream = null; + + // Method 1: Using current class classloader + try { + inputStream = MedicineInvoice.class.getResourceAsStream(resourcePath); + if (inputStream != null) { + log.info("Successfully loaded resource using class.getResourceAsStream: {}", resourcePath); + return inputStream; + } + } catch (Exception e) { + log.warn("Failed to load resource using class.getResourceAsStream: {}", e.getMessage()); + } + + // Method 2: Using thread context classloader (without leading slash) + try { + String pathWithoutSlash = resourcePath.startsWith("/") ? resourcePath.substring(1) : resourcePath; + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + inputStream = contextClassLoader.getResourceAsStream(pathWithoutSlash); + if (inputStream != null) { + log.info("Successfully loaded resource using context classloader: {}", pathWithoutSlash); + return inputStream; + } + } catch (Exception e) { + log.warn("Failed to load resource using context classloader: {}", e.getMessage()); + } + + // Method 3: Using system classloader + try { + String pathWithoutSlash = resourcePath.startsWith("/") ? resourcePath.substring(1) : resourcePath; + inputStream = ClassLoader.getSystemResourceAsStream(pathWithoutSlash); + if (inputStream != null) { + log.info("Successfully loaded resource using system classloader: {}", pathWithoutSlash); + return inputStream; + } + } catch (Exception e) { + log.warn("Failed to load resource using system classloader: {}", e.getMessage()); + } + + // Method 4: Try with different class as anchor + try { + inputStream = LocalStorage.class.getResourceAsStream(resourcePath); + if (inputStream != null) { + log.info("Successfully loaded resource using LocalStorage.class: {}", resourcePath); + return inputStream; + } + } catch (Exception e) { + log.warn("Failed to load resource using LocalStorage.class: {}", e.getMessage()); + } + + // Method 5: Try loading from external file system (fallback for JAR issues) + try { + String externalPath = resourcePath.startsWith("/") ? resourcePath.substring(1) : resourcePath; + java.io.File externalFile = new java.io.File(externalPath); + if (externalFile.exists()) { + inputStream = new FileInputStream(externalFile); + log.info("Successfully loaded resource from external file: {}", externalFile.getAbsolutePath()); + return inputStream; + } + } catch (Exception e) { + log.warn("Failed to load resource from external file: {}", e.getMessage()); + } + + // Method 6: Try loading from src/main/resources (development mode) + try { + String srcPath = "src/main/resources" + (resourcePath.startsWith("/") ? "" : "/") + resourcePath; + java.io.File srcFile = new java.io.File(srcPath); + if (srcFile.exists()) { + inputStream = new FileInputStream(srcFile); + log.info("Successfully loaded resource from source directory: {}", srcFile.getAbsolutePath()); + return inputStream; + } + } catch (Exception e) { + log.warn("Failed to load resource from source directory: {}", e.getMessage()); + } + + log.error("All resource loading methods failed for: {}", resourcePath); + return null; + } private JDialog dialog; private String patientName; @@ -94,16 +209,21 @@ public class MedicineInvoice{ /** * Shows the invoice directly in JasperViewer without creating a custom dialog */ - public void showDirectJasperViewer() { + public void showDirectJasperViewer() throws Exception { try { // This method now only fills the report and shows the viewer fillJasperPrint(); + + if (jasperPrint == null) { + throw new Exception("JasperPrint is null - report compilation failed"); + } + // Use the constructor to prevent the application from closing JasperViewer viewer = new JasperViewer(jasperPrint, false); viewer.setVisible(true); } catch (Exception e) { - e.printStackTrace(); - JOptionPane.showMessageDialog(null, "Error generating PDF: " + e.getMessage()); + log.info("error showing the jasper viewer, {}", e.getMessage()); + throw e; } } @@ -150,7 +270,7 @@ public class MedicineInvoice{ String pdfPath = "temp_medical_invoice.pdf"; // Use a temporary file name try { generatePdf(pdfPath); - displayPdfInLabel(pdfPath, pdfViewer); + } catch (Exception e) { e.printStackTrace(); JOptionPane.showMessageDialog(dialog, "Error generating PDF: " + e.getMessage()); @@ -209,6 +329,12 @@ public class MedicineInvoice{ try { // This method is almost identical to generatePdf, but exports to a byte array fillJasperPrint(); // Ensures jasperPrint is filled + + if (jasperPrint == null) { + throw new Exception("JasperPrint is null - report compilation failed"); + } + + log.info("Exporting JasperPrint to PDF bytes..."); return JasperExportManager.exportReportToPdf(jasperPrint); } catch (Exception e) { e.printStackTrace(); @@ -220,6 +346,11 @@ public class MedicineInvoice{ try { // Refactored to use a common method to fill the report fillJasperPrint(); + + if (jasperPrint == null) { + throw new Exception("JasperPrint is null - report compilation failed"); + } + // Export to PDF file JasperExportManager.exportReportToPdfFile(jasperPrint, pdfPath); } catch (Exception e) { @@ -254,7 +385,7 @@ public class MedicineInvoice{ // Call signature: (Tên, Ghi chú, Liều dùng, Đường dùng, Số lượng) medicineItems.add(InvoiceItem.createMedicine(medName, note, dosageInfo, route, amount)); } catch (Exception e) { - System.err.println("Error parsing medicine data row: " + java.util.Arrays.toString(medicine) + " | Error: " + e.getMessage()); + log.info("Error parsing medicine data row: " + java.util.Arrays.toString(medicine) + " | Error: " + e.getMessage()); } } } @@ -271,7 +402,7 @@ public class MedicineInvoice{ Double.parseDouble(service[3]) )); } catch (NumberFormatException e) { - System.err.println("Error parsing service data: " + e.getMessage()); + log.info("Error parsing service data: " + e.getMessage()); } } } @@ -293,7 +424,7 @@ public class MedicineInvoice{ supplementItems.add(InvoiceItem.createSupplement(supName, supNote, dosageInfo, supRoute, amount)); } catch (Exception e) { - System.err.println("Error parsing supplement data row: " + java.util.Arrays.toString(supplement) + " | Error: " + e.getMessage()); + log.info("Error parsing supplement data row: " + java.util.Arrays.toString(supplement) + " | Error: " + e.getMessage()); } } } @@ -308,7 +439,7 @@ public class MedicineInvoice{ parameters.put("medicineDS", medicineDS); parameters.put("serviceDS", serviceDS); parameters.put("supplementDS", supplementDS); - parameters.put(JRParameter.REPORT_LOCALE, new java.util.Locale("vi", "VN")); + parameters.put(JRParameter.REPORT_LOCALE, java.util.Locale.of("vi", "VN")); parameters.put("patientName", patientName != null ? patientName : ""); parameters.put("patientDOB", patientDOB != null ? patientDOB : ""); parameters.put("patientGender", patientGender != null ? patientGender : ""); @@ -321,93 +452,47 @@ public class MedicineInvoice{ parameters.put("checkupDate", date != null ? date : ""); parameters.put("patientDiagnos", diagnosis != null ? diagnosis : ""); parameters.put("checkupNote", notes != null ? notes : ""); - parameters.put("barcodeNumber", id != null ? id : ""); - parameters.put("driveURL", driveURL != null ? driveURL : ""); parameters.put("hasMedicines", !medicineItems.isEmpty()); parameters.put("hasServices", !serviceItems.isEmpty()); parameters.put("hasSupplements", !supplementItems.isEmpty()); + parameters.put("id", id); - String logoPath = "/BsK/client/ui/assets/icon/logo.jpg"; - // Load the logo as an InputStream - InputStream logoStream = MedicineInvoice.class.getResourceAsStream(logoPath); - if (logoStream == null) { - System.err.println("ERROR: Logo image not found on classpath: " + logoPath); - parameters.put("logoImage", null); - } else { - // Pass the InputStream to the report parameter - parameters.put("logoImage", logoStream); - } - String resourcePath = "/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/medserinvoice.jrxml"; - try (InputStream inputStream = MedicineInvoice.class.getResourceAsStream(resourcePath)) { - if (inputStream == null) { - - throw new FileNotFoundException("Không thể tìm thấy tệp mẫu Jasper report trong classpath: " + resourcePath); - } - JasperDesign jasperDesign = JRXmlLoader.load(inputStream); - JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign); - jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, new JREmptyDataSource()); - } - } - - private void displayPdfInLabel(String pdfPath, JPanel pdfPanel) throws Exception { - PDDocument document = PDDocument.load(new File(pdfPath)); - PDFRenderer pdfRenderer = new PDFRenderer(document); - - pdfPanel.setLayout(new BoxLayout(pdfPanel, BoxLayout.Y_AXIS)); - - for (int i = 0; i < document.getNumberOfPages(); i++) { - BufferedImage image = pdfRenderer.renderImageWithDPI(i, 150); - ImageIcon icon = new ImageIcon(image); - JLabel pageLabel = new JLabel(icon); - pdfPanel.add(pageLabel); - } - document.close(); - - dialog.revalidate(); - dialog.repaint(); - } - - - public static void printPdf(File pdfFile) { - try (PDDocument document = PDDocument.load(pdfFile)) { - PrinterJob printerJob = PrinterJob.getPrinterJob(); - printerJob.setJobName("Print Medicine Invoice"); - - if (printerJob.printDialog()) { - printerJob.setPrintable((graphics, pageFormat, pageIndex) -> { - if (pageIndex >= document.getNumberOfPages()) { - return Printable.NO_SUCH_PAGE; - } - - Graphics2D g2 = (Graphics2D) graphics; - g2.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); - - try { - PDFRenderer pdfRenderer = new PDFRenderer(document); - BufferedImage pageImage = pdfRenderer.renderImageWithDPI(pageIndex, 300); - - double scale = Math.min(pageFormat.getImageableWidth() / pageImage.getWidth(), - pageFormat.getImageableHeight() / pageImage.getHeight()); - - g2.scale(scale, scale); - g2.drawImage(pageImage, 0, 0, null); - - } catch (IOException e) { - e.printStackTrace(); - return Printable.NO_SUCH_PAGE; - } - - return Printable.PAGE_EXISTS; - }); - - printerJob.print(); - System.out.println("Printing completed."); - } else { - System.out.println("Print job canceled."); - } + // FIXED: Generate barcode and QR code as BufferedImage instead of InputStream + try { + // Generate barcode and get file path + String barcodePath = BarcodeGenerator.generateCode128WithFixedName(id, 200, 50, "invoice_barcode"); + parameters.put("barcodeNumber", barcodePath); + + // Generate QR code for the driveURL + String qrcodePath = BarcodeGenerator.generateQRCodeWithFixedName(driveURL, 220, 220, "invoice_qrcode"); + parameters.put("driveURL", qrcodePath); + } catch (Exception e) { + log.error("Error generating barcode/QR code images: {}", e.getMessage()); + // Set fallback parameters as null or empty if image generation fails + parameters.put("barcodeNumber", null); + parameters.put("driveURL", null); + } + + try { + // Use the new method that tries pre-compiled .jasper files first + JasperReport jasperReport = loadCompiledReport("medserinvoice"); + log.info("Successfully loaded/compiled jasper report"); + + log.info("Attempting to fill report with parameters..."); + jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, new JREmptyDataSource()); + log.info("Successfully filled jasper print"); + + // Verify jasperPrint is not null and has content + if (jasperPrint != null) { + log.info("JasperPrint created successfully with {} pages", jasperPrint.getPages().size()); + } else { + log.error("JasperPrint is null after fill operation!"); + } + } + catch (Exception e) { + log.info("error loading the input stream, {}", e.getMessage()); e.printStackTrace(); - JOptionPane.showMessageDialog(null, "Error printing PDF: " + e.getMessage()); } } diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/UltrasoundResult.java b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/UltrasoundResult.java index f6fe863..34c17e5 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/UltrasoundResult.java +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/UltrasoundResult.java @@ -1,30 +1,10 @@ package BsK.client.ui.component.CheckUpPage.PrintDialog; import BsK.client.LocalStorage; -import com.itextpdf.io.font.constants.StandardFonts; -import com.itextpdf.io.image.ImageDataFactory; -import com.itextpdf.kernel.colors.ColorConstants; -import com.itextpdf.kernel.font.PdfFont; -import com.itextpdf.kernel.font.PdfFontFactory; -import com.itextpdf.kernel.geom.PageSize; -import com.itextpdf.kernel.pdf.PdfDocument; -import com.itextpdf.kernel.pdf.PdfWriter; -import com.itextpdf.layout.Document; -import com.itextpdf.layout.borders.Border; -import com.itextpdf.layout.borders.SolidBorder; -import com.itextpdf.layout.element.Cell; -import com.itextpdf.layout.element.Image; -import com.itextpdf.layout.element.Paragraph; -import com.itextpdf.layout.element.Table; -import com.itextpdf.layout.element.Text; -import com.itextpdf.layout.property.HorizontalAlignment; -import com.itextpdf.layout.property.TextAlignment; -import com.itextpdf.layout.property.UnitValue; -import com.itextpdf.layout.property.VerticalAlignment; -import com.itextpdf.layout.element.AreaBreak; + + import lombok.extern.slf4j.Slf4j; -import org.apache.pdfbox.pdmodel.PDDocument; -import org.apache.pdfbox.rendering.PDFRenderer; + // --- JasperReports Imports --- import net.sf.jasperreports.engine.JREmptyDataSource; @@ -51,6 +31,7 @@ import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.io.*; +import java.io.ByteArrayInputStream; import java.util.List; import java.util.Map; import java.util.HashMap; @@ -58,10 +39,120 @@ import java.util.Locale; import net.sf.jasperreports.engine.JRParameter; import net.sf.jasperreports.engine.JRException; import java.util.ArrayList; -import org.slf4j.LoggerFactory; + @Slf4j public class UltrasoundResult { + + /** + * Load and compile Jasper report from JRXML with robust error handling for JAR environment + */ + private static JasperReport loadCompiledReport(String reportName) { + String jrxmlPath = "/print_forms/" + reportName + ".jrxml"; + + try (InputStream jrxmlStream = loadResourceAsStream(jrxmlPath)) { + if (jrxmlStream == null) { + throw new RuntimeException("JRXML resource not found: " + jrxmlPath); + } + + log.info("Compiling JRXML at runtime: {}", jrxmlPath); + + // Read all bytes to ensure complete stream reading in JAR environment + byte[] jrxmlContent = jrxmlStream.readAllBytes(); + log.info("JRXML content size: {} bytes", jrxmlContent.length); + + if (jrxmlContent.length == 0) { + throw new RuntimeException("JRXML file is empty: " + jrxmlPath); + } + + // Use ByteArrayInputStream for reliable reading in JAR environment + try (ByteArrayInputStream byteStream = new ByteArrayInputStream(jrxmlContent)) { + log.info("Loading JRXML design..."); + JasperDesign jasperDesign = JRXmlLoader.load(byteStream); + log.info("Compiling Jasper report..."); + JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign); + log.info("Successfully compiled report: {}", reportName); + return jasperReport; + } + } catch (Exception e) { + log.error("Failed to compile JRXML report {}: {}", jrxmlPath, e.getMessage()); + e.printStackTrace(); + throw new RuntimeException("Could not load or compile report: " + reportName, e); + } + } + + /** + * Robust resource loading method that works in both development and JAR environments + */ + private static InputStream loadResourceAsStream(String resourcePath) { + // Try multiple approaches to load the resource + InputStream inputStream = null; + + // Method 1: Using current class classloader + try { + inputStream = UltrasoundResult.class.getResourceAsStream(resourcePath); + if (inputStream != null) { + log.info("Successfully loaded resource using class.getResourceAsStream: {}", resourcePath); + return inputStream; + } + } catch (Exception e) { + log.warn("Failed to load resource using class.getResourceAsStream: {}", e.getMessage()); + } + + // Method 2: Using thread context classloader (without leading slash) + try { + String pathWithoutSlash = resourcePath.startsWith("/") ? resourcePath.substring(1) : resourcePath; + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + inputStream = contextClassLoader.getResourceAsStream(pathWithoutSlash); + if (inputStream != null) { + log.info("Successfully loaded resource using context classloader: {}", pathWithoutSlash); + return inputStream; + } + } catch (Exception e) { + log.warn("Failed to load resource using context classloader: {}", e.getMessage()); + } + + // Method 3: Using system classloader + try { + String pathWithoutSlash = resourcePath.startsWith("/") ? resourcePath.substring(1) : resourcePath; + inputStream = ClassLoader.getSystemResourceAsStream(pathWithoutSlash); + if (inputStream != null) { + log.info("Successfully loaded resource using system classloader: {}", pathWithoutSlash); + return inputStream; + } + } catch (Exception e) { + log.warn("Failed to load resource using system classloader: {}", e.getMessage()); + } + + // Method 5: Try loading from external file system (fallback for JAR issues) + try { + String externalPath = resourcePath.startsWith("/") ? resourcePath.substring(1) : resourcePath; + java.io.File externalFile = new java.io.File(externalPath); + if (externalFile.exists()) { + inputStream = new java.io.FileInputStream(externalFile); + log.info("Successfully loaded resource from external file: {}", externalFile.getAbsolutePath()); + return inputStream; + } + } catch (Exception e) { + log.warn("Failed to load resource from external file: {}", e.getMessage()); + } + + // Method 6: Try loading from src/main/resources (development mode) + try { + String srcPath = "src/main/resources" + (resourcePath.startsWith("/") ? "" : "/") + resourcePath; + java.io.File srcFile = new java.io.File(srcPath); + if (srcFile.exists()) { + inputStream = new java.io.FileInputStream(srcFile); + log.info("Successfully loaded resource from source directory: {}", srcFile.getAbsolutePath()); + return inputStream; + } + } catch (Exception e) { + log.warn("Failed to load resource from source directory: {}", e.getMessage()); + } + + log.error("All resource loading methods failed for: {}", resourcePath); + return null; + } private JDialog dialog; private final String checkupId; @@ -171,20 +262,20 @@ public class UltrasoundResult { } public JasperPrint createJasperPrint() throws JRException, IOException { - String jrxmlPath; + String reportName; if ("Dọc".equalsIgnoreCase(this.printType)) { - jrxmlPath = System.getProperty("user.dir") + "/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/ultrasoundresult_potrait.jrxml"; + reportName = "ultrasoundresult_potrait"; } else { - jrxmlPath = System.getProperty("user.dir") + "/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/ultrasoundresult.jrxml"; + reportName = "ultrasoundresult"; } - log.info("Using JRXML template: {}", jrxmlPath); + log.info("Using Jasper report template: {}", reportName); - try (InputStream inputStream = new FileInputStream(new File(jrxmlPath))) { + try { Map parameters = new HashMap<>(); // Set locale for date/number formatting - parameters.put(JRParameter.REPORT_LOCALE, new Locale("vi", "VN")); + parameters.put(JRParameter.REPORT_LOCALE, Locale.of("vi", "VN")); // Populate all the string parameters parameters.put("clinicPrefix", LocalStorage.ClinicPrefix != null ? LocalStorage.ClinicPrefix : ""); @@ -240,14 +331,16 @@ public class UltrasoundResult { // Google Drive URL for QR code generation parameters.put("driveURL", this.driveUrl); - // Load and compile the report - JasperDesign jasperDesign = JRXmlLoader.load(inputStream); - JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign); + // Load pre-compiled report or compile JRXML as fallback + JasperReport jasperReport = loadCompiledReport(reportName); // Fill the report JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, new JREmptyDataSource()); return jasperPrint; + } catch (Exception e) { + log.error("Error creating JasperPrint for report {}: {}", reportName, e.getMessage()); + throw new JRException("Failed to create ultrasound report", e); } } @@ -265,488 +358,4 @@ public class UltrasoundResult { return JasperExportManager.exportReportToPdf(jasperPrint); } - public void createDialog(JFrame parent) { - dialog = new JDialog(parent, "Kết quả siêu âm", true); - dialog.setSize(800, 700); - dialog.setResizable(true); - dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - dialog.setLayout(new BorderLayout()); - - dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL); - - dialog.addWindowListener(new WindowAdapter() { - @Override - public void windowIconified(WindowEvent e) { - if (parent != null) parent.setState(Frame.ICONIFIED); - } - - @Override - public void windowDeiconified(WindowEvent e) { - if (parent != null && parent.getState() == Frame.ICONIFIED) parent.setState(Frame.NORMAL); - } - }); - - JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); - JButton saveButton = new JButton("Lưu PDF"); - JButton printButton = new JButton("In PDF"); - buttonPanel.add(saveButton); - buttonPanel.add(printButton); - - JPanel pdfViewer = new JPanel(); - JScrollPane scrollPane = new JScrollPane(pdfViewer); - dialog.add(scrollPane, BorderLayout.CENTER); - dialog.add(buttonPanel, BorderLayout.SOUTH); - - try { - generatePdf(PDF_PATH); - displayPdfInLabel(PDF_PATH, pdfViewer); - } catch (Exception e) { - log.error("Error generating ultrasound PDF", e); - JOptionPane.showMessageDialog(dialog, "Lỗi khi tạo PDF: " + e.getMessage(), "Lỗi", JOptionPane.ERROR_MESSAGE); - } - - saveButton.addActionListener(e -> savePdf()); - printButton.addActionListener(e -> printPdf()); - - dialog.setLocationRelativeTo(parent); - dialog.setVisible(true); - } - - private void generatePdf(String pdfPath) throws Exception { - PdfWriter writer = new PdfWriter(pdfPath); - PdfDocument pdfDoc = new PdfDocument(writer); - Document document; - - boolean isLandscape = "ngang".equalsIgnoreCase(this.printType); - if (isLandscape) { - document = new Document(pdfDoc, PageSize.A4.rotate()); - } else { - document = new Document(pdfDoc, PageSize.A4); - } - document.setMargins(20, 20, 20, 20); - - String boldFontPath = "src/main/java/BsK/client/ui/assets/font/SVN-Arial Bold.ttf"; - PdfFont boldFont = PdfFontFactory.createFont(boldFontPath, "Identity-H", true); - String fontPath = "src/main/java/BsK/client/ui/assets/font/SVN-Arial Regular.ttf"; - PdfFont font = PdfFontFactory.createFont(fontPath, "Identity-H", true); - - String title = templateTitle != null ? templateTitle.toUpperCase() : "KẾT QUẢ SIÊU ÂM"; - - if (isLandscape) { - generateLandscapeLayout(document, boldFont, font, title); - } else { - addHeader(document, boldFont, font); - document.add(new Paragraph(title) - .setFont(boldFont).setFontSize(14) - .setTextAlignment(TextAlignment.CENTER) - .setMarginBottom(5)); - generatePortraitLayout(document, boldFont, font); - } - - document.close(); - } - - private Cell createHeaderBlock(PdfFont boldFont, PdfFont font) { - Cell headerContainer = new Cell().setBorder(Border.NO_BORDER).setPadding(0); - Table headerTable = new Table(UnitValue.createPercentArray(new float[]{0.3f, 0.7f})) - .setWidth(UnitValue.createPercentValue(100)) - .setBorder(Border.NO_BORDER) - .setMarginBottom(2); - try { - String logoPath = "src/main/java/BsK/client/ui/assets/icon/clinic_logo.png"; - Image logo = new Image(ImageDataFactory.create(logoPath)).scaleToFit(50, 50); - headerTable.addCell(new Cell().add(logo).setBorder(Border.NO_BORDER).setVerticalAlignment(VerticalAlignment.MIDDLE)); - } catch (Exception e) { - headerTable.addCell(new Cell().setBorder(Border.NO_BORDER)); - log.warn("Clinic logo not found", e); - } - - Paragraph clinicInfo = new Paragraph() - .add(new Text(LocalStorage.ClinicPrefix + " " + LocalStorage.ClinicName + "\n").setFont(boldFont).setFontSize(10)) - .add(new Text("Địa chỉ: " + LocalStorage.ClinicAddress + "\n").setFontSize(8)) - .add(new Text("Điện thoại: " + LocalStorage.ClinicPhone).setFontSize(8)) - .setFont(font); - headerTable.addCell(new Cell().add(clinicInfo).setBorder(Border.NO_BORDER).setVerticalAlignment(VerticalAlignment.MIDDLE)); - - headerContainer.add(headerTable); - return headerContainer; - } - - private void generateLandscapeLayout(Document document, PdfFont boldFont, PdfFont font, String title) throws Exception { - Table titleTable = new Table(UnitValue.createPercentArray(new float[]{1, 1})) - .setWidth(UnitValue.createPercentValue(100)) - .setMarginBottom(2); - - Paragraph titleParagraph = new Paragraph(title) - .setFont(boldFont).setFontSize(14) - .setTextAlignment(TextAlignment.CENTER) - .setMarginBottom(2); - - Table mainTable = new Table(UnitValue.createPercentArray(new float[]{1.2f, 0.8f})) - .setWidth(UnitValue.createPercentValue(100)) - .setMarginTop(0); - - Cell leftCell = new Cell().setBorder(Border.NO_BORDER).setPadding(1).setVerticalAlignment(VerticalAlignment.TOP); - - leftCell.add(createHeaderBlock(boldFont, font)); - - leftCell.add(new Paragraph(title) - .setFont(boldFont).setFontSize(14) - .setTextAlignment(TextAlignment.CENTER) - .setMarginBottom(2)); - - addPatientInfo(leftCell, boldFont, font, 8); - leftCell.add(new Paragraph("NỘI DUNG").setFont(boldFont).setFontSize(10).setMarginTop(2) - .setTextAlignment(TextAlignment.LEFT).setUnderline()); - - Image rtfImage = createRtfImage(this.rtfContent, PageSize.A4.rotate().getWidth() * 0.58f); - if (rtfImage != null) { - // Set maximum height to prevent page overflow - ensure single page layout - rtfImage.setMaxHeight(320); // Fixed max height to ensure single page - rtfImage.setAutoScale(false); - leftCell.add(rtfImage); - } - - // Add conclusion and suggestion to left column - leftCell.add(new Paragraph("KẾT LUẬN").setFont(boldFont).setFontSize(10).setMarginTop(3) - .setTextAlignment(TextAlignment.LEFT).setUnderline()); - leftCell.add(new Paragraph(this.conclusion).setFont(font).setFontSize(8)); - - leftCell.add(new Paragraph("ĐỀ NGHỊ").setFont(boldFont).setFontSize(10).setMarginTop(2) - .setTextAlignment(TextAlignment.LEFT).setUnderline()); - leftCell.add(new Paragraph(this.suggestion).setFont(font).setFontSize(8)); - - Cell rightCell = new Cell().setBorder(Border.NO_BORDER).setPadding(1).setVerticalAlignment(VerticalAlignment.TOP); - rightCell.add(new Paragraph("HÌNH ẢNH SIÊU ÂM").setFont(boldFont).setFontSize(10) - .setTextAlignment(TextAlignment.LEFT).setUnderline().setMarginBottom(1)); - Table imageTable = createImageTable(selectedImages); - rightCell.add(imageTable); - - rightCell.add(createSignatureBlock(font, boldFont)); - - mainTable.addCell(leftCell); - mainTable.addCell(rightCell); - document.add(mainTable); - } - - private void generatePortraitLayout(Document document, PdfFont boldFont, PdfFont font) throws Exception { - boolean multiPage = selectedImages.size() > 4; - addPatientInfo(document, boldFont, font, 8); - - if (multiPage) { - Table contentTable = new Table(1).setWidth(UnitValue.createPercentValue(100)); - Cell contentCell = new Cell().setBorder(Border.NO_BORDER).setPadding(0); - - contentCell.add(new Paragraph("NỘI DUNG").setFont(boldFont).setFontSize(10).setMarginTop(5) - .setTextAlignment(TextAlignment.LEFT).setUnderline()); - Image rtfImage = createRtfImage(this.rtfContent, PageSize.A4.getWidth() - 60); - if (rtfImage != null) { - contentCell.add(rtfImage); - } - - contentCell.add(new Paragraph("KẾT LUẬN").setFont(boldFont).setFontSize(10).setMarginTop(5) - .setTextAlignment(TextAlignment.LEFT).setUnderline()); - contentCell.add(new Paragraph(this.conclusion).setFont(font).setFontSize(8)); - contentCell.add(new Paragraph("ĐỀ NGHỊ").setFont(boldFont).setFontSize(10).setMarginTop(5) - .setTextAlignment(TextAlignment.LEFT).setUnderline()); - contentCell.add(new Paragraph(this.suggestion).setFont(font).setFontSize(8)); - - contentTable.addCell(contentCell); - document.add(contentTable); - addSignature(document, font, boldFont); - - document.add(new AreaBreak()); - addHeader(document, boldFont, font); - document.add(new Paragraph("HÌNH ẢNH SIÊU ÂM (tt)").setFont(boldFont).setFontSize(10) - .setTextAlignment(TextAlignment.LEFT).setUnderline()); - Table imageTable = createImageTable(selectedImages); - document.add(imageTable); - } else { - Table mainTable = new Table(UnitValue.createPercentArray(new float[]{1.2f, 0.8f})) - .setWidth(UnitValue.createPercentValue(100)) - .setMarginTop(5); - - Cell leftCell = new Cell().setBorder(Border.NO_BORDER).setPaddingRight(5); - leftCell.add(new Paragraph("NỘI DUNG").setFont(boldFont).setFontSize(10) - .setTextAlignment(TextAlignment.LEFT).setUnderline()); - Image rtfImage = createRtfImage(this.rtfContent, PageSize.A4.getWidth() * 0.55f - 40); - if (rtfImage != null) { - leftCell.add(rtfImage); - } - - Cell rightCell = new Cell().setBorder(Border.NO_BORDER); - rightCell.add(new Paragraph("HÌNH ẢNH").setFont(boldFont).setFontSize(10) - .setTextAlignment(TextAlignment.LEFT).setUnderline()); - Table imageTable = createImageTable(selectedImages); - rightCell.add(imageTable); - - mainTable.addCell(leftCell); - mainTable.addCell(rightCell); - document.add(mainTable); - - document.add(new Paragraph("KẾT LUẬN").setFont(boldFont).setFontSize(10).setMarginTop(5) - .setTextAlignment(TextAlignment.LEFT).setUnderline()); - document.add(new Paragraph(this.conclusion).setFont(font).setFontSize(8)); - document.add(new Paragraph("ĐỀ NGHỊ").setFont(boldFont).setFontSize(10).setMarginTop(5) - .setTextAlignment(TextAlignment.LEFT).setUnderline()); - document.add(new Paragraph(this.suggestion).setFont(font).setFontSize(8)); - - addSignature(document, font, boldFont); - } - } - - private Table createImageTable(List images) throws IOException { - int numImages = images.size(); - int numCols = numImages == 1 ? 1 : 2; - - Table imageTable = new Table(numCols) - .useAllAvailableWidth() - .setMarginTop(1).setMarginBottom(1); - - for(File imgFile : images) { - Image img = new Image(ImageDataFactory.create(imgFile.getAbsolutePath())); - - img.setAutoScale(true); - img.setMaxWidth(110f); - img.setMaxHeight(85f); - - Cell imgCell = new Cell() - .add(img) - .setBorder(new SolidBorder(ColorConstants.GRAY, 0.5f)) - .setPadding(1) - .setHorizontalAlignment(HorizontalAlignment.CENTER) - .setVerticalAlignment(VerticalAlignment.MIDDLE); - imageTable.addCell(imgCell); - } - - int remainder = numImages % numCols; - if (remainder != 0 && numImages > 1) { - imageTable.addCell(new Cell().setBorder(Border.NO_BORDER)); - } - return imageTable; - } - - private Image createRtfImage(String rtf, float availableWidth) { - if (rtf == null || rtf.trim().isEmpty()) { - return null; - } - try { - JTextPane pane = new JTextPane(); - pane.setEditorKit(new RTFEditorKit()); - pane.setBackground(Color.WHITE); - pane.setOpaque(true); - - pane.read(new ByteArrayInputStream(rtf.getBytes("ISO-8859-1")), null); - - pane.setSize(new Dimension((int) availableWidth, Integer.MAX_VALUE)); - Dimension prefSize = pane.getPreferredSize(); - pane.setSize(prefSize); - - int renderDPI = 240; // Further reduced DPI to make text appear even smaller - float scale = renderDPI / 72f; - - int imgWidth = (int) (prefSize.width * scale); - int imgHeight = (int) (prefSize.height * scale); - - if (imgWidth <= 0 || imgHeight <= 0) { - log.warn("Invalid image dimensions for RTF rendering: {}x{}", imgWidth, imgHeight); - return null; - } - - BufferedImage img = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_ARGB); - Graphics2D g2d = img.createGraphics(); - - g2d.scale(scale, scale); - - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - - pane.paint(g2d); - g2d.dispose(); - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ImageIO.write(img, "png", baos); - Image itextImage = new Image(ImageDataFactory.create(baos.toByteArray())); - - // Set width directly. The reduced DPI has already made the content smaller. - itextImage.setWidth(UnitValue.createPointValue(prefSize.width)); - - return itextImage; - - } catch (Exception e) { - log.error("Failed to convert RTF to Image", e); - return null; - } - } - - private void addHeader(Document document, PdfFont boldFont, PdfFont font) { - Table headerTable = new Table(UnitValue.createPercentArray(new float[]{1.2f, 3.8f, 2f})) - .setWidth(UnitValue.createPercentValue(100)) - .setBorder(Border.NO_BORDER) - .setMarginBottom(5); - try { - String logoPath = "src/main/java/BsK/client/ui/assets/icon/clinic_logo.png"; - Image logo = new Image(ImageDataFactory.create(logoPath)).scaleToFit(50, 50); - headerTable.addCell(new Cell().add(logo).setBorder(Border.NO_BORDER).setVerticalAlignment(VerticalAlignment.MIDDLE)); - } catch (Exception e) { - headerTable.addCell(new Cell().setBorder(Border.NO_BORDER)); - log.warn("Clinic logo not found", e); - } - - Paragraph clinicInfo = new Paragraph() - .add(new Text(LocalStorage.ClinicName + "\n").setFont(boldFont).setFontSize(10)) - .add(new Text("Địa chỉ: " + LocalStorage.ClinicAddress + "\n").setFontSize(8)) - .add(new Text("Điện thoại: " + LocalStorage.ClinicPhone).setFontSize(8)) - .setFont(font); - headerTable.addCell(new Cell().add(clinicInfo).setBorder(Border.NO_BORDER).setVerticalAlignment(VerticalAlignment.MIDDLE)); - - headerTable.addCell(new Cell().setBorder(Border.NO_BORDER)); - document.add(headerTable); - } - - private void addPatientInfo(Object container, PdfFont boldFont, PdfFont font, int fontSize) { - Table table = new Table(UnitValue.createPercentArray(new float[]{1,1})) - .setWidth(UnitValue.createPercentValue(100)) - .setFontSize(fontSize).setFont(font) - .setBorder(new SolidBorder(ColorConstants.GRAY, 0.5f)) - .setMarginBottom(1); // Reduced margin for compactness - - Cell left = new Cell().setBorder(Border.NO_BORDER).setPadding(1); - left.add(new Paragraph().add(new Text("Họ tên: ").setFont(boldFont)).add(patientName)); - left.add(new Paragraph().add(new Text("Năm sinh: ").setFont(boldFont)).add(patientDOB)); - left.add(new Paragraph().add(new Text("Giới tính: ").setFont(boldFont)).add(patientGender)); - - Cell right = new Cell().setBorder(Border.NO_BORDER).setPadding(1); - right.add(new Paragraph().add(new Text("Địa chỉ: ").setFont(boldFont)).add(patientAddress)); - right.add(new Paragraph().add(new Text("Ngày khám: ").setFont(boldFont)).add(checkupDate)); - right.add(new Paragraph().add(new Text("Mã khám: ").setFont(boldFont)).add(checkupId)); - - table.addCell(left); - table.addCell(right); - - if (container instanceof Document) { - ((Document) container).add(table); - } else if (container instanceof Cell) { - ((Cell) container).add(table); - } - } - - private void addSignature(Document document, PdfFont font, PdfFont boldFont) { - Table signatureTable = new Table(UnitValue.createPercentArray(new float[]{1, 1})) - .setWidth(UnitValue.createPercentValue(100)) - .setMarginTop(5); - - signatureTable.addCell(new Cell().setBorder(Border.NO_BORDER)); // empty cell for alignment - - Paragraph signParagraph = new Paragraph() - .add("Ngày " + checkupDate.substring(0,2) + " tháng " + checkupDate.substring(3,5) + " năm " + checkupDate.substring(6) + "\n") - .add(new Text("BÁC SĨ ĐIỀU TRỊ\n").setFont(boldFont)) - .add(new Text("(Ký và ghi rõ họ tên)\n\n").setFontSize(9).setItalic()) // Reduced newlines for signature space - .add(doctorName) - .setTextAlignment(TextAlignment.CENTER) - .setFont(font).setFontSize(10); - - signatureTable.addCell(new Cell().add(signParagraph).setBorder(Border.NO_BORDER)); - document.add(signatureTable); - } - - private void displayPdfInLabel(String pdfPath, JPanel pdfPanel) { - pdfPanel.removeAll(); - pdfPanel.setLayout(new BoxLayout(pdfPanel, BoxLayout.Y_AXIS)); - - try (PDDocument document = PDDocument.load(new File(pdfPath))) { - PDFRenderer pdfRenderer = new PDFRenderer(document); - float scale = 0.6f; - for (int i = 0; i < document.getNumberOfPages(); i++) { - BufferedImage image = pdfRenderer.renderImageWithDPI(i, 120); - int newWidth = (int) (image.getWidth() * scale); - int newHeight = (int) (image.getHeight() * scale); - ImageIcon icon = new ImageIcon(image.getScaledInstance(newWidth, newHeight, java.awt.Image.SCALE_SMOOTH)); - JLabel pageLabel = new JLabel(icon); - pageLabel.setAlignmentX(Component.CENTER_ALIGNMENT); - pageLabel.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0)); - pdfPanel.add(pageLabel); - } - } catch (IOException e) { - log.error("Error displaying PDF", e); - pdfPanel.add(new JLabel("Lỗi khi hiển thị PDF: " + e.getMessage())); - } - pdfPanel.revalidate(); - pdfPanel.repaint(); - } - - private void savePdf() { - JFileChooser fileChooser = new JFileChooser(); - fileChooser.setDialogTitle("Lưu file PDF"); - fileChooser.setSelectedFile(new File("ultrasound_" + checkupId + ".pdf")); - int userSelection = fileChooser.showSaveDialog(dialog); - if (userSelection == JFileChooser.APPROVE_OPTION) { - File fileToSave = fileChooser.getSelectedFile(); - try { - generatePdf(fileToSave.getAbsolutePath()); - JOptionPane.showMessageDialog(dialog, "PDF đã được lưu: " + fileToSave.getAbsolutePath()); - } catch (Exception ex) { - log.error("Error saving PDF", ex); - JOptionPane.showMessageDialog(dialog, "Lỗi khi lưu PDF: " + ex.getMessage(), "Lỗi", JOptionPane.ERROR_MESSAGE); - } - } - } - - private void printPdf() { - File pdfFile = new File(PDF_PATH); - try (PDDocument document = PDDocument.load(pdfFile)) { - PrinterJob printerJob = PrinterJob.getPrinterJob(); - printerJob.setJobName("In kết quả siêu âm - " + patientName); - - if (printerJob.printDialog()) { - printerJob.setPrintable(new Printable() { - @Override - public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { - if (pageIndex >= document.getNumberOfPages()) { - return NO_SUCH_PAGE; - } - try { - PDFRenderer pdfRenderer = new PDFRenderer(document); - BufferedImage pageImage = pdfRenderer.renderImageWithDPI(pageIndex, 300); - - Graphics2D g2d = (Graphics2D) graphics; - g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); - - double scale = Math.min(pageFormat.getImageableWidth() / pageImage.getWidth(), pageFormat.getImageableHeight() / pageImage.getHeight()); - g2d.drawImage(pageImage, 0, 0, (int) (pageImage.getWidth() * scale), (int) (pageImage.getHeight() * scale), null); - - return PAGE_EXISTS; - } catch (IOException e) { - log.error("Error rendering page for printing", e); - throw new PrinterException(e.getMessage()); - } - } - }); - printerJob.print(); - } - } catch (Exception e) { - log.error("Error printing PDF", e); - JOptionPane.showMessageDialog(dialog, "Lỗi khi in PDF: " + e.getMessage(), "Lỗi", JOptionPane.ERROR_MESSAGE); - } - } - - private Table createSignatureBlock(PdfFont font, PdfFont boldFont) { - Table signatureTable = new Table(UnitValue.createPercentArray(new float[]{1, 1})) - .setWidth(UnitValue.createPercentValue(100)) - .setMarginTop(2); // Reduced margin for compactness - - signatureTable.addCell(new Cell().setBorder(Border.NO_BORDER)); // empty cell for alignment - - Paragraph signParagraph = new Paragraph() - .add("Ngày " + checkupDate.substring(0,2) + " tháng " + checkupDate.substring(3,5) + " năm " + checkupDate.substring(6) + "\n") - .add(new Text("BÁC SĨ ĐIỀU TRỊ\n").setFont(boldFont)) - .add(new Text("(Ký và ghi rõ họ tên)\n\n").setFontSize(9).setItalic()) // Reduced newlines for signature space - .add(doctorName) - .setTextAlignment(TextAlignment.CENTER) - .setFont(font).setFontSize(10); - - signatureTable.addCell(new Cell().add(signParagraph).setBorder(Border.NO_BORDER)); - return signatureTable; - } } \ No newline at end of file diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/medserinvoice.jasper b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/medserinvoice.jasper deleted file mode 100644 index c826a78..0000000 Binary files a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/medserinvoice.jasper and /dev/null differ diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/test_ultrasound_print.java b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/test_ultrasound_print.java deleted file mode 100644 index 4405d24..0000000 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/test_ultrasound_print.java +++ /dev/null @@ -1,115 +0,0 @@ -package BsK.client.ui.component.CheckUpPage.PrintDialog.print_forms; - -import net.sf.jasperreports.engine.JREmptyDataSource; -import net.sf.jasperreports.engine.JasperReport; -import net.sf.jasperreports.engine.xml.JRXmlLoader; -import net.sf.jasperreports.engine.design.JasperDesign; -import net.sf.jasperreports.engine.JasperCompileManager; -import net.sf.jasperreports.engine.JasperFillManager; -import net.sf.jasperreports.engine.JasperPrint; -import net.sf.jasperreports.view.JasperViewer; -import net.sf.jasperreports.engine.JRParameter; - -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - - -public class test_ultrasound_print { - public static void main(String[] args) { - try { - // 1. Put the data sources into the parameters map - Map parameters = new HashMap<>(); - - // Set locale to Vietnamese for number formatting and dates - parameters.put(JRParameter.REPORT_LOCALE, new Locale("vi", "VN")); - - // 2. Sample data parameters - parameters.put("clinicName", "BSK CLINIC"); - parameters.put("clinicAddress", "123 Main Street, City, Country"); - parameters.put("clinicPhone", "0123-456-789"); - - parameters.put("patientName", "Nguyễn Thị B"); - parameters.put("patientDOB", "20/07/1985"); - parameters.put("patientGender", "Nữ"); - parameters.put("patientAddress", "456 Đường DEF, Phường UVW, Quận 2, TP.HCM"); - parameters.put("patientDiagnos", "Theo dõi thai kỳ tuần 12"); - - parameters.put("doctorName", "BS. Trần Văn C"); - parameters.put("checkupDate", "22/12/2024"); - - // 3. Add the RTF content for the notes, with corrected font sizes. - // RTF font sizes are in "half-points", so \fs24 = 12pt. - String rtfContent = "{\\rtf1\\ansi\n" + - "{\\fonttbl\\f0\\fnil Monospaced;\\f1\\fnil Times New Roman;}\n" + - "{\\colortbl\\red0\\green0\\blue0;\\red51\\green51\\blue51;\\red0\\green0\\blue255;}\n" + - "\n" + - "\\li0\\ri0\\fi0\\f1\\fs28\\i0\\b\\ul0\\cf2 Test\\fs24\\cf1\\par\n" + // Heading at 14pt, main text at 12pt - "\\par\n" + - "dawdawd\\par\n" + - "ad\\par\n" + - " aw\\par\n" + - "daw da\\b0 daw dad aw\\ul d awd awd \\par\n" + - "\\ul0\\tab\\tab\\ul awdawd\\ul0\\par\n" + - "\\li0\\ri0\\fi0\\ul0\\par\n" + - "}"; - parameters.put("checkupNote", rtfContent); - parameters.put("checkupConclusion", "Thai nhi phát triển bình thường, dự kiến sinh trong 3 tháng tới."); // Normal string - parameters.put("checkupSuggestion", "Bổ sung sắt và canxi, tái khám sau 4 tuần."); // Normal string - - - // 4. Add the re-checkup date - parameters.put("reCheckupDate", "ngày 29 tháng 12 năm 2024"); - - // 5. Add barcode number - parameters.put("barcodeNumber", "2024001235"); - - // 6. Set the number of images to display - int numberOfImages = 4; - parameters.put("numberImage", numberOfImages); - - // 7. Add logo image path - String projectDir = System.getProperty("user.dir"); - String logoPath = projectDir + "/src/main/java/BsK/client/ui/assets/icon/logo.jpg"; - parameters.put("logoImage", logoPath); - - // 8. Add paths for the 6 ultrasound images - String imageDir = projectDir + "/img_db/8/"; - String[] imageFiles = { - "IMG_8_20250619_033320.jpg", - "IMG_8_20250619_033621.jpg", - "IMG_8_20250619_033622.jpg", - "IMG_8_20250619_033623.jpg", - "IMG_8_20250628_220921.jpg", - "IMG_9_20250619_034013.jpg" - }; - - for (int i = 0; i < 6; i++) { - if (i < numberOfImages) { - parameters.put("image" + (i + 1), imageDir + imageFiles[i]); - } else { - parameters.put("image" + (i + 1), null); // Pass null for unused image slots - } - } - - // 9. Load and compile the report - String jrxmlPath = projectDir + "/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/ultrasoundresult.jrxml"; - InputStream inputStream = new FileInputStream(new File(jrxmlPath)); - - JasperDesign jasperDesign = JRXmlLoader.load(inputStream); - JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign); - - // 10. Fill the report. Since there's no table, we use an JREmptyDataSource. - JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, new JREmptyDataSource()); - - // 11. View the report - JasperViewer.viewReport(jasperPrint, false); // `false` to prevent app exit on close - - } catch (Exception e) { - e.printStackTrace(); - } - } -} \ No newline at end of file diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/ultrasoundresult.jasper b/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/ultrasoundresult.jasper deleted file mode 100644 index 85a7db4..0000000 Binary files a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/ultrasoundresult.jasper and /dev/null differ diff --git a/src/main/java/BsK/server/network/handler/ServerHandler.java b/src/main/java/BsK/server/network/handler/ServerHandler.java index cb64f36..ec9430b 100644 --- a/src/main/java/BsK/server/network/handler/ServerHandler.java +++ b/src/main/java/BsK/server/network/handler/ServerHandler.java @@ -124,9 +124,7 @@ public class ServerHandler extends SimpleChannelInboundHandler= CAST(strftime('%s', date('now', 'localtime', 'start of day')) AS INTEGER) * 1000 - AND - a.checkup_date < CAST(strftime('%s', date('now', 'localtime', 'start of day', '+1 day')) AS INTEGER) * 1000""" + date(a.checkup_date / 1000, 'unixepoch', '+7 hours') = date('now', '+7 hours')""" ); if (!rs.isBeforeFirst()) { @@ -2196,15 +2194,22 @@ public class ServerHandler extends SimpleChannelInboundHandler= CAST(strftime('%s', date('now', 'localtime', 'start of day')) AS INTEGER) * 1000\n" + - "AND a.checkup_date < CAST(strftime('%s', date('now', 'localtime', 'start of day', '+1 day')) AS INTEGER) * 1000" + """ + SELECT + a.checkup_id, a.checkup_date, c.customer_last_name, c.customer_first_name, + d.doctor_first_name, d.doctor_last_name, a.suggestion, a.diagnosis, a.notes, + a.status, a.customer_id, c.customer_number, c.customer_address, + a.customer_weight, a.customer_height, c.customer_gender, c.customer_dob, + a.checkup_type, a.conclusion, a.reCheckupDate, c.cccd_ddcn, a.heart_beat, + a.blood_pressure, c.drive_url, a.doctor_ultrasound_id, a.queue_number + FROM + checkup AS a + JOIN + customer AS c ON a.customer_id = c.customer_id + JOIN + Doctor D ON a.doctor_id = D.doctor_id + WHERE + date(a.checkup_date / 1000, 'unixepoch', '+7 hours') = date('now', '+7 hours')""" ); String[][] resultArray; diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/medserinvoice.jrxml b/src/main/resources/print_forms/medserinvoice.jrxml similarity index 95% rename from src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/medserinvoice.jrxml rename to src/main/resources/print_forms/medserinvoice.jrxml index b08e504..c95111c 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/medserinvoice.jrxml +++ b/src/main/resources/print_forms/medserinvoice.jrxml @@ -35,7 +35,7 @@ - + @@ -61,7 +61,6 @@ - @@ -69,6 +68,7 @@ + @@ -563,45 +563,41 @@ - <element kind="image" uuid="c596ac6f-18d9-4cfe-a74e-58b1f7d11ecc" x="-10" y="-4" width="90" height="83"> - <expression><![CDATA[$P{logoImage}]]></expression> - </element> - <element kind="textField" uuid="48bf4793-8d8d-427d-b739-8f34f051192f" x="80" y="-4" width="359" height="25" forecolor="#FF0905" fontName="Times New Roman" fontSize="18.0" bold="true" hTextAlign="Center"> + <element kind="textField" uuid="48bf4793-8d8d-427d-b739-8f34f051192f" x="1" y="-4" width="359" height="25" forecolor="#FF0905" fontName="Times New Roman" fontSize="18.0" bold="true" hTextAlign="Left"> <expression><![CDATA[$P{clinicPrefix}]]></expression> </element> - <element kind="staticText" uuid="d8e95ce7-3ac0-44a7-ac8f-65821b7f373c" x="80" y="47" width="150" height="15" fontName="Times New Roman" fontSize="12.0" bold="true" hTextAlign="Left"> + <element kind="staticText" uuid="d8e95ce7-3ac0-44a7-ac8f-65821b7f373c" x="1" y="47" width="150" height="15" fontName="Times New Roman" fontSize="12.0" bold="true" hTextAlign="Left"> <text><![CDATA[Địa chỉ: ]]></text> </element> - <element kind="textField" uuid="9883203e-fd4b-4110-a4b9-2c8c257ce5fa" x="126" y="47" width="314" height="15" fontName="Times New Roman" fontSize="12.0"> + <element kind="textField" uuid="9883203e-fd4b-4110-a4b9-2c8c257ce5fa" x="47" y="47" width="314" height="15" fontName="Times New Roman" fontSize="12.0" hTextAlign="Left"> <expression><![CDATA[$P{clinicAddress}]]></expression> </element> - <element kind="staticText" uuid="f00706ca-903c-4089-b3a1-33be68f6112b" x="80" y="62" width="150" height="15" fontName="Times New Roman" fontSize="12.0" bold="true" hTextAlign="Left"> + <element kind="staticText" uuid="f00706ca-903c-4089-b3a1-33be68f6112b" x="1" y="62" width="150" height="15" fontName="Times New Roman" fontSize="12.0" bold="true" hTextAlign="Left"> <text><![CDATA[SĐT:]]></text> </element> - <element kind="textField" uuid="2af00e22-702e-42cb-a6fb-19d401a58170" x="110" y="62" width="330" height="15" fontName="Times New Roman" fontSize="12.0"> + <element kind="textField" uuid="2af00e22-702e-42cb-a6fb-19d401a58170" x="31" y="62" width="330" height="15" fontName="Times New Roman" fontSize="12.0" hTextAlign="Left"> <expression><![CDATA[$P{clinicPhone}]]></expression> </element> - <element kind="component" uuid="35037abf-0984-4b9e-8a05-f8fae38d7dcc" x="490" y="0" width="65" height="43"> - <component kind="barcode4j:Code128"> - <codeExpression><![CDATA[$P{barcodeNumber}]]></codeExpression> - </component> - </element> <element kind="staticText" uuid="de38fb46-49af-4f48-8c33-f97680bcc7fa" x="135" y="71" width="284" height="21" fontName="Times New Roman" fontSize="18.0" bold="true" hTextAlign="Center"> <text><![CDATA[TOA THUỐC & DỊCH VỤ]]></text> <property name="com.jaspersoft.studio.unit.height" value="pixel"/> </element> - <element kind="component" uuid="b8dc3582-162b-47d9-9501-fbf3bfc63fbd" x="440" y="0" width="46" height="39"> - <component kind="barcode4j:QRCode"> - <codeExpression><![CDATA[$P{driveURL}]]></codeExpression> - </component> - </element> - <element kind="staticText" uuid="53b28743-6b3c-4700-b84d-a96a93371dbf" x="434" y="43" width="55" height="14" fontName="Times New Roman" fontSize="8.0" bold="false" hTextAlign="Center"> - <printWhenExpression><![CDATA[$P{driveURL} != null && !$P{driveURL}.trim().isEmpty()]]></printWhenExpression> + <element kind="staticText" uuid="53b28743-6b3c-4700-b84d-a96a93371dbf" x="377" y="62" width="55" height="14" fontName="Times New Roman" fontSize="8.0" bold="false" hTextAlign="Center"> + <printWhenExpression><![CDATA[$P{driveURL} != null]]></printWhenExpression> <text><![CDATA[Xem KQ online]]></text> </element> - <element kind="textField" uuid="9dcab6b1-a9ce-4aa9-9df9-232869b3ab24" x="80" y="21" width="359" height="25" forecolor="#FF0905" fontName="Times New Roman" fontSize="18.0" bold="true" hTextAlign="Center"> + <element kind="textField" uuid="9dcab6b1-a9ce-4aa9-9df9-232869b3ab24" x="1" y="21" width="359" height="25" forecolor="#FF0905" fontName="Times New Roman" fontSize="18.0" bold="true" hTextAlign="Left"> <expression><![CDATA[$P{clinicName}]]></expression> </element> + <element kind="image" uuid="bd44c818-46a4-4ccf-8ac4-1e78cce1442c" x="370" y="-4" width="68" height="66"> + <expression><![CDATA[$P{driveURL}]]></expression> + </element> + <element kind="image" uuid="9a508076-24a7-46db-a8d4-e5e643f26bd2" x="451" y="-4" width="104" height="44"> + <expression><![CDATA[$P{barcodeNumber}]]></expression> + </element> + <element kind="textField" uuid="6fa6eee4-7f0a-4741-8ede-1fd222ffed22" x="451" y="41" width="104" height="15" fontName="Times New Roman" fontSize="12.0" hTextAlign="Center"> + <expression><![CDATA[$P{id}]]></expression> + </element> diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/ultrasoundresult.jrxml b/src/main/resources/print_forms/ultrasoundresult.jrxml similarity index 100% rename from src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/ultrasoundresult.jrxml rename to src/main/resources/print_forms/ultrasoundresult.jrxml diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/ultrasoundresult_potrait.jrxml b/src/main/resources/print_forms/ultrasoundresult_potrait.jrxml similarity index 100% rename from src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/ultrasoundresult_potrait.jrxml rename to src/main/resources/print_forms/ultrasoundresult_potrait.jrxml diff --git a/temp-jar-extract/META-INF/MANIFEST.MF b/temp-jar-extract/META-INF/MANIFEST.MF new file mode 100644 index 0000000..c76b615 --- /dev/null +++ b/temp-jar-extract/META-INF/MANIFEST.MF @@ -0,0 +1,5 @@ +Manifest-Version: 1.0 +Created-By: Maven Archiver 3.6.1 +Build-Jdk-Spec: 21 +Main-Class: BsK.client.Client + diff --git a/temp/barcodes/invoice_barcode.png b/temp/barcodes/invoice_barcode.png new file mode 100644 index 0000000..5bcacfa Binary files /dev/null and b/temp/barcodes/invoice_barcode.png differ diff --git a/temp/qrcodes/invoice_qrcode.png b/temp/qrcodes/invoice_qrcode.png new file mode 100644 index 0000000..2053e46 Binary files /dev/null and b/temp/qrcodes/invoice_qrcode.png differ