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 @@
-
-
-
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
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