mirror of
https://github.com/tiennm99/BSK-All-in-One-Clinic-Management-System.git
synced 2026-10-20 02:16:44 +00:00
[update] Revise medical invoice generation to include detailed supplement information and enhance printing functionality with JasperReports integration. Update CheckUpPage and MedicineDialog to manage original prescriptions and track changes effectively, improving user experience during prescription modifications.
This commit is contained in:
1 parent
57a19bcbf7
commit
a579163960
11 files changed
+1138
-1001
No files matched your search
Binary file not shown.
@@ -267,5 +267,12 @@
|
||||
<version>7.0.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JasperReports PDF Extension - Required for PDF export -->
|
||||
<dependency>
|
||||
<groupId>net.sf.jasperreports</groupId>
|
||||
<artifactId>jasperreports-pdf</artifactId>
|
||||
<version>7.0.3</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 7.4 KiB |
@@ -1328,8 +1328,15 @@ public class CheckUpPage extends JPanel {
|
||||
genderComboBox.getSelectedItem().toString(),
|
||||
customerAddressField.getText() + ", " + (wardComboBox.getSelectedItem() != null ? wardComboBox.getSelectedItem().toString() : "") + ", " + (districtComboBox.getSelectedItem() != null ? districtComboBox.getSelectedItem().toString() : "") + ", " + (provinceComboBox.getSelectedItem() != null ? provinceComboBox.getSelectedItem().toString() : ""),
|
||||
doctorComboBox.getSelectedItem().toString(), diagnosisField.getText(),
|
||||
conclusionField.getText(), medicinePrescription, servicePrescription);
|
||||
medicineInvoice.createDialog(mainFrame);
|
||||
conclusionField.getText(), medicinePrescription, servicePrescription,
|
||||
// fake supplements
|
||||
new String[][] {
|
||||
{"1", "Vitamin D3", "1", "viên", "1 viên/ngày sau ăn sáng", "30", "2000", "60000", "Bổ sung vitamin D"},
|
||||
{"2", "Omega 3", "2", "viên", "2 viên/ngày sau ăn", "60", "1500", "90000", "Bổ sung dầu cá"},
|
||||
{"3", "Calcium 500mg", "1", "viên", "1 viên/ngày sau ăn tối", "30", "2500", "75000", "Bổ sung canxi"}
|
||||
}
|
||||
);
|
||||
medicineInvoice.showDirectJasperViewer(); // Use the direct JasperViewer method
|
||||
break;
|
||||
case "ultrasound":
|
||||
if (selectedImagesForPrint.isEmpty()) {
|
||||
|
||||
+73
-5
@@ -52,6 +52,7 @@ public class MedicineDialog extends JDialog {
|
||||
|
||||
private List<Medicine> medicines = new ArrayList<>();
|
||||
private String[][] medicinePrescription;
|
||||
private String[][] originalPrescription; // Store original data for comparison
|
||||
private static final Logger logger = LoggerFactory.getLogger(MedicineDialog.class);
|
||||
|
||||
public String[][] getMedicinePrescription() {
|
||||
@@ -87,12 +88,14 @@ public class MedicineDialog extends JDialog {
|
||||
public MedicineDialog(final Frame parent) {
|
||||
super(parent, "Đơn thuốc", true);
|
||||
this.medicinePrescription = new String[0][0];
|
||||
this.originalPrescription = new String[0][0];
|
||||
init(parent);
|
||||
}
|
||||
|
||||
public MedicineDialog(final Frame parent, String[][] existingPrescription) {
|
||||
super(parent, "Đơn thuốc", true);
|
||||
this.medicinePrescription = existingPrescription != null ? existingPrescription : new String[0][0];
|
||||
this.originalPrescription = deepCopyArray(existingPrescription);
|
||||
init(parent);
|
||||
if (existingPrescription != null) {
|
||||
for (String[] row : existingPrescription) {
|
||||
@@ -472,14 +475,35 @@ public class MedicineDialog extends JDialog {
|
||||
|
||||
okButton.addActionListener(e -> {
|
||||
collectPrescriptionData();
|
||||
if (medicinePrescription == null || medicinePrescription.length == 0) {
|
||||
JOptionPane.showMessageDialog(this, "Chưa có thuốc nào được chọn.", "Thông báo", JOptionPane.INFORMATION_MESSAGE);
|
||||
|
||||
// Check if there are changes compared to the original prescription
|
||||
boolean hasChanges = hasDataChanged();
|
||||
|
||||
if (!hasChanges) {
|
||||
// No changes made, allow closing without warning
|
||||
logger.info("No changes made to prescription.");
|
||||
dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
// If there are changes but no items selected, show a confirmation
|
||||
if (medicinePrescription == null || medicinePrescription.length == 0) {
|
||||
int choice = JOptionPane.showConfirmDialog(this,
|
||||
"Bạn đã xóa tất cả thuốc khỏi đơn. Bạn có muốn lưu thay đổi này không?",
|
||||
"Xác nhận",
|
||||
JOptionPane.YES_NO_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE);
|
||||
if (choice != JOptionPane.YES_OPTION) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Prescription saved.");
|
||||
for (String[] row : medicinePrescription) {
|
||||
logger.info("Med: ID={}, Name={}, Qty={}, Unit={}, M={}, N={}, E={}, Price={}, Total={}, Note={}",
|
||||
row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9]);
|
||||
if (medicinePrescription != null) {
|
||||
for (String[] row : medicinePrescription) {
|
||||
logger.info("Med: ID={}, Name={}, Qty={}, Unit={}, M={}, N={}, E={}, Price={}, Total={}, Note={}",
|
||||
row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9]);
|
||||
}
|
||||
}
|
||||
dispose();
|
||||
});
|
||||
@@ -660,6 +684,50 @@ public class MedicineDialog extends JDialog {
|
||||
}
|
||||
}
|
||||
|
||||
private String[][] deepCopyArray(String[][] original) {
|
||||
if (original == null) {
|
||||
return new String[0][0];
|
||||
}
|
||||
String[][] copy = new String[original.length][];
|
||||
for (int i = 0; i < original.length; i++) {
|
||||
if (original[i] != null) {
|
||||
copy[i] = new String[original[i].length];
|
||||
System.arraycopy(original[i], 0, copy[i], 0, original[i].length);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
private boolean hasDataChanged() {
|
||||
collectPrescriptionData();
|
||||
|
||||
// If lengths are different, there's a change
|
||||
if (originalPrescription.length != medicinePrescription.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If both are empty, no changes
|
||||
if (originalPrescription.length == 0 && medicinePrescription.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare each row
|
||||
for (int i = 0; i < originalPrescription.length; i++) {
|
||||
if (originalPrescription[i].length != medicinePrescription[i].length) {
|
||||
return true;
|
||||
}
|
||||
for (int j = 0; j < originalPrescription[i].length; j++) {
|
||||
String original = originalPrescription[i][j];
|
||||
String current = medicinePrescription[i][j];
|
||||
if (!java.util.Objects.equals(original, current)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.info("Cleaning up MedicineDialog listeners");
|
||||
|
||||
+243
-287
@@ -1,19 +1,14 @@
|
||||
package BsK.client.ui.component.CheckUpPage.PrintDialog;
|
||||
|
||||
import BsK.client.LocalStorage;
|
||||
import com.itextpdf.io.image.ImageData;
|
||||
import com.itextpdf.io.image.ImageDataFactory;
|
||||
import com.itextpdf.kernel.font.PdfFont;
|
||||
import com.itextpdf.kernel.font.PdfFontFactory;
|
||||
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.element.*;
|
||||
import com.itextpdf.layout.element.Image;
|
||||
import com.itextpdf.layout.property.UnitValue;
|
||||
import com.itextpdf.barcodes.Barcode128;
|
||||
import com.itextpdf.kernel.colors.ColorConstants;
|
||||
import BsK.client.ui.component.CheckUpPage.PrintDialog.print_forms.InvoiceItem;
|
||||
|
||||
// JasperReports imports
|
||||
import net.sf.jasperreports.engine.*;
|
||||
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
|
||||
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;
|
||||
@@ -50,37 +45,108 @@ public class MedicineInvoice{
|
||||
private String id;
|
||||
private String[][] med; // Name, Quantity, Price
|
||||
private String[][] services; // Name, Quantity, Price
|
||||
private String[][] supplements; // Name, Quantity, Price
|
||||
private static final DecimalFormat vndFormatter = new DecimalFormat("#,##0");
|
||||
|
||||
public static void main(String[] args) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
JButton openDialogButton = new JButton("Open Medicine Invoice");
|
||||
JFrame frame = new JFrame("Medicine Invoice Test");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setSize(600, 400);
|
||||
frame.setLayout(new GridLayout(3, 2, 10, 10));
|
||||
|
||||
openDialogButton.addActionListener(e -> new MedicineInvoice("1212", "Nguyễn Văn A", "01/01/1990", "0123456789",
|
||||
// Test Case 1: Only Medicines
|
||||
JButton medicineOnlyButton = new JButton("Only Medicines");
|
||||
medicineOnlyButton.addActionListener(e -> new MedicineInvoice("1001", "Nguyễn Văn A", "01/01/1990", "0123456789",
|
||||
"Nam", "123 Đường ABC, Quận XYZ, TP HCM", "Bác sĩ XYZ", "Sốt cao",
|
||||
"Nghỉ ngơi nhiều, uống nhiều nước",
|
||||
new String[][]{
|
||||
{"Paracetamol", "2", "5000"},
|
||||
{"Vitamin C", "1", "10000"},
|
||||
{"Amoxicillin", "1", "20000"}
|
||||
{"1", "Paracetamol", "2", "viên", "1", "2", "1", "5000", "10000", "Uống sau ăn"}
|
||||
},
|
||||
new String[][]{}, // No services
|
||||
new String[][]{} // No supplements
|
||||
).createDialog(frame));
|
||||
|
||||
// Test Case 2: Only Services
|
||||
JButton serviceOnlyButton = new JButton("Only Services");
|
||||
serviceOnlyButton.addActionListener(e -> new MedicineInvoice("1002", "Trần Thị B", "15/05/1985", "0987654321",
|
||||
"Nữ", "456 Đường DEF, Quận ABC, TP HCM", "Bác sĩ ABC", "Khám tổng quát",
|
||||
"Theo dõi định kỳ",
|
||||
new String[][]{}, // No medicines
|
||||
new String[][] {
|
||||
{"1", "Khám tổng quát", "1", "150000", "150000", "Kiểm tra sức khỏe tổng quát"},
|
||||
{"2", "Xét nghiệm máu", "1", "80000", "80000", "Xét nghiệm công thức máu"}
|
||||
},
|
||||
new String[][]{} // No supplements
|
||||
).createDialog(frame));
|
||||
|
||||
// Test Case 3: Only Supplements
|
||||
JButton supplementOnlyButton = new JButton("Only Supplements");
|
||||
supplementOnlyButton.addActionListener(e -> new MedicineInvoice("1003", "Lê Văn C", "20/12/1992", "0456789123",
|
||||
"Nam", "789 Đường GHI, Quận DEF, TP HCM", "Bác sĩ DEF", "Tư vấn dinh dưỡng",
|
||||
"Bổ sung vitamin và khoáng chất",
|
||||
new String[][]{}, // No medicines
|
||||
new String[][]{}, // No services
|
||||
new String[][] {
|
||||
{"1", "Vitamin D3", "1", "viên", "1 viên/ngày sau ăn sáng", "30", "2000", "60000", "Bổ sung vitamin D"},
|
||||
{"2", "Omega 3", "2", "viên", "2 viên/ngày sau ăn", "60", "1500", "90000", "Bổ sung dầu cá"}
|
||||
}
|
||||
).createDialog(frame));
|
||||
|
||||
// Test Case 4: Medicines + Services (No Supplements)
|
||||
JButton medServiceButton = new JButton("Medicines + Services");
|
||||
medServiceButton.addActionListener(e -> new MedicineInvoice("1004", "Phạm Thị D", "10/03/1988", "0789123456",
|
||||
"Nữ", "321 Đường JKL, Quận GHI, TP HCM", "Bác sĩ GHI", "Viêm họng",
|
||||
"Điều trị kháng sinh và theo dõi",
|
||||
new String[][]{
|
||||
{"1", "Amoxicillin", "1", "viên", "1", "1", "0", "20000", "20000", "Uống trước ăn 30 phút"}
|
||||
},
|
||||
new String[][] {
|
||||
{"Khám tổng quát", "1", "150000"},
|
||||
{"Xét nghiệm máu", "1", "80000"}
|
||||
{"1", "Khám tai mũi họng", "1", "100000", "100000", "Khám chuyên khoa"}
|
||||
},
|
||||
new String[][]{} // No supplements
|
||||
).createDialog(frame));
|
||||
|
||||
// Test Case 5: All Three Categories
|
||||
JButton allCategoriesButton = new JButton("All Categories");
|
||||
allCategoriesButton.addActionListener(e -> new MedicineInvoice("1005", "Hoàng Văn E", "25/07/1990", "0654321987",
|
||||
"Nam", "654 Đường MNO, Quận JKL, TP HCM", "Bác sĩ JKL", "Kiểm tra sức khỏe định kỳ",
|
||||
"Tổng quát + bổ sung dinh dưỡng",
|
||||
new String[][]{
|
||||
{"1", "Vitamin C", "1", "viên", "1", "0", "0", "10000", "10000", "Uống buổi sáng"}
|
||||
},
|
||||
new String[][] {
|
||||
{"1", "Khám tổng quát", "1", "150000", "150000", "Kiểm tra sức khỏe tổng quát"}
|
||||
},
|
||||
new String[][] {
|
||||
{"1", "Calcium 500mg", "1", "viên", "1 viên/ngày sau ăn tối", "30", "2500", "75000", "Bổ sung canxi"}
|
||||
}
|
||||
).createDialog(null));
|
||||
JFrame frame = new JFrame("Main Application");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setSize(400, 300);
|
||||
frame.setLayout(new FlowLayout());
|
||||
frame.add(openDialogButton);
|
||||
).createDialog(frame));
|
||||
|
||||
// Test Case 6: Empty Invoice (No data)
|
||||
JButton emptyButton = new JButton("Empty Invoice");
|
||||
emptyButton.addActionListener(e -> new MedicineInvoice("1006", "Võ Thị F", "05/11/1995", "0321654987",
|
||||
"Nữ", "987 Đường PQR, Quận MNO, TP HCM", "Bác sĩ MNO", "Tư vấn y tế",
|
||||
"Chỉ tư vấn, không kê đơn",
|
||||
new String[][]{}, // No medicines
|
||||
new String[][]{}, // No services
|
||||
new String[][]{} // No supplements
|
||||
).createDialog(frame));
|
||||
|
||||
frame.add(medicineOnlyButton);
|
||||
frame.add(serviceOnlyButton);
|
||||
frame.add(supplementOnlyButton);
|
||||
frame.add(medServiceButton);
|
||||
frame.add(allCategoriesButton);
|
||||
frame.add(emptyButton);
|
||||
|
||||
frame.setVisible(true);
|
||||
});
|
||||
}
|
||||
|
||||
public MedicineInvoice(String id, String patientName, String patientDOB, String patientPhone,
|
||||
String patientGender, String patientAddress, String doctorName, String diagnosis,
|
||||
String notes, String[][] med, String[][] services) {
|
||||
String notes, String[][] med, String[][] services, String[][] supplements) {
|
||||
this.id = id;
|
||||
this.patientName = patientName;
|
||||
this.patientDOB = patientDOB;
|
||||
@@ -100,9 +166,26 @@ public class MedicineInvoice{
|
||||
this.date = formattedDate;
|
||||
this.med = med;
|
||||
this.services = services;
|
||||
this.supplements = supplements;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shows the invoice directly in JasperViewer without creating a custom dialog
|
||||
*/
|
||||
public void showDirectJasperViewer() {
|
||||
try {
|
||||
String pdfPath = "medical_invoice.pdf";
|
||||
generatePdf(pdfPath);
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
|
||||
public void createDialog(JFrame parent) {
|
||||
dialog = new JDialog(parent, "Medicine Invoice", true);
|
||||
dialog.setSize(600, 600);
|
||||
@@ -179,14 +262,22 @@ public class MedicineInvoice{
|
||||
}
|
||||
});
|
||||
|
||||
// Print PDF Action
|
||||
// Print PDF Action - Show JasperViewer
|
||||
printButton.addActionListener(e -> {
|
||||
try {
|
||||
File pdfFile = new File(pdfPath);
|
||||
printPdf(pdfFile);
|
||||
if (jasperPrint != null) {
|
||||
// Close our custom dialog first
|
||||
dialog.dispose();
|
||||
|
||||
// Use the constructor to prevent the application from closing
|
||||
JasperViewer viewer = new JasperViewer(jasperPrint, false);
|
||||
viewer.setVisible(true);
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(dialog, "Report not generated yet. Please try again.");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
JOptionPane.showMessageDialog(dialog, "Error printing PDF: " + ex.getMessage());
|
||||
JOptionPane.showMessageDialog(dialog, "Error opening print viewer: " + ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -194,275 +285,140 @@ public class MedicineInvoice{
|
||||
dialog.setVisible(true);
|
||||
}
|
||||
|
||||
private JasperPrint jasperPrint; // Store JasperPrint for reuse
|
||||
|
||||
private void generatePdf(String pdfPath) throws Exception {
|
||||
PdfWriter writer = new PdfWriter(pdfPath);
|
||||
PdfDocument pdfDoc = new PdfDocument(writer);
|
||||
Document document = new Document(pdfDoc); // Default A4 size
|
||||
|
||||
// Set document margins - REDUCED
|
||||
document.setMargins(20, 25, 20, 25); // Smaller margins (top, right, bottom, left)
|
||||
|
||||
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);
|
||||
|
||||
// --- HEADER SECTION ---
|
||||
Table headerTable = new Table(UnitValue.createPercentArray(new float[]{1.5f, 3.5f}))
|
||||
.setWidth(UnitValue.createPercentValue(100))
|
||||
.setBorder(Border.NO_BORDER)
|
||||
.setMarginBottom(5); // Reduced margin bottom
|
||||
|
||||
try {
|
||||
String logoPath = "src/main/java/BsK/client/ui/assets/icon/clinic_logo.png";
|
||||
ImageData imageData = ImageDataFactory.create(logoPath);
|
||||
Image logo = new Image(imageData).scaleToFit(60, 60).setMarginRight(15); // Slightly smaller logo & margin
|
||||
headerTable.addCell(new Cell().add(logo).setBorder(Border.NO_BORDER).setVerticalAlignment(com.itextpdf.layout.property.VerticalAlignment.MIDDLE));
|
||||
} catch (Exception e) {
|
||||
headerTable.addCell(new Cell().setBorder(Border.NO_BORDER));
|
||||
System.err.println("Logo image not found or error loading: " + e.getMessage());
|
||||
}
|
||||
|
||||
Paragraph clinicInfoParagraph = new Paragraph()
|
||||
.add(new Text(LocalStorage.ClinicName + "\n").setFont(boldFont).setFontSize(12)) // Reduced font
|
||||
.add(new Text("Địa chỉ: " + LocalStorage.ClinicAddress + "\n").setFontSize(9)) // Reduced font
|
||||
.add(new Text("Điện thoại: " + LocalStorage.ClinicPhone).setFontSize(9)) // Reduced font
|
||||
.setFont(font);
|
||||
headerTable.addCell(new Cell().add(clinicInfoParagraph)
|
||||
.setTextAlignment(com.itextpdf.layout.property.TextAlignment.LEFT)
|
||||
.setVerticalAlignment(com.itextpdf.layout.property.VerticalAlignment.MIDDLE)
|
||||
.setBorder(Border.NO_BORDER).setPaddingLeft(5)); // Reduced padding
|
||||
|
||||
document.add(headerTable);
|
||||
// 1. Create data sources for medicines, services, and supplements
|
||||
java.util.List<InvoiceItem> medicines = new ArrayList<>();
|
||||
java.util.List<InvoiceItem> serviceItems = new ArrayList<>();
|
||||
java.util.List<InvoiceItem> supplementItems = new ArrayList<>();
|
||||
|
||||
// --- BARCODE FOR CHECKUP ID ---
|
||||
if (this.id != null && !this.id.isEmpty()) {
|
||||
Barcode128 barcode = new Barcode128(pdfDoc);
|
||||
barcode.setCodeType(Barcode128.CODE128);
|
||||
barcode.setCode(this.id); // Use the checkup ID for the barcode
|
||||
barcode.setBarHeight(10f); // Further reduced barcode height (from 15f)
|
||||
barcode.setX(0.5f); // Further reduce narrow bar width (from 0.6f)
|
||||
barcode.setN(1.5f);
|
||||
barcode.setFont(null);
|
||||
|
||||
Image barcodeImage = new Image(barcode.createFormXObject(ColorConstants.BLACK, ColorConstants.BLACK, pdfDoc));
|
||||
barcodeImage.setWidth(UnitValue.createPercentValue(15)); // Further reduced width (from 20%)
|
||||
barcodeImage.setHorizontalAlignment(com.itextpdf.layout.property.HorizontalAlignment.CENTER);
|
||||
barcodeImage.setMarginTop(1); // Further reduced space above barcode
|
||||
barcodeImage.setMarginBottom(1); // Further reduced space below barcode
|
||||
document.add(barcodeImage);
|
||||
|
||||
Paragraph idText = new Paragraph(this.id)
|
||||
.setFont(font).setFontSize(5) // Further reduced font size for ID text
|
||||
.setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER)
|
||||
.setMarginBottom(2); // Further reduced margin for the ID text
|
||||
document.add(idText);
|
||||
}
|
||||
|
||||
// --- INVOICE TITLE ---
|
||||
Paragraph titleParagraph = new Paragraph("TOA THUỐC")
|
||||
.setFontSize(18).setFont(boldFont) // Reduced font size
|
||||
.setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER)
|
||||
.setMarginBottom(8); // Reduced margin
|
||||
document.add(titleParagraph);
|
||||
|
||||
// --- PATIENT AND INVOICE DETAILS SECTION ---
|
||||
Table patientDoctorTable = new Table(UnitValue.createPercentArray(new float[]{55, 45})) // Adjusted column widths
|
||||
.setWidth(UnitValue.createPercentValue(100))
|
||||
.setFontSize(9).setFont(font) // Reduced font size
|
||||
.setMarginBottom(8); // Reduced margin
|
||||
|
||||
Cell patientInfoCell = new Cell().setBorder(Border.NO_BORDER).setPadding(3); // Reduced padding
|
||||
Paragraph pName = new Paragraph().add(new Text("Họ và tên: ").setFont(boldFont)).add(patientName);
|
||||
pName.setMultipliedLeading(1.0f);
|
||||
patientInfoCell.add(pName);
|
||||
Paragraph pDOB = new Paragraph().add(new Text("Ngày sinh: ").setFont(boldFont)).add(patientDOB);
|
||||
pDOB.setMultipliedLeading(1.0f);
|
||||
patientInfoCell.add(pDOB);
|
||||
Paragraph pGender = new Paragraph().add(new Text("Giới tính: ").setFont(boldFont)).add(patientGender);
|
||||
pGender.setMultipliedLeading(1.0f);
|
||||
patientInfoCell.add(pGender);
|
||||
Paragraph pPhone = new Paragraph().add(new Text("Số điện thoại: ").setFont(boldFont)).add(patientPhone);
|
||||
pPhone.setMultipliedLeading(1.0f);
|
||||
patientInfoCell.add(pPhone);
|
||||
Paragraph pAddress = new Paragraph().add(new Text("Địa chỉ: ").setFont(boldFont)).add(patientAddress);
|
||||
pAddress.setMultipliedLeading(1.0f);
|
||||
patientInfoCell.add(pAddress);
|
||||
patientDoctorTable.addCell(patientInfoCell);
|
||||
|
||||
Cell doctorInvoiceCell = new Cell().setBorder(Border.NO_BORDER).setPadding(3); // Reduced padding
|
||||
Paragraph pDoctor = new Paragraph().add(new Text("Bác sĩ: ").setFont(boldFont)).add(doctorName);
|
||||
pDoctor.setMultipliedLeading(1.0f);
|
||||
doctorInvoiceCell.add(pDoctor);
|
||||
Paragraph pDate = new Paragraph().add(new Text("Ngày lập: ").setFont(boldFont)).add(date);
|
||||
pDate.setMultipliedLeading(1.0f);
|
||||
doctorInvoiceCell.add(pDate);
|
||||
Paragraph pInvoiceId = new Paragraph().add(new Text("Đơn thuốc số: ").setFont(boldFont)).add(id);
|
||||
pInvoiceId.setMultipliedLeading(1.0f);
|
||||
doctorInvoiceCell.add(pInvoiceId);
|
||||
Paragraph pSpace1 = new Paragraph(" ");
|
||||
pSpace1.setMultipliedLeading(1.0f);
|
||||
doctorInvoiceCell.add(pSpace1);
|
||||
Paragraph pSpace2 = new Paragraph(" ");
|
||||
pSpace2.setMultipliedLeading(1.0f);
|
||||
doctorInvoiceCell.add(pSpace2);
|
||||
patientDoctorTable.addCell(doctorInvoiceCell);
|
||||
|
||||
document.add(patientDoctorTable);
|
||||
|
||||
// --- DIAGNOSIS AND NOTES ---
|
||||
Paragraph diagnosisParagraph = new Paragraph();
|
||||
diagnosisParagraph.add(new Text("Chẩn đoán: ").setFont(boldFont)).add(diagnosis);
|
||||
diagnosisParagraph.setFont(font).setFontSize(9).setMarginBottom(2).setMultipliedLeading(1.0f);
|
||||
document.add(diagnosisParagraph);
|
||||
|
||||
if (notes != null && !notes.trim().isEmpty()) {
|
||||
Paragraph notesParagraph = new Paragraph();
|
||||
notesParagraph.add(new Text("Ghi chú (chung): ").setFont(boldFont)).add(notes);
|
||||
notesParagraph.setFont(font).setFontSize(9).setMarginBottom(5).setMultipliedLeading(1.0f);
|
||||
document.add(notesParagraph);
|
||||
} else {
|
||||
document.add(new Paragraph().setMarginBottom(5));
|
||||
}
|
||||
|
||||
// --- MEDICINE TABLE ---
|
||||
Paragraph medicineSectionTitle = new Paragraph("CHI TIẾT THUỐC")
|
||||
.setFont(boldFont).setFontSize(11) // Reduced font size
|
||||
.setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER)
|
||||
.setMarginTop(3).setMarginBottom(3); // Reduced margins
|
||||
document.add(medicineSectionTitle);
|
||||
|
||||
Table medTable = new Table(UnitValue.createPercentArray(new float[]{3.8f, 1.7f, 1.5f, 1.5f, 2.5f})) // Adjusted column widths
|
||||
.setWidth(UnitValue.createPercentValue(100))
|
||||
.setFontSize(8).setFont(font) // Reduced font size for table content
|
||||
.setMarginBottom(5); // Reduced margin
|
||||
|
||||
medTable.addHeaderCell(new Cell().add(new Paragraph("Tên thuốc")).setFont(boldFont).setFontSize(9).setBackgroundColor(com.itextpdf.kernel.colors.ColorConstants.LIGHT_GRAY).setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER).setPadding(2));
|
||||
medTable.addHeaderCell(new Cell().add(new Paragraph("Liều dùng")).setFont(boldFont).setFontSize(9).setBackgroundColor(com.itextpdf.kernel.colors.ColorConstants.LIGHT_GRAY).setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER).setPadding(2));
|
||||
medTable.addHeaderCell(new Cell().add(new Paragraph("Số lượng")).setFont(boldFont).setFontSize(9).setBackgroundColor(com.itextpdf.kernel.colors.ColorConstants.LIGHT_GRAY).setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER).setPadding(2));
|
||||
medTable.addHeaderCell(new Cell().add(new Paragraph("Đơn giá (VNĐ)")).setFont(boldFont).setFontSize(9).setBackgroundColor(com.itextpdf.kernel.colors.ColorConstants.LIGHT_GRAY).setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER).setPadding(2));
|
||||
medTable.addHeaderCell(new Cell().add(new Paragraph("Thành tiền (VNĐ)")).setFont(boldFont).setFontSize(9).setBackgroundColor(com.itextpdf.kernel.colors.ColorConstants.LIGHT_GRAY).setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER).setPadding(2));
|
||||
|
||||
long medicineTotal = 0;
|
||||
// Convert medicine data to InvoiceItem objects
|
||||
if (med != null) {
|
||||
for (String[] medicine : med) {
|
||||
if (medicine == null || medicine.length < 10) {
|
||||
medTable.addCell(new Cell(1, 5).add(new Paragraph("Thông tin thuốc không đầy đủ").setItalic().setFontSize(8)).setPadding(2));
|
||||
continue;
|
||||
}
|
||||
Paragraph medNameAndNote = new Paragraph();
|
||||
medNameAndNote.add(new Text(medicine[1]).setFontSize(8));
|
||||
if (medicine[9] != null && !medicine[9].isEmpty()) {
|
||||
medNameAndNote.add(new Text("\nGhi chú: " + medicine[9]).setFontSize(7).setItalic());
|
||||
}
|
||||
medNameAndNote.setMultipliedLeading(1.0f);
|
||||
medTable.addCell(new Cell().add(medNameAndNote).setPadding(2));
|
||||
|
||||
String dosageInfo = String.format("S: %s, T: %s, C: %s", medicine[4], medicine[5], medicine[6]);
|
||||
medTable.addCell(new Cell().add(new Paragraph(dosageInfo).setFontSize(8)).setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER).setPadding(2).setVerticalAlignment(com.itextpdf.layout.property.VerticalAlignment.MIDDLE));
|
||||
medTable.addCell(new Cell().add(new Paragraph(medicine[2] + " " + medicine[3]).setFontSize(8)).setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER).setPadding(2).setVerticalAlignment(com.itextpdf.layout.property.VerticalAlignment.MIDDLE));
|
||||
try {
|
||||
medTable.addCell(new Cell().add(new Paragraph(vndFormatter.format(Long.parseLong(medicine[7]))).setFontSize(8)).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT).setPadding(2).setVerticalAlignment(com.itextpdf.layout.property.VerticalAlignment.MIDDLE));
|
||||
medTable.addCell(new Cell().add(new Paragraph(vndFormatter.format(Long.parseLong(medicine[8]))).setFontSize(8)).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT).setPadding(2).setVerticalAlignment(com.itextpdf.layout.property.VerticalAlignment.MIDDLE));
|
||||
medicineTotal += Long.parseLong(medicine[8]);
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("Error parsing medicine price/total: " + medicine[7] + " or " + medicine[8]);
|
||||
medTable.addCell(new Cell().add(new Paragraph("Lỗi giá")).setFontSize(8).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT).setPadding(2).setVerticalAlignment(com.itextpdf.layout.property.VerticalAlignment.MIDDLE));
|
||||
medTable.addCell(new Cell().add(new Paragraph("Lỗi giá")).setFontSize(8).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT).setPadding(2).setVerticalAlignment(com.itextpdf.layout.property.VerticalAlignment.MIDDLE));
|
||||
if (medicine != null && medicine.length >= 10) {
|
||||
try {
|
||||
String dosageInfo = String.format("S: %s, T: %s, C: %s",
|
||||
medicine[4] != null ? medicine[4] : "0",
|
||||
medicine[5] != null ? medicine[5] : "0",
|
||||
medicine[6] != null ? medicine[6] : "0");
|
||||
|
||||
medicines.add(InvoiceItem.createMedicine(
|
||||
medicine[1] != null ? medicine[1] : "", // medName
|
||||
dosageInfo, // dosage
|
||||
medicine[2] != null ? Integer.parseInt(medicine[2]) : 0, // amount
|
||||
medicine[7] != null ? Double.parseDouble(medicine[7]) : 0.0, // unitPrice
|
||||
medicine[9] != null ? medicine[9] : "" // medNote
|
||||
));
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("Error parsing medicine data: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
document.add(medTable);
|
||||
|
||||
Table medTotalTable = new Table(UnitValue.createPercentArray(new float[]{7.5f, 2.5f}))
|
||||
.setWidth(UnitValue.createPercentValue(100)).setBorder(Border.NO_BORDER).setMarginBottom(3);
|
||||
medTotalTable.addCell(new Cell().add(new Paragraph("Tổng tiền thuốc:")).setFont(boldFont).setFontSize(9).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT).setBorder(Border.NO_BORDER).setPadding(1));
|
||||
medTotalTable.addCell(new Cell().add(new Paragraph(vndFormatter.format(medicineTotal) + " VNĐ")).setFont(boldFont).setFontSize(9).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT).setBorder(Border.NO_BORDER).setPadding(1));
|
||||
document.add(medTotalTable);
|
||||
|
||||
long overallTotal = medicineTotal;
|
||||
|
||||
// --- SERVICES TABLE ---
|
||||
if (services != null && services.length > 0) {
|
||||
Paragraph serviceSectionTitle = new Paragraph("CHI TIẾT DỊCH VỤ")
|
||||
.setFont(boldFont).setFontSize(11) // Reduced font size
|
||||
.setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER)
|
||||
.setMarginTop(5).setMarginBottom(3); // Reduced margins
|
||||
document.add(serviceSectionTitle);
|
||||
|
||||
Table serviceTable = new Table(UnitValue.createPercentArray(new float[]{4.5f, 1.5f, 2f, 2.5f})) // Adjusted column widths
|
||||
.setWidth(UnitValue.createPercentValue(100))
|
||||
.setFontSize(8).setFont(font) // Reduced font size for table content
|
||||
.setMarginBottom(5); // Reduced margin
|
||||
|
||||
serviceTable.addHeaderCell(new Cell().add(new Paragraph("Tên dịch vụ")).setFont(boldFont).setFontSize(9).setBackgroundColor(com.itextpdf.kernel.colors.ColorConstants.LIGHT_GRAY).setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER).setPadding(2));
|
||||
serviceTable.addHeaderCell(new Cell().add(new Paragraph("Số lượng")).setFont(boldFont).setFontSize(9).setBackgroundColor(com.itextpdf.kernel.colors.ColorConstants.LIGHT_GRAY).setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER).setPadding(2));
|
||||
serviceTable.addHeaderCell(new Cell().add(new Paragraph("Đơn giá (VNĐ)")).setFont(boldFont).setFontSize(9).setBackgroundColor(com.itextpdf.kernel.colors.ColorConstants.LIGHT_GRAY).setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER).setPadding(2));
|
||||
serviceTable.addHeaderCell(new Cell().add(new Paragraph("Thành tiền (VNĐ)")).setFont(boldFont).setFontSize(9).setBackgroundColor(com.itextpdf.kernel.colors.ColorConstants.LIGHT_GRAY).setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER).setPadding(2));
|
||||
|
||||
long serviceTotal = 0;
|
||||
// Convert service data to InvoiceItem objects
|
||||
if (services != null) {
|
||||
for (String[] service : services) {
|
||||
if (service == null || service.length < 5) {
|
||||
serviceTable.addCell(new Cell(1, 4).add(new Paragraph("Thông tin dịch vụ không đầy đủ").setItalic().setFontSize(8)).setPadding(2));
|
||||
continue;
|
||||
}
|
||||
Paragraph serNameAndNote = new Paragraph();
|
||||
serNameAndNote.add(new Text(service[1]).setFontSize(8));
|
||||
if (service.length > 5 && service[5] != null && !service[5].isEmpty()) {
|
||||
serNameAndNote.add(new Text("\nGhi chú: " + service[5]).setFontSize(7).setItalic());
|
||||
}
|
||||
serNameAndNote.setMultipliedLeading(1.0f);
|
||||
serviceTable.addCell(new Cell().add(serNameAndNote).setPadding(2));
|
||||
serviceTable.addCell(new Cell().add(new Paragraph(service[2]).setFontSize(8)).setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER).setPadding(2).setVerticalAlignment(com.itextpdf.layout.property.VerticalAlignment.MIDDLE));
|
||||
try {
|
||||
serviceTable.addCell(new Cell().add(new Paragraph(vndFormatter.format(Long.parseLong(service[3]))).setFontSize(8)).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT).setPadding(2).setVerticalAlignment(com.itextpdf.layout.property.VerticalAlignment.MIDDLE));
|
||||
serviceTable.addCell(new Cell().add(new Paragraph(vndFormatter.format(Long.parseLong(service[4]))).setFontSize(8)).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT).setPadding(2).setVerticalAlignment(com.itextpdf.layout.property.VerticalAlignment.MIDDLE));
|
||||
serviceTotal += Long.parseLong(service[4]);
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("Error parsing service price/total: " + service[3] + " or " + service[4]);
|
||||
serviceTable.addCell(new Cell().add(new Paragraph("Lỗi giá")).setFontSize(8).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT).setPadding(2).setVerticalAlignment(com.itextpdf.layout.property.VerticalAlignment.MIDDLE));
|
||||
serviceTable.addCell(new Cell().add(new Paragraph("Lỗi giá")).setFontSize(8).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT).setPadding(2).setVerticalAlignment(com.itextpdf.layout.property.VerticalAlignment.MIDDLE));
|
||||
if (service != null && service.length >= 5) {
|
||||
try {
|
||||
serviceItems.add(InvoiceItem.createService(
|
||||
service[1] != null ? service[1] : "", // serName
|
||||
service.length > 5 && service[5] != null ? service[5] : "", // serNote
|
||||
service[2] != null ? Integer.parseInt(service[2]) : 0, // serAmount
|
||||
service[3] != null ? Double.parseDouble(service[3]) : 0.0 // serUnitPrice
|
||||
));
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("Error parsing service data: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
document.add(serviceTable);
|
||||
overallTotal += serviceTotal;
|
||||
|
||||
Table serTotalTable = new Table(UnitValue.createPercentArray(new float[]{7.5f, 2.5f}))
|
||||
.setWidth(UnitValue.createPercentValue(100)).setBorder(Border.NO_BORDER).setMarginBottom(3);
|
||||
serTotalTable.addCell(new Cell().add(new Paragraph("Tổng tiền dịch vụ:")).setFont(boldFont).setFontSize(9).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT).setBorder(Border.NO_BORDER).setPadding(1));
|
||||
serTotalTable.addCell(new Cell().add(new Paragraph(vndFormatter.format(serviceTotal) + " VNĐ")).setFont(boldFont).setFontSize(9).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT).setBorder(Border.NO_BORDER).setPadding(1));
|
||||
document.add(serTotalTable);
|
||||
// Convert supplement data to InvoiceItem objects
|
||||
if (supplements != null) {
|
||||
for (String[] supplement : supplements) {
|
||||
if (supplement != null && supplement.length >= 9) {
|
||||
try {
|
||||
supplementItems.add(InvoiceItem.createSupplement(
|
||||
supplement[1] != null ? supplement[1] : "", // supName
|
||||
supplement.length > 8 && supplement[8] != null ? supplement[8] : "", // supNote
|
||||
supplement[4] != null ? supplement[4] : "", // supDosage
|
||||
supplement[5] != null ? Integer.parseInt(supplement[5]) : 0, // supAmount
|
||||
supplement[6] != null ? Double.parseDouble(supplement[6]) : 0.0 // supUnitPrice
|
||||
));
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("Error parsing supplement data: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create data sources
|
||||
JRBeanCollectionDataSource medicineDS = new JRBeanCollectionDataSource(medicines);
|
||||
JRBeanCollectionDataSource serviceDS = new JRBeanCollectionDataSource(serviceItems);
|
||||
JRBeanCollectionDataSource supplementDS = new JRBeanCollectionDataSource(supplementItems);
|
||||
|
||||
// 2. Create parameters map
|
||||
java.util.Map<String, Object> parameters = new java.util.HashMap<>();
|
||||
|
||||
// Data sources
|
||||
parameters.put("medicineDS", medicineDS);
|
||||
parameters.put("serviceDS", serviceDS);
|
||||
parameters.put("supplementDS", supplementDS);
|
||||
|
||||
// Set locale for Vietnamese formatting
|
||||
parameters.put(JRParameter.REPORT_LOCALE, new java.util.Locale("vi", "VN"));
|
||||
|
||||
// Patient information
|
||||
parameters.put("patientName", patientName != null ? patientName : "");
|
||||
parameters.put("patientDOB", patientDOB != null ? patientDOB : "");
|
||||
parameters.put("patientGender", patientGender != null ? patientGender : "");
|
||||
parameters.put("patientAddress", patientAddress != null ? patientAddress : "");
|
||||
|
||||
// Clinic information
|
||||
parameters.put("clinicName", LocalStorage.ClinicName != null ? LocalStorage.ClinicName : "");
|
||||
parameters.put("clinicPhone", LocalStorage.ClinicPhone != null ? LocalStorage.ClinicPhone : "");
|
||||
parameters.put("clinicAddress", LocalStorage.ClinicAddress != null ? LocalStorage.ClinicAddress : "");
|
||||
|
||||
// Doctor and medical information
|
||||
parameters.put("doctorName", doctorName != null ? doctorName : "");
|
||||
parameters.put("checkupDate", date != null ? date : "");
|
||||
parameters.put("patientDiagnos", diagnosis != null ? diagnosis : "");
|
||||
parameters.put("checkupNote", notes != null ? notes : "");
|
||||
|
||||
// Barcode
|
||||
parameters.put("barcodeNumber", id != null ? id : "");
|
||||
|
||||
// Logo image path
|
||||
String logoPath = System.getProperty("user.dir") + "/src/main/java/BsK/client/ui/assets/icon/logo.jpg";
|
||||
parameters.put("logoImage", logoPath);
|
||||
|
||||
// Add conditional parameters to check if data sources have data
|
||||
parameters.put("hasMedicines", medicines != null && !medicines.isEmpty());
|
||||
parameters.put("hasServices", serviceItems != null && !serviceItems.isEmpty());
|
||||
parameters.put("hasSupplements", supplementItems != null && !supplementItems.isEmpty());
|
||||
|
||||
// 3. Load and compile the JRXML template
|
||||
String jrxmlPath = System.getProperty("user.dir") + "/src/main/java/BsK/client/ui/component/CheckUpPage/PrintDialog/print_forms/medserinvoice.jrxml";
|
||||
java.io.InputStream inputStream = new java.io.FileInputStream(new java.io.File(jrxmlPath));
|
||||
|
||||
JasperDesign jasperDesign = JRXmlLoader.load(inputStream);
|
||||
JasperReport jasperReport = JasperCompileManager.compileReport(jasperDesign);
|
||||
|
||||
// 4. Fill the report with data
|
||||
jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, new JREmptyDataSource());
|
||||
|
||||
// 5. Export to PDF
|
||||
JasperExportManager.exportReportToPdfFile(jasperPrint, pdfPath);
|
||||
|
||||
inputStream.close();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new Exception("Error generating PDF with JasperReports: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
// --- OVERALL TOTAL ---
|
||||
document.add(new LineSeparator(new com.itextpdf.kernel.pdf.canvas.draw.SolidLine(0.5f)).setMarginTop(5).setMarginBottom(3));
|
||||
Table overallTotalTable = new Table(UnitValue.createPercentArray(new float[]{7.5f, 2.5f}))
|
||||
.setWidth(UnitValue.createPercentValue(100)).setBorder(Border.NO_BORDER).setMarginBottom(10);
|
||||
overallTotalTable.addCell(new Cell().add(new Paragraph("TỔNG CỘNG THANH TOÁN:")).setFont(boldFont).setFontSize(10).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT).setBorder(Border.NO_BORDER).setPadding(1));
|
||||
overallTotalTable.addCell(new Cell().add(new Paragraph(vndFormatter.format(overallTotal) + " VNĐ")).setFont(boldFont).setFontSize(10).setTextAlignment(com.itextpdf.layout.property.TextAlignment.RIGHT).setBorder(Border.NO_BORDER).setPadding(1));
|
||||
document.add(overallTotalTable);
|
||||
|
||||
// --- SIGNATURE AREA ---
|
||||
Table signatureTable = new Table(UnitValue.createPercentArray(new float[]{50, 50}))
|
||||
.setWidth(UnitValue.createPercentValue(100))
|
||||
.setBorder(Border.NO_BORDER)
|
||||
.setMarginTop(15); // Reduced margin
|
||||
|
||||
signatureTable.addCell(new Cell().setBorder(Border.NO_BORDER));
|
||||
|
||||
Paragraph signatureParagraph = new Paragraph(); // Initialize paragraph
|
||||
signatureParagraph.add(new Text("Ngày " + date.substring(0,2) + " tháng " + date.substring(3,5) + " năm " + date.substring(6) + "\n").setFontSize(9));
|
||||
signatureParagraph.add(new Text("Bác sĩ điều trị\n\n\n").setFontSize(9)); // Reduced newlines for space
|
||||
signatureParagraph.add(new Text("(Ký, ghi rõ họ tên)").setFontSize(8).setItalic());
|
||||
signatureParagraph.setFont(font)
|
||||
.setTextAlignment(com.itextpdf.layout.property.TextAlignment.CENTER)
|
||||
.setMultipliedLeading(1.0f); // Applied to the Paragraph
|
||||
|
||||
signatureTable.addCell(new Cell().add(signatureParagraph).setBorder(Border.NO_BORDER));
|
||||
document.add(signatureTable);
|
||||
|
||||
document.close();
|
||||
}
|
||||
|
||||
private void displayPdfInLabel(String pdfPath, JPanel pdfPanel) throws Exception {
|
||||
|
||||
+729
-703
File diff suppressed because it is too large.
Load diff
+7
@@ -65,7 +65,14 @@ public class test_print {
|
||||
parameters.put("clinicName", " BSK CLINIC");
|
||||
parameters.put("clinicPhone", "0123-456-789");
|
||||
parameters.put("patientName", "Nguyen Van A");
|
||||
parameters.put("patientDOB", "15/03/1990");
|
||||
parameters.put("patientGender", "Nam");
|
||||
parameters.put("patientAddress", "123 Đường ABC, Phường XYZ, Quận 1, TP.HCM");
|
||||
parameters.put("clinicAddress", "123 Main Street, City, Country");
|
||||
parameters.put("doctorName", "BS. Nguyen Van B");
|
||||
parameters.put("checkupDate", "20/12/2024");
|
||||
parameters.put("checkupNote", "Bệnh nhân cần nghỉ ngơi và tái khám sau 1 tuần");
|
||||
parameters.put("patientDiagnos", "Viêm họng cấp tính, sốt nhẹ");
|
||||
|
||||
// Add logo image path
|
||||
String logoPath = System.getProperty("user.dir") + "/src/main/java/BsK/client/ui/assets/icon/logo.jpg";
|
||||
|
||||
@@ -46,6 +46,7 @@ public class ServiceDialog extends JDialog {
|
||||
|
||||
private List<Service> services = new ArrayList<>();
|
||||
private String[][] servicePrescription;
|
||||
private String[][] originalPrescription; // Store original data for comparison
|
||||
private static final Logger logger = LoggerFactory.getLogger(ServiceDialog.class);
|
||||
|
||||
public String[][] getServicePrescription() {
|
||||
@@ -72,12 +73,14 @@ public class ServiceDialog extends JDialog {
|
||||
public ServiceDialog(Frame parent) {
|
||||
super(parent, "Thêm dịch vụ", true);
|
||||
this.servicePrescription = new String[0][0];
|
||||
this.originalPrescription = new String[0][0];
|
||||
initUI(parent);
|
||||
}
|
||||
|
||||
public ServiceDialog(Frame parent, String[][] existingPrescription) {
|
||||
super(parent, "Thêm dịch vụ", true);
|
||||
this.servicePrescription = existingPrescription != null ? existingPrescription : new String[0][0];
|
||||
this.originalPrescription = deepCopyArray(existingPrescription);
|
||||
initUI(parent);
|
||||
if (existingPrescription != null) {
|
||||
for (String[] row : existingPrescription) {
|
||||
@@ -376,10 +379,29 @@ public class ServiceDialog extends JDialog {
|
||||
|
||||
okButton.addActionListener(e -> {
|
||||
collectPrescriptionData();
|
||||
if (servicePrescription == null || servicePrescription.length == 0) {
|
||||
JOptionPane.showMessageDialog(this, "Chưa có dịch vụ nào được chọn.", "Thông báo", JOptionPane.INFORMATION_MESSAGE);
|
||||
|
||||
// Check if there are changes compared to the original prescription
|
||||
boolean hasChanges = hasDataChanged();
|
||||
|
||||
if (!hasChanges) {
|
||||
// No changes made, allow closing without warning
|
||||
logger.info("No changes made to service prescription.");
|
||||
dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
// If there are changes but no items selected, show a confirmation
|
||||
if (servicePrescription == null || servicePrescription.length == 0) {
|
||||
int choice = JOptionPane.showConfirmDialog(this,
|
||||
"Bạn đã xóa tất cả dịch vụ khỏi đơn. Bạn có muốn lưu thay đổi này không?",
|
||||
"Xác nhận",
|
||||
JOptionPane.YES_NO_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE);
|
||||
if (choice != JOptionPane.YES_OPTION) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Service prescription saved.");
|
||||
dispose();
|
||||
});
|
||||
@@ -547,6 +569,50 @@ public class ServiceDialog extends JDialog {
|
||||
this.servicePrescription = prescriptionList.toArray(new String[0][]);
|
||||
}
|
||||
|
||||
private String[][] deepCopyArray(String[][] original) {
|
||||
if (original == null) {
|
||||
return new String[0][0];
|
||||
}
|
||||
String[][] copy = new String[original.length][];
|
||||
for (int i = 0; i < original.length; i++) {
|
||||
if (original[i] != null) {
|
||||
copy[i] = new String[original[i].length];
|
||||
System.arraycopy(original[i], 0, copy[i], 0, original[i].length);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
private boolean hasDataChanged() {
|
||||
collectPrescriptionData();
|
||||
|
||||
// If lengths are different, there's a change
|
||||
if (originalPrescription.length != servicePrescription.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If both are empty, no changes
|
||||
if (originalPrescription.length == 0 && servicePrescription.length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare each row
|
||||
for (int i = 0; i < originalPrescription.length; i++) {
|
||||
if (originalPrescription[i].length != servicePrescription[i].length) {
|
||||
return true;
|
||||
}
|
||||
for (int j = 0; j < originalPrescription[i].length; j++) {
|
||||
String original = originalPrescription[i][j];
|
||||
String current = servicePrescription[i][j];
|
||||
if (!java.util.Objects.equals(original, current)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.info("Cleaning up ServiceDialog listeners");
|
||||
|
||||
@@ -111,7 +111,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
"from checkup as a\n" +
|
||||
"join customer as c on a.customer_id = c.customer_id\n" +
|
||||
"join Doctor D on a.doctor_id = D.doctor_id\n" +
|
||||
"where a.status = 'PROCESSING'"
|
||||
"where a.status = 'ĐANG KHÁM'"
|
||||
);
|
||||
|
||||
if (!rs.isBeforeFirst()) {
|
||||
@@ -178,7 +178,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
"from checkup as a\n" +
|
||||
"join customer as c on a.customer_id = c.customer_id\n" +
|
||||
"join Doctor D on a.doctor_id = D.doctor_id\n" +
|
||||
"where a.status = 'PROCESSING'"
|
||||
"where a.status = 'ĐANG KHÁM'"
|
||||
);
|
||||
|
||||
if (!rs.isBeforeFirst()) {
|
||||
|
||||
Binary file not shown.
Reference in new issue
Block a user