diff --git a/.gitignore b/.gitignore
index 819ae17..9d58dd3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -250,3 +250,13 @@ image/checkup_media/8/IMG_8_20250807_001010.jpg
image/checkup_media/8/IMG_8_20250807_001050.jpg
image/checkup_media/8/ultrasound_8_20250807_001232_940.jpg
image/checkup_media/8/ultrasound_8_20250807_001253_394.jpg
+database/BSK.db
+database/BSK.db
+database/BSK.db-shm
+database/BSK.db-wal
+*.jar
+*.db
+*.db-shm
+*.db-wal
+database/*.db
+*.old
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 9dfa497..6546f14 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_Client.xml b/.idea/runConfigurations/BSK_Client.xml
index 70202fb..26fa555 100644
--- a/.idea/runConfigurations/BSK_Client.xml
+++ b/.idea/runConfigurations/BSK_Client.xml
@@ -1,10 +1,10 @@
-
+
+
+
+
-
-
-
-
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/BSK_Server.xml b/.idea/runConfigurations/BSK_Server.xml
index dedfb31..45533ca 100644
--- a/.idea/runConfigurations/BSK_Server.xml
+++ b/.idea/runConfigurations/BSK_Server.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/DATABASE_BACKUP_GUIDE.md b/DATABASE_BACKUP_GUIDE.md
new file mode 100644
index 0000000..ab44268
--- /dev/null
+++ b/DATABASE_BACKUP_GUIDE.md
@@ -0,0 +1,304 @@
+# 🗄️ BSK Clinic Database Backup Guide
+
+## ⚠️ **CRITICAL: Understanding SQLite WAL Mode**
+
+Your database uses **WAL (Write-Ahead Logging)** mode for better concurrent access. This creates **3 files**:
+
+```
+database/
+├── BSK.db ← Main database (updated periodically via "checkpoint")
+├── BSK.db-wal ← Write-Ahead Log (contains RECENT uncommitted data)
+└── BSK.db-shm ← Shared Memory (coordination file)
+```
+
+### **The Problem You Experienced:**
+
+```
+❌ WRONG - What Happened:
+1. You copied ONLY BSK.db (old data from last checkpoint)
+2. You LOST BSK.db-wal (contained checkups 184-1978)
+3. Result: 1795 checkups disappeared!
+
+✅ CORRECT - What You Should Do:
+1. Stop the server OR checkpoint first
+2. Copy the main BSK.db file (now contains all data)
+3. Restore it
+```
+
+---
+
+## 📋 **Backup Methods**
+
+### **Method 1: Using Built-in Google Drive Backup (RECOMMENDED) ✅**
+
+This is now **COMPLETELY SAFE** - backs up ALL 3 database files!
+
+**Steps:**
+1. Open **Server Dashboard**
+2. Click **"Sao lưu CSDL lên Drive"** button
+3. Watch the progress:
+ - "Đang kiểm tra các tệp cơ sở dữ liệu..."
+ - Shows size of each file (BSK.db, BSK.db-wal, BSK.db-shm)
+ - "Đang tải lên tất cả các tệp database..."
+ - "✅ Sao lưu hoàn tất!"
+4. ✅ Done! All files backed up to a timestamped folder.
+
+**What happens behind the scenes:**
+```java
+// server.jar automatically does this:
+1. Checks all 3 files: BSK.db, BSK.db-wal, BSK.db-shm
+2. Creates timestamped folder: "_Database_Backups/Backup_2025-01-15_14-30-00/"
+3. Uploads ALL files to that folder
+4. No data loss possible!
+```
+
+**Google Drive Structure:**
+```
+BSK_Clinic_Patient_Files/
+└── _Database_Backups/
+ ├── Backup_2025-01-15_14-30-00/
+ │ ├── BSK.db (main database)
+ │ ├── BSK.db-wal (uncommitted changes)
+ │ └── BSK.db-shm (shared memory)
+ └── Backup_2025-01-15_09-15-00/
+ └── ... (older backup)
+```
+
+---
+
+### **Method 2: Manual Backup with PowerShell Script**
+
+**For manual backups when server is running:**
+
+```powershell
+# Step 1: Checkpoint the database
+.\checkpoint_database.ps1
+
+# Step 2: Copy the database
+Copy-Item database\BSK.db "D:\Backups\BSK_backup_$(Get-Date -Format 'yyyy-MM-dd_HH-mm-ss').db"
+```
+
+**For manual backups when server is stopped:**
+
+```powershell
+# Just copy all 3 files
+Copy-Item database\BSK.db* "D:\Backups\"
+```
+
+---
+
+### **Method 3: Using SQLite Command Line**
+
+```bash
+# Option A: Checkpoint first (if server is running)
+sqlite3 database/BSK.db "PRAGMA wal_checkpoint(TRUNCATE);"
+
+# Option B: Create a proper backup
+sqlite3 database/BSK.db ".backup 'backup.db'"
+```
+
+---
+
+## 🔄 **Restoring from Backup**
+
+### **Method 1: Restore Complete Backup from Google Drive**
+
+**Steps:**
+1. **Stop the server** completely
+2. Download the **entire backup folder** from Google Drive
+3. Navigate to `_Database_Backups/Backup_YYYY-MM-DD_HH-MM-SS/`
+4. Download all 3 files:
+ - `BSK.db`
+ - `BSK.db-wal` (if present)
+ - `BSK.db-shm` (if present)
+5. **Delete or backup your current database files**:
+ ```powershell
+ # Backup current database
+ Move-Item database\BSK.db* backup_old\
+ ```
+6. **Copy downloaded files** to `database/` folder
+7. **Restart the server**
+8. ✅ **Done!** All data restored including uncommitted transactions
+
+### **Method 2: Restore Only Main DB (Data Loss Risk!)**
+
+⚠️ **WARNING:** Only use this if no WAL file exists in the backup!
+
+**Steps:**
+1. Stop the server
+2. Download only `BSK.db` from backup
+3. Copy to `database/` folder
+4. Restart server
+5. ⚠️ Any data in the WAL file at backup time is **lost**
+
+---
+
+## 🔧 **When to Checkpoint**
+
+SQLite automatically checkpoints when:
+- WAL file reaches **1000 pages** (~4MB)
+- Database is closed gracefully
+- Connection pool is shut down
+
+**Manual checkpoint is needed when:**
+- ⚠️ Server has been running for days without restart
+- ⚠️ You need to backup while server is running
+- ⚠️ WAL file is very large (>10MB)
+
+**Check WAL status:**
+```powershell
+.\checkpoint_database.ps1 -CheckOnly
+```
+
+---
+
+## 🚨 **Emergency: Recovering from Bad Backup**
+
+If you already uploaded a backup that's missing data:
+
+### **Option 1: Check if WAL files still exist at hospital**
+
+```powershell
+# At the hospital server, check:
+Get-ChildItem database\BSK.db*
+
+# If BSK.db-wal exists:
+sqlite3 database\BSK.db "PRAGMA wal_checkpoint(TRUNCATE);"
+# Now backup this file - it has all data!
+```
+
+### **Option 2: Restore from older backup + replay transactions**
+
+If WAL is gone, data is **permanently lost**. You'll need:
+1. Use the latest backup before modification
+2. Manually re-enter lost data
+3. Use filesystem folder IDs to identify missing checkups:
+
+```powershell
+# Find checkup folders
+Get-ChildItem image\checkup_media -Directory |
+ Where-Object { $_.Name -match '^\d+$' } |
+ Sort-Object { [int]$_.Name }
+
+# Compare with database
+sqlite3 database\BSK.db "SELECT checkup_id FROM Checkup ORDER BY checkup_id"
+```
+
+---
+
+## 📊 **Best Practices**
+
+### ✅ **DO:**
+- ✅ Use the built-in Google Drive backup button
+- ✅ Stop the server before manual file copies
+- ✅ Test your backups regularly
+- ✅ Keep multiple backup versions
+- ✅ Backup before schema changes
+- ✅ Document any manual database modifications
+
+### ❌ **DON'T:**
+- ❌ Copy only BSK.db while server is running
+- ❌ Modify the database on your machine while hospital uses it
+- ❌ Ignore WAL files during backup
+- ❌ Restore old backups without checking timestamps
+- ❌ Edit production database without testing first
+
+---
+
+## 🛠️ **Schema Change Workflow**
+
+When you need to add columns or modify the database:
+
+```
+CORRECT Process:
+──────────────────────────────────────────────────
+1. STOP the hospital server completely
+2. Backup using: .\checkpoint_database.ps1
+3. Download the backup
+4. Test changes on your machine
+5. Create migration script (ALTER TABLE commands)
+6. Send ONLY the migration script (not the whole DB)
+7. Run migration script at hospital
+8. Restart server
+9. Verify everything works
+
+NEVER:
+──────────────────────────────────────────────────
+❌ Download → Modify → Upload entire database
+ (This WILL cause data loss!)
+```
+
+### **Migration Script Example:**
+
+```sql
+-- migration_add_doctor_columns.sql
+BEGIN TRANSACTION;
+
+-- Add new column
+ALTER TABLE Doctor ADD COLUMN specialty TEXT;
+
+-- Update existing data if needed
+UPDATE Doctor SET specialty = 'General' WHERE specialty IS NULL;
+
+COMMIT;
+```
+
+**Apply migration:**
+```bash
+sqlite3 database/BSK.db < migration_add_doctor_columns.sql
+```
+
+---
+
+## 🔍 **Troubleshooting**
+
+### **Problem: WAL file is huge (>100MB)**
+
+```powershell
+# Force checkpoint
+sqlite3 database\BSK.db "PRAGMA wal_checkpoint(TRUNCATE);"
+
+# If it fails, connections are open:
+# Stop the server, then retry
+```
+
+### **Problem: "database is locked"**
+
+- Server is running → stop it first
+- Old connections → restart server
+- Check: `database\BSK.db-shm` (if exists, connections are active)
+
+### **Problem: Backup seems too small**
+
+```powershell
+# Check WAL size
+Get-Item database\BSK.db-wal
+
+# If WAL is large, you forgot to checkpoint!
+.\checkpoint_database.ps1
+```
+
+---
+
+## 📞 **Support**
+
+If you encounter data loss:
+1. **DON'T PANIC**
+2. **DON'T overwrite any files**
+3. Check if old backups exist on Google Drive
+4. Contact: [Your Support Contact]
+
+---
+
+## 📚 **Further Reading**
+
+- [SQLite WAL Mode Documentation](https://www.sqlite.org/wal.html)
+- [SQLite Backup Documentation](https://www.sqlite.org/backup.html)
+- [Understanding WAL Checkpoints](https://www.sqlite.org/wal.html#ckpt)
+
+---
+
+**Last Updated:** $(Get-Date -Format 'yyyy-MM-dd')
+**Version:** 1.0
+**Author:** BSK Development Team
+
diff --git a/database/BSK.db b/database/BSK.db
deleted file mode 100644
index 3705825..0000000
Binary files a/database/BSK.db and /dev/null differ
diff --git a/database/BSK.db-shm b/database/BSK.db-shm
deleted file mode 100644
index bb584d8..0000000
Binary files a/database/BSK.db-shm and /dev/null differ
diff --git a/database/BSK.db-wal b/database/BSK.db-wal
deleted file mode 100644
index 49b6f01..0000000
Binary files a/database/BSK.db-wal and /dev/null differ
diff --git a/pom.xml b/pom.xml
index 2da5cae..f61289f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -241,5 +241,12 @@
HikariCP5.1.0
+
+ com.yourcompany
+ jasper-fonts-timesnewroman
+ 1.0
+ system
+ ${project.basedir}/src/main/resources/fonts/timesnewroman-fonts.jar
+
\ No newline at end of file
diff --git a/src/main/java/BsK/client/ui/component/DataDialog/DataDialog.java b/src/main/java/BsK/client/ui/component/DataDialog/DataDialog.java
index 3ae2cdd..114f62b 100644
--- a/src/main/java/BsK/client/ui/component/DataDialog/DataDialog.java
+++ b/src/main/java/BsK/client/ui/component/DataDialog/DataDialog.java
@@ -12,7 +12,7 @@ import BsK.common.packet.res.DeleteCheckupResponse;
import BsK.common.packet.res.GetCheckupDataResponse;
import BsK.common.util.network.NetworkUtil;
import BsK.client.ui.component.CheckUpPage.CheckUpPage;
-import BsK.common.entity.CheckupData;
+ // import BsK.common.entity.CheckupData;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
diff --git a/src/main/java/BsK/client/ui/component/common/AddDialog/AddDialog.java b/src/main/java/BsK/client/ui/component/common/AddDialog/AddDialog.java
index 1679b16..8ec325e 100644
--- a/src/main/java/BsK/client/ui/component/common/AddDialog/AddDialog.java
+++ b/src/main/java/BsK/client/ui/component/common/AddDialog/AddDialog.java
@@ -997,10 +997,10 @@ private void setupDebounceSearch() {
JPanel searchPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
searchPanel.setBorder(BorderFactory.createTitledBorder("Tìm kiếm bệnh nhân"));
- //searchPanel.add(new JLabel("Tên BN:"));
+ searchPanel.add(new JLabel("Họ tên:"));
searchNameField = new JTextField(15);
- //searchPanel.add(searchNameField);
-
+ searchNameField.setToolTipText("Tìm kiếm theo họ tên (không cần dấu)");
+ searchPanel.add(searchNameField);
searchPanel.add(new JLabel("SĐT:"));
searchPhoneField = new JTextField(10);
diff --git a/src/main/java/BsK/server/Server.java b/src/main/java/BsK/server/Server.java
index e848ebd..e47c77b 100644
--- a/src/main/java/BsK/server/Server.java
+++ b/src/main/java/BsK/server/Server.java
@@ -332,9 +332,13 @@ public class Server {
}
/**
- * Initiates the backup of the main database file to Google Drive.
- * This is intended to be called from the ServerDashboard.
- * @throws IOException if the file cannot be found or the upload fails.
+ * Backs up the complete database set (BSK.db + WAL files) to Google Drive.
+ * Creates a timestamped folder and uploads all database files.
+ *
+ * This method backs up ALL database files (BSK.db, BSK.db-wal, BSK.db-shm)
+ * to prevent data loss from uncommitted WAL transactions.
+ *
+ * @throws IOException if the backup fails
*/
public static void backupDatabaseToDrive() throws IOException {
ServerDashboard dashboard = ServerDashboard.getInstance();
@@ -344,7 +348,7 @@ public class Server {
throw new IOException("Dịch vụ Google Drive không khả dụng.");
}
- // Define the path to the database
+ // Verify main database file exists
String dbPath = "database/BSK.db";
java.io.File dbFile = new java.io.File(dbPath);
@@ -353,7 +357,26 @@ public class Server {
throw new IOException("Không tìm thấy tệp cơ sở dữ liệu: " + dbPath);
}
- // Call the service to perform the backup
- googleDriveService.backupDatabaseFile(dbFile);
+ // Check for WAL files
+ java.io.File walFile = new java.io.File(dbPath + "-wal");
+ java.io.File shmFile = new java.io.File(dbPath + "-shm");
+
+ dashboard.addLog("Đang kiểm tra các tệp cơ sở dữ liệu...");
+ dashboard.addLog(" • BSK.db: " + (dbFile.length() / (1024 * 1024)) + " MB");
+
+ if (walFile.exists() && walFile.length() > 0) {
+ dashboard.addLog(" • BSK.db-wal: " + (walFile.length() / (1024 * 1024)) + " MB (chứa dữ liệu chưa commit)");
+ }
+
+ if (shmFile.exists()) {
+ dashboard.addLog(" • BSK.db-shm: " + (shmFile.length() / 1024) + " KB");
+ }
+
+ // Backup all files to a timestamped folder
+ dashboard.addLog("Đang tải lên tất cả các tệp database...");
+ String folderId = googleDriveService.backupCompleteDatabaseSet();
+
+ dashboard.addLog("✅ Sao lưu hoàn tất! Tất cả tệp đã được lưu vào Google Drive.");
+ log.info("Database backup completed successfully. Folder ID: {}", folderId);
}
}
\ No newline at end of file
diff --git a/src/main/java/BsK/server/database/DatabaseManager.java b/src/main/java/BsK/server/database/DatabaseManager.java
index 32a32ef..899ec82 100644
--- a/src/main/java/BsK/server/database/DatabaseManager.java
+++ b/src/main/java/BsK/server/database/DatabaseManager.java
@@ -47,4 +47,69 @@ public class DatabaseManager {
log.info("Database connection pool closed.");
}
}
+
+ /**
+ * Performs a WAL checkpoint to merge all WAL data into the main database file.
+ * This ensures the main .db file contains all recent data.
+ *
+ * IMPORTANT: Call this before backing up the database!
+ *
+ * Checkpoint modes:
+ * - PASSIVE: Tries to checkpoint without blocking (default)
+ * - FULL: Waits for all transactions to complete, then checkpoints
+ * - RESTART: Like FULL, then restarts the WAL
+ * - TRUNCATE: Like RESTART, then truncates WAL file to 0 bytes
+ *
+ * @param mode Checkpoint mode: "PASSIVE", "FULL", "RESTART", or "TRUNCATE"
+ * @return true if checkpoint succeeded, false otherwise
+ */
+ public static boolean checkpointWAL(String mode) {
+ log.info("Starting WAL checkpoint with mode: {}", mode);
+
+ try (Connection conn = getConnection();
+ var stmt = conn.createStatement()) {
+
+ // Execute checkpoint
+ var rs = stmt.executeQuery("PRAGMA wal_checkpoint(" + mode + ")");
+
+ if (rs.next()) {
+ int busy = rs.getInt(1); // 0 if successful, 1 if blocked
+ int walPages = rs.getInt(2); // Number of modified pages in WAL
+ int checkpointed = rs.getInt(3); // Number of pages checkpointed
+
+ if (busy == 0) {
+ log.info("✅ WAL checkpoint succeeded: {} pages checkpointed out of {} WAL pages",
+ checkpointed, walPages);
+ return true;
+ } else {
+ log.warn("⚠️ WAL checkpoint blocked by active transactions. " +
+ "Close all connections and try again.");
+ return false;
+ }
+ }
+
+ } catch (SQLException e) {
+ log.error("❌ Failed to checkpoint WAL", e);
+ return false;
+ }
+
+ return false;
+ }
+
+ /**
+ * Performs a FULL WAL checkpoint (recommended before backup).
+ * This ensures all data is written to the main database file.
+ *
+ * Usage example:
+ *
+ * // Before backing up database:
+ * DatabaseManager.checkpointWAL();
+ * // Now safe to copy BSK.db
+ *
+ *
+ * @return true if checkpoint succeeded, false otherwise
+ */
+ public static boolean checkpointWAL() {
+ return checkpointWAL("TRUNCATE");
+ }
}
\ No newline at end of file
diff --git a/src/main/java/BsK/server/network/handler/ServerHandler.java b/src/main/java/BsK/server/network/handler/ServerHandler.java
index 5173f6d..9107a22 100644
--- a/src/main/java/BsK/server/network/handler/ServerHandler.java
+++ b/src/main/java/BsK/server/network/handler/ServerHandler.java
@@ -385,10 +385,22 @@ public class ServerHandler extends SimpleChannelInboundHandler "v_" which matches "võ", "vò", "ve", "va", etc.
+ wildcardSearchPattern = createVietnameseWildcardPattern(accentStrippedSearchName);
+ }
+
if (hasNameSearch || hasPhoneSearch) {
queryBuilder.append(" WHERE ");
if (hasNameSearch) {
- // SỬA LỖI SQL: Dùng || thay vì CONCAT cho SQLite
+ // Use wildcard pattern that matches accented variants
queryBuilder.append("(LOWER(customer_first_name) LIKE ? OR LOWER(customer_last_name) LIKE ? OR ")
.append("LOWER(customer_last_name || ' ' || customer_first_name) LIKE ?)");
}
@@ -412,7 +424,7 @@ public class ServerHandler extends SimpleChannelInboundHandler resultList = new ArrayList<>();
while (rs.next()) {
String customerId = rs.getString("customer_id");
@@ -466,6 +478,9 @@ public class ServerHandler extends SimpleChannelInboundHandler "v_" (matches võ, vò, vó, vô, vơ, etc.)
+ * "nguyen" -> "n_u__n" (matches nguyễn, nguyen, etc.)
+ * "dat" -> "d_t" (matches đạt, dat, đát, etc.)
+ *
+ * @param input The search input (already lowercased and accent-stripped)
+ * @return SQL LIKE pattern with wildcards for accented characters
+ */
+ private String createVietnameseWildcardPattern(String input) {
+ StringBuilder pattern = new StringBuilder();
+
+ for (char c : input.toCharArray()) {
+ // Check if character is a Vietnamese vowel (including đ/d)
+ if (isVietnameseVowelOrD(c)) {
+ pattern.append('_'); // SQL wildcard for any single character
+ } else {
+ pattern.append(c);
+ }
+ }
+
+ return pattern.toString();
+ }
+
+ /**
+ * Checks if a character is a Vietnamese vowel or 'd/đ' that can have accents.
+ * Vietnamese vowels: a, ă, â, e, ê, i, o, ô, ơ, u, ư, y
+ * Also includes 'd' which can be 'đ'
+ */
+ private boolean isVietnameseVowelOrD(char c) {
+ return "aăâeêioôơuưyd".indexOf(c) >= 0;
+ }
+
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (cause instanceof IOException) {
diff --git a/src/main/java/BsK/server/service/GoogleDriveServiceOAuth.java b/src/main/java/BsK/server/service/GoogleDriveServiceOAuth.java
index 9816120..7a3be05 100644
--- a/src/main/java/BsK/server/service/GoogleDriveServiceOAuth.java
+++ b/src/main/java/BsK/server/service/GoogleDriveServiceOAuth.java
@@ -503,7 +503,9 @@ public class GoogleDriveServiceOAuth {
* @param dbFile The local database file to upload.
* @return The ID of the uploaded file in Google Drive.
* @throws IOException if the upload fails.
+ * @deprecated Use {@link #backupCompleteDatabaseSet()} instead to backup all WAL files
*/
+ @Deprecated
public String backupDatabaseFile(java.io.File dbFile) throws IOException {
// 1. Define the dedicated, private backup folder name
String backupFolderName = "_Database_Backups"; // Using underscore to sort it to the top
@@ -524,6 +526,79 @@ public class GoogleDriveServiceOAuth {
return fileId;
}
+ /**
+ * Backs up the complete database set (BSK.db, BSK.db-wal, BSK.db-shm) to Google Drive.
+ * Creates a timestamped folder and uploads all database files to prevent data loss.
+ *
+ * IMPORTANT: This method backs up ALL database files including WAL files to ensure
+ * no data is lost during backup.
+ *
+ * @return The folder ID of the backup folder containing all database files
+ * @throws IOException if any file upload fails
+ */
+ public String backupCompleteDatabaseSet() throws IOException {
+ // 1. Define the main backup folder name
+ String backupFolderName = "_Database_Backups";
+
+ // 2. Get or create the main backup folder
+ String mainBackupFolderId = findOrCreateFolder(this.rootFolderId, backupFolderName);
+ log.info("Using main database backup folder: {} (ID: {})", backupFolderName, mainBackupFolderId);
+
+ // 3. Create a timestamped subfolder for this backup session
+ String timestamp = new java.text.SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new java.util.Date());
+ String sessionFolderName = "Backup_" + timestamp;
+ String sessionFolderId = findOrCreateFolder(mainBackupFolderId, sessionFolderName);
+ log.info("Created backup session folder: {} (ID: {})", sessionFolderName, sessionFolderId);
+
+ // 4. Define all database files
+ String dbBasePath = "database/BSK.db";
+ java.io.File mainDbFile = new java.io.File(dbBasePath);
+ java.io.File walFile = new java.io.File(dbBasePath + "-wal");
+ java.io.File shmFile = new java.io.File(dbBasePath + "-shm");
+
+ int filesUploaded = 0;
+
+ // 5. Upload main database file (required)
+ if (!mainDbFile.exists()) {
+ throw new IOException("Main database file not found: " + dbBasePath);
+ }
+
+ log.info("Uploading main database file: BSK.db ({} MB)", mainDbFile.length() / (1024 * 1024));
+ uploadFileToFolder(sessionFolderId, mainDbFile, "BSK.db");
+ filesUploaded++;
+ log.info("✅ Uploaded BSK.db");
+
+ // 6. Upload WAL file (if exists)
+ if (walFile.exists()) {
+ long walSizeMB = walFile.length() / (1024 * 1024);
+ log.info("Uploading WAL file: BSK.db-wal ({} MB)", walSizeMB);
+
+ if (walSizeMB > 0) {
+ uploadFileToFolder(sessionFolderId, walFile, "BSK.db-wal");
+ filesUploaded++;
+ log.info("✅ Uploaded BSK.db-wal");
+ } else {
+ log.info("⏭️ Skipping empty WAL file");
+ }
+ } else {
+ log.info("ℹ️ No WAL file found (database may have been checkpointed)");
+ }
+
+ // 7. Upload SHM file (if exists)
+ if (shmFile.exists()) {
+ log.info("Uploading shared memory file: BSK.db-shm");
+ uploadFileToFolder(sessionFolderId, shmFile, "BSK.db-shm");
+ filesUploaded++;
+ log.info("✅ Uploaded BSK.db-shm");
+ } else {
+ log.info("ℹ️ No shared memory file found");
+ }
+
+ log.info("🎉 Database backup complete! {} file(s) uploaded to folder: {}", filesUploaded, sessionFolderName);
+
+ return sessionFolderId;
+ }
+
/**
* Deletes a file from Google Drive by its file ID.
* @param fileId The ID of the file to delete.
diff --git a/src/main/resources/print_forms/ultrasoundresult.jrxml b/src/main/resources/print_forms/ultrasoundresult.jrxml
index f289b14..4c5d521 100644
--- a/src/main/resources/print_forms/ultrasoundresult.jrxml
+++ b/src/main/resources/print_forms/ultrasoundresult.jrxml
@@ -60,36 +60,30 @@
-
+
-
+
-
-
-
-
+
-
+
-
+
-
-
-
@@ -252,9 +246,12 @@
-
+
+
+
+
diff --git a/src/main/resources/print_forms/ultrasoundresult_potrait.jrxml b/src/main/resources/print_forms/ultrasoundresult_potrait.jrxml
index 30d18cf..03510bb 100644
--- a/src/main/resources/print_forms/ultrasoundresult_potrait.jrxml
+++ b/src/main/resources/print_forms/ultrasoundresult_potrait.jrxml
@@ -65,34 +65,31 @@
-
+
-
+
-
-
-
-
+
-
+
-
+
-
+
@@ -170,7 +167,7 @@
-
+
@@ -185,7 +182,7 @@
-
+
diff --git a/temp/barcodes/invoice_barcode.png b/temp/barcodes/invoice_barcode.png
index 66a567e..8828c85 100644
Binary files a/temp/barcodes/invoice_barcode.png and b/temp/barcodes/invoice_barcode.png differ